Angular detectChanges 不适用于子组件 [英] Angular detectChanges not working on child Component
问题描述
我只是不知道为什么,但更改检测会在层次结构中的第一个孩子处停止.如果我手动调用更深一层的更改检测(在 sch-job-detail
中),则值会更新.
我构建了一个带有可扩展行的 MatTable
.
可扩展"行部分如下:
<ng-container matColumnDef="expandedDetail"><td mat-cell *matCellDef="let jobModel" [attr.colspan]="displayedColumns.length"></td></ng-容器>
如您所见,该表拥有一个 JobModel
(s) 数组,并且每一行接收其自己的 JobModel
实例.
JobModel
是一个 FormGroup
的包装器,它也是一个简单的接口对象 Job
的转置".
sch-job-detail
有其他子组件,例如:
<div class="col"><sch-job-row-工具栏[isNew]="jobModel.isNew"[isEdit]="jobModel.isEdit"[isError]="jobModel.isError"[isValid]="jobModel.isValid"...></sch-job-row-toolbar>
在可扩展行上,我有一个按钮,可让用户输入新的 Cron 表达式,然后将该 Cron 表达式添加到 FormGroup
的 FormControl
.
TableComponent
内部:
public addCronExpression(jobModel: JobModel): void {this.matDialog.open(CronDialogSmartComponent).afterClosed().pipe(filter(c =>!!c)).subscribe(c => {jobModel.addCronExpression(c)this.changeDetector.detectChanges()})}
JobModel#addCronExpression
:
public addCronExpression(cronExpression: string): void {const cronExpressions = this.formGroup.controls.cronExpressionscronExpressions.setValue([...cronExpressions.value, cronExpression])}
如您所见,由于我没有更改 JobModel
实例,所以我运行 detectChanges
来更新 TableComponent
及其子项,sch-job-row-toolbar
我想包括在内!
事情是 sch-job-row-toolbar
似乎没有重新计算它的绑定(ngOnChanges 没有运行).
所以这些值:
[isNew]="jobModel.isNew"[isEdit]="jobModel.isEdit"[isError]="jobModel.isError"[isValid]="jobModel.isValid"
没有改变.
我们可以以 JobModel#isEdit
为例:
get isEdit(): boolean {返回 this.formGroup.dirty ||Job.isEdit(this.job.status)}
我不知道发生了什么,但我知道如果我按下按钮或在其他地方切换选项卡,sch-job-row-toolbar
会收到更新的值.
所有组件都使用 onPush
策略.
说明性 GIF:
而且,有趣的是,当我从第一个选项卡做同样的事情时,它就起作用了!
尝试使用 Default
更改检测策略,但结果相同.
为什么不使用 @Input
和 @Output
来检测从父到子组件?我建议您使用 @Input (parent => child)
并使用 @Output (child=> parent
) 而不是 detectChanges()
.
Edit: I just don't know why, but change detection stop at the first child in the hierarchy. If I manually invoke change detection one level deeper (in sch-job-detail
), then the values are updated.
I've built a MatTable
with expandable rows.
The "expandable" row part is as follow:
<!-- Hidden cell -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let jobModel" [attr.colspan]="displayedColumns.length">
<div
class="detail-cell"
*ngIf="jobModel.isExpanded"
[@detailExpand]
>
<sch-job-detail
[jobModel]="jobModel"
...
></sch-job-detail>
</div>
</td>
</ng-container>
As you can see, the table owns an array of JobModel
(s), and each row receives its own JobModel
instance.
JobModel
is a wrapper for a FormGroup
, which is also a "transposition" of a simple interface object Job
.
sch-job-detail
has others children Components, for example:
<!-- Toolbar -->
<div class="col">
<sch-job-row-toolbar
[isNew]="jobModel.isNew"
[isEdit]="jobModel.isEdit"
[isError]="jobModel.isError"
[isValid]="jobModel.isValid"
...
></sch-job-row-toolbar>
</div>
On the expandable row I have a button which lets the user enter a new Cron expression, and that Cron expression is then added to the FormGroup
's FormControl
.
Inside the TableComponent
:
public addCronExpression(jobModel: JobModel): void {
this.matDialog
.open<CronDialogSmartComponent, any, string>(CronDialogSmartComponent)
.afterClosed()
.pipe(filter<string>(c => !!c))
.subscribe(c => {
jobModel.addCronExpression(c)
this.changeDetector.detectChanges()
}
)
}
JobModel#addCronExpression
:
public addCronExpression(cronExpression: string): void {
const cronExpressions = this.formGroup.controls.cronExpressions
cronExpressions.setValue([...cronExpressions.value, cronExpression])
}
As you can see, being that I do not change the JobModel
instance, I run detectChanges
to update the TableComponent
and its children, sch-job-row-toolbar
included I suppose!
The thing is sch-job-row-toolbar
does not seem to recalculate its bindings (ngOnChanges doesn't run).
So those values:
[isNew]="jobModel.isNew"
[isEdit]="jobModel.isEdit"
[isError]="jobModel.isError"
[isValid]="jobModel.isValid"
are not changed.
We can take JobModel#isEdit
as example:
get isEdit(): boolean {
return this.formGroup.dirty || Job.isEdit(this.job.status)
}
I have no clue what's happening, but I know that if I do press a button or switch a tab eberywhere else, sch-job-row-toolbar
receives the updated values.
All Components use onPush
strategy.
Explanatory GIF:
And, interestingly, when I do the same thing from the first Tab, it works!
Tried using Default
change detection strategy, but it's the same result.
Why don't you use @Input
and @Output
in order to detect changes from parent to child component?
I would like to suggest you to use @Input (parent => child)
and to use @Output (child=> parent
) instead of detectChanges()
.
这篇关于Angular detectChanges 不适用于子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!