Mastering Template Driven Forms in Angular"

11 min read
May 24, 2024

1. Introduction to Forms

Forms are essential in web applications as they allow users to enter information. In Angular, you can create forms using two methods: Template Driven Forms and Reactive Forms.

2. Overview of Template Driven Forms

Template Driven Forms use directives within the template to construct and manage the form model. This method is ideal for straightforward forms that have minimal validation needs.

3. Setting up Forms in Angular and Forms Control

Here are the steps to create a Template Driven Form in Angular:

  1. To allow the use of template-driven forms in your Angular module, import the FormsModule.
  2. To define the form, place the ngForm directive within your HTML form tag.
  3. Use different form input directives like ngModel to link form controls with component properties.

4. Understanding ngForm

The ngForm directive is responsible for generating an Angular form instance while offering various form-related features. Additionally, it monitors the form's validation status and manages how submissions are handled.

Here is a sample code illustrating how to set up a basic Template Driven Form in Angular:

<!-- app.component.html -->
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<label for="name">Name:</label>
<input type="text" id="name" name="name" ngModel required>

<label for="email">Email:</label>
<input type="email" id="email" name="email" ngModel required email>

<button type="submit">Submit</button>
</form>
// app.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
onSubmit(form: NgForm) {
// Form submission logic
console.log(form.value);
}
}

In this example:

  • We apply the ngForm directive to set up the form and connect it to the myForm template reference variable.
  • Input fields leverage ngModel to achieve two-way data binding, which allows the form controls to communicate with the component class.
  • When the form is submitted, we execute a method called onSubmit(). This method then logs the values from the form to the console.

Don't forget to import FormsModule into your Angular module if you want to use Template Driven Forms functionality.

5. Retrieving and Pre-setting Form Values

You can retrieve form values by utilizing the value property associated with the form. If you want to set default values for the form, you need to initialize the component properties that are linked to the form controls.

<!-- app.component.html -->
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<label for="name">Name:</label>
<input type="text" id="name" name="name" ngModel required>

<label for="email">Email:</label>
<input type="email" id="email" name="email" ngModel required email>

<button type="submit">Submit</button>
</form>
<button (click)="setDefaultValues()">Set Default Values</button>
// app.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name: string = 'John Doe';
email: string = 'john.doe@example.com';

onSubmit(form: NgForm) {
// Form submission logic
console.log(form.value);
}

setDefaultValues() {
this.name = 'Jane Doe';
this.email = 'jane.doe@example.com';
}
}

6. Understanding Various Form States

Angular forms come with various states like pristine, dirty, touched, and invalid.

  1. Pristine: The form control remains untouched and is still in its original state.
  2. Dirty: The form control value has been changed.
  3. Untouched: The form control hasn't been clicked on or had its focus yet.
  4. Touched: The form control has been blurred or focused.
  5. Valid: The form control value is valid.
  6. Invalid: The form control value is invalid.
  7. Pending: The form control is currently undergoing validation.
  8. Disabled: The form control is disabled.
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
registrationForm: FormGroup;

constructor(private formBuilder: FormBuilder) {
this.registrationForm = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
});
}

get firstName() {
return this.registrationForm.get('firstName');
}

get lastName() {
return this.registrationForm.get('lastName');
}

get email() {
return this.registrationForm.get('email');
}

onSubmit() {
console.log(this.registrationForm.value);
}
}
<form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
<label for="firstName">First Name</label>
<input type="text" id="firstName" formControlName="firstName">
<div *ngIf="firstName.invalid && (firstName.dirty || firstName.touched)">
<small *ngIf="firstName.errors.required">First Name is required.</small>
</div>

<label for="lastName">Last Name</label>
<input type="text" id="lastName" formControlName="lastName">
<div *ngIf="lastName.invalid && (lastName.dirty || lastName.touched)">
<small *ngIf="lastName.errors.required">Last Name is required.</small>
</div>

<label for="email">Email</label>
<input type="email" id="email" formControlName="email">
<div *ngIf="email.invalid && (email.dirty || email.touched)">
<small *ngIf="email.errors.required">Email is required.</small>
<small *ngIf="email.errors.email">Invalid email format.</small>
</div>

<button type="submit" [disabled]="registrationForm.invalid">Submit</button>
</form>

7. Form Validations

Angular offers built-in validators such as required, minLength, maxLength, and pattern. Additionally, you have the option to develop custom validators. You can check for validation errors through properties like form.control.errors.

Form Validation Concepts

  • Validators: Validators are functions that assess a form control, returning null when the control is valid or providing an error object if it is not.
  • Validation Errors: Validation errors are entities that provide details about why the validation process failed, including the nature of the error and any relevant parameters associated with it.
  • Validation Directives: In Angular, you can utilize validation directives within your template to attach validators to form controls and showcase validation errors.
// app.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
onSubmit(form: NgForm) {
// Form submission logic
console.log(form.value);
}
}
<!-- app.component.html -->
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
<label for="name">Name:</label>
<input type="text" id="name" name="name" ngModel required minlength="3">
<div *ngIf="myForm.controls['name'].invalid && (myForm.controls['name'].dirty || myForm.controls['name'].touched)">
<div *ngIf="myForm.controls['name'].errors?.required">Name is required.</div>
<div *ngIf="myForm.controls['name'].errors?.minlength">Name must be at least 3 characters long.</div>
</div>

<label for="email">Email:</label>
<input type="email" id="email" name="email" ngModel required email>
<div *ngIf="myForm.controls['email'].invalid && (myForm.controls['email'].dirty || myForm.controls['email'].touched)">
<div *ngIf="myForm.controls['email'].errors?.required">Email is required.</div>
<div *ngIf="myForm.controls['email'].errors?.email">Please enter a valid email address.</div>
</div>

<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>

In this example:

  • We apply the required validator to make sure the name and email fields are filled out.
  • To make sure the name field contains a minimum of 3 characters, we apply the minlength validator.
  • We employ the email validator to confirm that the email field holds a legitimate email address.
  • We show error messages beside the form controls when they become invalid and have been interacted with or changed.
  • The submit button won't be clickable if there's something wrong with the form.

8. Form Groups and Form Control Class

Form groups enable you to assemble form controls into a single unit. You can create a group by using the FormGroup class, while the FormControl class is utilized to represent each individual form control.

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
userForm = new FormGroup({
name: new FormControl('John Doe'),
email: new FormControl('john.doe@example.com')
});

onSubmit() {
// Form submission logic
console.log(this.userForm.value);
}
}

9. Understanding One Way Data Binding in Angular Forms

One-way data binding in Angular forms signifies that any updates made in the component class will be mirrored in the template. However, modifications in the template won't directly impact the component class. This mechanism is implemented using property binding [()].

<!-- app.component.html -->
<input type="text" id="name" name="name" [ngModel]="name" (ngModelChange)="name = $event">

In this scenario, whenever the input field is altered, the name property in the component class gets updated because of the (ngModelChange) event binding. However, modifications to the name property within the component class don't automatically reflect back in the input field.

Read more in Tech