Search code examples
typescriptngrxngrx-store

How to create selector to select an item by id from ngrx store


I read ngrx store's documentation about selectors and need to figure out how to create a selector in order to select one item by item id. I already can do this as part of store subscription when I get all of the items from selectAllItems selector, but I need to figure out how to select specific item out of a list of items in the store. My main reason is that createSelector offers performance gains that I like to benefit from.

Here is my code:

import { AppState, Item } from '../../shared/models/index';
import { createSelector } from '@ngrx/store';

export const selectItems = (state: AppState) => state.eventsState;

export const selectAllItems = createSelector(selectItems, (allItems: { items: Item[] }) => {
  if (allItems && allItems.items) {
   return allItems.items.filter((item: Item) => (!item.active && !item.closed));
  } else {
    return allItems.items;
  }
});

Then in my controller i filter by id to get needed item:

this.store.select(selectors.selectAllItems)
  .filter(data => data !== null)
  .subscribe(allItems => {
    this.item = allItems.filter(item => {
      return item.id === this.navParams.data.id;
    });
  });

I would like to be able to create a selector for that specific item and use it like so:

this.store.select(selectors.selectItemById(this.navParams.data.id))
  .filter(data => data !== null)
  .subscribe(selectedItem => {
    this.item = selectedItem;
  });

Any help will be appreciated.


Solution

  • After some research I solved my own problem. I used factory function to get desired selectItemById selector. Here is my new selector:

    import { AppState, Item } from '../../shared/models/index';
    import { createSelector } from '@ngrx/store';
    
    export const selectItems = (state: AppState) => state.eventsState.items;
    
    export const getItemById = (id) => createSelector(selectItems, (allItems) => {
      if (allItems) {
        return allItems.find(item => {
          return item.itemId === id;
        });
      } else {
        return {};
      }
    });
    

    Then all I have to do in my controller is to call this selector and pass it an id of desired item to get the item out of the store:

    import * as selectors from '../../app/store/selectors';
    
    this.store.select(selectors.getItemById(id))
      .subscribe((item) => {
        this.item = item;
      });