1

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

n00dl3
  • 21,213
  • 7
  • 66
  • 76
Athomas
  • 533
  • 1
  • 6
  • 19
  • I suggest you to check this question: http://stackoverflow.com/questions/36076700/what-is-the-proper-use-of-an-eventemitter, you shouldn't use `@Output` in your services – eko May 17 '17 at 10:38

1 Answers1

4

@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));
Community
  • 1
  • 1
n00dl3
  • 21,213
  • 7
  • 66
  • 76
  • I tried this, still the method in subscribe in the component is not being executed – Athomas May 17 '17 at 11:13
  • is `authenticate` called somewhere ? – n00dl3 May 17 '17 at 11:14
  • Yes, authenticate service is called from a component. Its being executed without any issue. – Athomas May 17 '17 at 11:15
  • Can you reproduce in plunkr ? – n00dl3 May 17 '17 at 11:19
  • @ConfusionPrevails how do you know the method in subscribe is not called? – eko May 17 '17 at 11:26
  • I have put logs in the method executed in subscribe i.e, in setName, they are not printed. Neither is the value of the variable updated. – Athomas May 17 '17 at 11:28
  • @n00dl3 I have added the code to plunkr. I haven't used plunkr before, so not sure if this is the right way. Thank you for the help.plnkr.co/edit/CpnQlf0CkkaiYvOk0h1y?p=preview – Athomas May 17 '17 at 12:03
  • I realized my mistake. I had added LoginService as provider in Header component as well as LoginComponent. After I moved this to app.module, I am getting the right value in subscribe. – Athomas May 17 '17 at 12:44