Template Driven Form in Angular

Template Driven Form in Angular

Template Driven Form in Angular

In this article, I will guide you about template form. when to use template driven form.

In Real life example, when you visit hospital a paper present to you and requested to write basic info about your self. as well as in school admission form also an example. These information uploaded to software. so form is basically a paper that collect information. In technical prospective, angular provide us template driven form to collect information about the things.


Note: If your are using form in angular must import FormModule in AppModule.


Template Driven Forms

  • Easy to use
  • Suitable for simple scenarios.
  • Not recommend for complex scenarios.
  • Syntax similar to older version of AngularJS
  • Syntax used for template driven form Two way data binding( [(NgModel)]).
  • Minimal component code
  • Automatic track of the form and its data(handled by Angular)
  • Unit testing is another challenge
  • Templates are validated via directives
  • Unit testing is a problem for template driven forms is because they are value changes and validity checks are asynchronous.
  • Data model is un-structured
  • predictability in template form is Asynchronous
  • Form validation, as we add more and more validator tags to a field or when we start adding complex cross-field validations the readability of the form decreases


When to use Template Driven Forms:

When your app have basic and simple requirement for forms such as sign in, you should use template-driven forms.

Example Template Driven Form

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';        //import FormsModule
 
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
 
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule                    //Add in Imports Array
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
<form #SingUpForm="ngForm">

//we create a variable in template.In angular it is called template reference
//variable

What is ngForm?

The ngForm does the following:


  • Binds itself to the <Form> directive
  • Creates a top-level FormGroup instance
  • CreatesFormControl instance for each of child control, which has ngModel directive.
  • CreatesFormGroup instance for each of the NgModelGroup directive.


FormControl instance in template driven

They are firstName, lastname, and other fields. We need to bind them to formControl instance. We do this by using the ngModel directive.

<input type="text" name="firstname" ngModel>
<form #singUpForm="ngForm" (ngSubmit)="onSubmit(singUpForm)">
 
  <p>
    <label for="firstname">First Name</label>
    <input type="text" name="firstname" ngModel>
  </p>
 
  <p>
    <label for="lastname">Last Name</label>
    <input type="text" name="lastname" ngModel>
  </p>
 
  <p>
    <label for="email">Email </label>
    <input type="text" id="email" name="email" ngModel>
  </p>
 
  <p>
    <label for="gender">Geneder</label>
    <input type="radio" value="male" name="gender" ngModel> Male
    <input type="radio" value="female" name="gender" ngModel> Female
  </p>
 
  <p>
    <label for="isMarried">Married</label>
    <input type="checkbox" name="isMarried" ngModel>
  </p>
 
  <select name="country" ngModel>
    <option [ngValue]="c.id" *ngFor="let c of countryList">
      {{c.name}}
    </option>
  </select>
 
  <p>
    <button type="submit">Submit</button>
  </p>
  
</form>
import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Template driven forms';
 
  countryList:country[] = [
    new country("1", "Pakistan"),
    new country('2', 'UAE'),
    new country('3', 'USA')
  ];
}
 
export class country {
  id:string;
  name:string;
 
  constructor(id:string, name:string) {
    this.id=id;
    this.name=name;
  }

 onSubmit(contactForm) {
    console.log(contactForm.value);
  }
}

Built-in Validators

The Built-in validators use the HTML5 validation attributes like required, minlength, maxlength & pattern. Angular interprets these validation attributes and add the validator functions to FormControl instance.


Required Validation

The required validator returns true only if the form control has non-empty value entered.


Minlength Validation

This Validator requires the control value must not have less number of characters than the value specified in the validator.

For Example, minlength validator ensures that the user name value has at least 20 characters.

<input type="text" id="userName" name="userName" required minlength="20">

Maxlength Validation

This Validator requires that the number of characters must not exceed the value of the attribute.

For Example, maxlength validator ensures that the user name value has maximum value up to 20 characters.

<input type="text" id="userName" name="userName" required maxlength="20">

Pattern Validation

This Validator requires that the control value must match the regex pattern provided in the attribute. For example, the pattern ^[a-zA-Z]+$ ensures that the only letters are allowed (even spaces are not allowed). Let us apply this pattern to the username.

<input type="text" id="userName" name="username" pattern="^[a-zA-Z]+$">

Email Validation

This Validator requires that the control value must be a valid email address.


<input type="text" id="email" name="email" required email>

Validation Styling

Similar to model-driven forms we can access each model form controls state by going through the top-level form group.

The ngForm directive makes the top-level FormGroup available to us via its form property, so we can show the valid, dirty or touched state of our email field like so:

<pre>Valid? {{f.form.controls.email?.valid}}</pre>
<pre>Dirty? {{f.form.controls.email?.dirty}}</pre>
<pre>Touched? {{f.form.controls.email?.touched}}</pre>

Elvis operator

The ? is called the Elvis operator. only try to call the property on the right of ? if the property on the left of ? is not null. In template-driven forms the controls can sometimes be null when Angular is building the page, so to be safe we use the Elvis operator.

<pre>Valid? {{f.form.controls.email?.valid}}</pre>

Resetting the Form

<form (ngSubmit)="onSubmit()" #myForm="ngForm">
  @ViewChild('myForm') form: any;

   onSubmit() {
    if (this.form.valid) {
      console.log("Form Submitted!");
      this.form.reset();
    }
  }

NgModelGroup Directive

The ngModelGroup directive allows you to group together related inputs so that you structure the object represented by the form in a useful and predictable way. ngModelGroup is often used in combination with fieldset as they mostly represent the same idea of “grouping together inputs.”

import {Component, ViewChild} from "@angular/core";
@Component({
    selector: 'app',
    template: `
<form 
    #formRef="ngForm" 
    (ngSubmit)="onSubmit(formRef.value)"
    >
    <fieldset ngModelGroup="login">
        <input 
            #usernameRef="ngModel"
            name="username"
            [(ngModel)]="username"
            type="text"        
            required
            minlength="3"
        >    
        <div *ngIf="usernameRef.errors?.required">This field is required</div>
        <div *ngIf="usernameRef.errors?.minlength">This field must be longer than {{usernameRef.errors?.minlength.requiredLength}} characters. You only typed {{usernameRef.errors?.minlength.actualLength}}</div>
        
        <input type="password" ngModel name="password">
    </fieldset>
    <button type="submit">Submit</button>
</form> 
{{formRef.value | json}}   
{{formRef.valid | json}}   
   
`
})
export class AppComponent {
    username = "Zeeshan";

    onSubmit(formValue){
        console.log(formValue);
    }
}

Output

{ "login": { "username": "Zeeshan", "password": "" } } true
import {Component, ViewChild} from "@angular/core";
@Component({
    selector: 'app',
    template: `
<form 
    #formRef="ngForm" 
    (ngSubmit)="onSubmit(formRef.value)"
    >
    <fieldset ngModelGroup="login">
        <input 
            #usernameRef="ngModel"
            name="username"
            [(ngModel)]="username"
            type="text"        
            required
            minlength="3"
        >    
        <div *ngIf="usernameRef.errors?.required">This field is required</div>
        <div *ngIf="usernameRef.errors?.minlength">This field must be longer than {{usernameRef.errors?.minlength.requiredLength}} characters. You only typed {{usernameRef.errors?.minlength.actualLength}}</div>
        
        <input type="password" ngModel name="password">
    </fieldset>
     <fieldset ngModelGroup="signUp">
        <input 
            #usernameRef="ngModel"
            name="username"
            [(ngModel)]="username"
            type="text"        
            required
            minlength="3"
        >    
        <div *ngIf="usernameRef.errors?.required">This field is required</div>
        <div *ngIf="usernameRef.errors?.minlength">This field must be longer than {{usernameRef.errors?.minlength.requiredLength}} characters. You only typed {{usernameRef.errors?.minlength.actualLength}}</div>
        
        <input type="password" ngModel name="password">
    </fieldset>
    
    <button type="submit">Submit</button>
</form> 
{{formRef.value | json}}   
{{formRef.valid | json}}   
   
`
})
export class AppComponent {
    username = "Zeeshan";

    onSubmit(formValue){
        console.log(formValue);
    }
}

Output

{ "login": { "username": "Zeeshan", "password": "" }, 
  "signUp": { "username": "Zeeshan", "password": "" } } true

Displaying the Validation/Error messages

Angular creates a FormControl for each and every field, which has ngModel directive applied. The FormControl exposes the state of form element like valid, dirty, touched, etc.

There are two ways in which you can get the reference to the FormControl.

  • One way is to use the contactForm variable. We can use the myForm.controls.firstname.valid to find out if the firstname is valid.
  • The other way is to create a new local variable for each FormControl For Example, the following firstname=”ngModel” creates the firstname variable with the FormControl instance.
<input type="text" id="firstname" name="firstname" required minlength="10" 
            #firstname="ngModel">

Now, we have a reference to the firstname FormControl instance, we can check its status. We use the valid property to check if the firstname has any errors.

 
<div *ngIf="!firstname?.valid && (firstname?.dirty || firstname?.touched)">
   Invalid First Name
</div>

Share Article:
  • Facebook
  • Instagram
  • LinkedIn
  • Twitter
  • Recent Posts