是否可以在TypeScript中设置Angular SelectionModel对象的CompareWith函数

gre*_*cks 5 selectionmodel angular-material angular mat-table

我有一个在其模板中呈现 mat-table 的组件。我想预先选择一些行。我的 SelectionModel 包含代表每个选定项目的对象(不是简单的字符串或数字),并且比较这些对象的方法比本机 SelectionModel 的方法更复杂。

如果这是一个垫选择表单控件,我可以使用 [compareWith] 指令来提供自定义比较函数,例如

<mat-select [compareWith]="myCompareFunction"  >...
Run Code Online (Sandbox Code Playgroud)

但这不是合适的解决方案 - 因为我需要表格演示。我密切关注 Angular 文档中的示例。这里的mat-table 示例每行都有一个带有选择复选框的 mat-table,这是我遵循的方法。

在示例的组件代码中,它使用 SelectionModel 对象。

import {SelectionModel} from '@angular/cdk/collections';
....
....
selection = new SelectionModel<PeriodicElement>(true, []);
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种为 SelectionModel 对象提供自定义比较函数的方法。SelectionModel 是否可以通过函数的重写进行子类化,或者可以以某种方式“注入”方法吗?

我尝试对 SelectionModel 进行子类化并声明一个新的 CompareWith 函数,但这似乎不是所需要的。有人可以建议吗?

   import { SelectionModel } from '@angular/cdk/collections';
   import { InputOptionIf } from '../formosa-interfaces/dynamic-field-config-if';

   export class ModalSelectSelectionModel extends SelectionModel<InputOptionIf>{
      compareWith(o1:any,o2:any) {
        console.log("ModalSelectSelectionModel.compareWith()")
        return( <InputOptionIf>o1.label==<InputOptionIf>o2.label);
      }
   }  
Run Code Online (Sandbox Code Playgroud)

ema*_*sie 3

如果您陷入角度<14,您可以扩展 SelectionModel 并重写该isSelected方法。在 CDK 实现中,SelectionModel 使用 Set 来存储选择,并使用 来检查某个项目是否包含在该集合中Set.has。值得庆幸的是,唯一Set.has被调用的地方是 in isSelected。类中的其他地方都用于isSelected检查该项目是否已经存在。

您还应该重写取消选择方法,以首先使用compareWith函数查找选择中的值。这可确保取消选择的值与集合中的值是同一实例。如果没有这个,某些值可能不会按预期取消选择。

下面是一个示例实现,它接受 CompareWith 函数,其方式与 Angular 14 实现的工作方式相同。当您升级到 Angular 14 时,您应该能够简单地将 ComparableSelectionModel 替换为 SelectionModel。

export class ComparableSelectionModel<T> extends SelectionModel<T> {
  private compareWith: (o1: T, o2: T) => boolean;

  constructor(
    _multiple?: boolean, 
    initial?: T[], 
    _emitChanges?: boolean, 
    compareWith?: (o1: T, o2: T) => boolean) {
    super(_multiple, initial, _emitChanges);

    this.compareWith = compareWith ? compareWith : (o1, o2) => o1 === o2;
  }

  override isSelected(value: T): boolean {
    return this.selected.some((x) => this.compareWith(value, x);
  }

  /**
   * We also need to override deselect since you may have objects that 
   * meet the comparison criteria but are not the same instance.
   */
  override deselect(...values: T[]): void {
    // using bracket notation here to work around private methods
    this['_verifyValueAssignment'](values);

    values.forEach((value) => {
      // need to find the exact object in the selection set so it 
      // actually gets deleted
      const found = this.selected.find((x) => this.compareWith(value, x);
      if (found) {
        this['_unmarkSelected'](found);
      }
    });

    this['_emitChangeEvent']();
  }
}

Run Code Online (Sandbox Code Playgroud)