Angular 2 Form Validation

Learn the ins and outs of form validation with Angular 2.

Free Course

Getting Started with Angular 2

Angular 2 is the shiny new framework that comes with a lot of new concepts. Learn all the great new features.

Angular 2.0 final was made official just a few days ago and there’s never been a better time to dive in. In the last few weeks, we saw some pretty radical changes to the framework with:

In this tutorial we are going to look at what’s changed with forms and more importantly how to handle form validation the right way with Angular 2.

Forms bring life to our applications. It’s how we capture user input and make our applications useful. For a long time, forms have been difficult to get right. Angular 1.x made it a little easier, but came with its own set of issues and challenges, and some features like sane validation didn’t come until the framework was well into it’s 5th year.

Angular 2.x aims to make the creation and validation of forms simple, intuitive, and manageable. Pretty ambitious goals, but with the breadth of knowledge the team has from building Angular 1.x, I think Angular 2 forms can live up to these expectations. Before we dive into writing code, let’s learn a bit about Angular 2 Forms.

Angular 2 Forms - What’s New, What’s Changed

Angular 2.x forms can be written in two ways.

Template Driven Forms

Template driven forms, as the name suggests, are forms built entirely in your UI. This is the typical way we built forms in the past and is useful for building very simple forms in Angular 2.

Model Driven (Reactive) Forms

Model driven or reactive forms, while similar to template driven forms, add an additional layer of complexity and functionality by having you to declare the model of the form in your component class.

This additional functionality allows for greater control over your forms as well as making it easier to unit test your application. We’ll take a look at some of these features in this tutorial.

Setting Up Our Application

We will write multiple different forms in this tutorial, with varying levels of complexity. To get started let’s setup our application. If you would like to just follow along, you can get all the code we are going to write from this Github repo.

We will setup our application with the Angular CLI. If you don’t already have the CLI installed, run

npm install -g angular-cli

Make sure you have the latest version of the CLI, which at the time of this post is beta-15.

With the CLI installed, create a new directory called ng2forms and in this directory run:

ng init

The ng init command will bootstrap our application, download all the external dependencies we’ll need, configure webpack, and basically do all of the setup work for us. Once the ng init has completed the setup process, navigate to localhost:4200 and you will see a message saying “app works!”.

Simple Form

Next, let’s scaffold out the different forms we’ll be writing. We’ll start off by writing a very simple form to familiarize ourselves with the syntax. In your src/app directory, create a new component called app.simpleform.ts. In this file, we’ll scaffold out the most basic component:

// We’ll import our dependencies
import { Component } from '@angular/core';

@Component({
  selector: 'simple-form',
  // We’ll inline the template of our form
  template : `
    <h1>Simple Form</h1>
  `
})
export class SimpleFormComponent {
}

Model-Driven (Reactive) Form

For our next component, we will build a reactive or model driven form. Create a new component titled app.complexform.ts. We’ll just scaffold it out for now with:

import { Component } from '@angular/core';

@Component({
  selector: 'complex-form',
  // For this form, we’ll write our UI in a separate file
  templateUrl : './app.complexform.html'
})
export class ComplexFormComponent {
}

This form uses an external template for the UI, so we’ll also need to create an app.complexform.html file. Go ahead and create this file. Inside this file, just add a placeholder message for now.

Validated Form

Finally, for our third form, we’ll do some fun stuff with validation. It’s only fitting to call this component app.formvalidations.ts, so do that, and again we’ll just scaffold the component with:

import { Component } from '@angular/core';

@Component({
  selector: 'form-validation',
  template : `
    <h1>Form Validation</h1>
  `
})
export class FormValidationComponent {
}

Including Our Forms in the App

Now that we have our components in place, let’s include them in our root @NgModule so that we can use them in our application. Open the app.module.ts file and make the following edits.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// By default, the app generated by ng init will include the FormsModule, here we’re requiring the ReactiveFormsModule as well
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
// Include the three components we created
import { SimpleFormComponent } from './app.simpleform';
import { ComplexFormComponent } from './app.complexform';
import { FormValidationComponent } from './app.formvalidation';

@NgModule({
  declarations: [
    AppComponent,
    // Declare the three components as part of the root NgModule
    SimpleFormComponent,
    ComplexFormComponent,
    FormValidationComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    // Including the ReactiveFormsModule in our application
    ReactiveFormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Finally, let’s go ahead and open the app.component.html file. This is our root component view and since we’ve declared our form components in the root module, we can use these components here without having to import them in the app.component.ts file. Let’s open up the file and include our three form components.

<div class="container">
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <simple-form></simple-form>
    </div>
  </div>
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <complex-form></complex-form>
    </div>
  </div>
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <form-validation></form-validation>
    </div>
  </div>
</div>

You’ve probably noticed the Bootstrap classes, so to conclude our setup let’s just include the Bootstrap 3 library in our application. In your index.html file simply include the following in the <head> of the document:

  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

Our setup is complete. Navigate to localhost:4200 and you should see the three components displayed. For now you’re only going to see the scaffolded message you added. Now we’re ready for the fun to begin.

Simple Form

We are ready to write our first Angular 2 form. If you’ve done any development with Angular 2 prior to RC5, you may remember how tedious it was to deal with all of the imports. Luckily, the NgModule we worked with earlier has, for the most part, taken care of this. In the imports key, we imported the FormsModule which gave us access to the majority of the forms APIs so we can just dive in and write our code.

For our simple form, we are going to create a components that captures the users first and last name, their gender, and finally a list of activities they would like to do. This data will be for an upcoming company trip and will help the event organizers plan the right activities.

Let’s go ahead and build our simple form. We’ll explain everything line by line. Open the app.simpleform.ts file and add the following:

import { Component } from '@angular/core';

@Component({
  selector: 'simple-form',
  template : `
  <div class="jumbotron">
    <h2>Template Driven Form</h2>
     <!-- Here we are declaring a local variable called “form” and setting it to an instance of ngForm. This is very important. Now our local form variable becomes of type FormGroup allowing us access to the FormGroup API’s on this local variable. We use this in the ngSubmit event where we send the value of the form via form.value -->
    <form #form="ngForm" (ngSubmit)="submitForm(form.value)">
      <div class="form-group">
        <label>First Name:</label>
        <!-- Since we are working with template driven forms, we can use the ngModel directive to capture the values of our forms. One thing to note if you are coming from Angular 1.x. Using ngModel as shown below creates a one-way data binding, so once we hit submit the data is only sent to the controller. If we wanted to use two-way data binding, we would have to wrap the ngModel in [()] and assign an attribute to it. Also the name of the field corresponds to the name attribute so our first input will be firstName. -->
        <input type="text" class="form-control" placeholder="John" name="firstName" ngModel required>
      </div>
      <div class="form-group">
        <label>Last Name</label>
        <input type="text" class="form-control" placeholder="Doe" name="lastName" ngModel required>
      </div>
      <div class="form-group">
        <label>Gender</label>
      </div>
      <!-- Radio and checkboxes work much the same way -->
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" ngModel>
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Female" ngModel>
          Female
        </label>
      </div>
      <div class="form-group">
        <label>Activities</label>
      </div>
      <label class="checkbox-inline">
        <input type="checkbox" value="hiking" name="hiking" ngModel> Hiking
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="swimming" name="swimming" ngModel> Swimming
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="running" name="running" ngModel> Running
      </label>
      <div class="form-group">
        <button type="submit" class="btn btn-default">Submit</button>
      </div>
    </form>
  </div>
  `
})
export class SimpleFormComponent {
  // Here we are implementing the submitForm function. All we are doing for right now is spitting out the details of the form to our console.
  submitForm(form: any): void{
    console.log('Form Data: ');
    console.log(form);
  }
}

Angular 2 Template Driven Form

We’ve just written our first Angular 2 form. Head over to localhost:4200 to see the results. If all went well, you should be able to fill out the fields and hit the submit field. Notice that we set a required flag on the first name and last name attributes. You will need to enter values here to be able to submit the form. Pretty easy right? If you are writing simple Angular 2 forms, this approach may be suitable. For advanced functionality though, you will want to leverage Angular 2’s reactive forms. Let’s take a look at how those work next.

Model Driven (Reactive) Forms

Reactive forms in Angular 2 allow for much greater control over form inputs, errors, and validations. With reactive forms, we can define our form model programmatically and ensure that inputs adhere to the constraints we place on the form. Reactive forms let us dynamically create a form inside our Angular class. The best way to explain how this works, is to write some code, so let’s do that.

We will recreate the form we made with the template driven approach, but this time we’ll make use of Angular 2’s reactive forms. Let’s first open up the app.complexform.ts file and add the following:

import { Component } from '@angular/core';
// We will need to import a couple of specific API’s for dealing with reactive forms
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'complex-form',
  templateUrl : './app.complexform.html'
})
export class ComplexFormComponent {
  // The FormGroup object as you may remember from the simple form example exposes various API’s for dealing with forms. Here we are creating a new object and setting its type to FormGroup
  complexForm : FormGroup;

  // We are passing an instance of the FormBuilder to our constructor
  constructor(fb: FormBuilder){
    // Here we are using the FormBuilder to build out our form.
    this.complexForm = fb.group({
      // We can set default values by passing in the corresponding value or leave blank if we wish to not set the value. For our example, we’ll default the gender to female.
      'firstName' : '',
      'lastName': '',
      'gender' : 'Female',
      'hiking' : false,
      'running' : false,
      'swimming' : false
    })
  }

  // Again we’ll implement our form submit function that will just console.log the results of our form
  submitForm(value: any):void{
    console.log('Reactive Form Data: ')
    console.log(value);
  }
}

Our complexForm object now knows its boundaries and constraints. The complexForm object has six different fields. We haven’t added validation to these fields in this example. When we go to build the UI for this form, we’ll only be able to add the six fields that we declared or else Angular will complain. Let’s build the UI next and see how it differs from the template driven approach. Open the app.complexform.html file and add the following:

<div class="jumbotron">
    <h2>Data Driven (Reactive) Form</h2>
    <!-- Right of the bat, we no longer declare a local variable but use the formGroup directive and set it the complexForm object we defined in the constructor. Throughout the form, we will reference the complexForm root object as can be seen in the submitForm function.-->
    <form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
      <div class="form-group">
        <label>First Name:</label>
        <!-- Rather than set an ngModel, we use the formControl directive to sync our input to the complexForm object. Notice that we are also setting the attribute we wish the corresponding input to sync with. We no longer need the name attribute, but can optionally add it. -->
        <input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
      </div>
      <div class="form-group">
        <label>Last Name</label>
        <input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
      </div>
      <div class="form-group">
        <label>Gender</label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" [formControl]="complexForm.controls['gender']">
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <!-- This works the same way for radio and checkboxes as can be seen below -->
          <input type="radio" name="gender" value="Female" [formControl]="complexForm.controls['gender']">
          Female
        </label>
      </div>
      <div class="form-group">
        <label>Activities</label>
      </div>
      <label class="checkbox-inline">
        <input type="checkbox" value="hiking" name="hiking" [formControl]="complexForm.controls['hiking']"> Hiking
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="swimming" name="swimming" [formControl]="complexForm.controls['swimming']"> Swimming
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="running" name="running" [formControl]="complexForm.controls['running']"> Running
      </label>
      <div class="form-group">
        <button type="submit" class="btn btn-default">Submit</button>
      </div>
    </form>
  </div>

As you can see the reactive forms approach requires a bit more work. The syntax is slightly different, but I would argue that it’s a lot more expressive and easier to understand where and how everything fits in. To see this form in action, head over to localhost:4200 and refresh the page. The form will behave the same as the template driven example above.

Reactive Angular 2 Form

Now that we understand a bit about the different ways to build Angular 2 forms, let’s take a look at form validation.

Angular 2 Form Validation

Form validation has traditionally been very challenging to get right. It’s still a wild west when it comes to form validation with certain browsers supporting native HTML5 validators, different frameworks and libraries handling validation different ways, and finally getting the user experience right can often be a challenging act.

Angular 2 supports validation for both it’s template driven and model driven approaches to forms. The model driven approach gives much greater control when it comes to validation, so we’ll use that approach. You can learn how to do template driven validation from the official Angular 2 docs.

Let’s add validation to the form we’ve been using so far. Open the app.formvalidation.ts file. We’ll combine our logic and template and do everything in the .ts file so that it’s easier to follow along. Our initial app.formvalidation.ts file will look like:

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

@Component({
  selector: 'form-validation',
  template : `
  <div class="jumbotron">
    <h2>Form w/ Validations</h2>
    <form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
      <div class="form-group">
        <label>First Name:</label>
        <input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
      </div>
      <div class="form-group">
        <label>Last Name</label>
        <input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
      </div>
      <div class="form-group">
        <label>Gender</label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" [formControl]="complexForm.controls['gender']">
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Female" [formControl]="complexForm.controls['gender']">
          Female
        </label>
      </div>
      <div class="form-group">
        <label>Activities</label>
      </div>
      <label class="checkbox-inline">
        <input type="checkbox" value="hiking" name="hiking" [formControl]="complexForm.controls['hiking']"> Hiking
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="swimming" name="swimming" [formControl]="complexForm.controls['swimming']"> Swimming
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="running" name="running" [formControl]="complexForm.controls['running']"> Running
      </label>
      <div class="form-group">
        <button type="submit" class="btn btn-default">Submit</button>
      </div>
    </form>
  </div>
  `
})
export class FormValidationComponent {
  complexForm : FormGroup;

  constructor(fb: FormBuilder){
    this.complexForm = fb.group({
      'firstName' : “”,
      'lastName': “”,
      'gender' : “Female”,
      'hiking' : false,
      'running' : false,
      'swimming' : false
    })
  }

  submitForm(value: any){
    console.log(value);
  }
}

Next, we are going to programmatically add validators to our form. To do this we’ll need to import the Angular validators from the forms package. Our imports will then look like this:

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

Now we can use the prebuilt Angular validators in our form. Let’s see how we can add validations to our form.

...
constructor(fb: FormBuilder){
    this.complexForm = fb.group({
      // To add a validator, we must first convert the string value into an array. The first item in the array is the default value if any, then the next item in the array is the validator. Here we are adding a required validator meaning that the firstName attribute must have a value in it.
      'firstName' : [null, Validators.required],
      // We can use more than one validator per field. If we want to use more than one validator we have to wrap our array of validators with a Validators.compose function. Here we are using a required, minimum length and maximum length validator.
      'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])],
      'gender' : [null, Validators.required],
      'hiking' : false,
      'running' :false,
      'swimming' :false
    })
...

If we look at our form now, we won’t notice a difference. We can still hit the submit button and the form will submit. We’ll have to add some additional markup in our template to make the validator do what we want. An easy win is to disable the submit button if the form is not valid.

<button type="submit" class="btn btn-primary" [disabled]="!complexForm.valid">Submit</button>

If we look at the form now, we’ll see the form is disabled. Notice how we are able to use the disabled API and aren’t required to use any specific Angular 2 conventions. We can make the from valid by adding a first name, a last name that is between 5 and 10 characters, and selecting a gender. If we do this, the submit button will no longer be disabled and we will be able to submit the form.

This works, but is not a great user experience. The user has no indication which form field is invalid or what to do to make it valid. Let’s add some additional markup in our view to tell the user which field is invalid. We’ll start by marking an invalid field a different color.

…
<div class="form-group" [ngClass]="{'has-error':!complexForm.controls['firstName'].valid}">
        <label>First Name:</label>
        <input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
      </div>
      <!-- We are using the ngClass directive to conditionally add a class to our div if the form is invalid -->
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['lastName'].valid}">
        <label>Last Name</label>
        <input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
      </div>
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['gender'].valid}">
        <label>Gender</label>
        <!-- Here we are using the ngIf directive to display an error message if the user has not selected a gender since we can’t color the radio buttons. -->
        <div class="alert alert-danger" *ngIf="!complexForm.controls['gender'].valid">You must select a gender.</div>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" [formControl]="complexForm.controls['gender']">
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Female" [formControl]="complexForm.controls['gender']">
          Female
        </label>
      </div>

...

This is a little bit better. The user now has some context to let them know what is wrong. As soon as they meet the criteria for making the input field valid, the error goes away. The problem we are having now is that the error messages are displayed all the time. This is not ideal. We don’t want the user seeing a bunch of error messages before they’ve even had a chance to start completing the form.

Form Validation Always On

If you’ve worked with Angular 1.x, you may remember the various attributes that each form element gets such as pristine, touched, etc. based on the state of the form. We get those same exact attributes for our Angular 2 forms. We can defer the error handling from displaying until the user has at least had some interaction with the form. Let’s see how we can do this. As we won’t need to make any TypeScript changes, we’ll just show the UI template portion of the component.

<div class="jumbotron">
    <h2>Form with Validations</h2>
    <form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
      <!-- We add an additional check to see if the user has at least clicked on the form field before displaying the error -->
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['firstName'].valid && complexForm.controls['firstName'].touched}">
        <label>First Name:</label>
        <input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
      </div>
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['lastName'].valid && complexForm.controls['lastName'].touched}">
        <label>Last Name</label>
        <input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
      </div>
      <div class="form-group">
        <label>Gender</label>
        <div class="alert alert-danger" *ngIf="!complexForm.controls['gender'].valid && complexForm.controls['gender'].touched">You must select a gender.</div>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" [formControl]="complexForm.controls['gender']">
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Female" [formControl]="complexForm.controls['gender']">
          Female
        </label>
      </div>
      <div class="form-group">
        <label>Activities</label>
      </div>
      <label class="checkbox-inline">
        <input type="checkbox" value="hiking" name="hiking" [formControl]="complexForm.controls['hiking']"> Hiking
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="swimming" name="swimming" [formControl]="complexForm.controls['swimming']"> Swimming
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="running" name="running" [formControl]="complexForm.controls['running']"> Running
      </label>
      <div class="form-group">
        <button type="submit" class="btn btn-primary" [disabled]="!complexForm.valid">Submit</button>
      </div>
    </form>
  </div>

Finally, let’s add some more context to our errors. We will display a message for each error. This will let the user know exactly what the problem is. Angular 2 gives us an easy way to know which validation has failed. Let’s see how this works. We’ll just show the UI template code here as we won’t be needed any additional TypeScript changes.

<div class="jumbotron">
    <h2>Form with Validations</h2>
    <form [formGroup]="complexForm" (ngSubmit)="submitForm(complexForm.value)">
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['firstName'].valid && complexForm.controls['firstName'].touched}">
        <label>First Name:</label>
        <input class="form-control" type="text" placeholder="John" [formControl]="complexForm.controls['firstName']">
        <!-- The hasError method will tell us if a particular error exists -->
        <div *ngIf="complexForm.controls['firstName'].hasError('required') && complexForm.controls['firstName'].touched" class="alert alert-danger">You must include a first name.</div>
      </div>
      <div class="form-group" [ngClass]="{'has-error':!complexForm.controls['lastName'].valid && complexForm.controls['lastName'].touched}">
        <label>Last Name</label>
        <input class="form-control" type="text" placeholder="Doe" [formControl]="complexForm.controls['lastName']">
        <!-- The hasError method can work with the built in validators but custom validators as well -->
        <div *ngIf="complexForm.controls['lastName'].hasError('required') && complexForm.controls['lastName'].touched" class="alert alert-danger">You must include a last name.</div>
        <div *ngIf="complexForm.controls['lastName'].hasError('minlength') && complexForm.controls['lastName'].touched" class="alert alert-danger">Your last name must be at least 5 characters long.</div>
        <div *ngIf="complexForm.controls['lastName'].hasError('maxlength') && complexForm.controls['lastName'].touched" class="alert alert-danger">Your last name cannot exceed 10 characters.</div>
      </div>
      <div class="form-group">
        <label>Gender</label>
        <div class="alert alert-danger" *ngIf="!complexForm.controls['gender'].valid && complexForm.controls['gender'].touched">You must select a gender.</div>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Male" [formControl]="complexForm.controls['gender']">
          Male
        </label>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="gender" value="Female" [formControl]="complexForm.controls['gender']">
          Female
        </label>
      </div>
      <div class="form-group">
        <label>Activities</label>
      </div>
      <label class="checkbox-inline">
        <input type="checkbox" value="hiking" name="hiking" [formControl]="complexForm.controls['hiking']"> Hiking
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="swimming" name="swimming" [formControl]="complexForm.controls['swimming']"> Swimming
      </label>
      <label class="checkbox-inline">
        <input type="checkbox" value="running" name="running" [formControl]="complexForm.controls['running']"> Running
      </label>
      <div class="form-group">
        <button type="submit" class="btn btn-primary" [disabled]="!complexForm.valid">Submit</button>
      </div>
    </form>
  </div>

Form Validation in Action

Our form is looking good now. We have pretty sophisticated validation in place. The user will always have context for what is causing the error and know the steps to take to correct it. This was just one way to handle validation. There are many others, but I think we covered the main methods of how validation in Angular 2 works so now you can explore and see what works best for your use cases.

Angular 2 also has a pretty great infrastructure in place for creating your own validators. We won’t do that in this tutorial, but we will cover it in a future post. Angular 2 comes with a pretty good list of validators including: required, minimum length, maximum length, null and pattern validator which allows you to define any regular expression to match the input against.

Aside: Building an Angular 2 Form to Interact with the Auth0 API

Angular 2 Login Form

So far the forms we’ve written have been fairly static. We didn’t do anything with the input other than log it to the console. To close out this tutorial, let’s write a dynamic login form. Rather than building a backend server to handle the authentication, we’ll use the Auth0 API to authenticate a user. Sign up for a free Auth0 account to get started.

Auth0 Management Dashboard

Once you have your Auth0 account created, login to the management dashboard and get your Client Id. This is all we’ll need for now. Let’s go ahead and create a new component called app.login.ts. We’ll scaffold this component as follows:

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import {Http, Response, Request, RequestMethod} from '@angular/http';

@Component({
  selector: 'login-form',
  template : ``
})
export class LoginComponent {
}

Next, let’s include our newly created component in our root module so that we can use this component throughout our application.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { SimpleFormComponent } from './app.simpleform';
import { ComplexFormComponent } from './app.complexform';
import { FormValidationComponent } from './app.formvalidation';
// Add the login component
import { LoginComponent } from './app.login'

@NgModule({
  declarations: [
    AppComponent,
    SimpleFormComponent,
    ComplexFormComponent,
    FormValidationComponent,
    // Add it to our declarations so that we can use this component in our app.
    LoginComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Finally, we’ll add our login component to our root component view. Open the app.component.html file and make the following edits:

<div class="container">
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <simple-form></simple-form>
    </div>
  </div>
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <complex-form></complex-form>
    </div>
  </div>
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <form-validation></form-validation>
    </div>
  </div>
  <!-- Add the new login form component -->
  <div class="row">
    <div class="col-sm-6 col-sm-offset-3">
      <login-form></login-form>
    </div>
  </div>
</div>

Now we’re ready to implement our login form. Let’s open the app.login.ts file. We’ll inline our template again. Let’s examine the code line by line and explain how we are going to do this.

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
// We are going to be making a call to an external API and we’ll use the Angular HTTP library to accomplish this. Here we are importing the API’s we’ll need to work with.
import {Http, Response, Request, RequestMethod} from '@angular/http';

@Component({
  selector: 'login-form',
  template : `
  <!-- We’ll display the login form only if the user is not logged in -->
  <div class="jumbotron" *ngIf="!authenticated">
    <h2>Login Form</h2>
    <!-- We are going to build a reactive form and use many of the concepts we learend in the previous section in regards to validation. -->
    <form [formGroup]="loginForm" (ngSubmit)="submitForm(loginForm.value)">
      <div class="form-group" [ngClass]="{'has-error':!loginForm.controls['email'].valid && loginForm.controls['email'].touched}">
        <label>Email:</label>
        <input class="form-control" type="text" placeholder="John@doe.com" [formControl]="loginForm.controls['email']">
        <div *ngIf="loginForm.controls['email'].hasError('required') && loginForm.controls['email'].touched" class="alert alert-danger">You must add an email.</div>
      </div>
      <div class="form-group" [ngClass]="{'has-error':!loginForm.controls['password'].valid && loginForm.controls['password'].touched}">
        <label>Password:</label>
        <input class="form-control" type="password" placeholder="Password" [formControl]="loginForm.controls['password']">
        <div *ngIf="loginForm.controls['password'].hasError('required') && loginForm.controls['password'].touched" class="alert alert-danger">You must add a password.</div>
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-primary" [disabled]="!loginForm.valid">Submit</button>
      </div>
    </form>
  </div>
  <!-- If the user is authenticated we’ll display their profile picture and email as well as provide a way to logout -->
  <div class="jumbotron text-center" *ngIf="authenticated">
    <img src="{{profile.picture}}" />
    <h2>Welcome, {{profile.email}}</h2>
    <a (click)="logout()">Logout</a>
  </div>
  `
})
export class LoginComponent {
  // We are going to declare our variables here. We’ll have a loginForm that will represent our reactive form, an authenticated boolean that will be true or false based on the users auth status and finally a profile object that will hold the user data.
  loginForm : FormGroup;
  authenticated: boolean
  profile : Object;

  constructor(fb: FormBuilder, public http: Http){
    // We’ll check if the user is logged in once this component is loaded. We’ll do this by checking if a jwt key value pair exists in local storage.
    if(localStorage.getItem('jwt')){
      this.authenticated = true;
      // If the jwt key value exists, we’ll know the user is logged in, so we’ll get their profile.
      this.profile = JSON.parse(localStorage.getItem('profile'));
    }
    // For our form, we’ll just have two fields and we’ll require both of them to be filled out before the form can be submitted
    this.loginForm = fb.group({
      'email' : [null, Validators.required],
      'password': [null, Validators.required],
    })
  }

  submitForm(value: any){
    // Once the form is submitted and we get the users email and password we’ll format our request based on the Auth0 API.
    let form = {
      'client_id' : 'YOUR-AUTH0-CLIENTID',
      'username' : value.email,
      'password' : value.password,
      'connection' : 'Username-Password-Authentication',
      'grant_type' : 'password',
      'scope' : 'openid name email'
    }
    // Once we have our data formed, we’ll send the request using the Angular 2 HTTP library.
    this.http.post('https://YOUR-AUTH0-DOMAIN.auth0.com/oauth/ro', form).subscribe(
      (res:any)=>{
        // We’ll subscribe to the request and capture the response
        let data = res.json();
        // If we get an id_token, we’ll know the request is successful so we’ll store the token in localStorage. We won’t handle the error use case for this tutorial.
        if(data.id_token){
          localStorage.setItem('jwt', data.id_token);
          // Finally, we’ll call our getUserInfo function which will get the user details from Auth0
          this.getUserInfo(data);
        }
      }
    )
  }

  // Here we are similarly calling the Auth0 API, this time the /tokeninfo endpoint which will return the users data we requested. All we’ll need to pass to the request is our JSON Web Token.
  getUserInfo(data: any){
    let form = {
      'id_token' : data.id_token
    }
    this.http.post('https://reviewgen.auth0.com/tokeninfo', form).subscribe(
      (res:any)=>{
        let data = res.json();
        this.profile = data;
        localStorage.setItem('profile', JSON.stringify(data));
        this.authenticated = true;
        // We’ll use the reset() method to reset the form. So if a user logs out they will need to enter their credentials again. If we did not do this, the previous values would still be displayed.
        this.loginForm.reset();
      }
    )
  }

  // We’ll implement a logout function that removes the jwt and user profile from localStorage and sets the authenticated boolean to false which will cause the component to display the login form.
  logout(){
    localStorage.removeItem('jwt');
    localStorage.removeItem('profile');
    this.authenticated = false;
  }
}

Our login form is ready to be tested. Navigate to localhost:4200 and you should see the newly created login form. You’ll need to have an Auth0 user account created before you can login. You can create an account from your Auth0 Dashboard in the Users section and then test this functionality.

Login Component Authenticated

Writing your own authentication mechanism is no easy task. We only added the ability to login, and even that was pretty incomplete. The Auth0 Lock widget can handle all things auth for us including sign in, sign up, social connections, enterprise federation, multifactor authentication and much more. We can integrate Lock with our Angular 2 applications using the angular2-jwt library.

Putting It All Together

Today we looked at how Angular 2 helps us create and validate forms. We looked at the different ways users can create forms and the benefits of each. Validation can be a daunting task, but Angular 2 comes with a lot of helpers right out of the gate which help a great deal. Finally, we added some actual functionality to our forms, by calling the Auth0 API and showing how you can make HTTP requests with Angular 2 forms. If you would like to see the completed demo, you can get it from Github, and if you want to implement it yourself, be sure to sign up for a free Auth0 account.