Search code examples
angularobservableangular2-servicesangular-cli

Subscription to an Observable never triggers


I created a project with Angular-CLI 1.0.0-beta.18 (updated yesterday). I'm trying to detect a change in a service, from a component.

  • I create an observable in the service
  • I subscribe to it from the component
  • The subscription never triggers on update :/

I tried to implement the solution from this answer, this Plunkr and this cookbook, no dice.

Here's the service :

import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Article } from './article';

@Injectable()
export class ArticleService {

    // Placeholder for article's
     articles: Article[] = [
         { _id: 1, title: "Article 1", text: "Text for article 1", created: new Date() },
         { _id: 2, title: "Article 2", text: "Text for article 2", created: new Date() }
     ];

    // Observable openArticle source
    private _openArticleSource = new ReplaySubject<Article>(1);
    // Observable openArticle stream
    openArticle$ = this._openArticleSource.asObservable();

    // Simulate GET /articles/:_id
    getArticleById(_id: number): Article {
        let article = this.articles
            .filter(article => article._id === _id)
            .pop();

        console.log("Pushing article to observable : ", article) // This gets logged, along with the article
        this._openArticleSource.next(article); // Should trigger the subscription, but doesn't

        return article;
    }
}

Here's the listening component :

import { Component } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { ArticleService } from '../article.service';

@Component({
  selector: 'column-open-article',
  templateUrl: './column-open-article.component.html',
  providers: [ArticleService]
})


export class ColumnOpenArticleComponent {

  openArticle;
  subscription: Subscription;

  constructor(private articleService: ArticleService) {
    this.subscription = articleService
              .openArticle$
              .subscribe(article => {
                console.log("Subscription triggered", article); // Never gets logged
                this.openArticle = article; // Never gets updated
              })
  }


  ngOnDestroy() {
    // prevent memory leak when component is destroyed
    console.log("Unsubscribing")
    this.subscription.unsubscribe();
  }
}

Then I call getArticleById(1) from another component, and I can see "Pushing article to observable" in the console, so the observable is updated but doesn't trigger the subscription.

If I place the subscription directly inside the service, it triggers without problem, and I can see "Subscription triggered" in the console.

But if I place the same code in the component, it doesn't work.

Any ideas?


Solution

  • Looks like you have multiple instances of ArticleService.

    Don't provide ArticleService on every component because this way every component instance will get a new ArticleService instance.

    Either provide it on a common parent component so that both get the same instance from the parent injected

    or

    provide it in @NgModule{ providers: [ArticleService]}, then it will be provided at the application root scope andevery component and service that injects ArticleService will get the same instance injected.