Search code examples
htmlangularformsvalidationcomponents

Property 'nameFormControl' does not exist on type 'ContactComponent'


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!


Solution

  • FormGroup issue

    You should not set [formGroup] on your form fields and [formControl] should be formControlName

    <!-- Incorrect -->
    <input matInput [formGroup]="contactForm" [formControl]="nameFormControl"
    
    <!-- Correct -->
    <input matInput formControlName="nameFormControl"
    

    The @IF issue

    You can't access the control directly You need to use the formGroup like this

    @if (contactForm.controls.emailFormControl.hasError('required'))