Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2, unsubsribe from event in ngOnDestroy [duplicate]

Tags:

In my application I have some components that communicate by means of EventService.

@Injectable() export class EventService {   public myEvent: EventEmitter<any> = new EventEmitter();   constructor() {} } 

This service is injected in a EmitterComponent that emits the event when a button is clicked

@Component({   selector: 'emitter',   template: `<button (click)="onClick()">Click me</button>`, }) export class EmitterComponent {   constructor(private eventService:EventService) {}   onClick() {     this.eventService.myEvent.emit();   } } 

and in a ReceiverComponent that subscribes to the event and for each event received increments a counter

@Component({   selector: 'receiver',   template: `Count: {{count}}`, }) export class ReceiverComponent {   public count = 0;   constructor(private eventService:EventService) {     this.eventService.myEvent.subscribe(() => this.count++;);   } } 

The application has multiple views (in this example just two): PageA and PageB. EmitterComponent and ReceiverComponent are in PageA. Every time I go to PageB and come back to PageA, a new ReceiverComponent is created and when I click the button in EmitterComponent, the event callback function of ReceiverComponent is executed several times.

To avoid this I unsubscribe ReceiverComponent from myEvent in ngOnDestroy

ngOnDestroy() {   this.eventService.myEvent.unsubscribe(); } 

but this causes the following Exception

EXCEPTION: Error during instantiation of ReceiverComponent!. ORIGINAL EXCEPTION: Error: Cannot subscribe to a disposed Subject 

How can I avoid that? How to unsubscribe correctly?

For a better understanding I've created this plunker where you can see the error and some comments in the console.

like image 430
TizianoL Avatar asked Jan 21 '16 14:01

TizianoL


2 Answers

You get a subscription from .subscribe(). Use its unsubscribe() method to cancel the subscription.

@Component({   selector: 'receiver',   template: `Count: {{count}}`, }) export class ReceiverComponent {   public count = 0;   private subscription;   constructor(private eventService:EventService) {     this.subscription = this.eventService.myEvent.subscribe(() => this.count++;);   }   ngOnDestroy() {     this.subscription.unsubscribe();   } } 

See also

  • how to unsubscribe several subscriber in angular 2

  • timer.unsubscribe is not a function Angular2

like image 52
Günter Zöchbauer Avatar answered Oct 07 '22 23:10

Günter Zöchbauer


I think your should cancel the subscription, as described below:

export class ReceiverComponent {   public count = 0;   private id;    constructor(private eventService:EventService) {     this.id = Date.now();     console.log("ReceiverComponent constructor " + this.id);     this.subscription = this.eventService.myEvent.subscribe(() => {       console.log("count " + this.count + " (id ReceiverComponent instance: " + this.id + ")");       this.count++;     });   }    ngOnDestroy() {     console.log("onDestroy of ReceiverComponent " + this.id)     //this cause "Cannot subscribe to a disposed Subject."     //this.eventService.myEvent.unsubscribe();     this.subscription.unsubscribe();   } } 

In fact, EventEmitters are shared observables, i.e. hot observables. Here is a link that could interest you: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md.

Hope it helps you, Thierry

like image 28
Thierry Templier Avatar answered Oct 08 '22 00:10

Thierry Templier