In this article, we will discuss the concept of Forms in Angular 8. Form objects are always the backbone of any web-based application. Because, we can use forms for many purposes within the application like login, submit a request, ask the user to fill in some information, place an order, etc. So, in this article, we will discuss different aspects of Forms object in Angular Framework.
About Angular Forms
When we want to start developing any web-based application, we always find that a large number of UI or interfaces are very much form dependent. This is very much true for any enterprise-type application also, since most of the interfaces of that application are a large form which contains multiple tabs, dialogs, grid, etc. And also these types of forms always contain non-trivial business validation logic. Since in a component-based framework, we need to split a form into multiple small and reusable pieces of code. These components can be used across the entire application which basically provides many architectural benefits including flexibility and design changes.
Angular 8 deals with the forms of objects through ngModel. The instance two-way data binding technique of ng-model in the Angular framework is really a life-saver, because it provides automatic sync between the form and the view model objects. For using the forms module in Angular, we need to inject the FormModule in our application module.
Types of Angular Forms
As a modern full-fledged UI Framework, Angular has its own full-fledged libraries for developing complex form-based UI. The current Angular framework has two types of form-building strategies as,
- Template Driven Form
- Model Drive Form or Reactive Form
Both the above technology belongs to the @angular/forms packages and are totally based on the form-control classes. But in spite of that, both the techniques are different from each other in respect to their own philosophy, programming style, and technique.
In the below section, we will discuss in detail items related to the above two types of Angular Forms.
Template Driven Forms
In Angular Framework, Template-driven are those forms where we can write logic, validations, controls, etc. in the HTML template part of the component. Basically, the Template is totally responsible for setting the form elements in the UI, for implementing the validation using form control, etc. With the help of Template, we can also provide the Form Group within the HTML template. Template-driven forms are perfect for the simple scenario-based interface where we can easily use the two-way data binding of Angular. For Template-driven form, Angular provides some form-specific directives which we can use to bind the form input data without model variable. Due to this form-specific directive, we can add extra functionality and behavior to a plain HTML form. In the end, the Template itself takes care of binding the values with the model and the form validation.
Benefits of Template Driven Forms
In Angular Framework, we can obtain some benefit for using Template-Driven form as below,
- It is much easier to use
- This technique works perfectly in simple scenarios
- It totally depends on two-way data binding techniques i.e. ngModel syntax.
- It requires a minimum of code in the component part since most of the work is done in the HTML template part.
- It automatically tracks the form element and its control.
- Despite the above benefits, it has some drawbacks like –
- Template-driven form techniques fail when we want to design some complex form in the UI section
- We can’t perform any Unit Testing based on the Template Driven Form.
Model-Driven Forms
Model-Driven form technique is often called a Reactive Form technique in Angular. It provides a model-driven approach to the UI to handling form inputs towards the component variable. Using this technique, we can create and update a simple form of control, progress to using multiple controls within a form group to validate the form control values, etc.
Model-driven or Reactive forms normally use an explicit and immutable approach to manage the state of a form control at any given point of time. If any change occurrs in the form control, then it will return a new state through which Angular can maintain the integrity of the model variables between changes. Basically, reactive forms are normally based on observable streams. So, every form's input controls and values provide the input value as a stream which is accessed by the reactive form synchronously. With the help of reactive forms, we can perform a straightforward process to perform unit testing on the form controls. This can be done very easily since we can be assured that form data is consistent and predictable whenever requested.
Reactive forms or Model-driven forms are different compared to template-driven forms. Reactive forms always provide more predictability with synchronous access towards the data model variable, provide immutability with observables operators and also keep track of changes using observable streams.
Benefits of Model-Driven Forms
In Angular Framework, we can obtain some benefit for using Model-Driven form or Reactive Form techniques as below,
- In Reactive Forms, form definition including logic related coding mainly maintained within the TypeScript part of the component. Since using this technique, we create form controls programmatically using FormGroup or FormBuilder class. In HTML template, HTML form tags are only used to put a reference of TypeScript based form-control class.
- It provides us programmatic and full control of the form value updates and form validations.
- In this technique, we can create a dynamic structure-based form at run time.
- We can implement custom form validation.
- Since the entire form-based part is in typescript class or component, it is much easier to write unit tests in reactive forms.
- Despite the above benefits, it has some drawback like –
- This technique requires much more coding, especially in the TypeScript part.
- It is a little bit complex to understand and maintain the code.
Template-Driven Form vs Reactive Form
The comparison between Template-Driven Form and Reactive Forms (Model-Driven Forms) are as below,
Template-Driven Form | Reactive Form |
Template-Driven Form is less explicit, and it is mainly created by Directives. | Reactive Form is more explicit and normally created within the Component class. |
It supports the unstructured data model | It always supports the structured data model. |
It uses directives for implementing Form validations | It uses the function for implementing Form Validations |
When form control value changes, it provides an asynchronous mechanism to update form controls. | When form control value changes, it provides synchronous mechanism to update form controls. |
Form Controls
FormControl class is mainly used to assign any form related fields in the Angular component. This class is also used in the FormBuilder class method. It is used mainly for ease of access. With the help of references of the FormControl in place of FormControl class, we can gain access to the inputs in the template without using the Form itself. Similarly, we can use any instance of FormControl to access its parent group by using its root property. When we define a form of control, it requires two properties: an initial value and a list of validators.
Reactive Form Validation
Angular Framework provides many validators to validate the form control input values in any application. These validations can be imported along with the related dependencies for procedural forms. In general, the common practice for using Form validations are using .valid and .untouched to determine if we need to raise an error message. As an inbuilt validator, we can use hasError() method on the form element to validate the data.
Reactive Form Custom Validation
As per the built-in validators, it is very useful if we can create our own custom validator for our purpose. Angular Framework always allows us to do just that, with minimal effort. A simple function takes the FormControl instance and returns null if everything is fine. If the test fails, it returns an object with an arbitrarily named property. In this case, we need to use the property name .hasError() for the test.
- <div [hidden]="!password.hasError('hasSpecialChars')">
- Your password must have Special Characters like @,#,$, etc!
- </div>
Demo 1 - Template Driven Form
Now, in this demo, we will demonstrate how to define a template-driven form in Angular.
app.component.ts - import { Component, OnInit } from '@angular/core';
- import { NgForm } from '@angular/forms';
-
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls : ['./custom.css']
- })
- export class AppComponent implements OnInit {
- private formData: any = {};
- private showMessage: boolean = false;
-
- constructor() {
- }
-
- ngOnInit(): void {
- }
-
- registerUser(formdata: NgForm) {
- this.formData = formdata.value;
- this.showMessage = true;
- }
- }
app.component.html
- <h2>Template Driven Form</h2>
- <div>
- <form #signupForm="ngForm" (ngSubmit)="registerUser(signupForm)">
- <table style="width:60%;" cellpadding="5" cellspacing="5">
- <tr>
- <td style="width :40%;">
- <label for="username">User Name</label>
- </td>
- <td style="width :60%;">
- <input type="text" name="username" id="username" [(ngModel)]="username" required>
- </td>
- </tr>
- <tr>
- <td style="width :40%;">
- <label for="email">Email</label>
- </td>
- <td style="width :60%;">
- <input type="text" name="email" id="email" [(ngModel)]="email" required>
- </td>
- </tr>
- <tr>
- <td style="width :40%;">
- <label for="password">Password</label>
- </td>
- <td style="width :60%;">
- <input type="password" name="password" id="password" [(ngModel)]="password" required>
- </td>
- </tr>
- <tr>
- <td style="width :40%;"></td>
- <td style="width :60%;">
- <button type="submit">Sign Up</button>
- </td>
- </tr>
- </table>
- </form>
- <div *ngIf="showMessage">
- <h3>Thanks You {{formData.username}} for registration</h3>
- </div>
- </div>
Now check the output in the browser,
Demo 2 - Model-Driven Form
Now in this demo, we will discuss how to develop a Reactive Form in Angular 8 Framework. For that, we first need to develop a login form component as below –
app.component.ts - import { Component, OnInit, ViewChild } from '@angular/core';
- import { Validators, FormBuilder, FormControl, FormGroup } from '@angular/forms';
-
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls : ['./custom.css']
- })
- export class AppComponent implements OnInit {
- private formData: any = {};
-
- username = new FormControl('', [
- Validators.required,
- Validators.minLength(5)
- ]);
-
- password = new FormControl('', [
- Validators.required,
- hasExclamationMark
- ]);
-
- loginForm: FormGroup = this.builder.group({
- username: this.username,
- password: this.password
- });
-
- private showMessage: boolean = false;
-
- constructor(private builder: FormBuilder) {
- }
-
- ngOnInit(): void {
- }
-
- registerUser() {
- this.formData = this.loginForm.value;
- this.showMessage = true;
- }
- }
-
- function hasExclamationMark(input: FormControl) {
- const hasExclamation = input.value.indexOf('!') >= 0;
- return hasExclamation ? null : { needsExclamation: true };
- }
app.component.html
- <h2>Reactive Form Module</h2>
- <div>
- <form [formGroup]="loginForm" (ngSubmit)="registerUser()">
- <table style="width:60%;" cellpadding="5" cellspacing="5">
- <tr>
- <td style="width :40%;">
- <label for="username">User Name</label>
- </td>
- <td style="width :60%;">
- <input type="text" name="username" id="username" [formControl]="username">
- <div [hidden]="username.valid || username.untouched" class="error">
- <div [hidden]="!username.hasError('minlength')">
- Username can not be shorter than 5 characters.
- </div>
- <div [hidden]="!username.hasError('required')">
- Username is required.
- </div>
- </div>
- </td>
- </tr>
- <tr>
- <td style="width :40%;">
- <label for="password">Password</label>
- </td>
- <td style="width :60%;">
- <input type="password" name="password" id="password" [formControl]="password">
- <div [hidden]="password.valid || password.untouched" class="error">
- <div [hidden]="!password.hasError('required')">
- The password is required.
- </div>
- <div [hidden]="!password.hasError('needsExclamation')">
- Your password must have an exclamation mark!
- </div>
- </div>
- </td>
- </tr>
- <tr>
- <td style="width :40%;"></td>
- <td style="width :60%;">
- <button type="submit" [disabled]="!loginForm.valid">Log In</button>
- </td>
- </tr>
- </table>
- </form>
- <div *ngIf="showMessage">
- <h3>Thanks You {{formData.username}} for registration</h3>
- </div>
- </div>
Now, for using the reactive form we need to inject ReactiveFormModule in our app.module.ts file as below –
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
- import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-
- import { AppComponent } from './app.component';
-
- @NgModule({
- declarations: [
- AppComponent
- ],
- imports: [
- BrowserModule, FormsModule, ReactiveFormsModule
- ],
- providers: [],
- bootstrap: [AppComponent],
- schemas: [NO_ERRORS_SCHEMA]
- })
- export class AppModule { }
Now check the output in the browser,
Conclusion
In this article, we discussed another important feature of Angular Framework i.e. Angular Form. Also, we discussed the Template Driven Forms and Reactive Forms (Model-Driven Form). Now, in the next article, we will discuss the concept of Service in Angular.