Angular Forms : Template Driven

( 1 user )

A form is very basic entity of any web application. It is a group of input controls in a web app where we can ask user to fill up data and submit to the server. Almost every web application has this basic requirement. Every front end frameworks have their own implementations to incorporate a form in a web page and so does Angular.

Forms can be simple to complex. A complex form where the controls have dependencies to other controls in the same form if is really tough to handle. However, Angular with its features like two way data binding and validations makes it so easy to implement even the most complicated forms. Here, we are going to discuss the same that how Angular does this.

In Angular there are 2 ways in which a form can be implemented.

  • Template-driven Forms
  • Reactive Forms

Template driven Forms

The template driven forms, as the name implies, are build using Angular template syntax using form-specific directives. We use model variables directly inside the Angular template. So lets get started with implementation of a small app for booking a ticket for a movie show. The following steps will be our simple form flow:

  • Input User Name
  • Select Cinema Hall
  • Select Movie
  • Select Available Timings
  • Submit the form
  • Get and E-Ticket

FormsModule

Before using forms in our Angular application, we need to import Angular's "FormsModule" module.


import { FormsModule } from '@angular/forms';
...
...
@NgModule({
    imports: [BrowserModule, FormsModule],
    declarations: [App],
    bootstrap: [App]
})
		

Example App

Continuing our earlier discussed app model, we are going to implement the same in Angular using template driven Forms.

Create Movie model

Now, we will create a file model/movie.ts and create a model class named "Movie"


export class Movie {
  constructor(
    public name: string,
    public cinemaHall: string,
    public timing: string) {   
  }
}			
			

Create BookMovie component


Next, create a book movie component

import { Component, OnInit } from '@angular/core';
import { Movie } from '../models/movie';

@Component({
  selector: 'book-movie',
  templateUrl: './bookMovie.component.html'
})
export class BookMovieComponent implements OnInit {
  model: Movie;  
  uName: string;
  movies: string[];
  cinemaHalls: string[];
  movieTimings: string[];
  submitted: boolean = false;
  
  constructor() { }
  
  ngOnInit() {
      this.uName = "";
      this.model = new Movie("Titanic", "Classic Cinemas", "21:30");
      this.movies = ["Titanic", "Ice Age 3", "Jumanji"];
      this.cinemaHalls = ["Classic Cinemas", "NY Studios", "Mega Screens"];
      this.movieTimings = ["10:10", "13:40", "5:25", "21:30"];
  }

  onSubmit() {
    this.submitted = true;
  }
}			
			

In the above code, we have created the following:

  • A Movie object model
  • A UserName object model
  • A collection of movies
  • A Collection of Cinema Halls
  • A Collection of movie timings

Create Template

Here is the code of our template.


<div class="container">
  <div *ngIf="!submitted">
    <h1>Book a movie</h1>
    <form (ngSubmit)="onSubmit()" #bookMovieForm="ngForm">
      <div class="form-group">
        <label for="userName">User Name</label>
        <input type="text" class="form-control" name="userName" #userName="ngModel" [(ngModel)]="uName" required>
        <div class="alert alert-danger" [hidden]="userName.valid">User name is required</div>
      </div>
      <div class="form-group">
        <label for="name">Choose a movie</label>
        <select class="form-control" name="name" #name="ngModel" [(ngModel)]="model.name" required>
          <option *ngFor="let m of movies" [value]="m"></option>
        </select>
      </div>
      <div class="form-group">
        <label for="cinemaHall">Choose cinema hall</label>
        <select class="form-control" name="cinemaHall" #cinemaHall="ngModel" [(ngModel)]="model.cinemaHall" required>
          <option *ngFor="let c of cinemaHalls" [value]="c"></option>
        </select>
      </div>
      <div class="form-group">
        <label for="timing">Movie Timing</label>
        <select class="form-control" name="timing" #timing="ngModel" [(ngModel)]="model.timing" required>
          <option *ngFor="let mt of movieTimings" [value]="mt"></option>
        </select>
      </div>
      <button type="submit" class="btn btn-default" [disabled]="!bookMovieForm.valid">Submit</button>
    </form>
  </div>
  <div *ngIf="submitted">
    <h2>Here is your e-ticket:</h2>
    <div class="row">
      <div class="col-4">User Name : </div>
      <div class="col-8 pull-left"></div>
    </div>
    <div class="row">
      <div class="col-4">Cinema Hall : </div>
      <div class="col-8 pull-left"></div>
    </div>
    <div class="row">
      <div class="col-4">Movie Name : </div>
      <div class="col-8 pull-left"></div>
    </div>
    <div class="row">
      <div class="col-4">Movie Timing : </div>
      <div class="col-8 pull-left"></div>
    </div>
    <br />
    <button class="btn btn-default" (click)="submitted=false">Edit</button>
  </div>
</div>
			

If we see the template, there are two pieces of code. One is when the form is not submitted (*ngIf="!submitted") and the other is when form gets submitted (*ngIf="submitted").

Lets discuss the below line of code.


<form (ngSubmit)="onSubmit()" #bookMovieForm="ngForm">
			

The ngSubmit is and event that invokes the Form's classic Submit action and the #bookMovieForm is a reference to Angular ngForm module.
Note: You don't need to add "ngForm" to the directive list. Angular itself attaches ngForm directive to the form.

Tracking Control state

Along with many other features ngForm provides us with ability to track the control's state. For e.g. Whether the control is valid or not. Along with keeping the track of control's state, it simultaneously update the control's class with Angular's classes that reflect the state.

StateClass if trueClass if false
The control has been visited.ng-touchedng-untouched
The control's value has changed.ng-dirtyng-pristine
The control's value is valid.ng-validng-invalid

Form validation

Since Angular keeps track of the control's state we can use the state information to know if the control's value is valid or not as per validation applied. In the following line of code, we are hiding the validation message if control's "valid" property is true.


<div class="alert alert-danger" [hidden]="userName.valid">User name is required</div>
		

If all control's "valid" property is true, the form's "valid" property also becomes true. Hence in the following code we are disabling the "Submit" button if the form is invalid or if any control is invalid.


<button type="submit" class="btn btn-default" [disabled]="!bookMovieForm.valid">Submit</button>
		

Now, our code is ready to book a movie and get and e-ticket.

Summary

  • Import FormsModule in App module import section.
  • Create a Form component with model variables.
  • Create a Form template binding those model variables.
  • Use control's and form's valid property for validation and displaying error messages.
  • Use bind ngSubmit event to invoke the Form's submit action.

Live Code

You can access the full live source code here - Angular Template Driven forms

To Do

* Note : These actions will be locked once done and hence can not be reverted.

1. Track your progress [Earn 200 points]

2. Provide your ratings to this chapter [Earn 100 points]

0
Life Cycle Hooks
Angular Forms : Reactive
Note : At the end of this chapter, there is a ToDo section where you have to mark this chapter as completed to record your progress.