Search code examples
angularangular2-routingangular2-templateangular2-formsangular2-services

Communicate between component via service observable fail


I want to create log-in form, when login successfully, the root component receive data then display it. I created login service and root component could receive notification with subscribe() method, but it seems not work. here is my code:

//app.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';

import { HttpConstant } from './constants/http.response';
import { LoginService } from './services/login.service';

@Component({
    moduleId: module.id,
    selector: 'app',
    templateUrl: 'app.component.html',
    providers: [LoginService]
})

export class AppComponent {
  currentUser = 'Anonymous';

  constructor(private loginService: LoginService) {
      console.log(loginService);
      loginService.logInAnnouncement$.subscribe(email => {
          console.log(email);
          this.currentUser = email;
      });
  }
}
//login.service.ts
import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Observable } from 'rxjs';
import { Subject }    from 'rxjs/Subject';

import { Profile } from '../entities/profile';
import { GuardService } from './guard.service';

@Injectable()
export class LoginService {

    private headers = new Headers();
    private loginUrl = 'api/v1/auth/login';
    private email = new Subject<string>();

    /**
    * Observable string streams
    */
    logInAnnouncement$ = this.email.asObservable();

    constructor(private http: Http, private guard: GuardService) {
    }

    login(email, password): Observable<any> {
        this.headers.append('Content-Type', 'application/json');
        this.headers.append('Accept', 'application/json');
        return this.http
          .post(this.loginUrl, JSON.stringify({email: email, password: password}), {headers: this.headers})
          .map((res:Response) => res.json());
    }

    announceLogIn(email: string) {
        this.email.next(email);
        this.logInAnnouncement$.subscribe(email=>{
            console.log(email);
        });
        console.log('OK');
    }
}
//login.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { LoginService } from '../services/login.service';
import { Profile } from '../entities/profile';
import { HttpConstant } from '../constants/http.response';


@Component({
    moduleId: module.id,
    selector: 'fix-login',
    templateUrl: 'login.component.html',
    providers: [LoginService, HttpConstant],
})

export class LoginComponent implements OnInit {

    profile: Profile;
    validatingHandler: ValidateError;
    // profile: Profile;

    constructor(private loginService: LoginService,
                 private router: Router) { 
        this.profile = new Profile();
        this.validatingHandler = new ValidateError();
    }

    ngOnInit(): void {

    }

    doLogin(event): void {
        event.preventDefault();
        this.loginService.login(this.profile.email, this.profile.password)
            .subscribe((data: Object) => {
                if (data.status == 0) {
                    this.loginService.announceLogIn(this.profile.email);
                    this.router.navigate(['/']);
                }
            }, err => { 

                if (err.status == HttpConstant.HTTP_INVALID_INPUT ) {
                    this.validatingError(err.json());
                }
            })

    }

    private validatingError(error): void {
        this.validatingHandler = new ValidateError();
        this.validatingHandler._email = error.email;
        this.validatingHandler._password = error.password;
    }


}

class ValidateError {
    _email: string;
    _password: string;
}

Solution

  • Don't add LoginService to providers of every component. This way every component will get its own instance injected.

    Add it to providers of @NgModule() instead, this way all components will get the same instance injected.