2016-06-28 9 views
12

abonniert haben einen Dienst und eine Komponente zu verhindern versuchen, die es verwendet:ObjectUnsubscribedError, wenn ich zweimal

  • PagesService
  • PagesListComponent

Im PagesService ich eine Reihe von Pages haben. I benachrichtigen Änderungen in der Anordnung über einen BehaviorSubject die beide abonniert haben.

Die PagesService werden unter bootstrap bereitgestellt, damit nur eine Instanz freigegeben wird. Das liegt daran, dass ich das Array behalten muss, anstatt die Seiten jedes Mal herunterzuladen, wenn sie benötigt werden.

Der Code ist der folgende:

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

Dies funktioniert das erste Mal, beide das Abonnement onInit und de Abmeldung onDestroy. Aber wenn ich zu der Liste zurückkomme und versuche, mich erneut anzumelden (um den aktuellen Wert von Seiten [] abzurufen und auf zukünftige Änderungen zu warten), löst es den FehlerEXCEPTION: ObjectUnsubscribedError aus.

Wenn ich mich nicht abmelde, wird jedes Mal, wenn ich in die Liste eintrete, ein neues Abonnement gestapelt, und alle werden ausgelöst, wenn ein next() empfangen wird.

Antwort

30

Ich würde das Abonnement erhalten und abmelden auf es auf diese Weise und nicht auf das Motiv direkt:

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

können Sie erwähnen, warum hat das direkte Abmelden auf dem injizierten Betreff nicht funktioniert? –

5

.subscribe() gibt ein Abonnement

  • du
  • abmelden verwenden sollten


zB Parent hat ein reloadSubject: Betreff;

  • child1 -> abonniert
  • child2 -> abonniert

child1 - "WORKS" -> sein Abonnement

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


child2 die Abmelden - "funktioniert nicht" - > das gesamte Elternteil abmelden

ngOnInit{ 
    parent.subscribe(); 
} 

onDestroy{ 
    parent.unsubscribe(); 
} 

Wenn Sie auf der übergeordneten abmelden rufen beide Kinder weg sind.
Wenn Sie das Abonnement abmelden, die Sie von der bekommen.subscribe() dann wird nur ein Kind abgemeldet.

Bitte korrigieren Sie mich, wenn ich falsch liege!