在Angular 6应用中的所有组件上进行强制更改检测

时间:2018-10-11 10:26:58

标签: angular

我正在为Angular 6应用程序开发一个简单的网格组件。基本上,它由一个主要组件app-grid组成,它是一个HTML表。在它的内部有一定数量的行,它们是另一个组件(app-row)。最后,在每一行的内部,都有一些保存对象的单元格,它们位于另一个组件app-cell中。

这是架构图:

Component architecture

在类似Angular的模板表示法中,用于构建上述组件的代码如下:

<app-grid>
    <app-row *ngFor="let row of grid.rows; let i=index">
        <tr [ngClass]="{ 'row-highlighted' : row.highlighted }">
            <td> #{{ i }} </td>
            <app-cell *ngFor="let cell of row.cells">
                <td [ngClass]="{ 'cell-highlighted' : cell.highlighted }">
                </td>
            </app-cell>
        </tr>
    </app-row>
</app-grid>

用于构建此数据的内部数据结构存储在app-grid组件中,它看起来像这样:

grid = {
    title: 'SAMPLE GRID',        

    rows: [
        { 
          row_id: 20, 
          cells: [
            { cell_id: 201, cell_data: { DATA IN HERE } },
            { cell_id: 202, cell_data: { DATA IN HERE } },
            { cell_id: 203, cell_data: { DATA IN HERE } }
          ]
        },
        { 
          row_id: 30, 
          cells: [
            { cell_id: 301, cell_data: { DATA IN HERE } },
            { cell_id: 302, cell_data: { DATA IN HERE } },
            { cell_id: 303, cell_data: { DATA IN HERE } }
          ]
        }
    ]
};

为了提高性能,app-rowapp-cell组件均使用changeDetection: ChangeDetectionStrategy.OnPush进行编码,因此我手动触发更改检测。

我希望能够突出显示特定的单元格(例如,上图中的单元格[3,2])和包含该单元格的行。为此,我只需要向<tr>的{​​{1}}和想要的app-row的{​​{1}}中添加一个特殊的类,就可以在上面的代码示例中看到。

我遇到的问题是<td>样式会立即应用,因此该行会突出显示,但是单元格不会应用该样式,直到我与它进行交互(例如,如果将其悬停) 。为此,我在app-cell组件中使用以下伪代码创建了一个方法:

<tr>

app-gridhighlightRowAndCell(row_id, cell_id) { Search 'grid.rows' for a row with 'row_id' identifier; If found Set row.highlighted to true; Search 'row.cells' in the found row for a cell with 'cell_id' identifier; If found Set cell.highlighted to true; // FORCE CHANGE DETECTION this.appRef.tick(); this.changeDetectorRef.detectChanges(); } 都不更新单元格样式,但是该行的样式立即更改。如果我将鼠标悬停在单元格上,则会应用样式。

我如何告诉Angular更新受影响组件的视图(或所有组件,都没有关系)?

谢谢

4 个答案:

答案 0 :(得分:1)

据我所知,变更检测用于处理数据和数据变更。因此,这将不是更好的方法。

更适合您[ngClass]="{someCondition: 'someClass'}"或[ngStyle]并将其绑定到某个变量。

答案 1 :(得分:0)

您是否遇到了提示您使用ChangeDetectionStrategy.OnPush的性能问题?我认为最常见的用例是输入控件,在该控件中您有一个非常特定的事件,希望触发更改检测。

在您的情况下,实际上并没有这样的事件,我宁愿使用ChangeDetectionStrategy.Default来完全避免复杂性。对于大多数用例来说,它确实很好用。

此外,如果您要触发所有组件的变更检测,那么无论如何,推模型都不会带来任何好处-实际上,您的性能很可能会变差。

答案 2 :(得分:0)

所有原始类型均按值传递。对象,数组和函数也按值传递

因此,为了触发组件中的更改检测,我们需要更改对象引用。

highlightRowAndCell(row_id, cell_id) {

    Search 'grid.rows' for a row with 'row_id' identifier;

    If found
        //Set row.highlighted to true;
        this.row={
        highlighted=true;
         }
        Search 'row.cells' in the found row for a cell with 'cell_id' identifier;

        If found     
           // Set cell.highlighted to true;
           this.cell={highlighted=true}
}

参考:https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4

答案 3 :(得分:0)

如上所述,app-row组件具有行的<tr>元素和单元格的<td>,因此理想的是将突出显示的视觉样式设置为行和单元格。如前所述,我在highlightRowAndCell组件中使用了一种方法(app-grid)将视觉样式应用于适当的行和单元格。问题在于,当我设置row.highlighted = truecell.highlighted = true时,Angular不会检测到这些更改,因为它们是数组内对象的属性。因此,为强制其检测更改,我在@Input组件中添加了以下app-row

app-grid.component.html模板:

<app-row [...]
  [highlighted]="row.highlighted">
</app-row>

app-row.component.ts:

export class AppRowComponent implements OnInit, OnDestroy {
  [...]

  @Input() highlighted: boolean;

  [...]
}

现在,在this.changeDetectorRef.detectChanges();组件内的highlightRowAndCell方法中运行app-grid可以使Angular刷新受影响的app-row并立即应用样式。