angular icon indicating copy to clipboard operation
angular copied to clipboard

Custom directive implementing controlValueAccessor does not trigger writeValue if the formControl has been updated by another controlValueAccessor

Open manueledones opened this issue 4 years ago • 2 comments

Which @angular/* package(s) are the source of the bug?

forms

Is this a regression?

No

Description

I've created a custom directive implementing controlValueAccessor and added it to two html input elements.

The writeValue function is not called if the input value is provided using [formControl] and the value is updated through the registerOnChange callback.

The writeValue is instead correctly called if the input value is provided by [(ngModel)] instead of [formControl]

Export class customDirective implements controlValueAccessor ...

With ngModel works fine
<input customDirective [(ngModel)]="value" />
<input customDirective [(ngModel)]="value" />

With formControl there's the issue
<input customDirective [formControl]="myFormControl" />
<input customDirective [formControl]="myFormControl" />

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-ivy-a2loir?file=src%2Fapp%2Fapp.component.html

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in

No response

Anything else?

No response

manueledones avatar Sep 17 '21 10:09 manueledones

I've just stumbled over the same bug.

The buggy behavior seems to be due to this code specifying emitModelToViewChange: false in its options: https://github.com/angular/angular/blob/8ebc946c0e7bf80d26ec8268acb4ff0af9e5c34a/packages/forms/src/model.ts#L1471

This leads to the following if-statement evaluating to false. However it is only within this if-block, where all the other "writeValue()" instances are called (stored in the _onChange array).

https://github.com/angular/angular/blob/8ebc946c0e7bf80d26ec8268acb4ff0af9e5c34a/packages/forms/src/model.ts#L1338-L1341

NicBright avatar Dec 21 '21 09:12 NicBright

This is still an issue on Angular 14 (didn't test on 17 yet)

mistic100 avatar May 14 '24 12:05 mistic100

FWIW this repros on ng17 and I assume ng18 since there's no meaningful change in the relevant code. You don't need a custom value accessor, it repros with the default value accessors:

<!-- With ngModel works fine -- >
<input [(ngModel)]="value" />
<input [(ngModel)]="value" />

<!-- With formControl there's the issue -->
<input [formControl]="myFormControl" />
<input [formControl]="myFormControl" />

The control value accessor pushes a new value to the model here: https://github.com/angular/angular/blob/8ebc946c0e7bf80d26ec8268acb4ff0af9e5c34a/packages/forms/src/directives/shared.ts#L223 This assumes that only a single view is bound to the model: the view sent us the value, it's already up to date, no need to write it back. As a consequence all other views except the one that triggered the change goes out of sync.

For [(ngModel)] the change detector pushes the value to all views, that's why it seems to work.

bachratyg avatar Jul 03 '24 14:07 bachratyg