ObjectUnsubscribedError при попытке запретить подписку дважды
У меня есть Сервис и компонент, который его использует:
-
PagesService
-
PagesListComponent
В PagesService
у меня есть массив Pages
. Я уведомляю об изменениях в массиве через BehaviorSubject
, на который оба подписаны.
PagesService
предоставляются в bootstrap
, чтобы иметь только один общий экземпляр. Это потому, что мне нужно сохранить массив, а не загружать страницы каждый раз, когда они нужны.
Код следующий:
pages.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/Rx';
import { Http, Response } from '@angular/http';
import { Page } from './../models/page';
@Injectable() export class PagesService {
public pages$: BehaviorSubject<Page[]> = new BehaviorSubject<Page[]>([]);
private pages: Page[] = [];
constructor(private http: Http) { }
getPagesListener() {
return this.pages$;
}
getAll() {
this.http.get('/mockups/pages.json').map((res: Response) => res.json()).subscribe(
res => { this.resetPagesFromJson(res); },
err => { console.log('Pages could not be fetched'); }
);
}
private resetPagesFromJson(pagesArr: Array<any>) {
// Parses de Array<any> and creates an Array<Page>
this.pages$.next(this.pages);
}
}
pages_list.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router-deprecated';
import { BehaviorSubject } from 'rxjs/Rx';
import { PagesService } from '../../shared/services/pages.service';
import { GoPage } from '../../shared/models/page';
@Component({
moduleId: module.id,
selector: 'go-pages-list',
templateUrl: 'pages_list.component.html',
styleUrls: ['pages_list.component.css']
})
export class PagesListComponent implements OnInit {
pages$: BehaviorSubject<GoPage[]>;
pages: GoPage[];
constructor(private pagesService: PagesService, private router: Router) { }
ngOnInit() {
this.pages$ = this.pagesService.getPagesListener();
this.pages$.subscribe((pages) => { this.pages = pages; console.log(pages) });
this.pagesService.getAll();
}
ngOnDestroy() {
this.pages$.unsubscribe();
}
}
Это отлично работает в первый раз, как подписка onInit, так и отказ от подписки onDestroy. Но когда я вернусь в список и попытаюсь снова подписаться (чтобы получить текущее значение страниц [] и прослушать будущие изменения), он запускает ошибку EXCEPTION: ObjectUnsubscribedError
.
Если я не откажусь от подписки, каждый раз, когда я вхожу в список, новая подписка укладывается в стек, и все они запускаются, когда получен следующий().
Ответы
Ответ 1
Я бы получил подписку и отменил ее подписку таким образом, а не по теме напрямую:
ngOnInit() {
this.pages$ = this.pagesService.getPagesListener();
this.subscription = this.pages$.subscribe((pages) => { // <-------
this.pages = pages; console.log(pages);
});
this.pagesService.getAll();
}
ngOnDestroy() {
this.subscription.unsubscribe(); // <-------
}
Ответ 2
.subscribe() возвращает подписку
- Вы должны использовать это, чтобы отменить подписку
например
У родителя есть reloadSubject: Subject;
- child1 → подписка
- child2 → подписка
child1 - "WORKS" → отписаться от подписки
ngOnInit{
sub: Subscription = parent.subscribe();
}
onDestroy{
this.sub.unsubscribe();
}
child2 - "НЕ РАБОТАЕТ" → отменить подписку на весь родительский
ngOnInit{
parent.subscribe();
}
onDestroy{
parent.unsubscribe();
}
Если вы вызываете отказ от подписки на родителя, у обоих детей нет.
Если вы отмените подписку, которую вы получаете от .subscribe()
то только один ребенок не подписывается.
Пожалуйста, поправьте меня, если я ошибаюсь!