首页 > 解决方案 > 角度:身份验证失败时如何阻止微调器加载?

问题描述

我的代码需要帮助。我是角度方面的新手,我对ngrx的效果有疑问。因此,在我的身份验证服务中,我声明了一个可观察类型的登录失败,我希望当我的身份验证登录失败时,微调器停止旋转并再次输入数据。我应该在 ngrx/effect 中添加什么部分?

服务组件

 public loginFailed: Observable<boolean>;

NGRX/效果

 @Effect()
 public login$: Observable<any> = 
  this.actions$.pipe(
  ofType(AuthActionTypes.LoginAction),
  mergeMap((action: Login) => 
  this.authService.login(action.payload).
  pipe(
  map((user: User) => {

    if(user.username != null && user.password != null) {
      this.authService.loginFailed
    }

    return {
      type: AuthActionTypes.LoginSuccessAction,
      payload: user
    }
  }),
  catchError(() => {
    return of({

    });
  })
))

HTML

 <div fxLayoutAlign="center center" class="button">
    <button class="btn-login" type="button" color="primary" [disabled]="isLoginBtnDisabled" (click)="onSubmit()"
        mat-button>
   <mat-icon *ngIf="isLoginBtnDisabled; else loginText">
    <mat-spinner diameter="20"></mat-spinner>
  </mat-icon>
  <ng-template #loginText>Login</ng-template>
</button>

标签: angularngrx-effects

解决方案


那么有很多方法。我会说以下。这里有2个州。一种是认证状态,一种是加载状态。

您应该有 2 个减速器,一个处理加载状态,一个处理身份验证部分。

根据 UX 设计,您通常希望每次完成请求时微调器都显示为覆盖,与您所在的页面/组件无关。

实现此目的的一种方法是使用 LoadingService 创建此叠加层,loadingService 与 loadingState 一起使用(该示例使用来自 Angular Material 的 CDK 叠加层完成)。

@Injectable()
export class LoadingService {

  private overlayRef: OverlayRef;
  private currentCount = 0;

  constructor(private overlay: Overlay, private store: Store<ApplicationState>) {
    this.store.pipe(
      select(fromLoading.loadingState)
    ).subscribe(loadingState => {
        if (loadingState.count > this.currentCount) {
          if (this.currentCount === 0) {
            this.overlayRef = this.cdkOverlayCreate();
            this.overlayRef.attach(new ComponentPortal(MatSpinner));
          }
        } else if (loadingState.count === 0 && this.currentCount !== 0) {
          this.overlayRef.dispose();
        }
        this.currentCount = loadingState.count;
      }
    );
  }

  cdkOverlayCreate(): OverlayRef {
    return this.overlay.create(
      {
        hasBackdrop: true,
        backdropClass: 'dark-backdrop',
        positionStrategy: this.overlay.position()
          .global()
          .centerHorizontally()
          .centerVertically()
      }
    );
  }
}

正如我之前所说,您希望加载显示独立​​于您所在的组件。这意味着应该从 HTTP 拦截器完成对状态的操作。它可能看起来像这样。

@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
  constructor(private store: Store<ApplicationState>) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.store.dispatch(new fromLoading.IncrementLoadingAction());
    return next.handle(req).pipe(
      finalize(() => this.store.dispatch(new fromLoading.DecrementLoadingAction())));
  }
}

每次请求完成时,加载状态都会增加,而当请求完成(失败与否)时,状态会减少。加载服务订阅此状态并通过显示/隐藏/保留覆盖来对更改做出反应。

完成此操作后,每次请求完成时都会出现加载,包括身份验证。

对于您的示例,您应该在执行请求时在效果内分派一个显示加载的操作,并在成功错误情况下分派一个隐藏加载程序的操作 (catchError()=> {...})。您可以从效果返回多个操作

return [{
      type: AuthActionTypes.LoginSuccessAction,
      payload: user
    }, {
      type: LoginActionTypes.DecrementLoading,
    }]

并且您还应该在执行身份验证请求之前调度增加加载的操作。

this.store.dispatch(new LoadingIncrementAction())
this.authService.login(action.payload).

推荐阅读