I'm trying to implement ngrx v4 to my angular project and struggling with getting data from ngrx store. I wrote Actions, Reducer and Effects based on provided api documentation on github page and it seems to me everything is correct but instead of data I get store State like this:
So I appreciate if somebody could help me to figure out where my mistake is. Thanks in advance. My code below
interface.ts
export interface Category {
id?: number;
name: string;
used: boolean;
}
actions.ts
import { Action } from '@ngrx/store';
import {Category} from '../categories';
export const GET_CATEGORIES = '[Category] Get data';
export const GET_CATEGORIES_ERROR = '[Category] Get data error';
export const GET_CATEGORIES_SUCCESS = '[Category] Get data success ';
export class GetCategories implements Action {
readonly type = GET_CATEGORIES;
}
export class GetCategoriesError implements Action {
readonly type = GET_CATEGORIES_ERROR;
}
export class GetCategoriesSuccess implements Action {
readonly type = GET_CATEGORIES_SUCCESS;
constructor(public payload: Category[]) { }
}
export type All = GetCategories | GetCategoriesSuccess | GetCategoriesError
reducer.ts
import * as CategoriesActions from './categories.actions';
import {Category} from '../categories';
export type Action = CategoriesActions.All;
export function categoriesReducer (state: Category[], action: Action) {
switch (action.type) {
case CategoriesActions.GET_CATEGORIES: {
return state;
}
case CategoriesActions.GET_CATEGORIES_ERROR: {
return state;
}
case CategoriesActions.GET_CATEGORIES_SUCCESS: {
return action.payload;
}
default: {
return state;
}
}
}
effects.ts
...
import {CategoriesService} from './categories.service';
@Injectable()
export class CategoriesEffects {
@Effect() getCategories$: Observable<Action> = this.actions$
.ofType('GET_CATEGORIES')
.mergeMap(action => this.categoriesService.getCategories()
.map(data => ({type: 'GET_CATEGORIES_SUCCESS', payload: data }))
.catch(() => of({ type: 'GET_CATEGORIES_ERROR', payload: {message: 'Oops something is wrong'} }))
);
constructor(
private actions$: Actions,
private categoriesService: CategoriesService
) {}
}
component.ts
interface CategoryState {
categories: Category[]
}
@Component({
selector: 'app-categories',
templateUrl: './categories.component.html',
styleUrls: ['./categories.component.css'],
})
export class CategoriesComponent implements OnInit {
categories$: Observable<Category[]>;
constructor(private store: Store<CategoryState>) {
console.log(this.categories$) // undefined
this.categories$ = this.store.select('categories');
console.log(this.categories$) // store state
}
ngOnInit() {
this.getCategories()
}
getCategories () {
this.store.dispatch({ type: 'GET_CATEGORIES' });
}
}
module
@NgModule({
imports: [
...
StoreModule.forRoot({ categories: categoriesReducer }),
EffectsModule.forRoot([CategoriesEffects]),
],
declarations: [ CategoriesComponent ],
providers: [ CategoriesService ],
entryComponents: []
})
export class CategoriesModule {}
Since you are using ngrx/store : 4.1
You should have a reducer factory to inject the reducers to the StoreModule
import {ActionReducerMap} from '@ngrx/store';
import {Category} from '../categories';
import * as categoryReducer from './categories.reducer';
export interface CategoryState {
categories: Category[]
}
export interface AppStates {
categoryState: CategoryState;
}
export const categoryReducers: ActionReducerMap<AppStates> = {
categoryState: categoryReducer.reducer
};
Use the reducer factory to inject into the module as below,
StoreModule.forRoot(categoryReducers)
import {categoryReducers} from './store/categories.reducer.factory';
Your constructor should take the AppStates
as the type for Store
as
constructor(private store: Store<AppStates>){}
And your effect should use be
@Effect()
getCategories$: Observable<Action> = this.actions$
.ofType(CategoriesActions.GET_CATEGORIES)
.mergeMap(action => this.categoriesService.getCategories()
.map(data => ({type: CategoriesActions.GET_CATEGORIES_SUCCESS, payload: data }))
.catch(() => of({ type: CategoriesActions.GET_CATEGORIES_ERROR, payload: {message: 'Oops something is wrong'} }))
);