【问题标题】:NgIf not updating when variable changes变量更改时 NgIf 不更新
【发布时间】:2018-05-08 13:19:57
【问题描述】:

对,所以我有一个标题组件(导航栏),其中包含以下模板:

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

当用户通过身份验证时,这部分导航应该是可见的。找出它通过 authService 检查。

要检查用户是否经过身份验证,每次路由更改都会运行以下代码:

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

NgIf 语句调用这个方法:

public isAuthenticated(){
     return this.authenticated;
}

根据日志,'authenticated'正在正确地在真假之间变化,但 Ngif 没有以某种方式响应变化。

头component.ts看起来像这样:

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

}

任何帮助将不胜感激。谢谢。

编辑:

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

【问题讨论】:

  • 应该是*ngIf
  • 你能发布AuthService类吗? isAuthenticated() 方法的返回类型是什么?
  • isAuthenticated() 返回一个布尔值。我已将 AuthService 添加到帖子中。
  • @Daanvz 是的,但它的默认值为 false,它通过订阅 Login 方法中从 this.http.post 返回的 Observable 来异步更新。
  • @Daanvz 你可以试试我的回答吗?

标签: angular typescript service angular-ng-if


【解决方案1】:

一个好方法是通过响应式编码与 Observable 共享数据。

在您的服务中,创建一个 BehaviorSubject 及其 Observable:

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

每次您想更新您的价值时,请在您的主题上发送next

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

组件方面,只需订阅 observable 以在本地为每个主题更改设置值:

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

或者使用异步管道在模板中显示值:

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

【讨论】:

  • @ Florian D - 嗨,我也暴露了同样的问题,我按照 AJT82 的建议通过在“提供者”中插入身份验证服务解决了这个问题,但我想要一个性能应用程序从各个角度来看,所以我想在这种情况下实现 observables。你写了“每次你想更新你的值,我给你以下关于你的主题:”但是当登录状态改变时我需要更新值,从登录到未登录,反之亦然,如何拦截这个事件?
【解决方案2】:

问题在于您在组件级别提供服务,这意味着您所有将服务添加到组件中providers 数组的组件都将拥有自己的自己的服务实例 ,所以这根本不是共享服务。你想要一个单例服务,所以only在你的ngModule.providers数组中设置服务

也像其他人提到的那样,在模板中调用方法是一个非常糟糕的主意,这个方法在每次更改检测时都会调用,这很常见,所以它真的会伤害应用程序的性能。

您可以像建议的那样使用 Observables,或者在您的服务中只使用一个共享变量。从长远来看,我建议使用 Observables,但根据具体情况,共享变量就可以了。以下是两者的示例:Passing data into "router-outlet" child components (angular 2)

【讨论】:

  • 谢谢!这有很大帮助。现在它是单例,一切正常。
  • 非常欢迎您,很高兴听到它解决了您的问题 :)
  • 将服务插入提供者也适用于我
【解决方案3】:

模板应该是

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

【讨论】:

    【解决方案4】:

    另一个对我有用的解决方案是使用 rxjs firstValueFrom() 函数替换 toPromise() 并在那里传递你的 observable https://rxjs.dev/deprecations/to-promise

    const promise = firstValueFrom(this.OTPSentObservable);
        promise.then((data) => {
          console.log('OTP Sent', data);
          this.isLoading = false;
          this.isOtpReceived = true;
        })

    【讨论】:

      猜你喜欢
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-29
      • 2020-05-04
      • 1970-01-01
      • 2015-01-17
      • 1970-01-01
      相关资源
      最近更新 更多