angularngrx-effectsngrx-store-4.0

angular 4.0.2, ngrx/store, reducers


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)

Solution

  • 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.