31
// Part of service
public someEvent: EventEmitter<number> = new EventEmitter();

....

// Component
@Component({
  selector: 'some-component',
  template: `...`
})
export class SomeComponent {
  constructor(public service: Service) {
    this.service.someEvent.subscribe((x) => {
      // Do something
    });
  }
}

SomeComponent is displayed in / route. When I navigate to different route in my application, and come back again, SomeComponent will subscribe to the event again, causing callback to fire twice. How to subscribe to the event once or unsubscribe on destroy of the component and subscribe again?

// Can't subscribe after.
ngOnDestroy() {
  this.service.someEvent.unsubscribe();
}
Eggy
  • 4,052
  • 7
  • 23
  • 39
  • Have you tried it with ngOnInit? – micronyks Jan 17 '16 at 13:59
  • @micronyks Yes I did, no success though. Also according to [this site](http://learnangular2.com/lifecycle/) `ngOnInit` is fired every time just like constructor function, but it waits for child components to initialize. – Eggy Jan 17 '16 at 14:02
  • 1
    `OnInit` is for binding, not gonna work for you... try [`CanReuse`](https://angular.io/docs/ts/latest/api/router/CanReuse-interface.html) – Sasxa Jan 17 '16 at 14:04
  • `EventEmitter` is **not** supposed to be used in services but only for `@Output()`s of components and directives. Use `Observable` or `Subject` instead. – Günter Zöchbauer Sep 28 '16 at 05:14
  • In my case, after I navigate another route and come back again, the subscription is not triggering which I couldn't resolved. I use it on 'NgOnInit' method, and also have unsubscribe method on 'NgOnDestroy' method – İsmail Şener Mar 16 '17 at 12:36
  • I have a similar problem.. but still using unsubscribe the issue is there. https://stackoverflow.com/questions/44464655/angular-2-app-events-are-raised-multiple-times – Rolando Jun 09 '17 at 21:43

2 Answers2

39

A call to subscribe returns an instance of Disposable, which has a method dispose.

Or if you are using RxJS 5, dispose has been renamed to unsubscribe (thanks @EricMartinez).

And from the RxJS docs:

...when we're no longer interested in receiving the data as it comes streaming in, we call dispose on our subscription.


Store the result of your call to subscribe and later dispose of the subscription within ngOnDestroy.

RxJS 5:

export class SomeComponent implements OnDestroy {
  constructor(public service: Service) {
    this.subscription = this.service.someEvent.subscribe((x) => {...});
  }
  ngOnDestroy() {
      this.subscription.unsubscribe();
  }
}

RxJS <5:

export class SomeComponent implements OnDestroy {
  constructor(public service: Service) {
    this.subscription = this.service.someEvent.subscribe((x) => {...});
  }
  ngOnDestroy() {
      this.subscription.dispose();
  }
}
Raphaël Balet
  • 6,334
  • 6
  • 41
  • 78
sdgluck
  • 24,894
  • 8
  • 75
  • 90
  • 5
    In RxJS 5 [dispose was renamed to unsubscribe](https://github.com/ReactiveX/RxJS/blob/master/MIGRATION.md#subscription-dispose-is-now-unsubscribe) – Eric Martinez Jan 17 '16 at 14:23
  • 2
    Thanks! Just like @EricMartinez said, `unsubscribe` instead of `dispose`. – Eggy Jan 17 '16 at 14:28
  • I am having the same problem with the event emitter firing 1, 2, 3 or more times. When I add unsubscribe to ngOnDestroy, however, I get "ObjectUnsubscribedError" :( – brando Apr 12 '16 at 20:01
  • Never mind: I fixed it by doing this.subscription = this.service.someEvent.subscribe((x) => {...}); in the constructor – brando Apr 12 '16 at 20:34
4

You can do something like this:

import { OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Rx';

export class SomeComponent implements OnDestroy {
  private _subscription: Subscription;
  constructor(public service: Service) {
    this._subscription = this.service.someEvent.subscribe((x) => {
      // Do something
    });
  }
}

ngOnDestroy(){
  this._subscription.unsubscribe();
}
S2S2
  • 8,322
  • 5
  • 37
  • 65
ShellZero
  • 4,415
  • 12
  • 38
  • 56