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

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.

Если я не откажусь от подписки, каждый раз, когда я вхожу в список, новая подписка укладывается в стек, и все они запускаются, когда получен следующий().

4b9b3361

Ответ 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() то только один ребенок не подписывается.

Пожалуйста, поправьте меня, если я ошибаюсь!