I was using ControlValueAccessor to create an custom input in Angular. I recognized that the validation of the FormControls stoped working.
Here is a simple example I made on Stackblitz.
@Component({
selector: 'app-text-field',
templateUrl: './text-field.component.html',
standalone: true,
imports: [CommonModule, FormsModule],
})
export class TextFieldComponent implements ControlValueAccessor, OnInit {
protected control = inject(NgControl); // control should be injected
onChange(value: string) {}
onTouch() {}
value = '';
ngOnInit(): void {
this.control.valueAccessor = this;
}
registerOnChange(fn: (value: string) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouch = fn;
}
writeValue(value: string) {
this.value = value;
}
}
I can't provide NG_VALIDATORS
as it creates a circular dependency and couldn't find any code that is still usable in Angular 16+ or could be considered as best practice.
So what is the best way to support validation?
Edit1:
Here is also the way the input is used:
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, TextFieldComponent],
template: `
<form [formGroup]="form">
<app-text-field formControlName="a" />
</form>
<p>{{ form.errors }}</p>
`,
})
export class App {
form = new FormGroup({
a: new FormControl<string>('', {
validators: [
Validators.required,
Validators.maxLength(8),
Validators.minLength(2),
],
}),
});
constructor() {
this.form.valueChanges.subscribe((val) =>
console.log(val, this.form.errors)
);
}
}
As Chellappan pointed out in the comments, the code is just fine. The ControlValueAccessor already gets validated by the FormGroup. There is currently a bug that errors of FormControls don't get exposed to the FormGroup, what led to a missunderstanding.