I have a ControlValueAccessor directive that performs value formatting but its @HostBinding('value')
works only the first time.
@Component({
selector: 'my-app',
template: `
Value: {{value}}<br/>
<input type="text" uppercase [(ngModel)]="value">
<button type="button" (click)="reset()">Reset</button>
`,
})
export class AppComponent {
value = 'Angular ' + VERSION.major;
reset() {
this.value = 'Reset';
}
}
@Directive({
selector: 'input[uppercase]',
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UpperCaseInputDirective), multi: true }],
})
export class UpperCaseInputDirective implements ControlValueAccessor {
@HostBinding('value') lowerValue = '';
...
}
Please see full example at https://stackblitz.com/edit/angular-ivy-vfahu3?file=src%2Fapp%2Fapp.component.ts
<input>
to "reset" as expected.<input>
stays with "Test". I would expect it to change to "reset" as it did in point 1.Can you explain me this behavior? Any clues?
Side note: I know the example above could be implemented by other means, but it just a simplification of case where I am using <input type="datetime-local>
and the directive translates input value to ISO format.
I realized that the value was not updated due to Angular optimization - it does not propagate value to DOM if it thinks that value did not change. In point 1 it changes bound variable to value "Reset" and in point 3 it "thinks" the value is still "Reset" and therefore it does not update DOM.
When I update bound variable this.lowerValue
in onChange
listener (point 2) then Reset button works event in point 3:
@HostListener('change', ['$event']) onChange(event: Event) {
if (event.target instanceof HTMLInputElement) {
this.lowerValue = event.target.value?.toLocaleUpperCase();
}
this._onChangeCallback(this.lowerValue);
}