Alright, at the store there already was a user and we are adding businessUnitRecords with the following files:
- state-management/actions/business-unit-record.actions.ts
import { Action } from '@ngrx/store';
import { BusinessUnitRecordModel } from '../../models/business-unit-
record.model';
import { BusinessUnitRecordUpdatePayload } from 'src/app/models/business-unit-record-update-
payload.model';
export enum BusinessUnitRecordActionTypes {
LoadBusinessUnitRecords = '[BusinessUnitRecord] Load Business Unit
Records',
LoadBusinessUnitRecordsSuccess = '[BusinessUnitRecord] Load Business Unit
Records Success',
LoadBusinessUnitRecordsFail = '[BusinessUnitRecord] Load Business Unit
Records Failure',
UpdateBusinessUnitRecord = '[BusinessUnitRecord] Update Business Unit
Record'
}
export class LoadBusinessUnitRecords implements Action {
readonly type = BusinessUnitRecordActionTypes.LoadBusinessUnitRecords;
constructor() {}
}
export class LoadBusinessUnitRecordsSuccess implements Action {
readonly type = BusinessUnitRecordActionTypes
.LoadBusinessUnitRecordsSuccess;
constructor(public payload: Array<BusinessUnitRecordModel>) {
}
}
export class LoadBusinessUnitRecordsFail implements Action {
readonly type = BusinessUnitRecordActionTypes
.LoadBusinessUnitRecordsFail;
constructor(public payload: string) {}
}
export class UpdateBusinessUnitRecord implements Action {
readonly type = BusinessUnitRecordActionTypes
.UpdateBusinessUnitRecord;
constructor(public payload: BusinessUnitRecordUpdatePayload) {
}
}
export type BusinessUnitRecordActions = LoadBusinessUnitRecords |
LoadBusinessUnitRecordsSuccess | LoadBusinessUnitRecordsFail |
UpdateBusinessUnitRecord;
- state-management/effects/business-unit-record.effect.ts
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store, Action, select } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import { mergeMap, map, catchError, tap, switchMap } from 'rxjs/operators';
import { IMainStore } from '../store/store';
import * as fromBusinessUnitRecords from '../actions/business-unit-
record.actions';
import { BusinessUnitRecordsContract } from '../../contracts/business-unit-
records.contract';
import { BusinessUnitRecordModel } from '../../models/business-unit-
record.model';
@Injectable()
export class BusinessUnitRecordEffects {
constructor(
private businessUnitRecordsContract: BusinessUnitRecordsContract,
private actions$: Actions<fromBusinessUnitRecords
.BusinessUnitRecordActions>,
private store: Store<IMainStore>
) {
}
@Effect()
loadBusinessUnitRecords$: Observable<Action> = this.actions$.pipe(
ofType(fromBusinessUnitRecords.BusinessUnitRecordActionTypes
.LoadBusinessUnitRecords),
mergeMap((a, i) => {
return this.businessUnitRecordsContract.GetBusinessUnitRecordsObj().pipe(
map(businessUnitRecords => new fromBusinessUnitRecords
.LoadBusinessUnitRecordsSuccess(businessUnitRecords)
),
catchError((err, ii) => {
return of(new
fromBusinessUnitRecords.LoadBusinessUnitRecordsFail(err.message));
})
)
})
);
}
- state-management/reducers/business-unit-record.reducer.ts
import { BusinessUnitRecordStore } from '../store/store';
import { BusinessUnitRecordActions, BusinessUnitRecordActionTypes } from
'../actions/business-unit-record.actions';
import { IBusinessUnitRecordStore } from '../../models/business-unit-
record.model';
export function BusinessUnitRecordReducer(
state = BusinessUnitRecordStore,
action: BusinessUnitRecordActions
) : IBusinessUnitRecordStore {
switch(action.type){
case BusinessUnitRecordActionTypes.LoadBusinessUnitRecordsSuccess:
return {
...state,
businessUnitRecords: action.payload
};
case BusinessUnitRecordActionTypes.UpdateBusinessUnitRecord:
action.payload.businessUnitRecordsContract.UpdateBusinessUnitRecord(
action.payload.businessUnitRecordModel,
action.payload.whatToDo,
action.payload.error
);
return {
...state,
businessUnitRecords: state.businessUnitRecords.map(bu => {
if (bu.BusinessUnitID == action.payload
.businessUnitRecordModel.BusinessUnitID) {
bu.isProcessing = action.payload
.businessUnitRecordModel.isProcessing;
}
return bu;
})
};
default: {
return state;
}
}
}
- state-management/selectors/business-unit-record.selector.ts
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { IBusinessUnitRecordStore } from '../../models/business-unit-
record.model';
import { IMainStore } from '../store/store';
export const getBusinessUnitFeatureState = createFeatureSelector<IMainStore,
IBusinessUnitRecordStore>('businessUnitRecords');
export const getAllBusinessUnits = createSelector(
getBusinessUnitFeatureState,
state => state.businessUnitRecords
);
- state-management/store/store.ts
import { IUserStore } from '../../models';
import { IBusinessUnitRecordStore } from '../../models/business-unit-
record.model';
export interface IMainStore {
businessUnitRecords: IBusinessUnitRecordStore,
user: IUserStore
}
export const UserStore: IUserStore = {
user: null
}
export const BusinessUnitRecordStore: IBusinessUnitRecordStore = {
businessUnitRecords: null
}
Alright, in order to use this stuff at a component, you'll want a constructor that starts out like this.
constructor(public store: Store<IMainStore>
Put records in the store if they are not yet there as follows (or otherwise, just update the store from the database).
this.store.dispatch(new LoadBusinessUnitRecords());
Pull records from the store like so:
this.store.select(getAllBusinessUnits).subscribe(businessUnitRecords => {
this.businessUnitRecords = businessUnitRecords;
})
Write back a record:
this.store.dispatch(new
UpdateBusinessUnitRecord(businessUnitRecordUpdatePayload));
My write back is kinda bad as it assumes that the call to the API will succeed and then immediately calls out to the store.
Addendum 6/13/2019: Something that is missing is the loop in of the effects at a module. See: this
Addendum 12/26/2019: In looking at what is above I realize there is no spec for IBusinessUnitRecordStore. It would have to look something like so:
export interface IBusinessUnitRecordStore {
businessUnitRecords: Array<BusinessUnitRecord>;
}
StoreModule.forRoot({ models: BusinessUnitRecordReducer }), probably also needs to go in the imports in the module before the EffectsModule import. Import that up top from @ngrx/store to get it afloat. BusinessUnitRecordUpdatePayload is going to look like so:
export class BusinessUnitRecordUpdatePayload {
model: BusinessUnitRecord;
whatToDo: string;
error: string;
}
No comments:
Post a Comment