5

Using @ngrx/data I want to handle the result of the getWithQuery API call differently than the default.

Currently if this returns an array of entities, this gets loaded in the entityCache directly.

So far I've used the standard pattern shown in the overview:

export const entityMetadata: EntityMetadataMap = {
  PurchaseOrder: {}
};
@Injectable({
  providedIn: "root"
})
export class PurchaseOrderService extends EntityCollectionServiceBase<
  PurchaseOrder
> {
  constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
    super("PurchaseOrder", serviceElementsFactory);
  }
}

Instead I want to handle the following API response and load the entities in the entityCache as the normal getWithQuery would but also stick the total elsewhere in my store.

{
    "entities": [{...}, {...}, ..., {...}],    // list of entities
    "total": 100
}

Naturally I get the following error if this API response is returned:

enter image description here

My understanding is that a default reducer gets created and registered for each entity providing the EntityCollectionDataService interface with the add / delete / getAll / getById / getWithQuery / update methods.

I want to keep these methods but override the getWithQuery reducer to achieve my aim.

This is mentioned in Customizing Entity Reducer Behavior

But quite often you'd like to extend a collection reducer with some additional reducer logic that runs before or after.

How can this be actually done?

I still get the above error if I try to override getWithQuery inside my PurchaseOrderService

  getWithQuery(params) {
    return super.getWithQuery(params).pipe(tap(result => console.log(result)));
  }
Andrew Allen
  • 6,512
  • 5
  • 30
  • 73

1 Answers1

4

Managed to get this working using a custom EntityDataService

@Injectable()
export class PurchaseOrderDataService extends DefaultDataService<
  PurchaseOrder
> {
  constructor(
    http: HttpClient,
    httpUrlGenerator: HttpUrlGenerator,
    logger: Logger,
    config: DefaultDataServiceConfig
  ) {
    super("PurchaseOrder", http, httpUrlGenerator, config);
  }

  getWithQuery(params: string | QueryParams): Observable<PurchaseOrder[]> {
    return super.getWithQuery(params).pipe(
      tap(res => console.log(res)),
      map((res: any) => res.entities)
    );
  }
}

Then this needs to be registered:

@NgModule({
  providers: [PurchaseOrderDataService] // <-- provide the data service
})
export class EntityStoreModule {
  constructor(
    entityDataService: EntityDataService,
    purchaseOrderDataService: PurchaseOrderDataService
  ) {
    entityDataService.registerService(
      "PurchaseOrder",
      purchaseOrderDataService
    ); // <-- register it
  }
}

And import this alongside EntityDataModule.forRoot({ entityMetadata }),

Andrew Allen
  • 6,512
  • 5
  • 30
  • 73
  • Hello, but where are you passing the custom structure '{entities": [{...}, {...}, ..., {...}], "total":100}' to the state? Getting the same doubt, since I need to add more properties to the state, pagination in this case. Tks. – Fausto Braz Mar 18 '20 at 08:23
  • The documentation doesn't have a good code example https://ngrx.io/guide/data/entity-reducer#collection-reducer-factory – Fausto Braz Mar 18 '20 at 08:29
  • 1
    @FaustoBraz I'd actually use a slightly different method now [see this answer](https://stackoverflow.com/a/60553070/4711754) but I'll explain above - doing `map((res: any) => res.entities)` means the default reducer kicks in and adds the entities to the state. In the above example total is not saved. My link gives a way of saving additional properties to a collection. I believe Pagination to be dependent on actual details - can you either ask a new question or in the [ngrx gitter channel](https://gitter.im/ngrx/platform). Keep an eye on the issues on ngrx platform github eg. #2434 – Andrew Allen Mar 18 '20 at 08:45
  • As mentioned in other comments, this won't actually add the total to your store. To do that, follow the tutorial here: https://ngrx.io/guide/data/entity-metadata#additionalcollectionstate – Christian Jensen Jun 28 '21 at 16:03