NgIf not updating when variable changes

Daanv z picture Daanv z · Nov 24, 2017 · Viewed 26.2k times · Source

Right, so i have a header component (navbar) which contains the following template:

<ng-template [ngIf] = "authService.isAuthenticated()">
  <li>
    <a routerLink="Landing" class="navbar-brand" (click)="Logout()"><span class="xvrfont">Logout</span><i class="fa fa-sign-in" aria-hidden="true"></i></a>
  </li>
  <li>
    <a routerLink="Profile" class="navbar-brand"><span class="xvrfont">{{authService.getUsername()}}</span><i class="fa fa-user-circle" aria-hidden="true"></i></a>
  </li>
</ng-template>

This part of the nav should be visible when the user is authenticated. to find out it checks via authService.

To check if a user is authenticated, the following code is ran on every route change:

checkAuthenticated(){
   if  (localStorage.getItem('token') != null){ this.authenticated = true; }
   else { this.authenticated = false; }
   console.log(this.authenticated); // for Debugging. 
}

The NgIf statement calls this method:

public isAuthenticated(){
     return this.authenticated;
}

According to the logs, 'authenticated' is changing between true and false correctly, but the Ngif isn't responding to the changes somehow.

the header component.ts looks like this:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import {AuthService} from "../auth/auth.service";

@Component({
  selector: 'app-header',
  providers: [AuthService],
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class HeaderComponent implements OnInit {

  constructor(private authService: AuthService) { }

  ngOnInit() {
  }

  Logout(){
    this.authService.Logout();
  }

}

Any help would be appreciated. Thanks.

Edit:

auth.service.ts:

import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Router} from "@angular/router";
import 'rxjs/add/operator/map';

@Injectable()
export class AuthService {

  public apiroot = 'http://localhost:3100/';
  public loginResponseMessage = '';
  public registerResponseMessage = '';
  public authenticated = false;


  public constructor(private http: HttpClient,
                     private router: Router) {

  }



  SignUp(username: string, password: string) {
    const User = JSON.stringify({username: username, password: password});
    let response: any;
    this.http.post(this.apiroot + 'register', User, {headers: new HttpHeaders()
      .set('content-type', 'application/json; charset=utf-8')})
      .subscribe(res => {
        response = res;
        this.registerResponseMessage = response.message;
        console.log(this.registerResponseMessage);
      });
  }

  Login(username: string, password: string) {
    const User = JSON.stringify({username: username, password: password});
    let response: any;
    this.http.post(this.apiroot + 'authenticate', User, {headers: new HttpHeaders()
      .set('content-type', 'application/json; charset=utf-8')})
      .subscribe(res => {
        response = res;
        this.loginResponseMessage = response.message;
        if (response.token) {
          localStorage.setItem('token', response.token);
          this.authenticated = true;
          localStorage.setItem('user', response.username);
          this.router.navigate(['/']);
        }
        else{  /* Do Nothing */  }
      });
  }


  Logout(): void{
    this.authenticated = false;
    localStorage.removeItem('token');
    console.log(this.isAuthenticated());
    this.router.navigate(['/Landing']);
  }

  isAuthenticated(){
    return this.authenticated;
  }

  checkAuthenticated(){
    if  (localStorage.getItem('token') != null){ this.authenticated = true; }
    else { this.authenticated = false; }
    console.log(this.authenticated); // for Debugging.
  }



  getUsername(){
    var result = localStorage.getItem('user');
    return result;
  }
}

Answer

Florian D picture Florian D · Nov 24, 2017

A good way is to share data through reactive coding with Observable.

In your service, create a BehaviorSubject and its Observable:

private _isAuthenticatedSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public isAuthenticatedObs: Observable<boolean> = _isAuthenticatedSubject.asObservable();

Each time you want to update your value, do a next on your subject:

_isAuthenticatedSubject.next(true); // authenticated
_isAuthenticatedSubject.next(false); // no more

Component side, just subscribe the observable to set the value locally for every subject changes:

this.authService.isAuthenticatedObs.subscribe(isAuth => this.isAuth = isAuth);

Or display value in your template with async pipe:

<ng-template *ngIf = "authService.isAuthenticatedObs | async">