10

I started using ngrx/entity package, where I can manage store by adapter. There is addOne method I'd like to use, but it adds item to the end of collection. I wanna add one at the beginning. Could you please help me with that? How to add item at the beginning with EntityAdapter.

How I create entity adapter:

export const adapter: EntityAdapter<AssetTreeNode> = createEntityAdapter({
  selectId: (model: AssetTreeNode) => model.Id
});

Reducer looks like that:

export function reducer(state: AssetListState = initialState, action: AssetListAction) {
  switch (action.type) {
    (...)
    case ASSET_LIST_ADD_ITEM:
      let assetToAdd: AssetTreeNode = Object.assign({} as AssetTreeNode, 
        action.payload.asset, 
        { Id: action.payload.createdAssetId });
      return adapter.addOne(assetToAdd, state); <--- I wanna add here at the end.
    (...)
    default:
      return state;
  }
}
magos
  • 3,371
  • 4
  • 29
  • 54

3 Answers3

5

There is no proper way provided by @ngrx/entity team. One of the answer mentions to use sort-comparator. But i believe using sort-comparator is not the right way to go. Suppose there is two click actions and in one action we need to append item below and in other action on top. here we will run into the same problem again.

I had run into the same issue and my solution to the problem is to reconstruct the list when we want the item on top of the list.

To add at the top of entity list

const { selectAll } = myAdapter.getSelectors();
...
...
on(MyActions.addItem, (state, { item }) =>{
    return myAdapter.setAll([item ,...selectAll(state)], { ...state})
}),

To add at the bottom of entity list

on(MyActions.addItem, (state, { item}) =>{
   return myAdapter.addOne(item, state)
}),
Rameez Rami
  • 5,322
  • 2
  • 29
  • 36
  • If you happen to be using an older version of `ngrx` like me, you can use `addAll` instead of `setAll`. More info here: https://github.com/nrwl/nx/issues/3698 – Leniel Maccaferri Oct 28 '21 at 00:18
4

The only way to change this behavior would be to use the sortComparer when you create the adapter - docs.

export const adapter: EntityAdapter<User> = createEntityAdapter<User>({
  sortComparer: (a: User, b: User) => a.name.localeCompare(b.name),
});
Abhay
  • 3,151
  • 1
  • 19
  • 29
timdeschryver
  • 14,415
  • 1
  • 19
  • 32
  • Is it possible to add second rule to sort comparer? I prefer to firstly check isNew prop and then sort by name. But sort function has to return number, not boolean, that's why I'm hesitated how to compose it. – magos Aug 24 '18 at 07:35
  • To be honest I don't know if you could solve your case with it tho… It could only be possible if your added id's would have an higher id. If this is the case you could order based on ids in desc order. – timdeschryver Aug 24 '18 at 08:28
  • i've tried this one but it doesn't seem to work with dates. Here's a snippet ```export function sortByCreateDate(a: Bookmark, b: Bookmark): number { return Number(b.created_at) - Number(a.created_at); } export const adapter: EntityAdapter = createEntityAdapter({ sortComparer: sortByCreateDate, }); ``` – The.Wolfgang.Grimmer Sep 03 '20 at 09:30
1

Maybe you could place the item at the begining and replace the list

on(addAsset, (state, { payload }) => {
  const currentList = Object.values(state.entities);
  const newList = [payload, ...currentList];
  return adapter.setAll(newList, state);
});