5
votes

I am writing an angular 2 application where I try to use ChangeDetectionStrategy.OnPush everywhere, for performance reasons. I have a complex component that needs OnPush in order to work smoothly, which contains another component that is displaying a form (created with FormBuilder). I now noticed that when I click on a slider, the internal value of it is updated (i.e. form.value), but the slider component does not visualize this new value, i.e. it is stuck at the old position.

My first idea to fix this, was to set the leaf component's change detection strategy to DEFAULT, but this had no effect as apparently this requires changing the change detection strategy of its parent components too (which is not possible in my application).

Then I came up with this idea:

@Component({
   ...
})
class MyComponent implements OnInit {
  constructor(private zone: NgZone) {}

ngOnInit() {
  INIT_FORM();

  this.form.valueChanges
    .subscribe(() => {
      this.zone.run(() => {});
    });
  }
}

but it has no effect.

Is there any possibility to make angular 2 forms work inside a component that uses OnPush?

2
You need to make sure that at least one of @Inputs used by your component that is OnPush have a new reference everytime a relevant change happens. A good guide on making the whole application to use OnPush can be found herekbtz

2 Answers

4
votes

Not tested myself but invoking change detection manually might do what you want:

@Component({
   ...
})
class MyComponent implements OnInit {
  constructor(private cdRef: ChangeDetectorRef) {}

ngOnInit() {
  INIT_FORM();

  this.form.valueChanges
    .subscribe(() => {
      this.cdRef.detectChanges();
    });
  }
}
1
votes

Let me respond with something that i have been answering on another posts, you could do something better !, let me know if this works :

when you use reactive forms you can use a really cool method called updateValueAndValidity(); that triggers a change detection.

private changeControlValue(control, value: number) {
    control.setValue(value);
    control.updateValueAndValidity();
  }

You can also use this method when updating the validators added to a form, example:

this.control.setValidators([Validators.required, Validators.minLength(5)]);
control.updateValueAndValidity();

This should do the trick ! I think this is one of the best adventages of using reactive forms or form controls against ng-model.

I don't recommend to use valueChanges at your form as you are open to forget to de-subscribe and create a memory leak, even you remember it can be tedious to create this flow.

And remember, when using onPush change detection only three things are going to be detected as changes by Angular:

1- Inputs and Outputs. 2- Html events that the user can do, like (click). 3- Async events like subscriptions.

I hope i helped you !.