angular 2 observable.subscribe не выполняется до тех пор, пока не будет вызван во второй раз

#angularjs #angular2-services #angular2-observables

#angularjs #angular2-services #angular2-observables

Вопрос:

Я пытаюсь заставить этот компонент получать строковые данные из сервиса, который возвращает наблюдаемое

 import { Component, OnInit, OnDestroy } from '@angular/core';
import { TabFourService } from "./tabfour.service";
import { Subscription } from "rxjs";

@Component({
    selector: 'tab-four',
    template: `
                {{title}}
              `
})

export class TabFourComponent implements OnInit, OnDestroy{
    title: string = "This is Tab four";

    subscription: Subscription;

    constructor(private tabfourService: TabFourService){}

    ngOnInit(){
        console.log("now in init");
        this.getItems();
        this.getItems();
    }

    getItems(){
        console.log("now in get items");
        this.subscription = this.tabfourService.getItems()
                                .subscribe(data => console.log("testing observable"));
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}
  

Вот простой сервис:

 import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';
import { Observable } from "rxjs";

@Injectable()
export class TabFourService {
    items: string;

    private itemSource = new Subject<string>();

    constructor(){}

    itemSource$ = this.itemSource.asObservable();

    getItems(): Observable<string> {
        this.itemSource.next("aaa");
        return this.itemSource$;
    }

}
  

Я указываю службу в качестве поставщика в @NgModule (), чтобы она могла использоваться всеми экземплярами компонента. Существует также маршрутизатор для TabFourComponent, поэтому каждый раз, когда я перехожу к нему, я должен видеть «testing observable» в консоли.
Но это не отображалось, пока я дважды не вызвал GetItems ().
Интересно, почему это не сработало в первый раз.

 tabfour.component.ts:20  now in init
tabfour.component.ts:26  now in get items
tabfour.component.ts:26  now in get items
tabfour.component.ts:28  testing observable
  

Редактировать:

В то время как в другом случае, когда службы предоставляют данные из http.get

 // in service
getLibraryFromDatabase(): Observable<any[]> {
  return this.http.get(<some url>)
             .map(data => data.json())
             .catch(this.handleError);
}
  

Компоненту не нужно снова вызывать метод сервиса после подписки.

 // in component
ngOnInit() {
    this.subscription = this.libraryService.getLibraryFromDatabase()
                        .subscribe(libs => this.createLibs(libs));
}
  

Комментарии:

1. В случае, указанном при редактировании, вы одновременно оформляете подписку на метод И выполняете http-вызов в методе, на который вы подписываетесь.

Ответ №1:

Если подписанный метод не вызывается до второго выполнения GetItems(), это потому, что событие инициируется ДО того, как подписка будет взята на себя ответственность. Зарегистрируйте подписку в методе ngOnInit (это лучшее место для выполнения подобных действий), а затем вызовите метод, который запускает событие, на которое вы подписались:

 ngOnInit() {
    this.subscription = this.tabfourService.getItems()
                            .subscribe(data => console.log("testing observable"));
    // The subscription has been taken in charge, now call the service's method
    this.tabFourService.getItems();
}
  

Комментарии:

1. Спасибо за ваш ответ. Я отредактировал свой вопросительный пост, приведя к другой ситуации. Интересно, в чем разница между ними. Почему в предыдущем случае нам нужно сначала зарегистрировать подписку?