Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 forms + OnPush

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?

like image 873
highwaychile Avatar asked Sep 25 '16 13:09

highwaychile


People also ask

What is OnPush in Angular?

The OnPush strategy changes Angular's change detection behavior in a similar way as detaching a component does. The change detection doesn't run automatically for every component anymore. Angular instead listens for specific changes and only runs the change detection on a subtree for that component.

What triggers OnPush change detection?

Input Reference But with OnPush strategy, the change detector is only triggered if the data passed on @Input() has a new reference. This is why using immutable objects is preferred, because immutable objects can be modified only by creating a new object reference.

What is Changedetectionstrategy in Angular?

What is Change Detection Strategy in Angular ? Angular Change Detection Strategy are the methods by which the updates to the component is tracked and component is triggered to Re-render.

How do I turn off change detection?

Select the devices in which you want to enable/disable change detection. Click on the 3 horizontal dots at the top right corner to get device option list. Click on "Enable Change Detection" from the given list. Select "Enable" or "Disable" operation based on your requirement.


2 Answers

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();
    });
  }
}
like image 195
Günter Zöchbauer Avatar answered Oct 07 '22 06:10

Günter Zöchbauer


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

like image 28
Alan Buscaglia Avatar answered Oct 07 '22 04:10

Alan Buscaglia