首页 > 解决方案 > 如何在不更改 @Input 引用的情况下使用 OnPush 策略更新 Angular UI?

问题描述

我有一个具体的组件,它用一个 @Input() 扩展了一个抽象类data。PrimeNGdata表使用@Input 来显示行。PrimeNG 表使用 Angular OnPush 策略。

当我将对象推送到 @Inputdata数组时,更改不会反映在 UI 中。

data如果我在将对象推送到数组后更改了引用(通过类似 this.data = deepCopy(this.data) as Field[]),则更改将显示在 UI 中。

在这种情况下,我不希望更改 的引用,data因为其他组件可能会操纵该数据,并且我不希望同步同一数据的多个不同副本。

如何在不更改引用的情况下强制 Angular 更新 UI?ChangeDetectorRef.detectChanges() 不会相应地更新 UI。

带有 PrimeNG 表的抽象表类:

@Directive()
export abstract class TableComponent<T> implements OnChanges {

  @Input() data: T[];

  @ViewChild('dt') dataTable: Table; // PrimeNG table which displays rows of data

  ...
}

具有 addRow() 函数的具体类:

@Component({
  selector: 'app-table',
  templateUrl: '...',
  styleUrls: ['...']
})
export class SomeComponent extends TableComponent<Field> implements OnInit, OnChanges {

  ...

  public addRow(): void {
    const field = {} as Field;
    field.id = 1;
    
    this.data.push(field);

    // this.changeDetectorRef.detectChanges(); // Does not update the UI
    // this.data = deepCopy(this.data) as Field[]; // Updates the UI by changing reference
  }
}

标签: angularprimengangular2-changedetection

解决方案


我想出了一个解决方案,可以使 UI 正确更新。

将 PrimeNG 表value属性绑定到返回所有预期数据的函数可以解决 UI 不更新的问题。

public addRow(): void {
    const field = {} as Field;
    field.id = 1;
    
    this.data.push(field);
}

public getData(): Field[] {
    return this.data.filter(field => field.id > 0);
}

组件模板片段:

<p-table #dt [columns]="cols"
             [value]="getData()"
             [paginator]="true"
             [paginatorPosition]="'both'"
             [rows]="10">
...

推荐阅读