How to subscribe service in Angular

13,992

Solution 1

isOpen is a boolean. A boolean is just a primitive without any publish/subscribe functionality.

What you want is an Observable that you can actually subscribe to. We'll use a BehaviorSubject here, as you can give it an initial value.

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

@Injectable()
export class ConnectService {
  public isOpen$ = new BehaviorSubject(false);

  public toggle(): void {
    this.isOpen$.next(!this.isOpen$.getValue());
    console.log('Im inside toggle');
  }

  public getIsOpen(): Observable<boolean>{
    console.log('Im inside getIsOpen');
    return this.isOpen$;
  }
}

Then subscribe to it using this.connectService.isOpen$.subscribe(isOpen => ...).

Solution 2

of(this.isOpen) will only emit a value one time. What you need is something like a BehaviorSubject, which always emits its most recent value.

@Injectable()
export class ConnectService {

  public isOpen = new BehaviorSubject<boolean>(false);

  public toggle(): void {
    this.isOpen.next(!this.isOpen.value);
    console.log('Im inside toggle');
  }

}

And in your component you can then directly subscribe to your subject, no need to create an additional Observable:

public ngOnInit(): void {
  this.connectionService.isOpen.subscribe(x => this.isFirstComponentExpanded = x);
}
Share:
13,992

Related videos on Youtube

obar
Author by

obar

Updated on June 04, 2022

Comments

  • obar
    obar almost 2 years

    i have 3 objects: - first component - connect service - second component

    First component when is folded/expanded should expand/fold second component via service.

    In service i have function toggle() and it should only change a bool variable of boolean isOpen. Next to it i have other function getIsOpen() with return type Observable. Code looks like this:

    import { Injectable } from '@angular/core';
    import { Observable } from 'rxjs/internal/Observable';
    import { of } from 'rxjs/internal/observable/of';
    
    @Injectable()
    export class ConnectService {
      public isOpen = false;
    
      public toggle(): void {
        this.isOpen = !this.isOpen;
        console.log('Im inside toggle');
      }
    
      public getIsOpen(): Observable<boolean>{
        console.log('Im inside getIsOpen');
        return of(this.isOpen);
      }
    }
    

    In second component i try to subscribe:

    public ngOnInit(): void {
      this.connectionService.getIsOpen().subscribe(x => this.isFirstComponentExpanded = x);
    }
    

    But only effect is only after the page load, after click, the second component didn't fold or expand. How to listen every change inside service without event emmiter (i need to avoid any event emitters there, only observables, subscribes and subjects).

    • robert
      robert almost 5 years
      Check this stackblitz
    • obar
      obar almost 5 years
      Well, i have same implementation as you and ... not working. Damn ... maybe there is a issue, something else blocking this i think but how :/
    • robert
      robert almost 5 years
      Create a stackblitz from your implementation.
    • obar
      obar almost 5 years
      Too many files to add, but i have 1 to 1 and on stackblitz it working fine, have console.logs like i want, inside app is invalid.
    • obar
      obar almost 5 years
      Maybe the issue is in location? first component is a part of different module than second
    • obar
      obar almost 5 years
      Ok guys, someody else added service to providers inside module where is window and this making implementation invalid. Now everything is ok. I think other solutions work's too.
  • obar
    obar almost 5 years
    Property 'asObservable' does not exist on type 'Observable<BehaviorSubject<boolean>>'. at return of(this.isOpen).asObservable();
  • Reactgular
    Reactgular almost 5 years
    @obar sorry, I forgot to remove the of(...). I've updated the answer.
  • obar
    obar almost 5 years
    i tried subscribe like this to code above: this.connectService.isOpen$.subscribe(isOpen => this.firstComponentIsExpanded); and in console i onlt get Im inside toggle (can't get into getIsOpen())
  • obar
    obar almost 5 years
    Still can't get into getIsOpen(), console log logging only at page reload
  • fjc
    fjc almost 5 years
    If you want to use getIsOpen, you need to call it and subscribe to the result: this.connectService.getIsOpen().subscribe(isOpen => this.firstComponentIsExpanded);
  • Reactgular
    Reactgular almost 5 years
    @obar getIsOpen() only gets called once.
  • obar
    obar almost 5 years
    Value isFirstComponentExpanded won't change, i getting log on every click but cant get the value of bool inside service in component.
  • obar
    obar almost 5 years
    Yes, i wan't to call it multiple times, on every toggle, not only once
  • obar
    obar almost 5 years
    Same, only getting im inside toggle. Im inside getIsOpen appear only once after load but i want to appear every time with toggle. If first component toggled service, second component must know about it every time
  • fjc
    fjc almost 5 years
    Then please share a copy of your application on codepen or similar.
  • obar
    obar almost 5 years
    This is not my first attempt to make it works properly, if i have sample of working code maybe i can understand this, i can't make it with parts of code and every time i failing at this moment :/ Why i can't get into getIsOpen every time? I really need to avoid event emitters inside services.