覆盖 NGRX DefaultPersistenceResultHandler 的 handleSuccess

gar*_*ert 3 ngrx angular

我在使用 @ngrx/data 时遇到了一些困难,希望你们中的一位天才可以帮助我。

我有一个实体集合,想存储一些额外的信息,以减少到服务器的往返次数并减少冗余负载。我有一个数据表,并且只想一次将一页加载到实体集合中,为了能够做到这一点,我想向我的集合中添加额外的元数据,以便我知道何时加载更多数据。例如,当我到达加载数据的末尾时加载更多(分页需要知道存在多少条记录以及加载了多少条记录)。

根据文档,我可以添加 additionalCollectionState 但需要某种方式来更新新的状态属性。

我想我会复制/粘贴他们作为基础的示例代码并修改它以反映我自己的属性..问题是我立即在 => Action上收到打字稿错误

通用类型“操作”需要 1 个类型参数

export class AdditionalPersistenceResultHandler  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 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;
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

我也不确定这是否是解决此问题的正确方法,或者我是否将其处理得太复杂,我是否可以“简单地”以某种方式手动更新额外的集合状态(在我的数据服务调用 getWithQuery() 中),如果是这样呢?将是最好的/推荐的方法。

干杯和感谢

加里

更新

在安德鲁指出我明显的导入错误之后,我现在已经实现了结果处理程序,但出现以下错误

ERROR in Error during template compile of 'AdditionalPropertyPersistenceResultHandler'
  Class AdditionalPropertyPersistenceResultHandler in D:/dev/angular/ng-vet/src/app/treatments/services/treatments-entity-result-handler.ts extends from a Injectable in another compilation unit without duplicating the decorator
    Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.
Run Code Online (Sandbox Code Playgroud)

考虑到stackblitz没有它并且它工作得很好,这没有任何意义。

我的 entityMetadataMap

const entityMetadata: EntityMetadataMap = {
  TreatmentTemplate: {
    entityDispatcherOptions: {
      optimisticUpdate: true
    }
  },
  Treatment: {
    additionalCollectionState: {
      totalRecords: 0
    },
    entityDispatcherOptions: {
      optimisticUpdate: true
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

和提供者:

providers: [
    TreatmentsDataService,
    TreatmentEntityService,
    TreatmentTemplateResolver,
    TreatmentTemplatesDataService,
    TreatmentTemplateEntityService,
    {
      provide: PersistenceResultHandler,
      useClass: AdditionalPropertyPersistenceResultHandler
    },
    {
      provide: EntityCollectionReducerMethodsFactory,
      useClass: AdditionalEntityCollectionReducerMethodsFactory
    }
  ]
Run Code Online (Sandbox Code Playgroud)

我基本上复制粘贴了stackblitz中的方法..

在 ^8.0.2 的角度和 ^8.6.0 的 ngrx 可能是问题吗?

And*_*len 5

使用additionalCollectionState.

默认的 QUERY_MANY_SUCCESS 减速器期望action.payload.data是一个实体数组,但 QUERY_MANY 操作action.payload.data将是 api 返回的任何内容。

说它回来了

interface QueryManyAPIResponse<T> {
    total: number,
    entities: T[]
}
Run Code Online (Sandbox Code Playgroud)

您可以total向操作负载添加属性,但action.payload.data必须是实体。

@Injectable()
export class AdditionalPersistenceResultHandler  extends DefaultPersistenceResultHandler {

    handleSuccess(originalAction: EntityAction): (data: any) => Action {
        const actionHandler = super.handleSuccess(originalAction);

        return function(data: any) {
            /** Default success action */
            const successAction = actionHandler.call(this, data);

            /** Change payload for query many */
            if (successAction && data && data.total) {
                (successAction as any).payload.total = data.total;
            }
            if (successAction && data && data.entities) {
                (successAction as any).payload.data = data.entities;
            }

            return action;
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

这只是对操作进行更改。

虽然默认的 reducer 会处理实体,但需要NgRx Docs的第 2 步和第 3 步将总数作为属性添加到实体集合中。


分页需要知道有多少记录存在以及有多少已加载

已加载的数量是可推导出的(id.length,因此您可以为此使用选择器),因此不需要保存在商店中。

我有一个实体集合,想存储一些额外的信息,以减少到服务器的往返次数并减少冗余负载。

这是一个很难的问题。我发现减少 api 调用的最干净、最直接的方法是使用服务器端分页表(请参阅下面的参考资料)并在表之前提供一个页面,该页面提供一个带有统计信息的仪表板(需要实现此 API),其中包含各种过滤器和链接到带有内置查询参数的表格页面。

如果数据已经在第 1 页上,很少有人会花时间在分页的 mat 表中进行分页。
而且没有人愿意。

仪表板.component.html

        <button
          mat-raised-button
          [routerLink]="['/procurement/orders']"
          [queryParams]="{ awaitingPrices: 'yes', employeeID: userID }"
        >
          {{ statistics.awaitingPricesUser }}
        </button>
Run Code Online (Sandbox Code Playgroud)

orders.component.html(容器)

<app-order-find (filter)="onFilter($event)"></app-order-find>
<app-order-filters
  [suppliers]="suppliers$ | async"
  [employees]="employees$ | async"
  [filters]="filters"
  (filtersUpdate)="updateFilters($event)"
></app-order-filters>
<app-orders-table
  [totalNumberOfOrders]="totalNumberOfOrders$ | async"
  [filters]="filters"
  (review)="onReview($event)"
  (edit)="onEdit($event)"
  (delete)="onDelete($event)"
>
  ></app-orders-table
>
Run Code Online (Sandbox Code Playgroud)

备择方案

您是否希望将所有数据加载到存储中,即在后台加载第 1、2、...、最后一页的分页数据。加载所有数据后,您可以完全通过选择器进行客户端分页。

如果您希望在表格和详细信息视图之间来回切换,或者在相同页面和相同过滤器上来回切换,您可以保留缓存映射{ urlWithQueryParams: entityIds }并使用选择器从商店获取。如果您删除相关实体,则需要将它们扔掉。

参考

服务器端分页表 - https://blog.angular-university.io/angular-material-data-table/