Reputation: 3714
There is a parent component with default changeDetection
and two child components with onPush
change detection strategy. While the input variable is being updated, the template will not update. I can't used async pipes in the ChildBComponent
as it is a global UI component for the project and refactoring is not an option. How do I go about this?
parent.ts
@Component({
selector: 'parent',
template: `
<div>
<child-a>
<child-b [label]="firstLabel"></child-b>
<child-b [label]="secondLabel"></child-b>
<child-b label="Just a plain label"></child-b>
</child-a>
</div>`
})
export class ParentComponent implements OnInit {
public ngOnInit(): void {
this.httpService.loadData()
.subscribe(data => {
this.someValue = 1;
this.otherValue = 2;
});
}
// getters to explicitly trigger change detection
public get firstLabel(): string {
return `Something ${ this.someValue || '?'}`;
}
public get secondLabel(): string {
return `Different ${ this.otherValue || '?'}`;
}
}
child-a.ts
@Component({
selector: 'child-a',
template: `
<div>Layout wrapper</div>
<ng-content></ng-content>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildBComponent implements AfterContentInit {
}
child-b.ts
@Component({
selector: 'child-b',
template: '<div>{{ label }}</div>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildBComponent implements AfterViewInit, OnDestroy {
@Input public label: string;
}
I tried converting @Input
into getter/setter - to no avail. When debugging, the changes are coming through, but the template will only update if I click on the component itself. Throwing in a markForCheck()
didn't help either.
And idea is helpful.
Edit: Added StackBlitz. Please use a wide preview to see the issue; miraculously it works properly when mobile view elements are shown.
Upvotes: 0
Views: 1131
Reputation: 3171
The problem is not with Change Detection, and the label values are correctly reflected in html. The change in countA
and countB
values do get reflected in HTML, it's just the CSS that gives the impression as if the html is not updated.
In fieldtabs.component.html
you have logic to display tabs via <ul>
and you also have <ng-content>
.
The problem is when the device has max width of 767.98px
, the <ul *ngIf="!vertical" class="fieldtabs--tabs-container">
element is not shown as a result of below CSS:
@media (max-width: 767.98px) {
.fieldtabs--tabs-container {
display:none
}
}
whereas the <fieldtab>
i.e the Content Children are only visible when device max width is 767.98px
. Below is the CSS responsible for the same:
.fieldtabs-l {
display: none
}
@media (max-width: 767.98px) {
.fieldtabs-l {
display:flex;
align-items: center
}
}
The fieldtab template html responsible for displaying label
has the above class:
<div *ngIf="!invisible" class="fieldtabs-l fieldtab--accord"
So when device max width is 767.98px:
{{ label }}
interpolation present within your OnPush Content child fieldtab
template is visible{{ tab.label }}
interpolation present within your OnPush fieldtabs
template is not visibleWhen width is greater than 767.98px, the opposite happens i.e {{ tab.label}}
is what you see on the screen, which doesn't get updated as the tabs
are being constructed within ngAfterContentInit
and the method won't be called again when countA
and countB
get assigned new values.
Upvotes: 1