Form Validation is very important in frontend, and Angular do this very well. The Template Driven Forms with ngModel can easily use Angular validation to show errors while filling form controls. Angular also tracks state of fom controls, like dirty, pristine, touched etc and update css class associated with it.

Angular validation classes

Control Visited Control Value change Control Value valid
ng-touched : true ng-dirty : true ng-valid : true
ng-untouched : false ng-pristine : false ng-valid : false

Template Driven Form

Lets create a Template Driven Form for validation purpose in template file.

Create a login object is component class with four keys, name, age, pass and email.

          <-- app.component.html -->

<form novalidate #loginform="ngForm">

<div> <label>Name: <input type="text" required name="name" [(ngModel)]="login.name"></label></div>

<div> <label>Age: <input type="number" required name="age" [(ngModel)]="login.age"></label></div>

<div> <label>Password: <input type="password" required name="password" [(ngModel)]="login.pass"></label></div>

<div> <label>Email: <input type="email" required name="email" [(ngModel)]="login.email"></label></div>
        
<div> <button [disabled]="loginform.invalid">Send</button></div>
        
</form>
        /* app.component.ts */
  import { Component } from '@angular/core';
  import { RouterOutlet } from '@angular/router';
  import { CommonModule } from '@angular/common';
  import { FormsModule } from '@angular/forms';
  
  
  @Component({
    selector: 'app-root',
    standalone: true,
    imports: [RouterOutlet,FormsModule,CommonModule],
    templateUrl: './app.component.html',
    styleUrl: './app.component.css'
  })
  export class AppComponent {
    title = 'myApp';
    login={name:"",age:0,pass:"",email:""};
  }  

Add template variables

Lets add validation controls in our form. Make sure each form control have name attribute and [(ngModel)] for two way data binding.

Add hash (#) to declare template variable. in each form control with unique name.

          <-- app.component.html -->
    
<form novalidate #loginform="ngForm">
            
<div> <label>Name: <input #name=ngModel type="text" required name="name" [(ngModel)]="login.name"></label></div>
    
<div> <label>Age: <input #age=ngModel type="number" required name="age" [(ngModel)]="login.age"></label></div>
    
<div> <label>Password: <input #pass=ngModel type="password" required name="password" [(ngModel)]="login.pass"></label></div>
    
<div> <label>Email: <input #email=ngModel type="email" required name="email" [(ngModel)]="login.email"></label></div>
            
<div> <button [disabled]="loginform.invalid">Send</button></div>
            
</form>

Add CSS

          <-- app.component.css -->

form div{ margin: 10px 0; }
.error{ color: #c00; }
.warn{ color: #f90; }
.success{ color: #080; } 

Add Validation

Now we will add validation in template driven form. We will use <span> elements for validation messages with hidden attribute.

With addition to this, we can also add css classes to change text color as per validation state. Like for errors , use red color and for success, use green colors.

Enter Name
Enter Age
Enter Password
Enter Email
          <-- app.component.html -->
        
<form novalidate #loginform="ngForm">
                
<div><label>Name: <input #name=ngModel type="text" required name="name" [(ngModel)]="login.name"></label>
<span class="success" [hidden]="name.invalid">Valid Name</span>
<span class="error" [hidden]="name.valid || name.dirty">Enter Name</span>
<span class="error" [hidden]="name.valid || name.pristine">Enter Valid Name</span>
</div>
        
<div><label>Age: <input #age=ngModel type="number" min="18" max="25" required name="age" [(ngModel)]="login.age"></label>
<span class="success" [hidden]="age.invalid">Valid Age</span>
<span class="error" [hidden]="age.valid || age.dirty">Enter Age</span>
<span class="error" [hidden]="age.valid || age.pristine">Enter Valid Age</span>
</div>
        
<div><label>Password: <input #pass=ngModel type="password" pattern="[\w]{8,12}" required name="password" [(ngModel)]="login.pass"></label>
<span class="success" [hidden]="pass.invalid">Password Accepted</span>
<span class="error" [hidden]="pass.valid || pass.dirty">Enter Password</span>
<span class="error" [hidden]="pass.valid || pass.pristine">Invalid Password</span>
</div>
        
<div><label>Email: <input #email=ngModel type="email" pattern="[\w]{1,}\@[\w]{1,}\.[a-zA-Z]{2,}" required name="email" [(ngModel)]="login.email"></label>
<span class="success" [hidden]="email.invalid">Valid Email</span>
<span class="error" [hidden]="email.valid || email.dirty">Enter Email</span>
<span class="error" [hidden]="email.valid || email.pristine">Enter Valid Email</span>
</div>
                
<div><button [disabled]="loginform.invalid">Send</button></div>
                
</form>