Угловой 7 - вход выбора мата иногда не открывается при использовании охранников - PullRequest
1 голос
/ 06 апреля 2019

Я начинаю со структуры нескольких приложений в Angular, и я обнаружил странное поведение при выборе mat из Angular Material ...

Я не могу открыть раскрывающийся список - наложение не появляется, и обычное событие нажатияотправляется вместо материала, открытого с помощью e.preventDefault.Чтобы проверить это поведение, я использую (клик) обработчик для регистрации событий.

Если работает - журнал событий (e.preventDefault не вызывается, выберите оверлей, открытый нормально). Если нет - щелкните событие, зарегистрированное - любые изменения в пользовательском интерфейсе

Итак ... Сначала я 'Я проверил, что это может быть проблема с Материалом, поэтому я переключился на NG-Zorro - рекомендуется из рамки angular.io и все тот же ...

После многих часов отладки, тестирования иПоиск Я обнаружил, что проблема с AuthGuard - все еще не знаю почему, но позвольте мне сначала описать поток аутентификации.

Целевая страница -> Войти в Google с перенаправлением в приложение -> Авторизовать действие (ngrx), отправленное наinit (в app.component) -> эффект ngrx с отслеживанием токена gapi и отправкой действия успешной аутентификации -> эффект и вызов 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',
},

Итак ... Все выглядит хорошо для меня (если у кого-то есть хорошая практика для этого кода - любой отзыв будет приятным :)).Но когда я запускаю это и обновляю страницу, селектор хочет иногда работать.Хорошо, большую часть времени.Но когда я иду на посадку, то вход в систему, то после входа я перенаправлен на страницу, кажется, работает нормальноПроблема только в том, что я напрямую вызываю этот маршрут, когда я вхожу в систему.

См. Анимацию ниже enter image description here

Другой трек состоял в том, что когда я просто return trueв этой защите, или сделайте так, чтобы это было как можно больше, например, используя какой-нибудь канал задержки или что странно, когда я отображаю это в true, это работает.Но с ожидаемой проверкой это не будет.

Я буду очень благодарен за любые предложения, потому что я потратил на это 4 последних дня с рефакторингом, тестированием и отладкой: (* ​​1042 *

Вот репо сПример проекта: https://github.com/wojtek1150/mat-select-error

Привет, Ш

1 Ответ

2 голосов
/ 09 апреля 2019

Изменить this._authState.next(this.getProfile(r.id_token)) на this.ngZone.run(() => this._authState.next(this.getProfile(r.id_token)));

Вам нужно передать лямбду на ngZone

...