Custom change detection with onPush is broken
See original GitHub issueRelated to Angular issues with ControlValueAccessor
and OnPush
components:
- https://github.com/angular/angular/issues/10816
- https://github.com/angular/angular/issues/25191
- https://github.com/angular/angular/issues/18748
- https://github.com/angular/angular/issues/12607
- https://github.com/angular/angular/issues/11563
Currently, setting a component to use the OnPush
change detection strategy is not safe with ngx-sub-form
as you’d end up with a “shift”. If you type “Hello” in an input and then add “A” the displayed value would be “Hello”. If after that you add a B, the value displayed would be “HelloA”, etc. Late by 1 change basically.
When calling the onChange
hook from the ControlValueAccessor
, Angular should run a change detection but it seems that it’s not the case.
Workaround
Not a beautiful one but at least simple and it’s still possible to use OnPush
…
In order to trigger a change detection, we can use the async pipe with a value coming from the form. So for every form that has at least a child (otherwise it’s not needed), you can do the following: [attr.data-ngx-sub-form-issue-93]="formGroup.valueChanges | async"
.
For e.g., from a sub component:
<div [formGroup]="formGroup" [attr.data-ngx-sub-form-issue-93]="formGroup.valueChanges | async">
<-- ... -->
</div>
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:8
Alright after trying it previsouly then reverting the fix, I finally gave this another go today.
I’ve added
OnPush
for all the components in the demo app using the rewrite. This broke a few e2e tests so I had something to iterate with quickly.I believe that by using
markDirty
it is now fixed. Here’s the commit: https://github.com/cloudnc/ngx-sub-form/pull/188/commits/274420a982b6b7aaa3b7ae449521b4f9f1eeb8f9All the e2e tests are passing correctly again
With Angular v9 around the corner and Ivy, we might be able to do all that without having to create a module and pass the
ChangeDetectorRef
🙌.We should be able to mark the component as dirty by passing the component’s reference (this) 🔥
So we should put that on hold as not having to setup a module is quite nice and if we can keep it that way we should probably