I have an issue with NgRx selector, which returns undefined. All the actions are dispatched and effects and reducers got triggered. But the returned value is undefined.
account.actions.ts
export const loadProfile = createAction('[Account Resolver] Load Profile');
export const profileLoaded = createAction('[Load Profile Effect] Profile Loaded', props<{ profile: Profile }>());
account.effects.ts
loadProfile$ = createEffect(() =>
this.actions$.pipe(
ofType(AccountActions.loadProfile),
concatMap(() => this.accountService.getProfile()),
map((profile: Profile) => profileLoaded({ profile }))
)
);
account.reducer.ts
export const accountReducer = createReducer(
initialAccountState,
on(AccountActions.profileLoaded, (state, action) => {
return {
...state,
profile: action.profile
};
}),
)
account.resolver.ts
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.store.pipe(
tap(() => {
if (!this.loading) {
this.loading = true;
this.store.dispatch(loadProfile());
}
}),
first(),
finalize(() => (this.loading = false))
);
}
account.selectors.ts
export const selectAccountState = createFeatureSelector<fromAccount.AccountState>('account');
export const selectProfile = createSelector(selectAccountState, account => account.profile);
account.component.ts
ngOnInit() {
this.store
.pipe(
select(selectProfile),
tap(profile => {
this.profileForm.patchValue(profile);
}),
takeUntil(this.destroy)
)
.subscribe();
}
And here, in component i have undefined while patchValue method is called. When I am using async pipe (just to test), it works as expected. But I need to update a form value ... Where have I missed something?
I think your problem is the resolver, you seem to be using the pipe operator directly in the store instead of using the select operator first, also you should add a filter(v => !!v) that ensures it only returns when the profile is no longer undefined, the profile is undefined while is loading and the first operator will get that undefined which will make your resolver render the UI while is undefined and your ngOnInit get an undefined value. As a personal preference, I don't tend to use the resolve the way you are doing it because it won't allow you to add loading section while the profile is loaded, I think is simply better to fire the loadProfile in the ngInit of your component and add a isLoading property to your state that you can query via a selector