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

Oleksiy Kononenko picture Oleksiy Kononenko · Nov 27, 2017 · Viewed 16.2k times · Source

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.

Answer

Oleksiy Kononenko picture Oleksiy Kononenko · Dec 11, 2017

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;
  });