cuznerdexter
cuznerdexter

Reputation: 596

NX + NGRX TypeError: entities is not iterable. Why?

I have used Ngrx in the past and had no issues. Now I am trying to use Entities for 1st time and it is not working at all.

I have an Angular9+ app in an NX workspace calling some mock data from a service.

Anyone tell me what is wrong? I cannot figure it out. (this is long post)

Actions file:

....
export const loadSheetData = createAction('[SheetData] Load SheetData');

export const loadSheetDataSuccess = createAction(
  '[SheetData] Load SheetData Success',
  props<{ sheetData: SheetDataEntity[] }>()
);
....

Effects file

....
@Injectable()
export class SheetDataEffects {
  loadSheetData$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SheetDataActions.loadSheetData),
      fetch({
        run: (action) => {
          return this.bottomSheetSvc.getSheetData().pipe(
            tap((obj) => 
            catchError(error => of(new Error('Effect failed') ) ),
            map((data) => SheetDataActions.loadSheetDataSuccess({ sheetData: data}) ) );

        onError: (action, error) => {
          return SheetDataActions.loadSheetDataFailure({ error });
        },
      })
    )
  );
....

Model file

export interface SheetDataEntity {
  id: string | number; // Primary ID
  info: string;
  link: string;
  icon?: string; 
  isDisabled?: boolean;
}

Reducer file

export const SHEETDATA_FEATURE_KEY = 'sheetData';

export interface State extends EntityState<SheetDataEntity> {
  selectedId?: string | number; // which SheetData record has been selected
  loaded: boolean; // has the SheetData list been loaded
  error?: string | null; // last none error (if any)
}

export interface SheetDataPartialState {
  readonly [SHEETDATA_FEATURE_KEY]: State;
}

export const sheetDataAdapter: EntityAdapter<SheetDataEntity> = createEntityAdapter<
  SheetDataEntity
>();

export const initialState: State = sheetDataAdapter.getInitialState({
  // set initial required properties
  entities: {
    0: {}
  },
  loaded: false,
});

const sheetDataReducer = createReducer(
  initialState,
  on(SheetDataActions.loadSheetData, (state) => ({
    ...state,
    loaded: false,
    error: null,
  })),
  on(SheetDataActions.loadSheetDataSuccess, (state, { sheetData }) => 
  {
    console.log('TEMP1:', state, sheetData);
    let temp = sheetDataAdapter.setAll(sheetData, { ...state, loaded: true })
    console.log('TEMP2:', temp);
    return temp;
  }
    
  ),
  on(SheetDataActions.loadSheetDataFailure, (state, { error }) => ({
    ...state,
    error,
  }))
);

export function reducer(state: State | undefined, action: Action) {
  console.log('SHEET REDUCER::', state, action);
  return sheetDataReducer(state, action);
}

Selectors file

....
export const getAllSheetData = createSelector(
  getSheetDataState,
  (state: State) => selectAll(state)
);
....

Service data

dummyData: any = {
    ids: [5, 4, 3, 2, 1],
    entities: {
      1: {
        id: 1,
        info: 'test info 1',
        link: '/test1',
        icon: 'test icon 1', 
        isDisabled: false
      },
      2: {
        id: 2,
        info: 'test info 2',
        link: '/test2',
        icon: 'test icon 2', 
        isDisabled: false
      },
      3: {
        id: 3,
        info: 'test info 3',
        link: '/test3',
        icon: 'test icon 3', 
        isDisabled: false
      },
      4: {
        id: 4,
        info: 'test info 4',
        link: '/test4',
        icon: 'test icon 4', 
        isDisabled: false
      },
      5: {
        id: 5,
        info: 'test info 5',
        link: '/test5',
        icon: 'test icon 5', 
        isDisabled: false
      }
    }

  };

Component file

sheetData$: Observable<SheetDataEntity[]>;

constructor(
    private store: Store<State>,
    ) {

      this.sheetData$ = this.store.pipe( select( selectors.getAllSheetData ) );
    }

  ngOnInit(): void {
    this.store.dispatch( actions.loadSheetData() );
  }

Template file

<sheet-item 
        *ngFor="let item of (sheetData$ | async)" 
        [item]="item" 
        (onUpdateSelectedLink)="updateSelectedLink($emit)">
    </sheet-item>

Upvotes: 1

Views: 1846

Answers (2)

Savan Gadhiya
Savan Gadhiya

Reputation: 1145

Delete your node_modules, clear the cache, and reinstall it. It worked for me. Maybe the node_modules are corrupted which is why we are getting this error.

Upvotes: 0

cuznerdexter
cuznerdexter

Reputation: 596

Yay! finally success. Was a dumb error! I modified the service mock data to be a normal array of items. Then passed that into the ’success action’. Got confused trying to follow multiple tutorials all using different Angular versions and code styles. Thanks @derekkite / @RoboZoom (in Gitter) you set me on the right path. :)

run: (action) => {
          return this.bottomSheetSvc.getSheetData().pipe(
            tap((obj) => console.log('Effect: switch:', obj)),
            catchError(error => of(new Error('Effect failed') ) ),
            map((dataObj) => SheetDataActions.loadSheetDataSuccess({ sheetData: dataObj.data }) ) );
        },
    

Upvotes: 1

Related Questions