0

sorry if this is trivial.

I'm new to Angular 4 and I'm struggling with a seemingly simple issue: having 2 or more components subscribe to an Observable provided by a (login) Injectable.

My goal is to have:

  1. A view invoke an event on component1
  2. component1 will invoke a method on a login.service
  3. login.service will make a REST call
  4. The response is "broadcast" using a .next()
  5. component1 and component2 will react accordingly

This works perfectly when there is only 1 component but when I introduce another component that subscribe()s to the Observable, the 2nd component only gets notified at the very beginning (ie: it only receives one message) whereas component1 continues to work as expected and receives all messages.

I initially used Subject and BehaviorSubject with the asObservable() method but then fell-back to plain Observable with similar results.

Here is a snippet to help demonstrate:

login.service:

@Injectable()
export class LoginService {

    private _loggedIn = new BehaviorSubject<booelan>(false);
    public loggedIn$ = this._loggedIn.asObservable();


    login() {
        // call API service
        this._loggedIn.next(true);
    }
 }

component1:

@Component({
    selector: 'app-test1',
    template: `<button (click)="login()"`,
    providers: [ LoginService ]
})

export class AppTest1Component {
    subscription: Subscription;
    observer: Observer;

    constructor(private loginService: LoginService) {}

    ngOnInit() {
        this.subscription = this.loginService.loggedIn$.subscribe(
            state => { console.log('got event!', state); },
            error => { console.log('Error:', error)},
            () => { console.log('Complete'); }
        );
    }

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

component2:

@Component({
    selector: 'app-test2',
    template: `<button (click)="login()"`,
    providers: [ LoginService ]
})

export class AppTest2Component {
    subscription: Subscription;
    observer: Observer;

    constructor(private loginService: LoginService) {}

    ngOnInit() {
        this.subscription = this.loginService.loggedIn$.subscribe(
            state => { console.log('got event!', state); },
            error => { console.log('Error:', error)},
            () => { console.log('Complete'); }
        );
    }

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

What is the simplest way to have several components subscribe to an Observable that would presumably be provided by a service, and receive ALL messages?

The question posted here: Angular - shared service between components doesn't work does not related to Observables and Subscriptions.

mstubbies
  • 85
  • 3

1 Answers1

0

As explained by echonax, your issue seems to be related to this topic .

By adding LoginService as a provider of both components, you are actually creating 2 instances of the said service.

@Component({
    selector: 'app-test2',
    template: `<button (click)="login()"`,
    providers: [ LoginService ] /* you are creating a new instance of the service here /*
})

If you want to have the same instance, or what is called a shared service, you have to declare the provider in the module they are in and remove the providers in the components :

@NgModule({
    ...
    providers: [LoginService],
    ...
})

If by any chance the two components you mentionned are in seperate modules, you have to declare the service as providers in one module, and then import this module to the other :

/* NgModule of the Module2 */
@NgModule({
    imports: [
    Module1], /* you import the module which has the service as provider */
    providers: [] /* Really important point here, you have to leave providers blank or at least with no reference to the shared service, or you will create a new instance of the said service */
   ...
})

I'm not totally sure it would solve your problem, but I'm almost certain you have to use a shared service anyway in your app, based on the code you provided.

nvkfr
  • 140
  • 1
  • 9
  • You are both correct. Thank you Echonax and nvkfr. I struggled with this all day. I had already declared the service in my @NgModules but I foolishly instantiated a new copy in each component as you saw in my snippets. Once I removed the Providers from both components, everything worked perfectly. THANK YOU! – mstubbies Jun 14 '17 at 08:48