I am trying to follow the NgRx walkthrough but adapt it to something a bit more complex than adding or removing books.
I want to have an array of University Objects, and be able to find a university by Id then change it's total_student number.
I am nearly there. Completely stuck with the reducers.
Models/univeristy.model.ts:
export interface University {
id: string | undefined;
name: string | undefined;
total_students: number | undefined;
}
Actions/university.actions.ts:
import { createActionGroup, props } from '@ngrx/store';
import { University } from '@models/university';
export const UniversityActions = createActionGroup({
source: 'University',
events: {
'Change Student Total': props<{ universityId: string, total_students: number }>(),
},
});
export const UniversityApiActions = createActionGroup({
source: 'University API',
events: {
'Retrieved Universities': props<{ universities: Array<University> }>(),
},
});
Actions/action-types.ts:
import * as ActionTypes from './university.actions';
export {ActionTypes};
I am losing my way here...
Reducers/collection.reducer.ts :
import { createReducer, on } from '@ngrx/store';
import { UniversityActions } from '@actions/actions/university.actions';
export const initialState: Array<string> = [];
export const collectionReducer = createReducer(
initialState,
on(UniversityActions.changeStudentTotal, (state, { universityId, total }) => {
// How to modify the state to change the total of a specific univeristy in the list?
// Find the univeristy by universityId then create a new record for it with the new total?
...state,
universities: { ...state.universities, universities: {id: universityId, total: total} },
})
);
Reducers/university.reducer.ts :
import { createReducer, on } from '@ngrx/store';
import { ActionTypes } from '@state/actions/action-types';
import { University } from '@models/university.model';
export interface UniversityState {
universities: University[];
status: 'start' | 'loading' | 'error' | 'success';
error: string;
}
// The starting global values
export const initialState: Array<University> = [];
export const universityReducer = createReducer(
initialState,
on(
ActionTypes.UniversityApiActions.retrievedUniversities,
(_state, { universities }) => universities
)
);
Selectors/university.selectors.ts:
import { createSelector, createFeatureSelector } from '@ngrx/store';
import { University } from '@models/university.model';
export const selectUniversity = createFeatureSelector<Array<University>>('universities');
export const selectUniversityState =
createFeatureSelector<Array<string>>('collection');
export const selectUniversities = createSelector(
selectUniversity,
selectUniversityState,
(universities, collection) => {
return collection.map((id) => universities.find((university) => university.id === id)!);
}
);
Any help appreciated!
Given the id, you would need to search for the university and replace its data without mutating the store content. You could do it like the following:
on({...}),
on(UniversityActions.changeStudentTotal, (state, {universityId, total}) => {
const universityCopy = [...state.universities]; // create a copy of the original,
const index = universityCopy.findIndex(university => university.id === univertisyId);
// you should add a validation if "index" is -1 if it doesn't find any
const searchedUniversity = {...universityCopy[index]} as University;
// Modify the copy as you need
searchedUniversity.total_students = total;
universityCopy[index] = {...searchUniversity} as University;
state.universities = [...universityCopy]; // give back to "universities" a 'new' array
return { ...state };
}),
on({...})
Since you are using NgRx
, you could also make use of NgRx Entity
for CRUD operations (Create, Retrieve, Update, Delete)
, instead of passing in the university id
you should instead pass in a university object
on(UniversityActions.changeStudentTotal, (state, {theModifiedUniversityObject}) =>
({...state, universities: adapter.updateOne(theModifiedUniversityObject, state.universities)}))
There are also available operations such as:
updateMany
upsertOne
(either Add or Update)upsertMany
addOne
deleteOne
For more information about NgRx Entity
you can read the official docs