This article will give you much information about Template Driven Forms and how to create form with Template Driven Forms approach and implement validation with Template Driven Forms with Angular 6 and TypeScript.

Forms are useful when you need to gather information from the user. It provides an interface from where a user can fill all required details and validate the information before submitting the data. Validation is not only required for checking the required data but also use for checking pattern of data. When talking about form and validation in Angular, we have two different ways to create forms, the first one is the Template Driven Forms and another one is Reactive Forms. Today we only focus on Template Driven Form and know what it is and why we should use it. Apart from this, we will also learn how to create Template Driven Forms along with validations. 

So, lets the first understand what Template Driven Forms is and what are the reasons to use it. 

What and why Template Driven Forms

As the name suggests,  in this approach to create forms, we more focus on Template instead of components code. We add the template with different types of control like input, dropdown, checkbox etc and bind directive with them to handle the behavior of template. It is not a new approach, however, we have also used this approach in Angular JS. This is a similar way to create a form using ngModel and two-way data-binding as we did in Angular JS. In Template Driven Forms, validations are implemented using HTML 5 attributes like required, minLength, maxLength, pattern etc This is not very complex while implementing, it is very easy to use. We can not use Template Driven Forms approach to create forms in each scenario, this is only feasible and fit with those scenarios where form structure is simple and handling the simple scenario.

If you are willing to write test cases for the app then don't use this approach, since with the Template Driven Forms, testing the form is not easy. Another point, I would like to mention here that due to so many codes in Template sides, it creates the complexity to understand template codes and create readability issues. 

Create Angular Project

Now let's move forward to practical demonstration and step by step understanding how to create Template Driven Forms and implement validation with that. So, we are going to create an Angular project [For this demonstration, we are using Angular version 6]. You can follow below steps to create a new Angular 6 CLI project. 

  1. Open Visual Studio Code and press CTRL + ~ to open a terminal window.
  2. Move to the particular directory where the project needs to be created.
  3. To create a new Angular CLI project, type command ng new FormValidationDemo --routing and press Enter.
  4. Execute command npm install bootstrap@3 to add bootstrap with the project.
  5. Now we have project ready, now move to that project folder and run the project using a command as  ng serve --open

For more about how to create an Angular CLI project with step by step instructions, please follow this article

More articles on Angular which you may like.
 
Implementation of Template Driven Forms

Before moving to the next step, first, we will configure Bootstrap, so that we can use the bootstrap classes. So, open styles.css and add following code which is responsible for importing bootstrap CSS from installed node packages.

@import "node_modules/bootstrap/dist/css/bootstrap.min.css";

.invalid-data {
    border: 2px solid red;
}

.valid-data {
    border: 2px solid rgb(19, 92, 4);
}

To implement the Template Driven Forms with an Angular project, we first need to add a module which is essential for providing all the required components of the Template Driven Form. So, open the app.mdoule.ts and add the FormsModule imported from @angular/forms. Point to note here that FormsModule is used for creating Template Driven Forms and ReactiveFormsModule is used for created Reactive Forms.

After that, we will add one component as name 'TemplateDrivenFormComponent' where we will create a form and validation with that. To add a new component, move to app folder in terminal windows and type the command as follows.

ng g c TemplateDrivenForm

So, now we have component ready. Let confirm the route to reach with this component.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TemplateDrivenFormComponent } from 'src/app/template-driven-form/template-driven-form.component';

const routes: Routes = [  
  {
    path: 'templateform',
    pathMatch: 'full',
    component: TemplateDrivenFormComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Now lets create a simple form using bootstrap classes where user can enter his/her address details. So, just open the 'template-driven-form.component.html' and add the following HTML code. 

<div class="row">
  <div class="col-md-4 col-md-offset-4" style="margin-top: 50px; border: 1px solid rgb(100, 98, 98); padding: 30px;">
    <form class="form-horizontal" role="form">
      <fieldset>
        <legend>Address Details:
          <strong>Template Driven Form</strong>
        </legend>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">Address</label>
          <div class="col-sm-10">
            <input type="text" name="address" placeholder="Enter Address" class="form-control">
          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">City</label>
          <div class="col-sm-10">
            <input type="text" name="city" placeholder="Enter City Name" class="form-control">
          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">State</label>
          <div class="col-sm-4">
            <input type="text" name="state" placeholder="State" class="form-control">
          </div>

          <label class="col-sm-2 control-label" for="textinput">Postcode</label>
          <div class="col-sm-4">
            <input type="text" name="postcode" placeholder="Enter Post Code" class="form-control">
          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">Country</label>
          <div class="col-sm-10">
            <select class="form-control" name="country">
              <option>---Select---</option>
              <option *ngFor="let item of countryData" [value]="item">
                {{item}}
              </option>
            </select>
          </div>
        </div>

        <div class="form-group">
          <div class="col-sm-2 form-check">
            <input type="checkbox" name="aggrement" class="form-check-input">
          </div>
          <label class="col-sm-10 form-check-label">I aggree to Terms & Conditions
          </label>
        </div>

        <div class="form-group">
          <div class="col-sm-12">
            <span style="color: red;">Please Aggree with Terms & Conditions.</span>
          </div>
        </div>

        <div class="form-group">
          <div class="col-sm-offset-2 col-sm-10">
            <div class="pull-right">
              <button type="submit" class="btn btn-primary" style="margin: 4px;">Save</button>
              <button type="reset" class="btn btn-default">Reset</button>
            </div>
          </div>
        </div>
      </fieldset>
    </form>
  </div>
</div>

First let see, what will be output of the above template. So, ru the app usig ng serve command. Now see the output, you will find the output as follows. Here we are going to create an Address form which has an address, city, state, postcode as an Input fields and country as a drop-down field. Apart from this, we have one checkbox for validating the terms and conditions. We will try to validate almost every control either that will be Input control or dropdown. Form validation will happen on the form's submission.Template Driven Forms in Angular

Above form is simple form and before converting above simple form to Template Driven Forms, we will create a Model as follows. 

export interface addressModel{
    address: string,
    city: string,
    state: string,
    postcode: number,
    country: any[],
    aggrement: boolean
}

Now, let modify the 'template-driven-form.component.ts' file as follows. Here we first construct the data for Country drop-down and construct a model with a type of addressModel with their default values. We have also defined one method as onFormSubmit() which will be called when we will submit the form. We are using console.log() for now to print the data in console window of the browser.

import { Component, OnInit } from '@angular/core';
import { addressModel } from 'src/app/data/address.model';

@Component({
  selector: 'app-template-driven-form',
  templateUrl: './template-driven-form.component.html',
  styleUrls: ['./template-driven-form.component.css']
})
export class TemplateDrivenFormComponent implements OnInit {

  countryData: any[] = ['India', 'US', 'UK'];

  model: addressModel = {
    address: '',
    city: '',
    state:'',
    postcode: null,
    country: null,
    aggrement: false
  };

  constructor() { }

  ngOnInit() {
  }

  onFormSubmit() {
    console.log("Full Address", this.model);  
  }
}

Now, its time to understand what are the attributes available from HTML 5 which can be used to validate the forms and these attributes are as follows. 

required: Value is required.
minlength: The minimum characters are required as a value.
maxlength: The maximum characters are required as a value.
pattern: The value should match the pattern.

In Angular, we can validate HTML controls as well as forms. There are different attributes available to validate form's control which return true or false.

untouched: The control is not touched yet.
touched: The control is touched.
pristine: The control's value is not modified or changed yet.
dirty: The control's value is modified or changed.
invalid: The control's value is not valid.
valid: The control's value is valid.


We can validate Form also using the following attributes.

pristine: Not any control's value has modified yet.
dirty: Some or all control's values have modified yet.
invalid: Form is not valid since control value is not valid.
valid: Form is valid.
submitted: The form has submitted.

Now, let change the above template one by one to implement Template Driven Forms along with validation.

First, let modify the form tag as follows, here you can see we are creating the instance of ngForm directive and defining ngSubmit event, which will call onFormSubmit() method once form will be valid. 

<form class="form-horizontal" role="form" #f="ngForm" (ngSubmit)="f.form.valid && onFormSubmit()">

As per the Angular.IO.

 The NgForm directive supplements the form element with additional features. It holds the controls you created for the elements with an ngModel directive and name attribute, and monitors their properties, including their validity. It also has its own valid property which is true only if every contained control is valid.

The #f is the reference variable to the form directive. Using this, we can handle the behavior of the forms.

Now let modify the template for Input control. First, we will use [(ngModel)] to use two-way data binding with model data. After that, we will add CSS class which changes the color of the control on being valid or invalid while submitting the form. Next, add the HTML 5 attribute like required to make value compulsory for that control.  Next is a very important point, here we will add ngModel directive with the name of the control along with the prefix of #.

Here #address="ngModel" exports NgModel into a local variable called name. NgModel mirrors many of the properties of its underlying FormControl instance, so you can use this in the template to check for control states such as valid and dirty. You can also add validation using touched or untouched.

<input type="text" [(ngModel)]="model.address" [ngClass]="{'invalid-data': address.invalid && f.submitted, 'valid-data': address.valid && f.submitted}"
              required name="address" #address="ngModel" placeholder="Enter Address" class="form-control">

<div *ngIf="address.invalid && f.submitted">
   <span style="color: red;">Please Enter Address.</span>
</div

As per the above guidelines which we have implemented with the Input control. We will follow for Dropdown and Checkbox as well respectively. 

<div class="col-sm-10">
  <select class="form-control" name="country" [(ngModel)]="model.country" #country="ngModel" [ngClass]="{'invalid-data': country.invalid && f.submitted, 'valid-data': country.valid && f.submitted}" required>
    <option [ngValue]="null">---Select---</option>
    <option *ngFor="let item of countryData" [value]="item">
      {{item}}
    </option>
  </select>

  <div *ngIf="country.invalid && f.submitted">
    <span style="color: red;">Please Select Country.</span>
  </div>
</div>

Checkbox validation is as follows.

<div class="form-group">
   <div class="col-sm-2 form-check">
     <input type="checkbox" [(ngModel)]="model.aggrement" [ngClass]="{'invalid-data': aggrement.invalid && f.submitted, 'valid-data': aggrement.valid && f.submitted}" required name="aggrement" #aggrement="ngModel" class="form-check-input">
  </div>
  <label class="col-sm-10 form-check-label">I aggree to Terms & Conditions
  </label>
</div>

We can change whole form code as similar to following code to make it Template Driven Forms along with validation implementations. 

<div class="row">
  <div class="col-md-4 col-md-offset-4" style="margin-top: 50px; border: 1px solid rgb(100, 98, 98); padding: 30px;">
    <form class="form-horizontal" role="form" #f="ngForm" (ngSubmit)="f.form.valid && onFormSubmit()">
      <fieldset>
        <legend>Address Details:
          <strong>Template Driven Form</strong>
        </legend>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">Address</label>
          <div class="col-sm-10">
            <input type="text" [(ngModel)]="model.address" [ngClass]="{'invalid-data': address.invalid && f.submitted, 'valid-data': address.valid && f.submitted}"
              required name="address" #address="ngModel" placeholder="Enter Address" class="form-control">

            <div *ngIf="address.invalid && f.submitted">
              <span style="color: red;">Please Enter Address.</span>
            </div>

          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">City</label>
          <div class="col-sm-10">
            <input type="text" [(ngModel)]="model.city" [ngClass]="{'invalid-data': city.invalid && f.submitted, 'valid-data': city.valid && f.submitted}"
              required name="city" #city="ngModel" placeholder="Enter City Name" class="form-control">

            <div *ngIf="city.invalid && f.submitted">
              <span style="color: red;">Please Enter City.</span>
            </div>
          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">State</label>
          <div class="col-sm-4">
            <input type="text" [(ngModel)]="model.state" name="state" placeholder="State" class="form-control">
          </div>

          <label class="col-sm-2 control-label" for="textinput">Postcode</label>
          <div class="col-sm-4">
            <input type="text" [(ngModel)]="model.postcode" [ngClass]="{'invalid-data': postcode.invalid && f.submitted, 'valid-data': postcode.valid && f.submitted}"
              required name="postcode" #postcode="ngModel" placeholder="Enter Post Code" class="form-control">

            <div *ngIf="postcode.invalid && f.submitted">
              <span style="color: red;">Please Enter Valid Post Code.</span>
            </div>
          </div>
        </div>

        <div class="form-group">
          <label class="col-sm-2 control-label" for="textinput">Country</label>
          <div class="col-sm-10">
            <select class="form-control" name="country" [(ngModel)]="model.country" #country="ngModel" [ngClass]="{'invalid-data': country.invalid && f.submitted, 'valid-data': country.valid && f.submitted}"
              required>
              <option [ngValue]="null">---Select---</option>
              <option *ngFor="let item of countryData" [value]="item">
                {{item}}
              </option>
            </select>

            <div *ngIf="country.invalid && f.submitted">
              <span style="color: red;">Please Select Country.</span>
            </div>
          </div>
        </div>

        <div class="form-group">
          <div class="col-sm-2 form-check">
            <input type="checkbox" [(ngModel)]="model.aggrement" [ngClass]="{'invalid-data': aggrement.invalid && f.submitted, 'valid-data': aggrement.valid && f.submitted}"
              required name="aggrement" #aggrement="ngModel" class="form-check-input">
          </div>
          <label class="col-sm-10 form-check-label">I aggree to Terms & Conditions
          </label>
        </div>

        <div class="form-group">
          <div class="col-sm-12" *ngIf="aggrement.invalid && f.submitted">
            <span style="color: red;">Please Aggree with Terms & Conditions.</span>
          </div>
        </div>

        <div class="form-group">
          <div class="col-sm-offset-2 col-sm-10">
            <div class="pull-right">
              <button type="submit" class="btn btn-primary" style="margin: 4px;">Save</button>
              <button type="reset" class="btn btn-default">Reset</button>
            </div>
          </div>
        </div>
      </fieldset>
    </form>
  </div>
</div>

So, we have done to converting a simple form to Template Driven Forms along with validation with each control. Let run the project and see the output. Once we will run the project and click to Save button, all required field's border will be in red color. If we fill the valid value for that control, it will become green. 

Form Validation in Angular

Conclusion

So, today we learned about Template Driven Forms in Angular and how to create it and implement validation with it using TypeScript.

I hope this post will help you. Please put your feedback using comment which helps me to improve myself for next post. If you have any doubts please ask your doubts or query in the comment section and If you like this post, please share it with your friends. Thanks