6

I have looked at the 2 other posts regarding this, the one with the wrapping around the larger state does not apply whilst the other one with registering multiple forFeature -- I have done some testing around that and even if I import it before or after the forRoot(reducers) in my app.module, it makes no difference.

I'm sure I'm missing something obvious around the configuration.

My configuration:

export const orderAdapter: EntityAdapter<IOrder> = createEntityAdapter<IOrder>({
  selectId: (order: IOrder) => order._id
});

export interface AllOrdersState extends EntityState<IOrder> {}

export const initialState: AllOrdersState = orderAdapter.getInitialState({
  ids: [],
  entities: {}
});

export const OrdersState = createFeatureSelector<AllOrdersState>('orders');

export const {
  selectIds,
  selectEntities,
  selectAll,
  selectTotal
} = orderAdapter.getSelectors(OrdersState);

My actual reducer:


export function ordersReducer(
  state: AllOrdersState = initialState,
  action: actions.OrdersActions
) {
    case actions.CREATE_MANY: {
      console.log(action.orders);
      return orderAdapter.addMany(action.orders, state);
    }
}

I register in my Order.Module as:

    StoreModule.forFeature('orders', ordersReducer),

My main reducer map:

const reducers: ActionReducerMap<AppState> = {
  order: orderReducer,
  admin: adminReducer,
  tlabs: tlabsReducer,
  reports: reportsReducer,
  settings: settingsReducer,
  orders: ordersReducer
};

Then the main import in app.module:

    StoreModule.forRoot(reducers),

Trying to read the entities:

Constructor:

 private store: Store<AppState>

Actual function:

this.store
      .select(ordersReducer.selectAll)

Where that import is taken from:

import * as ordersReducer from '../../../../../store/reducers/orders.reducer';
SebastianG
  • 8,563
  • 8
  • 47
  • 111
  • When or where in code do you refer the ` ids`? – Yeheshuah Oct 02 '19 at 09:38
  • I mean your ids is really defined when you try to access it? – Yeheshuah Oct 02 '19 at 09:41
  • 1
    When I export the initial state, the reducer itself works and when I dispatch an action to create the entities, the devtools shows me the data: https://i.imgur.com/wIxCiC8.png but if I dispatch an action from another reducer, it will remove that data. Selecting it then does not seem to work. EDIT: recording of the state: https://streamable.com/8jl17 – SebastianG Oct 02 '19 at 09:42

4 Answers4

5

I had this error because I was setting up my selector with the wrong feature key:

export const selectIocState = createFeatureSelector<fromIoc.IocState>('this_key_was_wrong');

it should match what you have loaded in the feature module:

StoreModule.forFeature('feature_key', iocReducer),
Post Impatica
  • 14,999
  • 9
  • 67
  • 78
  • I had essentially the same error, this post and Brandon Roberts' post in the project helped: https://github.com/ngrx/platform/issues/932#issuecomment-376022550 – Mike Dalrymple Apr 15 '21 at 02:39
  • I just had the same error, had a lower case letter instead of an uppercase. Thank you for making me double-check it! (Already had spent a hour banging my head against the wall ) – João Silva Dec 02 '21 at 12:33
  • Using string enums for cases like this always helps – O-9 Sep 01 '22 at 08:24
4

I had a similar error to that of yours in entity.js (NGRX implementation file). In my case, I had a lazy-loaded module with its own state that was initially undefined. Since entity selectors don't do any null check prior to grabbing the entity related fields (e.g. ids) it causes this error. My solution was to avoid using orderAdapter.getSelectors(OrdersState) and instead define my own protected selectors which are fairly simple:

export const selectIds = createSelector(selectOrderState, (state) => state?.ids);
export const selectEntities = createSelector(selectOrderState, (state) => state?.entities);
export const selectAll = createSelector(selectOrderState, (state) => (state?.ids as Array<string|number>)?.map(id => state?.entities[id]));
export const selectTotal = createSelector(selectOrderState, (state) => state?.ids?.length);

I don't love the fact that I'm not using the built-in selectors but at least this doesn't break my code. I hope the NGRX team provides a way to avoid situations like this.

Wildhammer
  • 2,017
  • 1
  • 27
  • 33
2

It looks like it's trying to read from OrdersState before it has been initialized. Your reducer doesn't actually return the default state in order to initialize it; At least you don't seem to, at the code you present.

Make your reducer return the default state.

export function ordersReducer(
  state: AllOrdersState = initialState,
  action: actions.OrdersActions
) {
    switch(action.type) {
        case actions.CREATE_MANY: {
          console.log(action.orders);
          return orderAdapter.addMany(action.orders, state);
        }

        default: { 
          return state // Here you should return the default state
        }
    }
}
Wildhammer
  • 2,017
  • 1
  • 27
  • 33
korteee
  • 2,640
  • 2
  • 18
  • 24
  • this works, I don't 100% understand why though, is it just the way things are initialized? I have indeed forgotten to return a default to my switch case. – SebastianG Oct 02 '19 at 09:57
0

I had the same error, when I forgot to add the "state" as as a second parameter for adapter.addOne(). So in OPs example if the redcuer was written in following way:

      return orderAdapter.addMany(action.orders); // !! lack of "state" as 2nd param

then the error would be exactly the same. In my case this was:

Uncaught TypeError: Cannot read properties of undefined (reading 'ids')
    at Object.operation [as addOne] (entity.js?9b56:59:1)
    at eval (eval at <anonymous> (mapping-fields-group.reducer.ts?fd4f:1:1), <anonymous>:1:17)
    at eval (mapping-fields-group.reducer.ts?fd4f:13:1)
    at eval (store.js?d450:1204:1)
    at combination (store.js?d450:215:1)
    at mappingsDataReducers (mappings-data-state.ts?7c86:21:1)
    at eval (store.js?d450:265:1)
    at combination (store.js?d450:215:1)
    at eval (store.js?d450:254:1)
    at computeNextEntry (store-devtools.js?777a:445:1)
walkeros
  • 4,736
  • 4
  • 35
  • 47