在CanActivate期间显示加载指示器

时间:2018-01-28 13:00:05

标签: angular

在我的 Angular 应用程序中,我使用CanActivate防护来保护某些路由器状态下的访问。

CanActivate守卫执行的检查可以持续3-4秒,如果没有加载指示器(即旋转器),则等待非常烦人。

是否有"标准"在CanActivate检查期间显示加载微调器的方法?

非常感谢

3 个答案:

答案 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>&nbsp; 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>&nbsp; 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”功能是否保存了我,如果遇到加载问题,请使用类似的内容。 这些其他评论中有一些非常骇客(不要骇客)