Hello StackOverflow community!
I’m developing an app in Angular + Node and I’ve encountered a big issue regarding forms and validators using Material Angular.
At the moment, I’m stuck with the HTML component not recognizing the input, and I don’t know what I’m missing.
I have this code:
contact.component.html:
<mat-card>
<mat-card-header>
<mat-card-title>Formulario de contacto</mat-card-title>
<mat-card-subtitle>Ponte en contacto conmigo</mat-card-subtitle>
</mat-card-header>
<form [formGroup]="contactForm">
<mat-card-content>
<mat-form-field>
<mat-label>Nombre y apellidos</mat-label>
<input matInput [formGroup]="contactForm" [formControl]="nameFormControl" required name="name" maxlength="128" autocomplete="off" autofocus>
@if (nameFormControl.hasError('required') || nameFormControl.hasError('pattern')) {
<mat-error>Por favor, rellena este campo</mat-error>
}
</mat-form-field>
</mat-card-content>
<mat-card-content>
<mat-form-field>
<mat-label>Correo electrónico</mat-label>
<input matInput [formControl]="emailFormControl" required name="email" maxlength="128" autocomplete="off">
@if (emailFormControl.hasError('required')) {
<mat-error>Por favor, rellena este campo</mat-error>
}
@else if (emailFormControl.hasError('email')) {
<mat-error>Debes introducir una dirección de correo electrónico válida</mat-error>
}
@else if (emailFormControl.hasError('pattern')) {
<mat-error>Debes introducir una dirección de correo electrónico válida</mat-error>
}
</mat-form-field>
</mat-card-content>
<mat-card-content>
<mat-form-field>
<mat-label>Mensaje</mat-label>
<textarea #contactBody matInput [formControl]="bodyFormControl" name="body" maxlength="1024" autocomplete="off"></textarea>
<mat-hint align="end">{{ contactBody.value.length }} / 1024</mat-hint>
@if (bodyFormControl.hasError('required') || bodyFormControl.hasError('pattern')) {
<mat-error>Por favor, rellena este campo</mat-error>
}
</mat-form-field>
</mat-card-content>
</form>
<button mat-raised-button color="primary" (click)="saveMessage()">Enviar formulario</button>
contact.component.ts:
import { Component, OnInit } from '@angular/core';
import { AbstractControl, ReactiveFormsModule, FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { AppService } from './../app.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ErrorStateMatcher } from '@angular/material/core';
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrl: './contact.component.scss'
})
export class ContactComponent implements ErrorStateMatcher {
contactForm: FormGroup = new FormGroup({
nameFormControl: new FormControl(''),
emailFormControl: new FormControl(''),
bodyFormControl: new FormControl(''),
})
constructor(private appService: AppService, private formBuilder: FormBuilder, private _snackBar: MatSnackBar) {}
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
ngOnInit(): void {
this.contactForm = this.formBuilder.group(
{
nameFormControl: [
'',
[
Validators.required,
Validators.pattern(/[S]/)
]
], emailFormControl: [
'',
[
Validators.required,
Validators.email,
Validators.pattern("^([a-zA-Z0-9-._]+)@([A-Za-z-]+).([a-z]{2,3}(.[a-z]{2,3})?)$")
]
], bodyFormControl: [
'',
[
Validators.required,
Validators.pattern(/[S]/g)
]
]
},
);
}
}
The issue is on the nameFormControl, emailFormControl and bodyFormControl, which are under the FormGroup contactForm.
Can you guys bring me some light to this subject?
Thank you very much!
3
Answers
FormGroup issue
You should not set [formGroup] on your form fields and [formControl] should be formControlName
The @IF issue
You can’t access the control directly
You need to use the formGroup like this
You should use formControlName if you are using it inside FormGroup, and don’t add [formGroup] on input fields. like this:
Remove [formGroup] in the input fields and just replace the followings:
With this :
Also you cannot access the control directly without the contactForm object.
So you need to replace following:
To:
Tip:
If you are using Visual Studio Code, then I would highly recommend using Angular Language Service Extension. It will show you the errors in the html file and help you fix them.
Also when you are using FormGroup, use can consider controls as the fields, so you can simply name them like this:
nameFormControl to name
emailFormControl to email
bodyFormControl to body
Like this:
Couple things you need to correct in your template :
Change your
[formControl]="nameFormControl"
toformControlName="nameFormControl"
and follow the same to other controls as wellRemove
[formGroup]="contactForm"
fromnameFormControl
Replace
@if (emailFormControl.hasError('required'))
from@if (contactForm.controls['emailFormControl'].hasError('required'))
Please find the corrected code below :