I have made an application using ngrx/store 4.0.2 with the help of example app from ngrx git repository for version 4.0.x. Other modules which i have used to run this part of the application i s. @angular/cli: 1.3.0 node: v8.1.3 npm : 5.3.0. I have other modules which follows the same pattern and everyone is showing the same problem. Please help me to rectify this problem.
My effect function to call api is .
@Effect() loadUsers$: Observable<Action> = this.actions$
.ofType(ObjectActions.LOAD_USERS)
.startWith(new ObjectActions.Loadusers())
.switchMap(() =>
this.service.loadUsers()
.map((users: UserModel[]) => new ObjectActions.Loaduserssuccess(users))
.catch(err => of(new ObjectActions.Loadusersfailure(err)))
)
My reducer is users.reducer.ts
export interface UserState {
user_ids: string[]
users: {[id: string]: Array<UserModel>}
selectedUserId: string| null;
}
const initialState: UserState = {
user_ids: [],
users: {},
selectedUserId: null
}
export function UsersReducer(state = initialState, action: UserActions.Actions): UserState {
switch(action.type){
case UserActions.LOAD_USERS_SUCCESS:
return {
user_ids: action.payload.user_ids,
users: action.payload.users,
selectedUserId: null
}
case UserActions.LOAD_USERS_FAILURE:
case UserActions.ADD_USER_SUCCESS:
return {
user_ids: [ ...state.user_ids, action.payload.user_id],
users: Object.assign({}, state.users, { [action.payload.user_id]: action.payload}),
selectedUserId: state.selectedUserId
};
case UserActions.ADD_USER_FAILURE:
case UserActions.GET_USER_SUCCESS:
case UserActions.SELECT_USER_SUCCESS:
return {
user_ids: state.user_ids,
users: state.users,
selectedUserId: action.payload,
}
case UserActions.DELETE_USER_SUCCESS:
enter code here
default:
return state
}
}
export const getUsersId= (state: UserState) => state.user_ids
export const getUsers = (state: UserState) => state.users
export const getAllUsers = createSelector(getUsers, getUsersId, (users, user_ids) => {
return user_ids.map(user_id => users[user_id]) || new Map();
});
export const selectedUserId = (state: UserState) => state.selectedUserId;
export const getSelectedUser = createSelector(getUsers, selectedUserId, (entities, selectedId) => {
return entities[selectedId];
});
export interface AppState {
users: fromUser.UserState;
loggedinuser: fromLogin.LoginState;
}
export const reducer: ActionReducerMap<AppState> = {
users: fromUser.UsersReducer,
loggedinuser: fromLogin.LoginReducer,
};
export const getUserAppState = createFeatureSelector<AppState>('users');
export const getUserState = createSelector(
getUserAppState,
(state: AppState) => state.users
);
export const getUsers = createSelector(getUserState, fromUser.getAllUsers)
On selecting getUsers from store, I am getting this error
UsersComponent.html:50 ERROR TypeError: Cannot read property 'map' of undefined
at users.reducer.ts:74
at index.js:76
at index.js:36
at index.js:90
at index.js:36
at store.es5.js:698
at memoized (store.es5.js:666)
at store.es5.js:702
at MapSubscriber.memoized [as project] (store.es5.js:666)
at MapSubscriber.webpackJsonp.../../../../rxjs/operator/map.js.MapSubscriber._next (map.js:77)
It is happening because the selectors are trying to loop something which is undefined. It mostly happens in this case where the store is empty before API call but you selector is trying to loop through it. As we save data to store only when API responds.