Skip to content

Instantly share code, notes, and snippets.

@luchillo17
Created October 21, 2020 03:30
Show Gist options
  • Save luchillo17/79cd4f33a8f799f421f3bf1fb5042bed to your computer and use it in GitHub Desktop.
Save luchillo17/79cd4f33a8f799f421f3bf1fb5042bed to your computer and use it in GitHub Desktop.
NGRX Data override request handling and data flow
import { ScrollingModule } from '@angular/cdk/scrolling';
import { registerLocaleData } from '@angular/common';
import localeEs from '@angular/common/locales/es';
import { LOCALE_ID, NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
DefaultDataServiceConfig,
EntityCollectionReducerMethodsFactory,
EntityDataModule,
PersistenceResultHandler,
} from '@ngrx/data';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { FormlyModule } from '@ngx-formly/core';
import { SocketIoModule } from 'ngx-socket-io';
import { environment } from '../environments/environment';
import { AppComponent } from './app.component';
import { APP_ROUTES } from './app.routes';
import { FullScreenDirective } from './directives/fullscreen.directive';
import { MarcadorDirective } from './directives/marcador.directive';
import { AuthModule } from './auth/auth.module';
import { PagesComponent } from './pages/pages.component';
import { AtencionTiketComponent } from './public/atencion-tiket/atencion-tiket.component';
import { ServiceModule } from './services/service.module';
import { AutoCompleteInputComponent } from './shared/components/auto-complete-input/auto-complete-input.component';
import { TimePickerInputComponent } from './shared/components/time-picker-input/time-picker-input.component';
import { SharedModule } from './shared/shared.module';
import { minlengthValidationMessages } from './shared/utils/formly-validation.util';
import { effects, metaReducers, reducers } from './store';
import {
CustomEntityCollectionReducerMethodsFactory,
CustomPersistenceResultHandler,
} from './store/custom-ngrx-data/custom-entity-data.service';
import {
defaultDataServiceConfig,
entityConfig,
} from './store/entity-metadata';
/**************** material e iconos ***************************************/
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from './shared/material/material.module';
import { appReducers } from './store/app.reducer';
registerLocaleData(localeEs);
@NgModule({
declarations: [
AppComponent,
AtencionTiketComponent,
FullScreenDirective,
MarcadorDirective,
PagesComponent,
TimePickerInputComponent,
],
imports: [
APP_ROUTES,
FlexLayoutModule,
FormsModule,
ReactiveFormsModule,
BrowserModule,
BrowserAnimationsModule,
MaterialModule,
ScrollingModule,
ServiceModule,
SharedModule,
AuthModule,
FormlyModule.forRoot({
types: [
{
name: 'autocomplete',
component: AutoCompleteInputComponent,
wrappers: ['form-field'],
},
{
name: 'timepicker',
component: TimePickerInputComponent,
wrappers: ['form-field'],
},
],
validationMessages: [
{ name: 'required', message: 'Este campo es requerido' },
{ name: 'minlength', message: minlengthValidationMessages },
],
}),
SocketIoModule.forRoot(environment.socketIOConfig),
StoreModule.forRoot(reducers, {
metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true
},
}),
EffectsModule.forRoot(effects),
StoreDevtoolsModule.instrument({
maxAge: 25,
logOnly: environment.production,
}),
EntityDataModule.forRoot(entityConfig),
],
providers: [
{ provide: LOCALE_ID, useValue: 'es' },
{ provide: DefaultDataServiceConfig, useValue: defaultDataServiceConfig },
{
provide: PersistenceResultHandler,
useClass: CustomPersistenceResultHandler,
},
{
provide: EntityCollectionReducerMethodsFactory,
useClass: CustomEntityCollectionReducerMethodsFactory,
},
],
bootstrap: [AppComponent],
})
export class AppModule { }
import { Injectable } from '@angular/core';
import {
DefaultPersistenceResultHandler,
EntityAction,
EntityCollection,
EntityCollectionReducerMethodMap,
EntityCollectionReducerMethods,
EntityDefinitionService,
} from '@ngrx/data';
import { Action } from '@ngrx/store';
import { Draft, produce } from 'immer';
import { APIResponse } from '../../models/api.model';
@Injectable()
export class CustomPersistenceResultHandler extends DefaultPersistenceResultHandler {
handleSuccess(originalAction: EntityAction): (data: any) => Action {
const actionHandler = super.handleSuccess(originalAction);
// return a factory to get a data handler to
// parse data from DataService and save to action.payload
return (resp: APIResponse) => {
const action = actionHandler(resp.data);
if (action && resp && resp.extra) {
// Save extra in payload
(action as any).payload.extra = resp.extra;
}
return action;
};
}
}
export class CustomEntityCollectionReducerMethods<
T
> extends EntityCollectionReducerMethods<T> {
readonly methods: EntityCollectionReducerMethodMap<T> = {
...this.methods,
setSelectedId: this.setSelectedId.bind(this),
};
protected queryManySuccess(
collection: EntityCollection<T>,
action: EntityAction<T[]>,
): EntityCollection<T> {
const ec = super.queryManySuccess(collection, action);
if ((action.payload as any).extra) {
// save the extra property from action.payload to entityCollection instance
(ec as any).extra = (action.payload as any).extra;
}
return ec;
}
protected queryAllSuccess(
collection: EntityCollection<T>,
action: EntityAction<T[]>,
): EntityCollection<T> {
const ec = super.queryAllSuccess(collection, action);
if ((action.payload as any).extra) {
// save the extra property from action.payload to entityCollection instance
(ec as any).extra = (action.payload as any).extra;
}
return ec;
}
protected setSelectedId(
collection: EntityCollection<T>,
action: EntityAction<number>,
): EntityCollection<T> {
return produce(
collection,
(draft: Draft<EntityCollection<T> & { selectedId: number }>) => {
draft.selectedId = action.payload.data;
},
);
}
}
@Injectable()
export class CustomEntityCollectionReducerMethodsFactory {
constructor(private entityDefinitionService: EntityDefinitionService) {}
/** Create the {EntityCollectionReducerMethods} for the named entity type */
create<T>(entityName: string): EntityCollectionReducerMethodMap<T> {
const definition = this.entityDefinitionService.getDefinition<T>(
entityName,
);
const methodsClass = new CustomEntityCollectionReducerMethods(
entityName,
definition,
);
return methodsClass.methods;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment