Jake Chambers
Jake Chambers

Reputation: 563

Component template variable not updating when service emits a change (angular)

I have a service:

@Injectable({ providedIn: 'root' })
export class AuthenticationService {
  signInChange: Subject<boolean> = new Subject<boolean>();
  isSignedIn: boolean;

  constructor() {
    this.isSignedIn = false;
  }

  signInChange: Subject<boolean> = new Subject<boolean>();
  isSignedIn: boolean;

  login() {
    this.auth2.signIn()
      .then(user => {
        this.isSignedIn = true;
        this.signInChange.next(this.isSignedIn)
      })
      .catch(error => {
        console.log("Error signing in")
      })
  }

  logout() {
    this.auth2.signOut()
      .then(user => {
        this.isSignedIn = false;
        this.signInChange.next(this.isSignedIn)
      })
      .catch(error => {
        console.log("Error signing out")
      })
  }

and a component:

export class HomeComponent implements OnInit {
  signInSubscription: Subscription;
  isSignedIn: any;

  constructor(private authService: AuthenticationService) {
    this.isSignedIn = authService.isSignedIn;
    this.signInSubscription = authService.signInChange.subscribe(value => {
      console.log("status changed to: " + value)
      this.isSignedIn = value
    })
  }

  checkValues() {
    console.log("Component says: " + this.isSignedIn);
    console.log("Auth says: " + this.authService.isSignedIn)
  }

and here is the HTML:

<div id = "login-test">
  <div class="g-signin2"></div>
  <button (click)="signIn()">Sign in</button>
  <button (click)="signOut()">Sign out</button>
  <button (click)="checkValues()">Check values</button>
  <p>{{this.isSignedIn}}</p>
</div>

So the observable works as expected (eg. when the sign in status is change the correct status is logged) BUT on the template itself the variable does not update when a change is observed.

Here's what I dont understand:

  1. When I click the Check Values button, the output is ALWAYS correct. The isSignedIn property is being set correctly every time there is an update in the service. BUT THE TEMPLATE ITSELF DOESN'T UPDATE.

  2. If I set up a button to only toggle the value {{this.isSignedIn}}, the template updates real time. Why will it not update real time if the change is coming from the observable?!?

Upvotes: 1

Views: 8311

Answers (1)

Barremian
Barremian

Reputation: 31125

Because the variable isSignedIn in HomeComponent is assigned once in it's constructor and never re-assigned. And you are on the right path setting up an observable in the service. When you need the up-to-date value in component, use only the observable and do not use the boolean flag from the service directly.

Do the following in the component. Move the assignment inside the subscription and avoid using the boolean flag from the service directly.

import { Component, ngOnInit, ChangeDetectorRef } from '@angular/core';

export class HomeComponent implements OnInit {
  signInSubscription: Subscription;
  isSignedIn: any;

  constructor(private authService: AuthenticationService, private changeDetectorRef: ChangeDetectorRef) {
    this.isSignedIn = authService.isSignedIn;
    this.signInSubscription = authService.signInChange.subscribe(value => {
      console.log("status changed to: " + value)
      this.isSignedIn = value;
      this.changeDetectorRef.detectChanges();
    })
  }

  checkValues() {
    console.log("Component says: " + this.isSignedIn);
    console.log("Auth says: " + this.authService.isSignedIn)
  }
}

Edit - include ChangeDetectorRef

Upvotes: 5

Related Questions