I have a reactive form with two fields.First is custom input using ControlValueAccessor, and last is just regular HTML input.
Problem is, after performing form.reset(), the value of custom input is retained event its value in reactive form is null already.

As you can see in image, the first time I input and clear the values, it is working well.
But, as second time and onwards, the input value is STILL retained in custom input component. While, the normal HTML input is cleared and working well regardless of how many times I click Clear Input. Can you help me, please? Did I miss to put something?
Files:
Here is the form:
ts file
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
firstName: [{ value: '', disabled: false }],
lastName: [{ value: '', disabled: false }],
});
}
clearInput() {
this.form.reset();
}
}
html file:
<form [formGroup]="form">
<app-custom-input formControlName="firstName"></app-custom-input>
<input formControlName="lastName" placeholder="Last name" />
<button (click)="clearInput()">Clear Input</button>
</form>
<br />
<pre>{{ form.value | json }}</pre>
Here is the custom input file:
ts file:
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-custom-input',
templateUrl: './custom-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true,
},
],
})
export class CustomInputComponent implements ControlValueAccessor {
value: string;
changed: (value: any) => void;
touched: () => void;
isDisabled: boolean;
writeValue(value: string): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.changed = fn;
}
registerOnTouched(fn: any): void {
this.touched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
onChange(event: Event): void {
const value: string = (<HTMLInputElement>event.target).value;
this.changed(value);
}
}
html file:
<input
placeholder="First name"
[disabled]="isDisabled"
[value]="value"
(input)="onChange($event)"
(blur)="touched()"
/>
Full working code is here
Ok, you doing things well, but, you have to research a little bit deeper about this problem. If you go through HTML specification, you may find that the value attribute for the input html element is just an initial value. And that's why you get only first change if you push the reset button (actually you assign value there and writeValue method invokes).
So the solutions are several, the simplest and relative to your code style is to get the reference to the input and assign value manually:
custom-input.component.html
<input
placeholder="First name"
[disabled]="isDisabled"
(input)="onChange($event)"
(blur)="touched()"
#inputRef
/>
custom-input.component.ts
export class CustomInputComponent implements ControlValueAccessor {
@ViewChild('inputRef')
inputRef: ElementRef<HTMLInputElement>;
changed: (value: any) => void;
touched: () => void;
isDisabled: boolean;
writeValue(value: string): void {
if (this.inputRef) {
this.inputRef.nativeElement.value = value;
}
}
...
Another solution is to use ngModel and then it can work with value property binded to the input.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With