I have a simple login page with a reactive form and subform component app-login-form
that uses ControlValueAccessor
, which is working, but I can't figure out how to display the errors in the subform. This is an example before I start creating more complex forms.
When submitted I try to access the subform and markAllAsTouched
, but when I'm watching the elements that the classes don't change.
I made a quick StackBlitz to show what I'm doing. How do I get the error messages to show up when I submit the form?
public onSubmit(event: Event): void {
if (this.form.valid) {
console.log('VALID', this.form.value);
} else {
console.log('INVALID', this.form.value);
Object.keys(this.form.controls).forEach((controlName) => {
console.log('SHOW_ERRORS', controlName);
const control = this.form.get(controlName);
// ISSUE: Nothing changes on the element still ng-untouched, and
// was expecting it to be ng-touched
control.markAllAsTouched();
});
}
}
I would take a slightly different approach and not use ControlValueAccessor
, but instead a "regular" child component and use ControlContainer
, then you can skip all that markAsTouched
stuff, as parent will be aware of anything going on in child.
parent:
this.form = this.formBuilder.group({});
template:
<app-login-form></app-login-form>
Child component, where we add formcontrols to existing parent form:
@Component({
selector: "app-login-form",
templateUrl: "./login-form.component.html",
styleUrls: ["./login-form.component.css"],
viewProviders: [
{
provide: ControlContainer,
useExisting: FormGroupDirective
}
]
})
export class LoginFormComponent implements OnInit {
childForm: FormGroupDirective;
constructor(
parentForm: FormGroupDirective,
private fb: FormBuilder
) {
this.childForm = parentForm;
}
ngOnInit() {
this.childForm.form.addControl('username', this.fb.control('', [Validators.required]));
this.childForm.form.addControl('password', this.fb.control('', [Validators.required]));
}
}
Then in template you just use formControlName
instead of [formControl]
, like:
<input matInput formControlName="username">
<mat-error *ngIf="childForm.hasError('required', 'username')">Required</mat-error>
Also remove the form tags from child, and also remember to add type="button"
in the icon, otherwise button will be considered submit
.
From parent form submit you can remove: control.markAllAsTouched();
I would have forked your stackblitz with the complete code, but seems like I'm not allowed to fork it. So hopefully I remembered to mention all changes I made, otherwise please provide a stackblitz which can be forked.