Подтвердить что ты не робот

Angular2, отписаться от события в ngOnDestroy

В моем приложении у меня есть некоторые компоненты, которые обмениваются с помощью EventService.

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

Эта услуга вводится в EmitterComponent, которая испускает событие при нажатии кнопки

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

и в ReceiverComponent, который подписывается на событие и для каждого полученного события увеличивается счетчик

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

Приложение имеет несколько видов (в этом примере всего два): PageA и PageB. EmitterComponent и ReceiverComponent находятся в PageA. Каждый раз, когда я перехожу к PageB и возвращаюсь к PageA, создается новый ReceiverComponent, и когда я нажимаю кнопку в EmitterComponent, функция обратного вызова события ReceiverComponent выполняется несколько раз.

Чтобы этого избежать, я отписываю ReceiverComponent из myEvent в ngOnDestroy

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

но это вызывает следующее исключение

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

Как я могу избежать этого? Как правильно отписаться?

Для лучшего понимания я создал этот plunker, где вы можете увидеть ошибку и некоторые комментарии в консоли.

4b9b3361

Ответ 1

Вы получаете подписку от .subscribe(). Используйте метод unsubscribe() для отмены подписки.

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

См. также

Ответ 2

Я думаю, что вы должны отменить подписку, как описано ниже:

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

Фактически, EventEmitter являются общими наблюдаемыми, то есть горячими наблюдаемыми. Вот ссылка, которая может вас заинтересовать: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md.

Надеюсь, это поможет вам, Thierry