How to implement Angular form using Angular template-driven form and its validation .?

Angular form are the most common and important for many web applications and are used for handling user input. User input data are taken from form, then validate and at last it is saved to database at server. We can create a form in Angular through the form tag of HTML. HTML comes with a number of form elements by default such as inputs, selects, and buttons.

An Angular provides a way to use these native elements and add some power to them. Angular allows us to add additional control to the form through its new directive like ngForm, ngModel, and ngModelGroup features.

In this tutorial, we will learn how to implment Angular template-driven form and how to validate it. Lets get started.

Types of Angular form

There are two primary mechanisms to work with forms in Angular, and each had its own Angular Module as
1. Template drive form (FormsModule)
2. Reactive form (ReactiveFormsModule)

In both types of form, we have common building blocks as FormControl, FormGroup, and FormArray. We will first learn the template-driven approach in this post, and in the next post, we’ll learn reactive forms.

Angular form: Template driven approach:

Angular template-driven forms, as the name suggests, start with the template, and use data binding to get the data to and from your components. It is template-first and allows us to create the logic of form via a component template. Creating and using forms is not simply we have to make the data binding form state tracking, validation, and error handling. Angular allows us to use ngModel in two different data binding.

  1. We can use one-way data binding through
    <input type=”email”name=”email”class=”form-control” ngModel>
  2. We can use two-way data binding [(ngModel)] called a banana in the box structure.
<input type="email" name="email" class="form-control [(ngModel)]="emailAddress">
{{ emailAddress }}
Angular form example

Example of Angular template-driven form

We can build almost any form with an Angular template-drive approach like login forms, contact forms, and pretty much any business form. Let demonstrate a template-driven approach by implementing an example. We have used ng-bootstrap for UI of angular form, which is optional. If you want to have the same UI then check our post on how to install ng-bootstrap in an Angular.

ng new templateForm

Import FormModule in app.module.ts

We have to register the FormsModule module in app.module.ts from ‘@angular/forms’. It provides required providers and directives for template-driven forms to work. Angular will automatically create a form that represents the JavaScript object of form when it detects a form element in a template of a component. Edit app.module.ts file.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular template-driven form ecample

We will create a simple user detail form to demonstrate a template-driven approach. We have a button in a form element where we called the form to submit the method directly. The default behavior of HTML will be triggered.

This button will submit the form and it will also trigger a javascript submit an event build in HTML. We can take advantage of using the angular ngSubmit directive, adding directly to the form element. This directive gives only one event in which we can listen whenever the form is submitted.

We can place ngSubmit directive on the form. The event made available by the ngSubmit directive will be fired whenever this form is submitted, so whenever this default behavior is triggered. The template reference variable on form #f=”profileForm”. It tells angular to give access to this form which we have created in our template component. This is how we get access to the form, to this javascript object created by Angular automatically.

<div class="container">
  <h4> Angular form example</h4>
  <form #profileForm="ngForm" (ngSubmit)="onSubmit(profileForm.value)"> 
    <div class="form-group">
      <label>Name </label>
       <input type="text" name="name" class="form-control" ngModel>
    </div>
    <div class="form-group">
      <label>Email : </label>
      <input type="email" name="email" class="form-control" ngModel="email">
    </div>
    <div ngModelGroup="address">
      <div class="form-group">
        <label>Address : </label>
        <input type="text" name="address" class="form-control" ngModel>
      </div>
      <div class="form-group">
        <label>Country</label>
        <select class="form-control" name="country" ngModel>
          <option value="india">India</option>
          <option value="france">France</option>
          <option value="germany">Germany</option>
          <option value="japan">Japan</option>
          <option value="Mongolia">Mongolia</option>
        </select>
      </div>
    </div>
    <div class="form-group">
      <label>Gender</label>
      <input type="radio" name="sex" class="form-control" value="Male" ngModel>Male
        <input type="radio" name="sex" class="form-control" value="Female" ngModel> Female
    </div>
    <div class="form-group">
      <input class="btn btn-primary" type="submit">
    </div>
  </form>

  <div>{{profileForm.value | json }}</div>
</div>

Edit app.component.ts file

We have one method in the app.component.ts typescript file to console log form object.

import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styles: [`
		input.ng-invalid {
			border-left: 5px solid red;
		}
		input.ng-valid {
			border-left: 5px solid blue;
		}
	`]
})
export class AppComponent {
  onSubmit(form: NgForm) {
    console.log(form);
  }
}

ngModel:
Angular will not automatically detect this input in this form and we may also need to control the form element. In input, we have to add ngModel directive from the two-way data binding. This will tell angular that input is actually control of the form. The ngModel is a directive made available in the formModule.

Name attribute:
By using the name attribute we can specify the name of the control in a form. To recognized input as a control in a form, we need to give angular the name of control by adding the name attribute on input. The name is the default attribute you can add to any HTML control.

Angular template-driven form validation

To add validation to an Angular template-driven form, we add the same validation attributes of HTML form, as Angular form extends and relies on a native HTML form. Angular uses directives to match these attributes with validator functions in the framework.We have template form reference #profileForm=”ngForm” in our template component. The ngForm gives access to form objects of javascript created by an Angular. It stores state information for the form, including the following.

  1. Values object containing all the controls inside the form.
  2. Groups of fields in the form.
  3. Fields in the form
  4. Validators value object like dirty, error, touched etc for Validation

Angular template-driven form validation example

We’ll demonstrate three validation, two for single form element and another for formGroup element called address which contains two-element location and country. The ngModelGroup directive creates and binds formGroup instance to a DOM element and can be used as a child of NgForm within form tags.

This directive will group inputs, and we need to set ngModelGroup equal to string to indicate group name. When we submit the form we have our group object in value object containing key-value pair of its all group elements. Use the ngModelGroup directive to validate a sub-group of forms separately from the rest of our form.

To valid the formGroup, the ngForm object has a control object which has a group name containing its validation state. All validation classes like ng-dirty touched and other classes are added to formGroup element. We can use these validation CSS class names on the formGroup to apply the style for formGroup validation state. The local reference on the ngModelGroup element gives access to the JavaScript representation of the object of formGroup.

angular-template-form-validation-
Angular template form validation screenshot

Edit an app.component.html to add form and validation code for angular template-driven approach.

<div class="container">
  <h4> Angular template form validation </h4>
  <form #profileForm="ngForm" (ngSubmit)="profileForm.form.valid && onSubmit(profileForm.value)">
    <div class="form-group">
      <label>Site name </label>
      <input type="text" name="name" class="form-control" [(ngModel)]="user.name" pattern="[a-z, A-Z, ' ']*"
        minlength="10" required>
      <p class="text-danger" [hidden]="profileForm.controls.name && (profileForm.controls.name.valid || (profileForm.controls.name.pristine))">
        Name is required with min length of 10 of alphabet character or white space
      </p>
    </div>

    <div class="form-group">
      <label>Email : </label>
      <input type="email" name="email" class="form-control" pattern="[a-z0-9._%+-][email protected][a-z0-9.-]+\.[a-z]{2,4}$"
        [(ngModel)]="user.email" required>
      <div class="text-danger" *ngIf="profileForm.controls.name && profileForm.controls.email.touched">
        <p *ngIf="profileForm.controls.email.errors?.required">Email is a required field!</p>
        <p *ngIf="profileForm.controls.email.errors?.pattern">This is not a valid Email!!!</p>
      </div>
    </div>
    <div ngModelGroup="address" ngModelGroup="adddress" #addressCtrl="ngModelGroup">
      <div class="form-group">
        <label>Address : </label>
        <input type="text" name="location" class="form-control" [(ngModel)]='user.address.location' required>
      </div>
      <div class="form-group">
        <label>Country</label>
        <select class="form-control" name="country" [(ngModel)]='user.address.country' required>
          <option value="india">India</option>
          <option value="france">France</option>
          <option value="germany">Germany</option>
          <option value="japan">Japan</option>
          <option value="Mongolia">Mongolia</option>
        </select>
      </div>
      <p *ngIf="addressCtrl.invalid && addressCtrl.touched" class="text-danger">
        formGroup element address invalid
      </p>
    </div>
    <button class="btn btn-primary float-right" type="submit">Submit</button>

  </form>

    <div *ngIf="profileForm.valid">{{profileForm.value | json }}</div>
</div>

<router-outlet></router-outlet>

Edit app.component.ts file to create a profile data object, containing all information about users.

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  user: any;

  constructor() {
  }

  ngOnInit() {
    this.user = {
      name: '',
      email: '',
      address: {
        location: '',
        country: ''
      }
    };
  }

  onSubmit(form: NgForm) {
    console.log(form);
  }
}

Angular form Control status CSS classes for form validation

When we use ngModel directive on a form, it allows angular detection is form control input and tracks the state of the form fields. Angular adds a couple of classes on form elements to indicate form element validation status. Angular automatically mirrors many control properties onto the form control element as CSS classes.

We can use these classes to style form to show warnings or style the form elements according to the state of the form element. The following classes are currently supported.

CSS class nameAngular form element status
ng-pristineData entry has not been touched
ng-dirtyThe input field has been interacted with
ng-touchedThe input field has received focus
ng-validData entry has passed validation
ng-invalidData entry has not passed validation
ng-untouchedSet this CSS class if a user has not tabbed out from the input control.

In this example, we apply the CSS style to input text through a form element class provided by an Angular. We can use an Angular ng-valid class to apply the CSS style to the input of the form and we can apply the style to the input text of firstName with the required attribute through an Angular ng-invalid class.

ngModelGroup Directive
The ngModelGroup, we can use this directive if we like to create a sub-group within a form. This can come in handy if you want to validate a sub-group of your form separately from the rest of your form, or if some values in your domain model make more sense to consume together in a nested object.

Angular form state

Like individual form field, we can validate, entire form using its states. Form also has states like valid, pristine, dirty, untouched, and touched also. In our template-driven approach, we have also applied valid states on our form using template references.

 <div *ngIf="profileForm.valid">{{profileForm.value | json }}</div>

Here we display only profileForm form value only when the form is valid, the same way we can enable or disabled submit button using form state value.

Conclusion
In this tutorial, we had learn how to implement an Angular template-driven form example with how to validate it. Angular template-driven forms are easy to build and the logic of the forms is control inside the component template.

Related Articles

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top