1

我从 Angular 中的多个应用程序结构开始,我发现在 Angular Material 中的 mat-select 上有奇怪的行为......

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

如果有效 - 没有事件日志(e.preventDefault 调用,选择正常打开的覆盖)如果没有 - 单击事件记录 - UI 上的任何更改

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

经过数小时的调试、测试和搜索,我发现问题出在 AuthGuard 上——仍然不知道为什么,但让我先描述一下身份验证流程。

登陆页面->使用Google登录并重定向到应用程序->授权在init(在app.component中)上调度的动作(ngrx)->带有监视gapi令牌并调度auth成功动作的ngrx效果->效果并为用户调用api数据 -> 登录成功。

我准备了这个 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;
  }
}

和简单的选择器

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',
},

所以......对我来说一切都很好(如果有人对此代码有任何好的做法 - 任何反馈都会很好:))。但是当我运行这个并刷新页面选择器时,有时需要工作。好吧,大部分时间。但是当我登陆然后登录然后登录后我被重定向到页面一切似乎工作正常。问题只有当我登录时直接调用此路由时。

看下面的动画 在此处输入图像描述

另一个轨道是,当我只是return true在那个守卫中,或者尽可能地使它与此相似,例如使用一些延迟管道或奇怪的东西时,当我将其映射为 true 时,它​​就起作用了。但是通过预期的检查它不会。

我将非常感谢任何建议,因为我在最后 4 天都在重构、测试和调试上花费了 :(

这是带有示例项目的仓库:https ://github.com/wojtek1150/mat-select-error

问候,W

4

1 回答 1

2

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

您需要将 lambda 传递给ngZone

于 2019-04-09T10:26:04.343 回答