javascript 作为元素属性的函数和检查错误后改变的角表达式

krcsximq  于 2023-01-11  发布在  Java
关注(0)|答案(1)|浏览(87)

我正在树表上创建一个摘要行,该树表也具有过滤功能(我正在使用ng Prime组件库,但我不认为这与错误或问题有密切关系)。我希望摘要行只摘要当前视图中的信息,因此当树展开或应用过滤器时,摘要应该更改。
我通过将一个函数设置为元素属性[attr.summaryFunction]=“summaryFunction],将行数据添加到Map中,从而实现了这个目标(i,rowData[col.field])",并使用ngDoCheck重新初始化Map。如果没有此步骤,则在ngDoCheck中重新初始化Map时,每次重画或更改都会累积总数,并导致错误的值。(我尝试用其他几个生命周期钩子ngOnInit、ngOnViewInit和ngOnChanges重新初始化Map,但唯一有效地重新初始化Map的生命周期钩子是ngDoCheck)。
我的方法非常好用(哎呀!),但是我在浏览器中得到ExpressionChangedAfterItHasBeenCheckedError,每列三次。为了解决这个错误,我尝试了文档中推荐的所有4种方法来修复错误:
1.使用不同的生命周期挂钩--〉总计不正确
1.我将这个.cd.detectChanges()添加到了汇总函数--〉无限循环中
1.我将if语句封装在setTimeout(()=〉if(statement){})--〉无限循环中

  1. Promise.resolve().then(()=〉if(语句){})--〉无限循环
    同样,我的方法目前完全按照我的想法工作,我只是想让这些恼人的错误消失。我还想了解为什么通常的修复会导致无限循环。
    这是我的TS层
export class PrimetreeComponent implements OnInit, DoCheck {
sampleData: TreeNode[] = []
columns: any[] = [];
summaryMap = new Map();
columnIndex = 0;

constructor(private nodeService: NodeService, private cd: ChangeDetectorRef) {}

  ngOnInit(): void {
    this.nodeService.getFilesystem().subscribe(data => {this.sampleData = data});

      this.columns = [
      {field: 'name', header: 'name'},
      {field: 'size', header: 'size'},
      {field: 'type', header: 'type'}]
  }

 ngDoCheck(): void {
  this.summaryMap = new Map();
 }

  summaryFunction(columnIndex:number, rowData:any){
    
    if(this.summaryMap.has(columnIndex)){
      //if row data is a non-number string we just count the rows
      if(Number(rowData)){
        this.summaryMap.set(columnIndex, this.summaryMap.get(columnIndex)+Number(rowData));
      } else {
        this.summaryMap.set(columnIndex, this.summaryMap.get(columnIndex)+1)
      }
    } else {
      if(Number(rowData)){
        this.summaryMap.set(columnIndex, Number(rowData));
      } else {
        this.summaryMap.set(columnIndex, 1)
      }
    } 
  }

}

这是我的HTML模板:

<p-treeTable #tt [value]="sampleData" [columns]="columns">
  <ng-template pTemplate="caption">
    <div style="text-align: right">
      <span class="p-input-icon-left">
        <i class="pi pi-search"></i>
        <input
          pInputText
          type="text"
          size="50"
          placeholder="Global Filter"
          (input)="tt.filterGlobal($any($event.target).value, 'contains')"
          style="width:auto"
        />
      </span>
    </div>
  </ng-template>
  <ng-template pTemplate="header" let-columns>
    <tr>
      <th *ngFor="let col of columns">
        {{ col.header }}
      </th>
    </tr>
    <tr>
      <th *ngFor="let col of columns">
        <input
          pInputText
          type="text"
          class="w-full"
          (input)="
            tt.filter($any($event.target).value, col.field, col.filterMatchMode)
          "
        />
      </th>
    </tr>
  </ng-template>
  <ng-template pTemplate="body" let-rowNode let-rowData="rowData" >
    <tr>
      <td *ngFor="let col of columns; let i = index;" [attr.summaryFunction]="summaryFunction(i,rowData[col.field])">
        <p-treeTableToggler
          [rowNode]="rowNode"
          *ngIf="i == 0"
          (columnIndex)="i"
        ></p-treeTableToggler>
        {{ rowData[col.field] }}
      </td>
    </tr>
  </ng-template>
  <ng-template pTemplate="emptymessage">
    <tr>
      <td [attr.colspan]="columns.length">No data found.</td>
    </tr>
  </ng-template>
<ng-template pTemplate="summary">
  <tr>
    <td *ngFor="let col of columns;  let i = index;">
      {{ col.header }}--sumMap--{{summaryMap.get(i) }}
    </td>
  </tr>
</ng-template>
iszxjhcz

iszxjhcz1#

我不熟悉将函数绑定到elements属性的方法,但对我来说这似乎有点笨拙。如果我错了请纠正我,但这样做的原因是当节点添加到dom时有一种方法来触发函数?
我自己没有测试过这个,但是我认为你可以使用@ContentChildren装饰器see docs,它公开了一个观察对象,你可以订阅它来对内容dom的变化做出React,理想情况下,你可以在一个步骤中运行摘要创建和更新summaryMap。
更新:
我对这个想法做了一些尝试,一个解决方案是使用@ViewChildren装饰器来获取当前呈现的所有行的QueryList,这可以通过以下方式实现:

<ng-template pTemplate="body" let-rowNode let-rowData="rowData" >
    <tr [ttRow]="rowNode" #tableRow [attr.file-size]="rowData.size">
      <td>
        <p-treeTableToggler [rowNode]="rowNode"></p-treeTableToggler>
        {{ rowData.name }}
      </td>
      <td>{{ rowData.size }}</td>
      <td>{{ rowData.type }}</td>
    </tr>
  </ng-template>

注意<tr [ttRow]="rowNode" #tableRow [attr.file-size]="rowData.size">上的模板ref以及将rowData.size绑定到元素的属性。
然后,您可以获取当前挂载到dom的行列表rows,如下所示:

// inside your component

@ViewChildren('tableRow') view_children!: QueryList<ElementRef>;

// get the list, calculate initial sum and subscribe to changes. 
// We do that in ngAfterViewInit lifecycle hook as the 
// list is guaranteed to be available at that point of time:

ngAfterViewInit() {
  this.calculateSum(this.view_children);

  this.view_children.changes.subscribe(
    (list: QueryList<ElementRef>) =>
      this.calculateSum(list)
  );
}

您可以找到此here的运行示例。

相关问题