在我的 Angular 应用程序中,我使用CanActivate
防护来保护某些路由器状态下的访问。
CanActivate
守卫执行的检查可以持续3-4秒,如果没有加载指示器(即旋转器),则等待非常烦人。
是否有"标准"在CanActivate检查期间显示加载微调器的方法?
非常感谢
答案 0 :(得分:9)
要回答你的问题,没有"标准"这样做的方法。
但这很容易。我通过以下方式解决了这个问题:
将AuthGuard服务导入app.component.ts
文件:
import { Component, OnInit } from '@angular/core';
// Import AuthGuard service here - double check the path
import { AuthGuard } from './services/auth.guard';
@Component({
selector: 'body',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
// Inject AuthGuard service here
constructor(private authGuard: AuthGuard) { }
ngOnInit() { }
});
将加载程序HTML添加到app.component.html
文件中:
<router-outlet></router-outlet>
<div class="central-loader" *ngIf="(authGuard.loader)"><div><i class="fa fa-spin fa-spinner"></i> Loading...</div></div>
注意上面的加载器HTML中的*ngIf
。这会检查authGuard.loader
变量,如果此变量的值设置为true
,则会加载此HTML代码。
在AuthGuard文件中(在我的情况下为services/auth.guard.ts
):
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable, Subject } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
private loader$ = new Subject<boolean>();
public loader = false;
constructor() {
this.loader$.debounceTime(300).subscribe(loader => {
this.loader = loader;
});
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
this.loader$.next(true);
// Returning an Observable for async checks
return new Observable<boolean>(obs => {
// Sample 2 second async request
setTimeout(() => {
this.loader$.next(false);
obs.next(true);
obs.complete();
}, 2000);
});
}
}
您还可以使用loader$
管道直接调用模板中的async
,例如:
<router-outlet></router-outlet>
<div class="central-loader" *ngIf="(authGuard.loader$ | async)"><div><i class="fa fa-spin fa-spinner"></i> Loading...</div></div>
(在这种情况下,将loader$
设置为公开。)
但是我不希望这个加载器出现,如果canActivate检查在不到300毫秒内完成,这就是我订阅loader$
debounceTime()
的原因。
我知道即使向观察者发送false
也会延迟300毫秒,但这对我来说没问题。
顺便说一下,这是我用于加载程序的CSS,水平和垂直居中,整页阻塞覆盖:
.central-loader {
position: fixed;
display: flex;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.2);
z-index: 1050;
}
.central-loader > div {
height: 42px;
line-height: 40px;
width: 200px;
text-align: center;
border: 2px #faf2cc solid;
color: #8a6d3b;
background-color: #fcf8e3;
margin: auto;
}
请勿忘记在app.module.ts
中导入AuthGuard:
import { NgModule } from '@angular/core';
....
// Import AuthGuard service here - double check the path
import { AuthGuard } from './services/auth.guard';
@NgModule({
....
providers: [
AuthGuard,
....
],
....
});
我希望这有帮助!
答案 1 :(得分:1)
尝试此操作,使用路由器事件。 很简单。
<div class="loading-icon" *ngIf="loading"></div>
并在app.component.ts
文件中:
this.router.events.subscribe(event => {
if (event instanceof GuardsCheckStart) {
this.loading = true;
console.log("GuardStart")
}
if (event instanceof GuardsCheckEnd) {
this.loading = false;
console.log("GuardEnd")
}
});
答案 2 :(得分:0)
您好,环顾四周后,我发现了这一点,请从头开始,然后在CanActivate Guard正在加载时点按该按钮。
import { Injectable } from '@angular/core';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { Observable, of } from 'rxjs';
import { switchMap, startWith, tap } from 'rxjs/operators';
import { User } from './user';
@Injectable({
providedIn: 'root'
})
export class AuthService {
user: Observable<User>;
constructor(private afAuth: AngularFireAuth,
private db: AngularFirestore) {
//// Get auth data, then get firestore user document || null
this.user = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.db.doc<User>(`users/${user.uid}`).valueChanges()
} else {
return of(null)
}
}),
// Add these lines to set/read the user data to local storage
tap(user => localStorage.setItem('user', JSON.stringify(user))),
startWith(JSON.parse(localStorage.getItem('user')))
)
}
}
请参阅“ tap”和“ startWith”功能是否保存了我,如果遇到加载问题,请使用类似的内容。 这些其他评论中有一些非常骇客(不要骇客)