简体   繁体   中英

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?!?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM