I am trying to retrieve the state for my application using NgRx but I cannot get it to work. I get the error:
ERROR TypeError: Cannot read properties of undefined (reading 'machines')
the error points to here in the selector below. I can add the ? operator, that causes the issue to go away but nothing render on the front end when i use the async pipe machine.selector.ts
export const selectMachines = (state: AppState) => state.machineState;
export const selectAllMachines = createSelector(
selectMachines,
(state) => state.machines
);
how I select the machines in my component
public allDevices$ = this.store.select(selectAllMachines);
machine reducer and state
export interface AppState {
machineState: MachinesState;
}
export interface MachinesState {
machines: Machine[];
}
const initialState: MachinesState = {
machines: [
{ id: '1', name: 'WASHER #1', status: Status.Available, type: 'Washer' },
{
id: '2',
name: 'WASHER #2',
status: Status.UnAvailable,
type: 'Washer',
user: 'Flat 4',
},
{ id: '3', name: 'DRYER #1', status: Status.Available, type: 'Dryer' },
{
id: '4',
name: 'DRYER #2',
status: Status.UnAvailable,
type: 'Dryer',
user: 'Flat 1',
},
],
};
export const machineReducer = createReducer(
initialState,
on(updateMachine, (state, { machine }) => {
const index = state.machines.findIndex((d) => d.id === machine.id);
state.machines[index] = machine;
return state;
}),
on(getMachines, (state) => {
return state;
})
);
CodePudding user response:
The way we set up our ngrx selectors is as follows:
- Define a constant variable name for the reducer, ex:
export const MY_CONSTANT = 'whatever'
- In your selectors, create a feature selector as so:
const getViewState = createFeatureSelector<IParticipantViewState>(MY_CONSTANT );
- In your module define the following for the store, along with its reducer:
StoreModule.forFeature(MY_CONSTANT , machineReducer , { initialState: myState}),
where myState is defined myState as initialState
which is imported from your reducer file where the initial state is set up.
This way we wirte up the store module for our particular feature, with a default reducer and an initialState set up. The feature selector gives us the slice that we need.
Finally, in your createSelector
it will look like what you made except you will pass in the getViewState
variable as the first argument.
CodePudding user response:
This line
public allDevices$ = this.store.select(selectAllMachines);
should be in ngOnInit
something like
import * as machineSelector from '../location-of-your-machine-selector';
export class YourComponent implements OnInit {
public allDevices$: Observable<Machine[]>;
constructor(private store: Store<AppState>) {}
ngOnInit(): void {
this.allDevices$ = this.store.select(machineSelector.selectAllMachines);
}
}
because its an async operation its a good idea to add an ngIf
to the html to make sure the machines
are loaded
<div *ngIf="allDevices$ | async as machines">
<div *ngFor="let machine of machines">{{machine.name}}</div>
</div>