10

I have an Angular component that dynamically creates various other types of component inside itself. It binds its own properties to child component @Input properties via an OnChanges hook.

This binding works fine when the child component's change detection is set to Default. Then the new inputs are detected and the component template is updated.

However, it doesn't work when change detection is OnPush, then the change is not detected. I believe the change should be detected because a new immutable object, a string, is assigned to a component @Input property.

Here's a plunker to demonstrate: https://plnkr.co/edit/0wHQghtww2HXVbC27bC1

How can I get this parent-to-dynamic-child property binding to work with ChangeDetectionStrategy.OnPush?

2
  • For anyone interested, here's the related GitHub issue with more info about why OnPush change detection works differently for dynamic components - github.com/angular/angular/issues/14087 Commented Feb 3, 2017 at 0:21
  • Is this issue fixed? Commented Feb 17, 2020 at 15:08

2 Answers 2

9

As possible workaround for OnPush component would be using setter together with cdRef.markForCheck():

change-detection-onpush.component.ts

@Component({
  selector: 'app-change-detection-onpush',
  template: `
    <div>
      ChangeDetectionStrategy.OnPush: {{ message || '[blank]' }}
    </div>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChangeDetectionOnPushComponent implements IMyComponent {
  private _message: string;

  constructor(private cdRef: ChangeDetectorRef) {}

  set message(val: string) {
    this.cdRef.markForCheck();
    this._message = val;
  }

  get message() {
    return this._message;
  }
}

Modified Plunker

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

4 Comments

Seems, Plunker not working, Would it be possible to move to working code to Stackblitz.
@Cegone Please look at this plunker plnkr.co/edit/NJRoUOvfrI8dQkWRoLcM?p=preview
Thank you @Yurzui, It's working for me. Actually, I missed this part, set message(val: string) { this.cdRef.markForCheck(); this._message = val; } But, When we try for Dump Component, Is this fine?, because we need to inject ChangeDetectorRef in Constructor.
if many input variable available in ChangeDetectionOnPushComponent component, is i need to put markForCheck() in all input variable?
0

Angular now has the setInput() method on ComponentRef https://angular.io/api/core/ComponentRef#setInput

So, you can easily set your inputs from within the host component like so:

const componentRef = viewContainerRef.createComponent<MyDynamicComponent>(MyDynamicComponent);
componentRef.setInput('myInputName', 'myInputValue');

Using this method should automatically call markForCheck() without having to specify additional logic in the child components.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.