Search code examples
angularangular2-serviceseventemitter

Using event emitter in Angular2 to share data between service and component


I have an angular2 application in which I have a login page. After login, I would like to display the user name in the header component.

    @Output() getUserName = new EventEmitter();

In the authenticate method of service

authenticate(loginRequest)  {
    let headers = new Headers({ 'Content-Type' : 'application/json' });
    let options = new RequestOptions({ headers: headers });
    let authenticateResp = this.http.post("http://localhost:8080/authenticate", JSON.stringify(loginRequest), options).map(result => result.json());
    authenticateResp.subscribe((authenticate => {
        this.getUserName.emit("My Name");
    }));    

    return authenticateResp; 
}

In the header component in constructor

@Component({
 .....
 providers:[LoginService]
})
export class HeaderComponent {
  userName : string;
  constructor(private loginService : LoginService) { 

      loginService.getUserName.subscribe(authenticated => this.setName(authenticated));
  }

  setName(authenticated) {
    this.userName = authenticated;
  }

}

When I debug, I can see the event emitting code getting executed, but the code in subscribe in the component is not called. What am I doing wrong here?

Appreciate any help


Solution

  • @Output() and EventEmitter are not meant to be used inside a service, as they are designed for inter-component communication.

    EventEmitter is (for now) a subclass of Subject, a standard Subject, will not keep the latest emitted value in memory, so if a value is emitted while there is no subscriber, the value just got ignored.

    A ReplaySubject will repeat the last emitted value to any new subscriber.

    Notes:

    • it is a good practice to only expose Observable instead of Subject.
    • You don't want to subscribe to authenticateResp inside your authenticate method and return authenticateResp at the same time as this will trigger the request twice if you subscribe to the returned value. You should use the do() operator, return the observable and subscribe where you need that data.
    private _userName = new ReplaySubject<string>();
    
    userName=this._userName.asObservable();
    
    authenticate(loginRequest)  {
        let headers = new Headers({ 'Content-Type' : 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this.http.post("http://localhost:8080/authenticate", JSON.stringify(loginRequest), options)
            .map(result => result.json())
            .do((authenticate => this._userName.next("My Name")));    
    }
    

    and inside your component :

    loginService.userName.subscribe(authenticated => this.setName(authenticated));