Search code examples
angularangular-servicesangular-components

Subscription in Component not receiving values from shared service Observable


I have this service:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MissionService {
    // Observable string sources
    private missionAnnouncedSource = new Subject<string>();
    private missionConfirmedSource = new Subject<string>();
    // Observable string streams
    missionAnnounced$ = this.missionAnnouncedSource.asObservable();
    missionConfirmed$ = this.missionConfirmedSource.asObservable();
    // Service message commands
    announceMission(mission: string) {
        this.missionAnnouncedSource.next(mission);
    }
    confirmMission(astronaut: string) {
        this.missionConfirmedSource.next(astronaut);
    }
}

This component:

export class ComponentOne {
    constructor(private service: MissionService) { }

    onClick() {
        console.log('entered in the onclick method');
        this.service.announceMission('mission started');
        this.service.missionAnnounced$.subscribe(response => console.log('from component 1: ' + response), error => console.log('error: ', error))
    }
}

This other component:

   export class ComponentTwo {
        constructor(private service: MissionService) {
        console.log('entered in constructor ComponentTwo')
            this.service.missionAnnounced$.subscribe(response => console.log('from component 2: ' + response),
                error => console.log('error: ', error));
        }
    }

I don't know why the console.log inside subscribe() with the value of the response on ComponentTwo is never printed, even the part of the message from component 2: is never showing up. However the message entered in constructor ComponentTwo is always showing up.. There is not any error message showing up neither


Solution

  • When using a Subject, you will only receive notifications of events (values) that are emitted subsequent to you calling subscribe. In this case, I suspect that the service is emitting its value before the subscription in ComponentTwo has been created.

    If you want the Subject to "remember" its last value, so that new subscribers will see the last value, see for example BehaviorSubject.

    Another possibility is that you are providing the service to both components independently, in which case you will actually have two distinct instances of your service. This would mean that events emitted on the service associated with ComponentOne will not be seen by ComponentTwo, and vice-versa.

    In order for two components to share the same instance of a provider, it should normally be provided in an @NgModule containing them both (and specifically not listed in two places, one for each Component). For example:

    @NgModule({
      declarations: [ComponentOne, ComponentTwo],
      providers: [MissionService],  // Will be shared by both components
      // ...
    })
    export class AppModule {
    }