2

I have a service file called user-status.service which calls up an api to get a value:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { HttpService } from "../../http.service";
import { Router } from "@angular/router";

@Injectable()
export class UserStatusService {

    private _userStatusResource = new BehaviorSubject<any>(null);
    reload$ = this._userStatusResource.asObservable();
    constructor(private router: Router, private httpService: HttpService) { }

    getUserDetails() {
        this.httpService.getUsersStatus()
            .subscribe(
            data => {
                console.log(data);
                this._userStatusResource.next(data.body);
            },
            () => console.log("")
            );
    }
}

Now on normal components where I want to get the value, I can't seem to get the value on oninit.

import { Component, OnDestroy, OnInit } from '@angular/core';
import { HttpService } from "../../http.service";
import { UserStatusService } from '../../shared/services/user-status.service';
import { Subscription } from "rxjs/Rx";

@Component({
  selector: 'app-event-management',
  templateUrl: './event-management.component.html'
})
export class EventManagementComponent implements OnInit {

    userStatus: any;
    private subscription1: Subscription;

    constructor(private httpService: HttpService, private userStatusService: UserStatusService) {

        this.subscription1 = this.userStatusService.reload$
            .subscribe(
            response => {
                this.userStatus = response;
if ((this.userStatus.isDefaultAdmin == false))
                {
                    alert("Do something");
                }
            });

    }

  ngOnInit() {
this.userStatusService.getUserDetails();
    }

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

}

The value coming from the subscription is always null (the alert "Do something" will never run). How can I get the value from the service on runtime?

I should also mention the point of this service file is because I only want to call that api once in the session, there's no need for me to make repeat calls to it.

Andrew Howard
  • 2,818
  • 5
  • 33
  • 59
  • 2
    You get null the first time because you use `BehaviorSubject` and pass a default value of `null`. This line `this.userStatus.isDefaultAdmin` may error because `this.userStatus` is null so `this.userStatus.isDefaultAdmin` probably fails and throws an exception. try Subject over BehaviorSubject – Ric Oct 17 '19 at 08:13

1 Answers1

3

Try changing BehaviorSubject to Subject so that the first call to next has the value instead of the null which you get when first subscribing, which is the default behavior.

Also, you could check for null values when subscribing:

this.subscription1 = this.userStatusService.reload$
  .subscribe(response => {
      if (!response)
          return;
      this.userStatus = response;
      if ((this.userStatus.isDefaultAdmin == false)) {
          alert("Do something");
      }
});
Ric
  • 12,855
  • 3
  • 30
  • 36
  • Thanks. I'm getting confused how I should be calling this.userStatusService.getUserDetails(); if it hasn't been called before. Do I need to declare it every single time in every component's ngOnInit()? Or can I combine it somehow in the subscription? – Andrew Howard Oct 17 '19 at 08:47
  • you can add it in each `ngOnInit` for each component, or, you could place that in some sort of `APP_Initializer` or route resolve. ie https://angular.io/api/router/Resolve or https://stackoverflow.com/questions/49707830/angular-how-to-correctly-implement-app-initializer – Ric Oct 17 '19 at 08:51
  • Would putting it in each ngOnInit be the best practise way? – Andrew Howard Oct 17 '19 at 08:53
  • it all depends on the use case! if it is likely to change frequently depending on the route then using a route resolve is a good way of capturing changes and handling it in each component. Or, setting it during app_init sets it once so that you can put the logic in one place and handle the change once – Ric Oct 17 '19 at 08:56
  • The information obtained from "this.httpService.getUsersStatus()" is only required once after the user logs in. So I guess "app_initializer" wouldn't be appropriate because the app needs to run first, then the user needs to login, and then that api call can be made. The information would still need to be remembered of course should the user refresh the page. – Andrew Howard Oct 17 '19 at 09:02
  • sounds like a good use case for using the route resolver, storing the user object etc in localstorage and then retrieving it in each component? – Ric Oct 17 '19 at 09:45
  • No problem. Lots of ways to achieve something, and angular/rxjs is fun – Ric Oct 17 '19 at 10:05
  • Yeah I prefer using it over any over type of state management. Is much more simpler and easier to implement. Do you use ngrx? Or stick with rxjs? – Andrew Howard Oct 17 '19 at 10:21
  • not had the pleasure of using ngrx yet, there is definitely future scope for it where I am now, as the app is growing and managing the state is becoming much more complex, ngrx could potentially help out by abstracting this away from the components. Just need to find the time to look into it....:D – Ric Oct 17 '19 at 10:25