Search code examples
javascriptangularngrx

Why is this selector's projector function returning undefined?


I am trying to create a selector that returns part of a feature selector. State is populated ansynchroniously via effect but starts with empty array.

Problem is that the projector function gets undefined passed in and I don't see why anymore.

selector.ts

import { createFeatureSelector, createSelector } from '@ngrx/store';

import { ChartState } from '../reducers/chart.reducer';

export const selectChartState = createFeatureSelector<ChartState>('chart');

export const selectFrameworksState = createSelector(
  selectChartState,
  (chart: ChartState) => chart.frameworks // <= here chart is undefined??
);

reducer.ts

import { Framework } from 'src/app/_interfaces/framework.interface';

import { Action, createReducer, on } from '@ngrx/store';

import * as ChartActions from '../actions/chart.actions';

export interface ChartState {
  frameworks: Framework[];
}

export const initialState: ChartState = {
  frameworks: []
};

export const chartReducer = createReducer(
  initialState,

  on(ChartActions.loadCharts, state => state),
  on(ChartActions.loadChartsSuccess, (state, action) => {
    return {...state, frameworks: [...action.data]};
  }),
  on(ChartActions.loadChartsFailure, (state) => state),

);

export function reducer(state: ChartState | undefined, action: Action) {
  return chartReducer(state, action);
}

module.ts

@NgModule({
  declarations: [
    ...  
  ],
  imports: [
    ...
    StoreModule.forFeature('chart', reducer),
    EffectsModule.forRoot([ChartEffects]) // forFeature() not working? Action provider?
  ],
  providers: [
    ...
  ]
})
export class ChartModule { }

app.component.ts

foo$ = this.store.pipe(select(selectFrameworksState));

Solution

  • The selector is called before the lazy loaded feature slice of the state is initialized.

    Access from within the ChartModule (where feature state is defined) the selector works fine.

    It is also recommended to decouple the state and only use it from within its module. If state is needed accross the whole app it might be better to move it to the root state.

    Thanks to @Jota.Toledo