web-dev-qa-db-fra.com

NgIf ne se met pas à jour lorsque la variable change

À droite, j'ai donc un composant d'en-tête (navbar) qui contient le modèle suivant:

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

Cette partie de la navigation doit être visible lorsque l'utilisateur est authentifié. pour le découvrir, vérifie via authService.

Pour vérifier si un utilisateur est authentifié, le code suivant est exécuté à chaque changement d'itinéraire:

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

L'instruction NgIf appelle cette méthode:

public isAuthenticated(){
     return this.authenticated;
}

Selon les journaux, 'authentifié' est passe correctement de vrai à faux, mais le Ngif ne répond pas aux changements d'une manière ou d'une autre.

l'en-tête component.ts ressemble à ceci:

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();
  }

}

Toute aide serait appréciée. Merci.

Modifier:

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;
  }
}
6
Daanv z

Le problème est que vous fournissez le service au niveau du composant, cela signifie que tous vos composants, qui ont le service ajouté au tableau providers dans le composant, auront leur propre instance de service, ce n'est donc pas du tout un service partagé. Vous voulez avoir un service singleton, donc seulement définissez le service dans votre tableau providers dans votre ngModule.

De plus, comme mentionné par d'autres, appeler des méthodes dans un modèle est une très mauvaise idée, cette méthode est appelée à chaque détection de changement, ce qui est souvent le cas, ce qui nuit vraiment aux performances de l'application.

Vous pouvez utiliser Observables comme suggéré, ou alors simplement avoir une variable partagée dans votre service. À long terme, je suggère Observables, mais selon le cas, seule une variable partagée est correcte. Voici un exemple pour les deux: Passage de données dans les composants enfants "router-outlet" (angulaire 2)

4
AJT82

Un bon moyen est de partager des données via un codage réactif avec Observable.

Dans votre service, créez un BehaviorSubject et son observable:

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

Chaque fois que vous souhaitez mettre à jour votre valeur, faites un next sur votre sujet:

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

Côté composant, il suffit de souscrire l'observable pour définir la valeur localement pour chaque changement de sujet:

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

Ou affichez la valeur dans votre modèle avec un canal asynchrone:

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

le modèle doit être

<ng-template *ngIf = "authService.isAuthenticated()">
2
Sajeetharan