Bereits hier https://gedoplan.de/angular-formulare-mit-controlvalueaccessor/ haben wir einen Blick darauf geworfen, wie eigene Formular-/Eingabe-Komponenten in Angular implementiert werden können. Eine Anforderung, die bei uns häufig in Projekten vorkommt, ist die flexible Ergänzung von Validatoren.
Konkret geht es darum, dass Validatoren zum einen „ganz normal“ über das Control definiert werden müssen und zum anderen die Komponente selber ergänzend weitere Validatoren hinzufügt. Ein typisches Beispiel: eine Komponente zur Erfassung einer Kundennummer, die einem bestimmten Format unterworfen ist (Validator auf Ebene der Eingabe-Komponente) und an bestimmten Stellen in der Anwendung ein Pflicht- oder Optionales-Feld ist (Validator auf Ebene der fachlichen Komponente).
Verwendung / fachliche Validatoren:
form = new FormGroup({
counter: new FormControl<number|null>(0, Validators.required())
})
<app-btn-in formControlName="counter"></app-btn-in>
Eingabe-Komponente
@Component({
selector: 'app-btn-in',
standalone: true,
templateUrl: './btn-in.component.html',
styleUrl: './btn-in.component.scss',
providers: [
//removed*: {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => BtnInComponent),}
]
})
export class BtnInComponent implements ControlValueAccessor, OnInit {
count = signal<number>(0);
disabled = false;
change!: (_: number) => void;
touch!: () => void;
constructor(private ngControl: NgControl) {
// * added instead
ngControl.valueAccessor = this;
effect(() => {
this.change(this.count());
});
}
ngOnInit() {
// additional validators
this.ngControl.control?.addValidators([Validators.max(10)])
this.ngControl.control?.updateValueAndValidity();
}
writeValue(obj: number): void {
this.count.set(obj)
}
registerOnChange(fn: any): void {
this.change = fn;
}
registerOnTouched(fn: any): void {
this.touch = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
Die grundlegende Implementierung ändert sich kaum. Die Unterschiede:
- wir injecten uns das NgControl (17)
- anstatt den ValueAccessor über den multi-Provider zu registrieren (07), setzen wir diesen selber (19) (ansonsten würden wir eine Circular Dependency erzeugen)
- im ngOnInit fügen wir zusätzliche Validatoren hinzu (26) und aktivieren diese über den zusätzlichen call „updateValueAndValidty()“