![](/img/trans.png)
[英]ngIf doesn't evaluate the expression when it changes. Angular and Firebase
[英]ngIf doesn't evaluate async code Angular and Firebase
我的AuthService中有一個屬性,可以告訴您是否登錄。
export class AuthService {
token: string;
isLogIn = new Subject<boolean>();
當我正確登錄時,另一方面,當我單擊注銷時,將isLogIn設置為true,將該屬性設置為false。 我的AppComponent中有這個邏輯(第一個組件已加載)。
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in.
this.authService.user = new User(user.displayName, user.email, user.photoURL, user.uid);
console.log(user);
this.isLoading = false;
this.authService.isLogIn.next(true);
} else {
// No user is signed in.
console.error('no user is login');
this.authService.isLogIn.next(false);
}
});
在我的HeaderComponent中,我有:
export class HeaderComponent implements OnInit {
isActivated = false;
constructor(private authService: AuthService) { }
ngOnInit() {
this.authService.isLogIn.asObservable().subscribe(
(data: boolean) => {
this.isActivated = data;
}
);
// this.isActivated = this.authService.isLogin();
}
}
模板:
<ng-template [ngIf]="!isActivated">
<a class="nav-item nav-link text-white anchor-hover"
routerLink="/login"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar
</a>
</ng-template>
<ng-template [ngIf]="isActivated">
<!--DROPDOWN PROFILE-->
<div class="btn-group" role="group" *ngIf="authService.user">
<button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{authService.user.displayName}}
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="#">Dropdown link</a>
<a class="dropdown-item" href="#">Dropdown link</a>
</div>
</div>
<a class="nav-item nav-link text-white anchor-hover"
routerLink="/dashboard"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard
</a>
</ng-template>
我在這里要解決的問題是,當用戶登錄時,我向他顯示了一個儀表板按鈕並隱藏了登錄按鈕,但這僅在刷新頁面或更改當前路線時才會顯示。 我不想更改路線或刷新頁面以查看不同的UI組件,具體取決於您是否登錄。
現在,我讓您查看整個文件:AppRouting模塊:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {HomeComponent} from './shared/home/home.component';
import {LoginComponent} from './public/login/login.component';
import {DashboardComponent} from './auth/dashboard/dashboard.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{path: 'login', component: LoginComponent},
{path: 'dashboard', component: DashboardComponent}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule{}
AppComponent.ts
import {Component, OnInit} from '@angular/core';
import * as firebase from 'firebase';
import {AuthService} from './public/services/auth.service';
import {User} from "./auth/models/user.model";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
isLoading = true;
constructor(private authService: AuthService) {}
ngOnInit() {
// this.authService.isLogIn.next(localStorage.length > 0);
firebase.auth().onIdTokenChanged(
(data) => {
console.log('TOKEN HAS CHANGED', data);
if(data) {
data.getIdToken().then(
(tk) => {
this.authService.token = tk;
}
);
} else {
console.log('You don\'t have a token yet, please login...');
// TODO this means that the user is new or have logout.
}
}
);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in.
this.authService.user = new User(user.displayName, user.email, user.photoURL, user.uid);
console.log(user);
this.isLoading = false;
this.authService.isLogIn.next(true);
} else {
// No user is signed in.
console.error('no user is login');
this.authService.isLogIn.next(false);
}
});
// check localstorage, so we can see if there is a logged user
if (this.authService.getLocalUserInfo()) {
this.authService.isLogIn.next(true);
} else {
this.authService.isLogIn.next(false);
}
}
}
AppComponent模板:
<div>
<app-header></app-header>
</div>
<div>
<router-outlet></router-outlet>
</div>
AppHeader.ts
import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../public/services/auth.service';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
isActivated = false;
constructor(private authService: AuthService) { }
ngOnInit() {
this.authService.isLogIn.asObservable().subscribe(
(data: boolean) => {
this.isActivated = data;
}
);
// this.isActivated = this.authService.isLogin();
}
}
AppHeader模板
<nav class="navbar navbar-expand-lg navbar-dark bg-custom-nav px-5">
<a class="navbar-brand" routerLink="/">MovieApp</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="container-fluid">
<div class="collapse navbar-collapse d-lg-flex justify-content-lg-between row" id="navbarNavAltMarkup">
<div class="navbar-nav px-sm-4 px-lg-0">
<a class="nav-item nav-link text-white"
routerLink="/"
routerLinkActive="active font-weight-bold"
[routerLinkActiveOptions]="{exact: true}">Inicio</a>
</div>
<div class="col-lg-8">
<app-search-bar></app-search-bar>
</div>
<div class="row">
<ng-template [ngIf]="!isActivated">
<a class="nav-item nav-link text-white anchor-hover"
routerLink="/login"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar
</a>
</ng-template>
<ng-template [ngIf]="isActivated">
<!--DROPDOWN PROFILE-->
<div class="btn-group" role="group" *ngIf="authService.user">
<button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{authService.user.displayName}}
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="#">Dropdown link</a>
<a class="dropdown-item" href="#">Dropdown link</a>
</div>
</div>
<a class="nav-item nav-link text-white anchor-hover"
routerLink="/dashboard"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard
</a>
</ng-template>
</div>
</div>
</div>
</nav>
AuthService.ts
import * as firebase from 'firebase';
import {Router} from '@angular/router';
import { Injectable } from "@angular/core";
import {Subject} from "rxjs/Subject";
import {User} from "../../auth/models/user.model";
@Injectable()
export class AuthService {
token: string;
isLogIn = new Subject<boolean>();
user: User;
constructor(private router: Router){}
signinWithFacebook() {
const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_location');
return firebase.auth().signInWithPopup(provider)
.then(
(res) => {
console.log(res);
this.getTokenId();
localStorage.setItem('userInfo', JSON.stringify(firebase.auth().currentUser.providerData[0]));
const userInfo = firebase.auth().currentUser.providerData[0];
this.user = new User(userInfo.displayName, userInfo.email, userInfo.photoURL, userInfo.uid);
this.isLogIn.next(true);
this.router.navigate(['/dashboard']);
}
);
}
getTokenId() {
firebase.auth().currentUser.getIdToken()
.then(
(tk) => {
return this.token = tk;
}
);
}
logout() {
return firebase.auth().signOut();
// handle in component
}
getLocalUserInfo(): boolean {
if(localStorage.getItem('userInfo')) {
const transformStoredUser = JSON.parse(localStorage.getItem('userInfo'));
this.user = new User(transformStoredUser.displayName, transformStoredUser.email, transformStoredUser.photoURL, transformStoredUser.uid);
return true;
} else {
return false;
}
}
isLogin():boolean {
if (localStorage.getItem('userInfo')) {
return true;
}
return false;
}
}
您可以在以下位置找到完整的項目: https : //github.com/lucasdavidferrero/movieApp還有一件事,我使用了異步管道,但是模板沒有反映出變化。 在github項目中,您會發現我在模板中使用了async,但是仍然存在相同的錯誤。 我希望有人可以幫助我。
我將嘗試幫助/回答,請注意您有很多代碼可以篩查,因此我可能錯過了一些顯而易見的東西。 無論如何,希望可以整理一下代碼,並為您指出正確的方向,您可能想研究AsyncPipe。
我想首先通過更改isLogIn = new Subject<boolean>();
來首先修改您的AuthService,使其與一些更好的做法保持內聯isLogIn = new Subject<boolean>();
private _isLogIn = new Subject<boolean>();
。 我們不想將Subject與其他將對其進行修改的組件共享,因此在AuthService中的任何地方,您只需要添加下划線...最后,導出要使用的Subject,我們可以添加如下的get函數:
get isLogIn(): Observable<boolean> {
return this._isLogIn.asObservable();
}
現在,我們不需要將asObservable()
到我們使用它的任何地方。
另外,我們希望將監視用戶狀態變化的位置從AppComponent移到AuthService。 然后,您可以在AppModule的構造函數中實例化該服務,以便您的應用程序啟動后,您的服務將開始監視auth狀態的更改。
您還可能會遇到一個問題,即auth狀態的NgZone
可能會超出范圍,因此雖然這不是必需的,但您可以/應該從核心導入NgZone
並將其傳遞到AuthService constructor(private router: Router, private _zone: NgZone) { }
所以當您更新auth狀態的值時,可以將其包裝在以下函數中:
this._zone.run(() => {
// your code here
}
現在,如果我要編寫您的header.component.ts
我會做這樣的事情:
export class HeaderComponent implements OnInit {
constructor(private authService: AuthService) { }
ngOnInit() {}
get isActivated(): Observable<boolean> {
return this.authService.isLogIn;
}
}
所以在這里,我只是將可觀察對象直接通過get函數傳遞給我們的模板。 因此,在模板中,我將像這樣實現AsyncPipe:
<div *ngIf="!(isActivated | async) else user">
<a class="nav-item nav-link text-white anchor-hover" routerLink="/login"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar
</a>
</div>
<ng-template #user>
<!--DROPDOWN PROFILE-->
<div class="btn-group" role="group" *ngIf="authService.user">
<button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{authService.user.displayName}}
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="#">Dropdown link</a>
<a class="dropdown-item" href="#">Dropdown link</a>
</div>
</div>
<a class="nav-item nav-link text-white anchor-hover"
routerLink="/dashboard"
routerLinkActive="active font-weight-bold">
<i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard
</a>
</ng-template>
AsyncPipe將自動訂閱和取消訂閱您的Observable,並處理刷新/區域更新。
現在,我做了一些概述/基本更改,以確保代碼按預期運行。 我邀請您嘗試一下,看看*ngIf
的工作是否更“整潔”。 但是您可能還想在Angular中查找其他內容... => https://stackoverflow.com/a/43006589/5076023
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.