angulartypescriptangular-materialangular-reactive-formsangular-forms

Error message not displaying when input is touched and invalid


I'm working on an Angular component where I want to display an error message if the input field is touched and invalid. However, the error message is not appearing as expected.

The error message "Name is required." should appear when the input field is touched and left empty (invalid). The plain HTML should be used and not the Angular Material input component. However, it does not show up. What might be causing this issue?

Below is my code:

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  template: `
    <form method="post">
      <label for="name">Name:</label>
      <div class="container">
        <input type="text" id="name" name="name" placeholder="Enter your name">
        <div *ngIf="control?.touched && control?.invalid" class="error">
          <div *ngIf="control?.hasError('required')">Name is required.</div>
        </div>
      </div>
      
      <button type="submit">Submit</button>
    </form>
  `,
})
export class App {
  name = 'Angular';
  contactForm!: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    this.contactForm = this.fb.group({
      name: new FormControl('', [Validators.required]),
    });
  }

  get control(): FormControl {
    return this.contactForm.get('name') as FormControl;
  }
}

StackBlitz


Solution

  • Reactive form must have a [formGroup] defined at the root of the form.

    <form [formGroup]="contactForm">
    

    Also initialize the form with a default object, it will help with form initialization.

    name = 'Angular';
    contactForm: FormGroup =  new FormGroup({});
    

    You must add the import for reactive forms module.

    import {
      FormBuilder,
      FormControl,
      FormGroup,
      ReactiveFormsModule,
      Validators,
    } from '@angular/forms';
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule, ReactiveFormsModule],
    

    You missed to add formControlName to the input form control.

    <input type="text" id="name" name="name" formControlName="name" placeholder="Enter your name">
    

    Reactive Forms Guide - Angular.dev

    Full Code:

    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    import { provideAnimations } from '@angular/platform-browser/animations';
    import { CommonModule } from '@angular/common';
    import {
      FormBuilder,
      FormControl,
      FormGroup,
      ReactiveFormsModule,
      Validators,
    } from '@angular/forms';
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule, ReactiveFormsModule],
      template: `
        <form [formGroup]="contactForm">
          <label for="name">Name:</label>
          <div class="container">
            <input type="text" id="name" name="name" formControlName="name" placeholder="Enter your name">
    
            {{control.touched}}
            {{control.invalid}}
            <div *ngIf="control?.touched && control?.invalid" class="error">
              <div *ngIf="control?.hasError('required')">Name is required.</div>
            </div>
          </div>
          
          <button type="submit">Submit</button>
        </form>
      `,
    })
    export class App {
      name = 'Angular';
        contactForm: FormGroup =  new FormGroup({});
    
      constructor(private fb: FormBuilder) {}
    
      ngOnInit(): void {
        this.contactForm = this.fb.group({
          name: new FormControl('', [Validators.required]),
        });
      }
    
      get control(): FormControl {
        return this.contactForm.get('name') as FormControl;
      }
    }
    
    bootstrapApplication(App, {
      providers: [provideAnimations()],
    }).catch((err) => console.error(err));
    

    Stackblitz Demo