Skip to content

Commit

Permalink
docs(data): add document about how customize a entityCollection level…
Browse files Browse the repository at this point in the history
… property of ngrx-data
  • Loading branch information
JiaLiPassion committed Jun 10, 2019
1 parent d81ddeb commit db7d7c6
Showing 1 changed file with 89 additions and 2 deletions.
91 changes: 89 additions & 2 deletions projects/ngrx.io/content/guide/data/entity-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Not every entity will have a primary key property named `id`. For some entities,

In these cases, you specify a `selectId` function that, given an entity instance, returns an integer or string primary key value.

In the _EntityCollectionReducer_ [tests](https://github.com/ngrx/platform/blob/master/modules/data/spec/reducers/entity-collection-reducer.spec.ts),
In the _EntityCollectionReducer_ [tests](https://github.com/ngrx/platform/blob/master/modules/data/spec/reducers/entity-collection-reducer.spec.ts),
the `Villain` type has a string primary key property named `key`.
The `selectorId` function is this:

Expand Down Expand Up @@ -206,7 +206,7 @@ Each NgRx Data entity collection in the the store has

You can add your own collection properties by setting the `additionalCollectionState` property to an object with those custom collection properties.

The _EntitySelectors_ [tests](https://github.com/ngrx/platform/blob/master/modules/data/spec/selectors/entity-selectors.spec.ts)
The _EntitySelectors_ [tests](https://github.com/ngrx/platform/blob/master/modules/data/spec/selectors/entity-selectors.spec.ts)
illustrate by adding `foo` and `bar` collection properties to test hero metadata.

```typescript
Expand All @@ -220,6 +220,93 @@ The property values become the initial collection values for those properties wh

The NgRx Data library generates selectors for these properties but has no way to update them. You'll have to create or extend the existing reducers to do that yourself.

If the property you want to add comes from `backend`, you will need some additional work to make sure the property can be saved into the store from `Effects` correctly.

#### Step1: Implement `PersistenceResultHandler` to save data from backend to action.payload

You need to create an `AdditionalPersistenceResultHandler extends DefaultPersistenceResultHandler` and overwrite the [handleSuccess](https://github.com/ngrx/platform/blob/master/modules/data/src/dataservices/persistence-result-handler.service.ts) method, the purpose is to parse the data got from `DataService` and retrieve the additional property then save it to `action.payload`. Here is a sample.


```typescript
export class AdditionalPropertyPersistenceResultHandler {
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 function(data: any) {
const action = actionHandler.call(this, data);
if (action && data && data.foo) {
// save the data.foo to action.payload.foo
(action as any).payload.foo = data.foo;
}
return action;
};
}
}
```

#### Step2: Overwrite `EntityCollectionReducerMethods` to save additional property from action.payload to EntityCollection instance

Now the additional property is set to `action.payload`, but we still need to set it to the instance of EntityCollection in the `reducer`, to do that, we need to create a `AdditionalEntityCollectionReducerMethods extends EntityCollectionReducerMethods`, and overwrite the method match your `action`, for example, if the additional property `foo` only available in `queryMany action(triggered by EntityCollectionService.getWithQuery)`, we can do like this.

```typescript
export class AdditionalEntityCollectionReducerMethods<T> extends EntityCollectionReducerMethods<T> {
constructor(public entityName: string, public definition: EntityDefinition<T>) {
super(entityName, definition);
}
protected queryManySuccess(
collection: EntityCollection<T>,
action: EntityAction<T[]>
): EntityCollection<T> {
const ec = super.queryManySuccess(collection, action);
if ((action.payload as any).foo) {
// save the foo property from action.payload to entityCollection instance
(ec as any).foo = (action.payload as any).foo;
}
return ec;
}
}
```

#### Step3: Register customized `EntityCollectionReducerMethods` and `AdditionalPersistenceResultHandler`.
Finally we need to register the `AdditionalPersistenceResultHandler` and `AdditionalEntityCollectionReducerMethods` to replace the default implementation.

Register `AdditionalPersistenceResultHandler` in `NgModule`,

```typescript
@NgModule({
{ provide: PersistenceResultHandler, useClass: PagePersistenceResultHandler },
})
```

Register `AdditionalEntityCollectionReducerMethods`, to do that, we need to create a `AdditionalEntityCollectionReducerMethodFactory`, for details, see [Entity Reducer](guide/data/entity-reducer)

```typescript
@Injectable()
export class AdditionalEntityCollectionReducerMethodsFactory {
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 AdditionalEntityCollectionReducerMethods(entityName, definition);
return methodsClass.methods;
}
}
```

then register this `AdditionalEntityCollectionReducerMethodsFactory` to `NgModule`,

```typescript
@NgModule({
{
provide: EntityCollectionReducerMethodsFactory,
useClass: AdditionalEntityCollectionReducerMethodsFactory
},
})
```

Now you can get `foo` from `backend` just like another `EntityCollection` level property.

<a id="plurals"></a>

## Pluralizing the entity name
Expand Down

0 comments on commit db7d7c6

Please sign in to comment.