Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Validation Using Template-Driven Forms in Angular 5

DZone's Guide to

Validation Using Template-Driven Forms in Angular 5

In this post, we are going to see how to perform validation processes using template-driven forms in Angular 5. Get ready to feel validated!

· Web Dev Zone ·
Free Resource

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Introduction

In this post, we are going to see how to perform validation using template-driven forms in Angular 5; this is just a different approach that you can follow, as we have discussed another way in our previous post. At the end of this article, you will get to know how you can implement validations in Angular 5 application using Template-Driven Forms. This post is a continuation of the Developing an Angular 5 App series; if you haven't gone through the previous posts yet, I strongly recommend you to do that. You can find the links to the previous posts below. I hope you will like this article.

Developing an Angular 5 App Series

These are the previous posts in this series. Please go ahead and have a look.

  1. What Is New and How to Set Up our First Angular 5 Application
  2. Angular 5 Basic Demo Project Overview
  3. Generating Your First Components And Modules in Angular 5 App
  4. Implement Validations in Angular 5 App

You can always clone or download the source code here.

Background

Validations have a vital role in all applications, no matter in what language it has been developed. And since it is an essential part, there are many ways to achieve it. We are going to look at the Template-Driven Forms approach here.

Using the Code

It is recommended to clone the project from GitHub so that you can try everything your own. Let's go ahead and write some code now.

Install Bootstrap

Before we begin, let's install bootstrap in our application.

PS F:\My Projects\ng5> npm install bootstrap --save

As we are developing this application using Angular CLI, we can add the reference to Bootstrap in our Angular-CLI.json file. The styles section of that file will look like the below code after you add the reference.

"styles": [
        "styles.css",
        "../node_modules/bootstrap/dist/css/bootstrap.min.css"
      ]

Please note that there are many other ways to configure Bootstrap in our application, but it is beyond the scope of this post to explain them all here.

Importing ngForm to a Variable

Let's clean up the code in our Registration component and add a new form which has a form variable which can hold the values of our form. There are many things you can do with this variable, for now, let's say it is our model values container.

<div class="container">
  <div class="row">
    <div class="no-float center-block col-lg-4 col-sm-4">
      <mat-card>
        <mat-card-header>
          <img mat-card-avatar src="../../../assets/images/App-login-manager-icon.png">
          <mat-card-title>Sign up</mat-card-title>
          <mat-card-subtitle>Trust us for your data, and sign up</mat-card-subtitle>
        </mat-card-header>
        <mat-card-content>
          <form #regsiterForm="ngForm" (ngSubmit)="register(regsiterForm)">
          </form>
        </mat-card-content>
      </mat-card>
    </div>
  </div>
</div>
import { OnInit, Component } from "@angular/core";

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css']
})
export class RegistrationComponent implements OnInit {
  constructor() {
  }

  ngOnInit() {
  }
}

Implement Validation for User Name Field Using Template-Driven Forms

As we have created our form, now it is time to generate out input controls for it.

<form #regsiterForm="ngForm" (ngSubmit)="register(regsiterForm)">
    <div class="signup-fields">
        <div class="form-group">
            <input type="text" required name="userName" class="form-control" placeholder="User Name">
        </div>
        <div>
            <button class="btn btn-primary btn-block" type="submit">Signup</button>
        </div>
    </div>
</form>

What we have above is create a simple HTML doc with a template-driven form, where we are going to introduce the validation. Let's modify the userName field now.

<input type="text" [(ngModel)]="userName" #userName="ngModel" required name="userName" class="form-control" placeholder="User Name">

What we are trying to achieve by the above code is to create a reference variable, userName, and assign the input's value to it. Basically, this is a two-way binding, where we can set the data from our component and update it in the form, and vice versa. Now, if you run your application, you should see an error like the one below.

Uncaught Error: Cannot assign to a reference or variable!
    at _AstToIrVisitor.visitPropertyWrite (compiler.js:26025)
    at PropertyWrite.visit (compiler.js:4585)
    at convertActionBinding (compiler.js:25475)
    at eval (compiler.js:27987)
    at Array.forEach (<anonymous>)
    at ViewBuilder._createElementHandleEventFn (compiler.js:27983)
    at nodes.(anonymous function) (webpack-internal:///./node_modules/@angular/compiler/esm5/compiler.js:27620:27)
    at eval (compiler.js:27928)
    at Array.map (<anonymous>)
    at ViewBuilder._createNodeExpressions (compiler.js:27927)

This is because we are using the same name for both the model and the reference variable. So we should change that. To do so, let's create a User Model (user.model.ts) and reference it in our Register component.

export class User {
    id: any;
    userName: string;
    email: string;
    userRole: string;
    profileImage: string;
    phoneNumber: string;
    firstName: string;
    lastName: string;
}
import { User } from '../models/user.model'

Now we can change our input as shown below.

<input type="text" [(ngModel)]="user.userName" #userName="ngModel" required name="userName" class="form-control" placeholder="User Name">

Please make sure to declare a user in the registration component.

export class RegistrationComponent implements OnInit {
  user = new User();
  constructor() {
  }

  ngOnInit() {
  }
}

Now, if you run your application, you can see that the Submit button will be enabled only if the form is valid, that is, only if you enter any values in the username field.

Decorate the Validation Message

Now we know that our form is working fine, but don't we need to give a message to the users if they haven't given any values in the fields? Let's add few more markups in our HTML.

<div class="form-group" [class.has-error]="userName.invalid" [class.has-success]="userName.valid">
    <input type="text" [(ngModel)]="user.userName" #userName="ngModel" required name="userName" class="form-control" placeholder="User Name">
    <span class="help-block" *ngIf="userName.errors?.required">
                  User Name is required
                </span>
</div>

We are dynamically enabling the classes has-errorand has-success by checking the valid and invalid property of the userName field. We are also showing our required field message in a new span if there are any required errors in our userName model. Now, if you run your app, you can see that the validation is working fine.

But isn't that validation shown by default? We should only show the message if the user touched our field, and refused to type anything, right? Let's add userName.touched to our markup.

<div class="form-group" [class.has-error]="userName.invalid && userName.touched" [class.has-success]="userName.valid">
    <input type="text" [(ngModel)]="user.userName" #userName="ngModel" required name="userName" class="form-control" placeholder="User Name">
    <span class="help-block" *ngIf="userName.errors?.required && userName.touched">
                  User Name is required
                </span>
</div>

Implement Validation for Other Fields as Well

Now it is time to implement validation in the other fields of our app.

<div class="container" style="margin-top:100px;">
  <div class="row justify-content-center align-items-center">
    <div class="col-lg-4 col-sm-4 center-block ">
      <mat-card>
        <mat-card-header>
          <img mat-card-avatar src="../../../assets/images/App-login-manager-icon.png">
          <mat-card-title>Sign up</mat-card-title>
          <mat-card-subtitle>Trust us for your data, and sign up</mat-card-subtitle>
        </mat-card-header>
        <mat-card-content>
          <form #regsiterForm="ngForm" (ngSubmit)="register(user)">
            <div class="signup-fields">
              <div class="form-group" [class.has-error]="userName.invalid && userName.touched" [class.has-success]="userName.valid">
                <input type="text" [(ngModel)]="user.userName" #userName="ngModel" required name="userName" class="form-control" placeholder="User Name">
                <span class="help-block" *ngIf="userName.errors?.required && userName.touched">
                  User Name is required
                </span>
              </div>
              <div class="form-group" [class.has-error]="email.invalid && email.touched" [class.has-success]="email.valid">
                <input type="text" required [email]="user.email !== ''" [(ngModel)]="user.email" name="email" class="form-control" placeholder="Email"
                  #email="ngModel">
                <span class="help-block" *ngIf="email.errors?.required && email.touched">
                  Email is required
                </span>
                <span class="help-block" *ngIf="email.errors?.email && email.touched">
                  Email is invalid
                </span>
              </div>
              <div class="form-group" [class.has-error]="password.invalid && password.touched" [class.has-success]="password.valid">
                <input type="password" [(ngModel)]="user.password" required class="form-control" name="password" placeholder="Password" #password="ngModel">
                <span class="help-block" *ngIf="password.invalid && password.touched">
                  Password is required
                </span>
              </div>
              <div class="form-group" [class.has-error]="confirmPasswordControl.invalid && confirmPasswordControl.touched" [class.has-success]="confirmPasswordControl.valid">
                <input type="password" required class="form-control" name="confirmPassword" placeholder="Confirm Password" [(ngModel)]="confirmPassword"
                  #confirmPasswordControl="ngModel">
                <span class="help-block" *ngIf="confirmPasswordControl.errors?.required && confirmPasswordControl.touched">
                  Confirm password is required
                </span>
              </div>
              <div>
                <button class="btn btn-primary btn-block" type="submit" [disabled]="regsiterForm.invalid">Signup</button>
              </div>
            </div>
          </form>
        </mat-card-content>
      </mat-card>
    </div>
  </div>
</div>

For email validation, we have given an additional attribute and set the condition as [email]="user.email !== ""; this makes it so that the required validation and email validation will not be shown together. This will show the required message if the user touched the field and did not give any values, and the email validation will get fired only if the entered value is not a valid email. Sounds good, right?

Add a Register Function

Finally, let's add our register function.

import { OnInit, Component } from "@angular/core";
import { User } from '../models/user.model';
@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css']
})
export class RegistrationComponent implements OnInit {
  user = new User();
  constructor() {
  }

  ngOnInit() {
  }

  register(user: User): void{
    console.log(user);
  }
}

Once that is done, let's open our browser console and see the data.

Here we have seen how we can implement validation using a template-driven form. I will write my next article about implementing custom validators using directives in Angular so that we can compare our password and confirm the password field.

Conclusion

Thanks a lot for reading. Did I miss anything that you think is needed? Did you find this post useful? I hope you liked this article. Please share your valuable suggestions and feedback with me.

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Topics:
web dev ,angular ,web application development ,validation

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}