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:

the addition of the Ahead-of-Time (AoT) compiler

introduction of the @NgModule decorator

a new Forms Module

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.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.

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:

import { Component } from '@angular/core' ; @ Component ( { selector : 'simple-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' , 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.

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' ; 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' ; @ NgModule ( { declarations : [ AppComponent , SimpleFormComponent , ComplexFormComponent , FormValidationComponent , ] , imports : [ BrowserModule , FormsModule , 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.

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 { submitForm ( form : any ) : void { console . log ( 'Form Data: ' ) ; console . log ( 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.

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' ; import { FormBuilder , FormGroup } from '@angular/forms' ; @ Component ( { selector : 'complex-form' , templateUrl : './app.complexform.html' } ) export class ComplexFormComponent { complexForm : FormGroup ; constructor ( fb : FormBuilder ) { this . complexForm = fb . group ( { 'firstName' : '' , 'lastName' : '' , 'gender' : 'Female' , 'hiking' : false , 'running' : false , 'swimming' : false } ) } 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 > < 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 >

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.

Now that we understand a bit about the different ways to build Angular 2 forms, let’s take a look at 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 ( { 'firstName' : [ null , Validators . required ] , '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 > < 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 > < 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.

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) " > < 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 ' ] " > < 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 ' ] " > < 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 >

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.

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.

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' ; import { LoginComponent } from './app.login' @ NgModule ( { declarations : [ AppComponent , SimpleFormComponent , ComplexFormComponent , FormValidationComponent , 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 > < 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' ; 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 { loginForm : FormGroup ; authenticated : boolean profile : Object ; constructor ( fb : FormBuilder , public http : Http ) { if ( localStorage . getItem ( 'jwt' ) ) { this . authenticated = true ; this . profile = JSON . parse ( localStorage . getItem ( 'profile' ) ) ; } this . loginForm = fb . group ( { 'email' : [ null , Validators . required ] , 'password' : [ null , Validators . required ] , } ) } submitForm ( value : any ) { let form = { 'client_id' : 'YOUR-AUTH0-CLIENTID' , 'username' : value . email , 'password' : value . password , 'connection' : 'Username-Password-Authentication' , 'grant_type' : 'password' , 'scope' : 'openid name email' } this . http . post ( 'https://YOUR-AUTH0-DOMAIN.auth0.com/oauth/ro' , form ) . subscribe ( ( res : any ) => { let data = res . json ( ) ; if ( data . id_token ) { localStorage . setItem ( 'jwt' , data . id_token ) ; this . getUserInfo ( data ) ; } } ) } 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 ; this . loginForm . reset ( ) ; } ) } 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.

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.

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.

Like this article? Follow @kukicado on Twitter

This content is sponsored via Syndicate Ads.