6

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.

Steve
  • 4,314
  • 3
  • 16
  • 21
  • Issue not resolving with this fix, can anyone help https://stackoverflow.com/questions/48973734/model-updates-but-angular-ui-does-not-rerender – kasimkha Feb 25 '18 at 13:13

1 Answers1

18

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);
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Awesome! Thanks for the quick reply. It seems to be working now, I had to change it to "new BehaviorSubject([])" as the angled brackets were causing an error. – Steve Aug 16 '17 at 17:16
  • Ah, sorry. I mixed up Java and TS. – JB Nizet Aug 16 '17 at 17:23
  • I would also add, all these years later, if you dont want the initial object to be sent out, use a replaySubject instead of a BehaviorSubject. – Aaron Gibson Mar 15 '22 at 14:28