typescript 当变量改变时 NgIf 不更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47474743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:04:06  来源:igfitidea点击:

NgIf not updating when variable changes

angulartypescriptserviceangular-ng-if

提问by Daanv z

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.

当用户通过身份验证时,这部分导航应该是可见的。找出它通过 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:

NgIf 语句调用此方法:

public isAuthenticated(){
     return this.authenticated;
}

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

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

the header component.ts looks like this:

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

}

Any help would be appreciated. Thanks.

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

Edit:

编辑:

auth.service.ts:

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

采纳答案by AJT82

The problem is that you are providing the service at component level, that means, that all your components, that have the service added to providersarray in component will have their own instanceof service, so this is not a shared service at all. You want to have a singleton service, so onlyset the service in your providersarray in your ngModule.

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

Also like mentioned by others, calling methods in template is a really bad idea, this method is called on each change detection, which is often, so it really hurts the performance of the app.

也像其他人提到的那样,在模板中调用方法是一个非常糟糕的主意,在每次更改检测时都会调用此方法,这经常发生,因此它确实损害了应用程序的性能。

You could use Observables like suggested, or then just have a shared variable in your service. In the long run I'd suggest Observables, but depending on case just a shared variable is alright. Here's a sample for both: Passing data into "router-outlet" child components (angular 2)

您可以像建议的那样使用 Observables,或者在您的服务中使用共享变量。从长远来看,我建议使用 Observables,但视情况而定,只需要一个共享变量就可以了。这是两者的示例:将数据传递到“路由器出口”子组件(角度 2)

回答by Florian D

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

一个好方法是通过 Observable 的反应式编码来共享数据。

In your service, create a BehaviorSubject and its Observable:

在您的服务中,创建一个 BehaviorSubject 及其 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 nexton your subject:

每次你想更新你的价值时,next就你的主题做一个:

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

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

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

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

Or display value in your template with async pipe:

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

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

回答by Sajeetharan

template should be

模板应该是

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