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 5, 2019
1 parent d81ddeb commit 452be79
Showing 1 changed file with 88 additions and 2 deletions.
90 changes: 88 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,92 @@ 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 store from `Effects` correctly.

1. You need to create a `AdditioanlPersistenceResultHandler extends DefaultPersistenceResultHandler` and overwrite [handleSuccess](../../../../../../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);
// here will 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;
};
}
}
```

2. Now the additional property is set to `action.payload`, but we still need to set it to the instance of EntityCollection in `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 `getWithQuery action`, 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;
}
}
```

3. 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 detail, please see this [doc](./entity-reducer.md)

```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 other `EntityCollection` level property.


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

## Pluralizing the entity name
Expand Down

0 comments on commit 452be79

Please sign in to comment.