Working on integrating ngrx with Angular. Authentication is successful, but facing issues with product store implementation:
Organizing the project using modules:
const routes: Routes = [
{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
{
path: 'home',
loadChildren: () => import('src/app/home/home.module')
.then(module => module.HomeModule)
}
]
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot(routes),
EffectsModule.forRoot([]),
StoreModule.forRoot({}),
StoreDevtoolsModule.instrument({
maxAge: 25,
logOnly: environment.production
}),
TopBarModule,
AuthModule,
HomeModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Injecting effect services in the home module:
const routes: Routes = [
{
path: '',
component: HomeComponent
}
]
@NgModule({
declarations: [
HomeComponent
],
imports: [
CommonModule,
RouterModule.forChild(routes),
EffectsModule.forFeature([
GetCategoryEffectsService,
GetProductEffectService
]),
StoreModule.forFeature('category', categoryReducers),
StoreModule.forFeature('product', productReducers),
],
providers: [
GetCategoriesService,
GetProductsService
]
})
export class HomeModule { }
The redux setup seems correct but the effect is not functioning properly:
@Injectable()
export class GetProductEffectService {
constructor(
private actions$: Actions,
private getProductsService: GetProductsService
) { }
getProducts$ = createEffect( () =>
this.actions$.pipe(
ofType(getProductAction),
switchMap(() => {
return this.getProductsService.getProducts().pipe(
map((products) => getProductActionSuccess({products}))
)
})
))
}
If subscribing to the method directly without store, all products are fetched...
Defined actions:
export const getProductAction = createAction(
ProductActionTypes.PRODUCT_ACTION
);
export const getProductActionSuccess = createAction(
ProductActionTypes.PRODUCT_ACTION_SUCCESS,
props<{products: ProductInterface[]}>()
);
export const getProductActionFailure = createAction(
ProductActionTypes.PRODUCT_ACTION_FAILURE,
props<{error: BackendErrorsInterface}>()
);
export enum ProductActionTypes {
PRODUCT_ACTION = '[Product] product action',
PRODUCT_ACTION_SUCCESS = '[Product] product action success',
PRODUCT_ACTION_FAILURE = '[Product] product action failure',
}
const initialState: ProductStateInterface = {
data: null,
error: null,
isLoading: false,
isSubmitting: false
}
const reducers = createReducer(
initialState,
on(
getProductAction,
(state): ProductStateInterface => ({
...state,
isLoading: true,
error: null
})
),
on(
getProductActionSuccess,
(state, action): ProductStateInterface => ({
...state,
data: action.products,
isLoading: false,
error: null
})
),
on(
getProductActionFailure,
(state, action): ProductStateInterface => ({
...state,
data: null,
isLoading: false,
error: action.error
})
)
);
export function productReducers(state: ProductStateInterface, action: Action){
return reducers(state, action);
}
Selecting actions in product selector file:
export const actionFeatureSelector = createFeatureSelector<
AppStateInterface,ProductStateInterface>('product');
export const productIsLoadingSelector = createSelector(
actionFeatureSelector,
(productState: ProductStateInterface) => productState.isLoading
);
export const getProductsSelector = createSelector(
actionFeatureSelector,
(productState: ProductStateInterface) => productState.data
);
export const productErrorSelector = createSelector(
actionFeatureSelector,
(productState: ProductStateInterface) => productState.error
);
export const productIsSubmittingSelector = createSelector(
actionFeatureSelector,
(productState: ProductStateInterface) => productState.isSubmitting
);
No update is observed in the store. Below is the component logic:
ngOnInit(): void {
this.initializeValues();
}
private initializeValues(): void {
this.store.pipe(select(getProductsSelector)) //.subscribe(test => console.log(test));
this.categories$ = this.store.pipe(select(categorySelector));
this.isLoading$ = this.store.pipe(select(isLoadingSelector));
}