2016-01-21 27 views
21

Nella mia applicazione ho alcuni componenti che comunicano tramite EventService.Angular2, annullare l'iscrizione dall'evento in ngOnDestroy

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

Questo servizio viene iniettato in una EmitterComponent che emette l'evento quando un pulsante viene premuto

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

e in un ReceiverComponent che sottoscrive l'evento e per ogni evento incrementi ricevuto un contatore

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

L'applicazione ha più viste (in questo esempio solo due): PageA e PageB. EmitterComponent e ReceiverComponent sono in PageA. Ogni volta che vado a PageB e torno a PageA, viene creato un nuovo ReceiverComponent e quando faccio clic sul pulsante in EmitterComponent, la funzione di callback dell'evento di ReceiverComponent viene eseguita più volte.

Per evitare questo a cancellarmi ReceiverComponent da myEvent in ngOnDestroy

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

ma questo fa sì che la seguente eccezione

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

Come posso evitare questo? Come annullare l'iscrizione correttamente?

Per una migliore comprensione, ho creato questo plunker in cui è possibile visualizzare l'errore e alcuni commenti nella console.

risposta

30

È possibile ottenere un abbonamento da .subscribe(). Usa il suo metodo unsubscribe() per annullare l'abbonamento.

@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(); 
    } 
} 

Vedi anche

+0

Questo è esattamente quello che ho fatto, ma questo provoca "Errore: Impossibile iscriversi a un soggetto disposto" quando cambio al fine di paginaB e tornare a paginaA – TizianoL

+3

Non sembra il lo stesso per me. Mi sto perdendo qualcosa? Nella tua domanda usi 'this.eventService.myEvent.unsubscribe();' vs 'subscription.unsubscribe();'. –

+1

Oh, mi dispiace, mio ​​male, non ho notato la differenza. Ora funziona, grazie mille! – TizianoL

2

Penso che il tuo dovrebbe annullare l'abbonamento, come descritto di seguito:

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 effetti, EventEmitter s sono osservabili condivisi, cioè osservabili caldi. Ecco un link che potrebbe interessarti: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md.

Spero che ti aiuta, Thierry