我正在为Angular 6应用程序开发一个简单的网格组件。基本上,它由一个主要组件app-grid
组成,它是一个HTML表。在它的内部有一定数量的行,它们是另一个组件(app-row
)。最后,在每一行的内部,都有一些保存对象的单元格,它们位于另一个组件app-cell
中。
这是架构图:
在类似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-row
和app-cell
组件均使用changeDetection: ChangeDetectionStrategy.OnPush
进行编码,因此我手动触发更改检测。
我希望能够突出显示特定的单元格(例如,上图中的单元格[3,2])和包含该单元格的行。为此,我只需要向<tr>
的{{1}}和想要的app-row
的{{1}}中添加一个特殊的类,就可以在上面的代码示例中看到。
我遇到的问题是<td>
样式会立即应用,因此该行会突出显示,但是单元格不会应用该样式,直到我与它进行交互(例如,如果将其悬停) 。为此,我在app-cell
组件中使用以下伪代码创建了一个方法:
<tr>
app-grid
和highlightRowAndCell(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更新受影响组件的视图(或所有组件,都没有关系)?
谢谢
答案 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 = true
和cell.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
并立即应用样式。