Angular 7 - mat-select 输入在使用守卫时有时无法打开

Angular 7 - mat-select input doesn't open sometimes when use guards

我从 Angular 中的多个应用程序结构开始,我在 mat-select 上发现了来自 Angular Material...

的奇怪行为

我无法打开下拉菜单 - 未出现叠加层并且调度了正常的点击事件而不是 material 使用 e.preventDefault 打开。要检查此行为,我使用(单击)处理程序来记录事件。

如果有效 - 没有事件日志(e.preventDefault 已调用,select 覆盖正常打开) 如果没有 - 单击事件记录 - UI

上的任何更改

所以...首先我检查过这可能是 Material 问题,所以我切换到 NG-Zorro - 从 angular.io 框架推荐并且仍然相同...

经过几个小时的调试、测试和搜索,我发现问题出在 AuthGuard - 仍然不知道为什么,但让我先描述一下授权流程。

着陆页 -> 使用 Google 登录并重定向到 App -> 授权操作 (ngrx) 在 init 上调度(在 app.component 中) -> ngrx 效果并监视 gapi token and dispatch auth success action -> effect and call to api for user data -> login success.

我准备了这个auth.effect用于测试

@Effect()
  authorize$: Observable<Action> = this.actions$.pipe(
    ofType(ActionTypes.Authorize),
    switchMap(() => this.authService.authState.pipe(
      map(user => {
        return user
          ? new AuthorizeSuccess(user)
          : new AuthorizeFailed();
      }),
      catchError(() => of(new AuthorizeFailed()))
    ))
  );

  @Effect()
  authorizeSuccess$: Observable<any> = this.actions$.pipe(
    ofType(ActionTypes.AuthorizeSuccess),
    switchMap((action: { type: string; payload: any }) => this.httpClient.get(`${environment.apiServerUrl}/users/me`)
      .pipe(take(1), map(response => {
        const user = new User(response ? { ...action.payload, ...ConvertingService.removeEmptyObjectValues(response) } : action.payload);
        return new LoginSuccess(user);
      }))
    ),
    tap(() => setTimeout(() => this.preloaderService.setInfinitely(true, false), 100)),
    catchError(() => of(new LoginFailed()))
  );

所以你可以看到动作流程。

Auth.reducer

export interface AuthenticationState {
  authorized: boolean
  profile: AuthUser
  user: User
}

export const initialState: AuthenticationState = {
  authorized: false,
  profile: null,
  user: null
};

export function authenticationReducer(
  state = initialState,
  action: Union
): AuthenticationState {
  switch (action.type) {

    case ActionTypes.AuthorizeSuccess:
      return {
        ...state,
        profile: action.payload
      };

    case  ActionTypes.LoginSuccess:
      return {
        ...state,
        user: action.payload,
        authorized: true
      };

   ...

    default:
      return state;
  }
}

简单select或

export interface AppState {
  auth: AuthenticationState;
  router: RouterReducerState<RouterStateUrl>;
}

export const reducers: ActionReducerMap<AppState> = {
  auth: authenticationReducer,
  router: routerReducer
};

// SELECTORS
export const selectAuth = (state: AppState) => state.auth;
export const selectRouter = (state: AppState) => state.router;
export const authState = createSelector(selectAuth, (state) => state.profile);
export const authorized = createSelector(selectAuth, (state) => state.authorized);
export const currentUser = createSelector(selectAuth, (state) => state.user);

最后守卫除了等待用户加载外什么都不做

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private store: Store<AppState>) { }

  canActivate(): Observable<boolean> {
    return this.checkStore().pipe(
      switchMap(() => of(true)),
      catchError(() => of(false))
    );
  }

  private checkStore(): Observable<boolean> {
    return this.store.pipe(
      select(authorized),
      filter(authenticated => authenticated),
      take(1)
    );
  }
}

这是通过

添加到路由中的
{
    canActivate: [AuthGuard],
    loadChildren: './modules/home/home.module#HomeModule',
    path: 'home',
},

所以...对我来说一切看起来都很好(如果有人对此代码有任何好的实践 - 任何反馈都会很好 :))。但是当我 运行 刷新页面 select 或有时想要工作时。好的,大部分时间。但是当我登陆然后登录然后登录后我被重定向到页面时似乎一切正常。仅当我登录时直接调用此路由时才会出现问题。

看下面的动画

另一个轨道是当我只是 return true 在那个守卫中,或者让它尽可能地类似于这个,例如使用一些延迟管或者什么奇怪的东西,当我将它映射到 true 时,有用。但是通过预期的检查它不会。

我将非常感谢任何建议,因为我花了最后 4 天时间进行重构、测试和调试:(

这是示例项目的回购:https://github.com/wojtek1150/mat-select-error

你好,W

this._authState.next(this.getProfile(r.id_token))更改为this.ngZone.run(() => this._authState.next(this.getProfile(r.id_token)));

您需要将 lambda 传递给 ngZone