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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With