Search code examples
angularngrxangular-ngrx-data

create a selector for a ngrx/data entity


I have a state and I'd like to create selectors from ngrx/data entities.

import {
  Action,
  ActionReducer,
  ActionReducerMap,
  createFeatureSelector,
  createSelector,
  MetaReducer
} from '@ngrx/store';
import {environment} from '../../environments/environment';
import * as fromRouter from '@ngrx/router-store';
import * as fromDrawer from './drawer';
import {InjectionToken} from '@angular/core';
import {NavigationItem} from '../models/navigation-item';

export interface State {
  router: fromRouter.RouterReducerState<any>;
  drawerNavigationItems: fromDrawer.State;
}

export const ROOT_REDUCERS = new InjectionToken<ActionReducerMap<State, Action>>('Root reducers token', {factory: () => ({
    router: fromRouter.routerReducer,
    drawerNavigationItems: fromDrawer.reducer,
  }),
});

export const metaReducers: MetaReducer<State>[] = !environment.production ? [] : [];

export const selectRouter = createFeatureSelector<
  State,
  fromRouter.RouterReducerState<any>
  >('router');

const {
  selectQueryParams,    // select the current route query params
  selectQueryParam,     // factory function to select a query param
  selectRouteParams,    // select the current route params
  selectRouteParam,     // factory function to select a route param
  selectRouteData,      // select the current route data
  selectUrl,            // select the current url
} = fromRouter.getSelectors(selectRouter);

export const selectRouteId = selectRouteParam('id');
export const selectStatus = selectQueryParam('status');


// Drawer

export const selectDrawerNavigationItems = (state: State) => state.drawerNavigationItems.items as NavigationItem[];

How do I use the pre-defined selectors or write my own with entities or services that came from ngrx/data?

As an example I'd like to create a selector that selects all "Community" entities and then, step 2, select 1 by selectRouteId. If you imagine a route /communities/:id, selectRouteId returns the Id, and now I'd like the data from the CommunityService and use the selector created or somehow imported and used in step 1 and return a result, 1 Community with the selectRouteId's id, so I can later do something like this.store.dispatch(selectCommunityByCurrentRouteId);

This question is specific to @ngrx/data.


Solution

  • See https://github.com/peterbsmith2/platform/blob/b2f17bfcc987bf63d10dd207263c0ca2a2e44373/projects/ngrx.io/content/guide/data/extension-points.md#custom-selectors.

    /* src/app/reducers/index.ts */
    import * as fromCat from './cat.reducer';
    import { Owner } from '~/app/models'
    
    export const ownerSelectors = new EntitySelectorsFactory().create<Owner>('Owner');
    
    export interface State {
      cat: fromCat.State;
    }
    
    export const reducers: ActionReducerMap<State> = {
      cat: fromCat.reducer
    };
    
    export const selectCatState = (state: State) => state.cat;
    
    export const {
      selectAll: selectAllCats
    } = fromCat.adapter.getSelectors(selectCatState);
    
    export const selectedCatsWithOwners = createSelector(
      selectAllCats,
      ownerSelectors.selectEntities,
      (cats, ownerEntities) => cats.map(c => ({
        ...c,
        owner: ownerEntities[c.owner]
      }))
    );