I've got this reducer
on(CmsActions.loadCmsTopNewsSelected, (state, { slug }) => {
let selected;
if (state.data) {
selected = state.data.items.find(item => item.data.slug.iv === slug);
}
return {
...state,
selected
};
})
and this guard
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)
);
}
it works nicely if I go to the route by router link,
but if I go directly the selected is undefined even if
the data has been loaded.
What's wrong?
UPDATE
I post more code for a better understanding By the way, I'm waiting to have the data loaded when the children route is running by the browser.
Routes Parent
{
path: 'news',
canLoad: [CmsNewsGuard],
loadChildren: () =>
import('./news/news.module').then(m => m.PublicNewsModule)
},
Children
{
path: ':slug',
canActivate: [CmsNewsGuardSelected],
component: PublicNewsPageDetailsComponent
},
{
path: '',
component: PublicNewsListComponent,
pathMatch: 'full'
}
Facade
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 }));
}
}
Selector
export const selectCmsNewsSelected = createSelector(
selectMarketAccountFeature,
(state: CmsState) => {
return state.news.selected;
}
);
UPDATE2
It workish with
return this.facade.selected$.pipe(
filter(selected => {
return !!selected;
}),
map(selected => {
if (selected) {
return true;
}
return this.router.parseUrl('/not-found');
})
);
but doing so I lost the goal show a not found page if the slug didn't exist :(
WORKED IT OUT!
I worked it out adding a check in the reducer
const current = state.data.items.find(item => item.data.slug.iv === slug);
if (!current) {
selected = null;
}
in the guard simply
filter(selected => {
return selected !== undefined;
}),