Angular 4 Subscribing to observable is not updating after change

Steve picture Steve · Aug 16, 2017 · Viewed 9.8k times · Source

I have a service with an observable which is being subscribed to via a component. This seems to work as the subscriber is showing the initial value. I have another component which is then updating the observable however the new value does not get shown.

Service:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of'; 

@Injectable()

export class BannerService {

    banners$: Observable<any[]> = Observable.of([]);

    getBanners(): Observable<any[]> {
        return this.banners$;
    }

    setBanners(banners: any[]): void {
        this.banners$ = Observable.of(banners);
    }

}

Component with subscriber:

import { Component, ViewEncapsulation, OnInit } from '@angular/core';

import { BannerService } from './../banner/banner.service';

@Component({
    selector: '.banner',
    templateUrl: './banner.component.html',
    styleUrls: ['./banner.component.sass'],
    encapsulation: ViewEncapsulation.None
})

export class BannerComponent implements OnInit {

    constructor(private bannerService: BannerService){}

    ngOnInit() {
        this.bannerService.banners$.subscribe(banners => {
            console.log(banners);
        });

    }
}

Component with setter:

import { Component, ViewEncapsulation, OnInit } from '@angular/core';

import { BannerService } from './../banner/banner.service';

@Component({
    selector: '.home-component',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.sass'],
    encapsulation: ViewEncapsulation.None
})

export class HomeComponent implements OnInit {

    data = {
        banners: [
            {
                title: 'Title 1',
                image: '../images/image1.jpg'
            },
            {
                title: 'Title 2',
                image: '../images/image2.jpg'
            },
            {
                title: 'Title 3',
                image: '../images/image3.jpg'
            }
        ]
    }

    constructor(private bannerService: BannerService){}

    ngOnInit(): void {
        this.bannerService.setBanners(this.data.banners);
    }

}

Any help would be really appreciated, I've tried a bunch of different things and can't get it working.

Answer

JB Nizet picture JB Nizet · Aug 16, 2017

You subscribe to an observable, and then you replace that observable by another one.

That's like giving someone an email address where he can read mails you send to him, but then replacing that email address by another one every time you send an email. Obviously, the receiver will never receive your mails if you send them to a different address.

You need to use the same, unique observable, and make it emit a new event. Using a Subject is the easiest way to do that:

banners$: Subject<any[]> = new BehaviorSubject<any[]>([]);

setBanners(banners: any[]): void {
    this.banners$.next(banners);
}