我从Angular中的多个应用程序结构入手,发现在Angular Material的mat-select上有奇怪的行为...
我无法打开下拉菜单-没有出现叠加层,并且调度了正常的click事件,而不是使用e.preventDefault打开材料。要检查此行为,我使用(单击)处理程序来记录事件。
如果有效-没有事件日志(调用e.preventDefault,请选择正常打开的叠加层) 如果没有,请点击事件已记录-用户界面上的任何更改
所以...首先,我检查了这可能是重大问题,因此我切换到NG-Zorro-从angular.io框架推荐,并且仍然相同...
经过数小时的调试,测试和搜索,我发现AuthGuard存在问题-仍然不知道为什么,但是让我首先描述身份验证流程。
着陆页->使用Google登录并重定向到App->授权在init(在app.component中)上分派的动作(ngrx)-> ngrx效果并监视gapi令牌并分派auth成功动作->效果并调用用于用户数据的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
答案 0 :(得分:2)
将this._authState.next(this.getProfile(r.id_token))
更改为this.ngZone.run(() => this._authState.next(this.getProfile(r.id_token)));
您需要将lambda传递给ngZone