Выбранная угловая защита ngrx не определена, даже если данные были загружены

У меня есть редуктор

on(CmsActions.loadCmsTopNewsSelected, (state, { slug }) => {
    let selected;
    if (state.data) {
      selected = state.data.items.find(item => item.data.slug.iv === slug);
    }
    return {
      ...state,
      selected
    };
  })

и этот охранник

canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {
    return this.checkStore().pipe(
      switchMap(() => {
        const slug = route.params.slug;
        this.facade.selected(slug);
        return this.facade.selected$.pipe(
          map(selected => {
            console.log('selected', selected);
            if (selected) {
              return true;
            }
            return this.router.parseUrl('/not-found');
          })
        );
      }),
      catchError(() => of(false))
    );
  }

  checkStore(): Observable<boolean> {
    return this.facade.loaded$.pipe(
      tap(loaded => {
        if (!loaded) {
          this.facade.load(this.ITEMS_TO_LOAD);
        }
      }),
      filter(loaded => {
        console.log('loaded', loaded);
        return loaded;
      }),
      take(1)
    );
  }

он отлично работает, если я иду по маршруту по ссылке маршрутизатора,

но если я пойду прямо, выбранный не определен, даже если

данные были загружены.

Что случилось?

ОБНОВИТЬ

Я публикую больше кода для лучшего понимания. Кстати, я жду загрузки данных, когда в браузере выполняется дочерний маршрут.

Родительские маршруты

{
   path: 'news',
   canLoad: [CmsNewsGuard],
   loadChildren: () =>
          import('./news/news.module').then(m => m.PublicNewsModule)
},

Дети

{
    path: ':slug',
    canActivate: [CmsNewsGuardSelected],
    component: PublicNewsPageDetailsComponent
  },
  {
    path: '',
    component: PublicNewsListComponent,
    pathMatch: 'full'
  }

Фасад

export class CmsNewsFacade {
  get data$(): Observable<CmsArray<CmsNews> | null> {
    return this.store.pipe(select(selectCmsNewsData));
  }

  get error$(): Observable<Required<ErrorDto> | null> {
    return this.store.pipe(select(selectCmsNewsError));
  }

  get loaded$(): Observable<boolean> {
    return this.store.pipe(select(selectCmsNewsLoaded));
  }

  get selected$(): Observable<CmsNews | undefined> {
    return this.store.pipe(select(selectCmsNewsSelected));
  }

  constructor(private store: Store<CmsState>) {}

  load(top: number): void {
    this.store.dispatch(CmsActions.loadCmsTopNews({ top }));
  }

  selected(slug: string): void {
    this.store.dispatch(CmsActions.loadCmsTopNewsSelected({ slug }));
  }
}

Селектор

export const selectCmsNewsSelected = createSelector(
  selectMarketAccountFeature,
  (state: CmsState) => {
    return state.news.selected;
  }
);

ОБНОВЛЕНИЕ2

Это работает с

return this.facade.selected$.pipe(
          filter(selected => {
            return !!selected;
          }),
          map(selected => {
            if (selected) {
              return true;
            }
            return this.router.parseUrl('/not-found');
          })
        );

но при этом я потерял цель показать не найденную страницу, если пул не существует :(

РАБОТАЕМ!

Я решил это, добавив проверку в редуктор

const current = state.data.items.find(item => item.data.slug.iv === slug);
if (!current) {
   selected = null;
}

в карауле просто

filter(selected => {
   return selected !== undefined;
}),

person Whisher    schedule 31.01.2020    source источник
comment
Пожалуйста, поделитесь и своим селектором. Вопрос: у вас лениво загружается кусок состояния?   -  person Anarno    schedule 31.01.2020
comment
Поделитесь своим селектором selectCmsNewsSelected   -  person Anarno    schedule 31.01.2020
comment
Я обновил пост   -  person Whisher    schedule 31.01.2020
comment
Это ожидаемое поведение. Ваш селектор - это константный экспорт, который постоянно загружается с нетерпением, но ваш редуктор привязан к вашей части состояния и загружается после загрузки модуля отложенной загрузки. См. Мой ответ отредактировать.   -  person Anarno    schedule 01.02.2020
comment
Я разобрался, но спасибо за помощь :)   -  person Whisher    schedule 01.02.2020


Ответы (1)


Я думаю, что ваш селектор пытается выбрать неопределенный фрагмент состояния, потому что, когда ваша страница загружена, ваш Guard проверяет условие быстрее, чем ваши данные появляются в магазине после загрузки. Это из-за ленивой загрузки. Ваша охрана предоставляется в виде загруженного модуля. Фрагмент вашего магазина объявлен в модуле с отложенной загрузкой, поэтому ваш Guard не принимает вашу навигацию при первой загрузке.

Как вы это решаете?

Проверьте, когда ваше состояние не определено, и в этом случае верните true, а когда ваше состояние обновляет, ваша охрана перенаправит вашего пользователя, если у него нет доступа.

person Anarno    schedule 31.01.2020