NgIf 在变量更改时不更新
NgIf not updating when variable changes
是的,所以我有一个 header 组件(导航栏),其中包含以下模板:
<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'是正确地在 true 和 false 之间切换,但是 Ngif 没有以某种方式响应这些更改。
header 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;
}
}
模板应该是
<ng-template *ngIf = "authService.isAuthenticated()">
一个好的方法是通过响应式编码与 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">
问题是您在组件级别提供服务,这意味着,将服务添加到组件中的 providers
数组的所有组件都将拥有自己的 实例 的服务,所以这根本不是共享服务。你想要一个单例服务,所以 只 在 ngModule.
的 providers
数组中设置服务
也像其他人提到的那样,在模板中调用方法是一个非常糟糕的主意,每次更改检测都会调用此方法,这种情况经常发生,因此确实会损害应用程序的性能。
您可以像建议的那样使用 Observables,或者在您的服务中只使用一个共享变量。在较长的 运行 中,我建议使用 Observables,但根据情况,仅共享变量就可以了。这是两者的示例:
另一个对我有用的解决方案是使用 rxjs firstValueFrom() 函数来替换 toPromise() 并在那里传递你的可观察对象
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;
})
是的,所以我有一个 header 组件(导航栏),其中包含以下模板:
<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'是正确地在 true 和 false 之间切换,但是 Ngif 没有以某种方式响应这些更改。
header 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;
}
}
模板应该是
<ng-template *ngIf = "authService.isAuthenticated()">
一个好的方法是通过响应式编码与 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">
问题是您在组件级别提供服务,这意味着,将服务添加到组件中的 providers
数组的所有组件都将拥有自己的 实例 的服务,所以这根本不是共享服务。你想要一个单例服务,所以 只 在 ngModule.
providers
数组中设置服务
也像其他人提到的那样,在模板中调用方法是一个非常糟糕的主意,每次更改检测都会调用此方法,这种情况经常发生,因此确实会损害应用程序的性能。
您可以像建议的那样使用 Observables,或者在您的服务中只使用一个共享变量。在较长的 运行 中,我建议使用 Observables,但根据情况,仅共享变量就可以了。这是两者的示例:
另一个对我有用的解决方案是使用 rxjs firstValueFrom() 函数来替换 toPromise() 并在那里传递你的可观察对象 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;
})