Forms in Angular 2

HTML forms have been around for a while, yet validation of user input solely using HTML and Javascript is still a painful task to tackle. Angular 2 has some nice features that make form management very easy and pretty much painless. This post will focus mostly on template-driven forms, which are the least verbose option offered by Angular 2.

Template-driven forms

Template-driven forms are my favorite option because most of the magic happens in the HTML template, which means that very little Typescript code has to be written. Here is the form we’re going to work with:

<form>
   <label>Firstname:&lt/label> 
   <input name="firstname" required="" type="text" />
   <label>Lastname:&lt/label> 
   <input name="lastname" type="text" />
   <label>Street:&lt/label> 
   <input name="street" type="text" />
   <label>Zip:&lt/label> 
   <input name="zip" type="text" />
   <label>City:&lt/label> 
   <input name="city" type="text" />
   <button type="submit">Submit</button>
</form>

This is just a regular form, nothing fancy in here. What I want to do is have Angular 2 handle the submission of that form. In order to do that, I need to add the following code:

<form  #form="ngForm" (ngSubmit)="logForm(form.value)" >

This does two things:

  1. It creates a local variable in our template called form, which has some magic powers. One of them is to hold the value of our form as a Javascript object, which can be accessed with form.value
  2. On submit, the logForm() method will be called on my component, with the current value of the form as a parameter.

By the way, you may wonder what my component looks like. There it is:

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

@Component({
  moduleId: module.id,
  selector: 'app-forms',
  templateUrl: 'forms.component.html',
  styleUrls: ['forms.component.css']
})
export class FormsComponent {

  logForm(value) {
    console.log(value);
  }
}

Pretty much an empty component. Its template is the HTML I introduced earlier. Now in order to make this work, we have to import some dependencies in our ngModule. Form specific code is highlighted below:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';
import { FormsComponent }  from './forms.component';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],
  declarations: [ FormsComponent ],
  bootstrap: [ FormsComponent ]
})
export class AppModule { }

Almost there! All we need now is to tell Angular which form elements we want to be bound to our form model. This is achieved using the ngModel directive as follows:

<input type="text" name="firstname" ngModel required>
<br/>
<label>Lastname:</label>
<input type="text" name="lastname" ngModel>
<br/>

Now if I fill out that form and hit the submit button, Angular 2 will call the logForm() method, which will basically output our form model to the browser console:

{firstname: "Alain", lastname: "Chautard"} 

That was easy, right? We just added a couple of directives to our HTML and we have an object that we could send to our server using AJAX.

What about validation?

My form already has a required attribute in place. If we try to submit the form with no first name information, it won’t be submitted and the browser will display a message to highlight the required field.

This is a great feature, yet it relies on browser specific implementations as it’s based on the HTML5 specification. Let’s see how to define our own custom error handling. First we tell the browser that we don’t want its default HTML5 behavior:

<form  #form="ngForm" (ngSubmit)="logForm(form.value)" novalidate >

Then we add the following definitions to our CSS file:

.ng-valid[required] {
  border-left: 5px solid #42A948; /* green */
}

.ng-invalid {
  border-left: 5px solid #a94442; /* red */
}

And… that’s it! Angular 2 automatically adds and removes CSS classes to each form element based on its validity. No Typescript code has to be written to achieve this. As a result, my form will now be styled as follows depending on the data entered:

validity-required-indicator

Let’s do more than CSS styling. Let’s say that we have a zip code field that is required, should be exactly 5 digits long, and that an error message will show up to help the user enter valid information. The following code will do exactly that:

<input type="text" name="zip" #zip="ngModel" required pattern="[0-9]{5}">
<div class="alert" [hidden]="zip.valid || zip.pristine">
  Please enter a 5-digit zipcode
</div>

Let’s take a look at the above code. First, we create a local variable using the #zip syntax. zip will give us access to form state attributes similar to the CSS classes that Angular 2 deals with.

Then we define a 5-digit pattern, which is regular HTML5 code, nothing Angularish here. Finally, we add a div that will be hidden if zip.valid is true or if zip.pristine is true. That way the error message will show up only if the user enters wrong information, and will be hidden as long as the text input is pristine, which means the user hasn’t typed anything yet.

As you can see, customizing our forms with validation and error messages is a fairly easy thing to do in Angular 2. The best part of it is that everything is achieved through HTML attributes, which means less Typescript code to write and to maintain.

Angular 2 RC5 released the final version the forms API, which means you can safely start using forms without fearing that next releases will have a different implementation.

What’s new in Angular 2 RC5?

Angular 2 RC5 was released a couple days ago. This RC5 version brings Angular 2 one step closer to its final release, as the Angular team stated in its announcement:

“RC5 represents our expected public API for our 2.0.0 release, including router and forms APIs”

That’s great news as it basically means that 2.0.0 is closer than ever. It also means that if there’s a RC6 in the future, it should not have any breaking changes.

Let’s take a quick look at what’s new in RC5:

NgModule

NgModule does not sound that exciting but it is! It’s a new decorator that looks like this:

import { NgModule }       from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { AppComponent }   from './app.component';

@NgModule({
    declarations: [AppComponent],
    imports:      [BrowserModule, RouterModule],
    bootstrap:    [AppComponent],
})
export class AppModule {}

If you’re not excited yet, I can understand that. Now if you’re written a little bit of Angular 2 code before RC5, you know that you had to list all of your dependencies with import statements and directive attributes in your components as follows:

import { Component } from '@angular/core';
import { HelloWorld2 } from './helloWorld2.component';

@Component({
  moduleId: module.id,
  selector: 'app-communication2',
  directives: [HelloWorld2],
  pipes: [ MyMagicPipe ]
  template: `<hello-world2 [message]="myMessage" (onClick)="myCallback($event)"></hello-world2>`

})

With NgModule, all of the repetitive boilerplate code used by most of your components / pipes/ services can be listed once for all in your NgModule declaration. Once you’ve done that, you can get rid of the directives declaration in your components (and you should – it will be removed from Angular 2.0.0 thus becoming a breaking change at that point).

NgModule is also the decorator we will now use to specify which component is the root component to bootstrap. A nice addition to Angular 2!

FormsModule, RouterModule, and Material Design modules

The Angular team already created a bunch of commonly used modules with NgModule so that we can import them easily. Another nice syntax shortcut added to Angular RC5.

Lazy-loading and Ahead-of-Time compilation

60% of Angular 2’s code size is the compiler. With Ahead-of-time compilation (AoT), Angular 2 can now be used without compiling your components / templates on the fly.

As a result, users should be able to see decreased start-up time for your app as the compilation work will laready be done when the page is loaded.

Also, we can expect the Angular 2 “runtime” dependency to be 60% smaller as a result, which would result in a faster download as well.

Lazy-loading is another option to make things happen faster, as you can now specify lazy pahts in the router that will load specific modules only when requested by the user:

@NgModule({
  declarations: [ MyComponent, MyHomeRoute ],
  bootstrap: [ MyComponent ],
  imports: [
    RouterModule.forRoot([
      { path: ‘home’, component: MyHomeRoute },
      { path: ‘lazy’, loadChildren: ‘./my-lazy-module’ }
    ])
})
class MyAppModule {}

All in all, no revolution with Angular 2 RC5, yet some good news that allow us to believe that the final release is getting closer and closer!

Angular 2 RC 1 is here!

Angular 2 got its two first release candidates this week. This happened exactly while I was giving a training session in San Diego to the Verizon Networkfleet team. At least this helped me convey the message that Angular development is an ever changing world where things can be different from one week to the next.

Angular 2

Now that Angular 2 is (almost) live, don’t hesitate to get in touch if you need some training. I’d be happy to help you and your team get up to speed with Angular 2.