web-dev-qa-db-fra.com

ObjectUnsubscribedError lors de la tentative d'empêcher deux abonnements

J'ai un service et un composant qui l'utilise:

  • PagesService
  • PagesListComponent

Dans le PagesService j'ai un tableau de Pages. Je notifie les changements dans le tableau via un BehaviorSubject auquel les deux sont abonnés.

Les PagesService sont fournis dans bootstrap, pour avoir une seule instance partagée. C'est parce que je dois conserver le tableau, au lieu de télécharger les pages chaque fois qu'elles sont nécessaires.

Le code est le suivant:

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

Cela fonctionne très bien la première fois, à la fois l'abonnement onInit et la désinscription onDestroy. Mais quand je reviens à la liste et essaie de m'abonner à nouveau (pour récupérer la valeur actuelle des pages [] et écouter les changements futurs), il déclenche l'erreurEXCEPTION: ObjectUnsubscribedError.

Si je ne me désabonne pas, chaque fois que j'entre dans la liste, un nouvel abonnement est empilé et tous sont renvoyés lors de la réception d'un prochain ().

33
AlvYuste

J'obtiendrais l'abonnement et je me désabonnerais de cette manière et non directement sur le sujet:

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(); // <-------
}
69
Thierry Templier

.subscribe () renvoie un abonnement

  • Vous devez l'utiliser pour vous désinscrire


par exemple. Le parent a un reloadSubject: Subject;

  • child1 -> s'abonne
  • child2 -> s'abonne

child1 - "WORKS" -> se désabonner de son abonnement

ngOnInit{ 
  sub: Subscription = parent.subscribe();
}
onDestroy{
  this.sub.unsubscribe();
}


child2 - "NE FONCTIONNE PAS" -> se désinscrire est le parent entier

ngOnInit{ 
  parent.subscribe();
}

onDestroy{
  parent.unsubscribe();
}

Si vous appelez le désabonnement du parent, les deux enfants sont partis.
Si vous vous désabonnez de l'abonnement que vous obtenez du .subscribe (), alors un seul enfant est désabonné.

S'il vous plait corrigez moi si je me trompe!

11
WorstCoderEver