Forms are the main building blocks of any application. When we use forms for login, registration, submission, help request, etc., it is necessary that whatever form we are developing, they must be user-friendly. And, it should have the indication of what went wrong etc.
Coming to the Angular Forms, Angular provides 2 approaches for developing forms - Template Driven and Reactive forms. Let’s try to explore the template-driven approach in this article.
Template Driven Forms
Template driven forms are simple forms which can be used to develop forms. These are called template-driven as everything that we are going to use in a application is defined into the template that we are defining along with the component. Let’s see step by step how we can develop and use these forms in the application.
Prerequisite
We need to import FormsModule in an Application module file (i.e.app. module.ts).
@angular/Forms
The code snippet for that can be like this.
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule } from '@angular/core';
- import {FormsModule} from '@angular/forms'
- import { AppComponent } from './app.component';
- @NgModule({
- declarations: [
- AppComponent,
-
- ],
- imports: [
- BrowserModule,
- FormsModule
- ],
- providers: [],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
Alright! This is the basic import that we need to do before we are ready to use these forms in our application so as to pass data from HTML to the component.
Let's have the code snippet of the form which we will be using here.
- <div class="container">
- <div class="row">
- <div class="form_bg">
- <form #regForm='ngForm' (ngSubmit)="Register(regForm)" >
- <h2 class="text-center">Registration page</h2>
- <br/>
- <div class="form-group">
- <input type="text" class="form-control" placeholder="First Name" name="firstname" ngModel >
- </div>
- <div class="form-group">
- <input type="text" class="form-control" placeholder="Last Name" name="lastname" ngModel >
- </div>
- <div class="form-group">
- <input type="email" class="form-control" id="email" placeholder="Email" name="email" ngModel>
-
- </div>
- <div class="form-group">
- </div>
- <br/>
- <div class="align-center">
- <button type="submit" class="btn btn-default" id="register" >Register</button>
- </div>
- </form>
- </div>
- </div>
- </div>
Above code has some elements - first name, last name, email, and a submit button. Now that our form is ready, we need to pass these value to component.
First step in using the forms is understanding the ngForm and the ngModel directives that we used above.
NgForm
It is the directive which helps to create the control groups inside form directive. It is attached to the <form> element in HTML and supplements form tag with some additional features. Some interesting things we can say about View are that whenever we use the directive in the application view, we need to assign some selector with it and the form is the said selector in our case. The next thing that we need to consider is the ngModel attribute that we have assigned to each HTML control. Let’s see what this attribute does.
NgModel
When we add NgModel Directive to the control, all the inputs are registered in the NgForm.
It creates the instance of the FormControl class from Domain model and assigns it to the form control element. This control keeps track of the user information and the state and validation status of the form control.
Next important thing to consider is that when we use NgModel with the form tag or most importantly, with the NgForm, we make use of the name property of HTML control. When we look at the above snippet, every control is assigned a name property and we have added the ngModel attribute to the control.
e.g.
<input type="email" class="form-control" id="email" placeholder="Email" name="email" ngModel>
Two main functionalities offered by NgForm and NgModel are the permission to retrieving all the values of the control associated with the form and then retrieving the overall state of controls in the form.
To expose ngForm in the application, we have used the following code snippet.
- <form #regForm='ngForm' (ngSubmit)="Register(regForm)" >
In this, we are exporting the ngForm value in the local variable “regform”. Now, the question arises, whether or not we need to use this local variable. Well, the answer is no. We are exporting ngForm in the local variable just to use some of the properties of the form and these properties are -
- regForm.Value: It gives the object containing all the values of the field in the form.
- regForm.Valid: This gives us the value indicating if the form is valid or not if it is valid value is true else value is false.
- regForm.touched: It returns true or false when one of the field in the form is entered and touched.
- regForm.submitted: It checks whether the form is submitted or not. It returns true and false value.
In the above case, we have noticed that the Form Tag has no action method or attribute specified there, so how so we post the data in the component?
Let’s have a look at the (ngSubmit)=”Register(regForm)”. Here, we are using the Event Binding concept and we are binding which will call the Register method in the component. Instead of the submit event of the form, we are using ngSubmit which will send the actual HTTP request instead of just submitting the form.
Now, when we look at the component, we can see that.
- import { Component, OnInit } from '@angular/core';
- import { NgForm } from '@angular/forms';
- @Component({
- selector: 'app-formdemobasics',
- templateUrl: './formdemobasics.component.html',
- styleUrls: ['./formdemobasics.component.css']
- })
- export class FormdemobasicsComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit() {
- }
-
- Register(regForm:NgForm){
- console.log(regForm);
-
- }
- }
Here, we have the Register method in the component. It accepts the ngForm object and it has all the values from the template to display in the console.
Note
In combination with the name attribute, ngModel creates the abstraction over the form state and it automatically shows up in the forms value collection (i.e.form.value).
Validations
Validation is an important aspect of programming. We cannot trust the user that’s why we always want to validate the data. So, to prevent the user from entering wrong data and show some proper value, we check and ask the users to add the proper data.
How do we validate the template driven forms then?
The answer is - by using the Angular set of common validators like minlength,maxlength, required, email. We just need to add the validator directive to the control for assigning the controls the validators.
Let's see the template of the new sign up form that we have added. The code snippet for the same is as follows.
- <div class="container">
- <div class="row">
- <div class="form_bg">
- <form #form="ngForm" (ngSubmit)="registerUser(form)">
- <h2 class="text-center">Registration page</h2>
- <br/>
- <div class="form-group">
- <input type="text" class="form-control" placeholder="First Name" name="firstname" required ngModel>
- </div>
- <div class="form-group">
- <input type="text" class="form-control" placeholder="Last Name" name="lastname" required ngModel>
- </div>
- <div class="form-group">
- <input type="email" class="form-control" id="email" placeholder="Email" name="email" email required ngModel #email="ngModel">
- <span class="help-bpx" *ngIf="email.touched && !email.valid ">Please enter the Email Value</span>
- </div>
- <div class="form-group">
- </div>
- <br/>
- <div class="align-center">
- <button type="submit" class="btn btn-default" id="register" [disabled]="!form.valid" >Register</button>
- </div>
- </form>
- </div>
- </div>
- </div>
Let's see the sample for the basic validation required for the user name.
- <input type="text" class="form-control" placeholder="First Name" name="firstname" required ngModel>
What we need here is that we need to show the Red Border whenever the first name is not entered in the control. Here, we can make use of the Angular CSS classes to achieve that, that will be applied and removed whenever the state of the form changes. The following are the classes which will be attached whenever the state is changed.
- ng-touched: Controls have been visited
- ng-untouched: controls have not been visited
- ng-dirty : control value has been changed
- ng-pristine:Controls value have not been changed
- ng-valid : control values are valid
- ng-invalid : control values are invalid
So, in order to draw a border around the first name whenever a user visits the control and does not add any value, we need to use these classes.
Here is how -
- input.ng-invalid.ng-touched
- {
- border-color: red;
- }
This is just the CSS logic that is adding the red border around the control and displaying it in the UI. Now, suppose, we have a requirement to show the validation message for the particular control state. Let's see another example for understanding this. Consider the email field.
We need to show the Required as well as to check if the email entered is valid or not. The following code snippet does that for us.
- <input type="email" class="form-control" id="email" placeholder="Email" name="email" email required ngModel #email="ngModel">
- <span class="help-bpx" *ngIf="email.touched && !email.valid ">Please enter the Email Value</span>
Here, we have used the template reference variable and assigned the ngModel (i.e. state of the control) to that variable. Here, we have a span element which is displayed only when the email is entered but the email is not valid. For that, we have used ngIf in the span element. It is structural directive which will be displayed only if the email entered is invalid.
References
- Angular official website (https:\\angular.io)
- https:\\rangle.io\