0

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.

4
  • Have you tried marking the parent for check in loadData.subscribe? Commented Feb 7, 2022 at 17:55
  • Can you please provide a minimal reproducible example on an online IDE like Stackblitz? Commented Feb 8, 2022 at 5:36
  • @Siddhant added the link to Stackblitz Commented Feb 8, 2022 at 16:31
  • @pop Thanks for the Stackblitz. I have added an answer trying to explain the issue. Commented Feb 8, 2022 at 17:33

1 Answer 1

1

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:

  • The {{ label }} interpolation present within your OnPush Content child fieldtab template is visible
  • The {{ tab.label }} interpolation present within your OnPush fieldtabs template is not visible

When 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.

Sign up to request clarification or add additional context in comments.

1 Comment

Correct. I guess, I‘d need to push changes to Fieldtabs.Component for it to reflect the label state correctly. Thx!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.