We're live-coding on Twitch! Join us!
Using Angular 2's Template-Driven Forms

Using Angular 2's Template-Driven Forms

Code Demo

There are two ways to build forms in Angular 2, namely model-driven and template-driven.

In this article, we will learn about buildling template-driven form with validation using the latest forms module, then we will talk about how the differences between the new template form and the deprecated one. Please refer to How to Build Model-driven Forms in Angular 2 if you would like to learn about model-driven forms.

Related Video Course: Angular v2+ Forms and Validation

Live demo on template-driven form with latest forms module.

Live demo on template-driven form with deprecated forms module (RC 4): http://plnkr.co/edit/tvALN2?p=preview


We will build a form to capture user information based on this interface.

// user.interface.ts

export interface User {
    name: string; // required with minimum 5 characters
    address: {
        street?: string; // required
        postcode?: string;

Here is how the UI will look:

Angular 2 Template-Driven Forms


  1. Set postcode default value to 8000;
  2. Show error message only when:-
    • the field is invalid and it’s dirty (the field is touched/edited), or
    • the field is invalid and the form is submitted

App Setup

Here's our file structure:

|- app/
    |- app.component.html
    |- app.component.ts
    |- app.module.ts
    |- main.ts
    |- user.interface.ts
|- index.html
|- styles.css
|- tsconfig.json

In order to use new forms module, we need to npm install @angular/forms npm package and import the forms module in application module.

better.dev Get Started w/ JavaScript for free!
$ npm install @angular/forms --save

Here's the module for our application app.module.ts:

// app.module.ts

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

import { AppComponent }   from './app.component';

  imports:      [ BrowserModule, FormsModule ], // import forms module here
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]

export class AppModule { }

The App Component

Let's move on to create our app component.

// app.component.ts
import { Component, OnInit } from '@angular/core';
import { User } from './user.interface';

  moduleId: module.id,
  selector: 'my-app',
  templateUrl: 'app.component.html',
export class AppComponent implements OnInit {
    public user: User; // our model

    ngOnInit() {
        // we will initialize our model here

    save(model: User, isValid: boolean) {
        // check if model is valid
        // if valid, call API to save customer
        console.log(model, isValid);

The code is pretty simple and descriptive by itself.

The HTML View

This is how our HTML view will look like.

    <h1>Add user</h1>
    <form #f="ngForm" (ngSubmit)="save(f.value, f.valid)" novalidate>
        <!-- we will place our fields here -->
        <button type="submit">Submit</button>


  1. The #f is the reference variable to the form directive. Refer to Angular official documentation for more details.
    • Layman explanation:
    • We need a way to retrieve the form data(all the values of our form fields like name, address, postcode, etc). Angular provide us a way, form is exported as ngForm. We then assign the form data to our local variable f.
  2. save() function will be called when we submit the form.
    • Layman explanation:
    • f.value - an object that refer to the all the form field values.
    • f.valid - a Boolean that indicates whether the form is valid (e.g. name field is mandatory. If user name field is not filled, f.valid should be false).


Now, let's initialize our user model.

// app.component.ts
/* ... */
ngOnInit() {
    // we will initialize our form here
    this.user = {
        name: '',
        address: {
            street: '',
            postcode: '8000' // set default value to 8000
/* ... */

Let's proceed to bind our user model to the view.

<!-- app.component.html -->
<form #f="ngForm" novalidate (ngSubmit)="save(f.value, f.valid)">
    <!-- we will place our fields here -->

        <!--bind name to ngModel, it's required with minimum 5 characters-->
        <input type="text" 
            name="name" [(ngModel)]="user.name" 
            #name="ngModel" required minlength="5">
        <!--show error only when field is not valid & it's dirty or form submited-->
        <small [hidden]="name.valid || (name.pristine && !f.submitted)">
            Name is required (minimum 5 characters).

    <!--adrress group-->
    <div ngModelGroup="address">
            <input type="text"
                name="street" [(ngModel)]="user.address.street"
                #street="ngModel" required>
            <small [hidden]="street.valid || (street.pristine && !f.submitted)" class="text-danger">
                Street is required.

            <label>Post code</label>
            <input type="text" 
                name="postcode" [(ngModel)]="user.address.postcode">

    <button type="submit">Submit</button>



  1. Use ngModel to bind the model to form control. The binding can be either one way or two way. In our case, we enable two way binding with banana in a box syntax [()].
  2. Use name attribute to register a form control with the form. E.g. we assign "name" to the name attribute, then when we retrieve the name field from form value (f.value).
  3. Use ngModelGroup to group element. E.g. address is a group. Under address, there are street and postcode.
  4. #street is the reference variable to the input directive.
    • Similar to #f, we need a way to read the input data. Angular provide us a way, so input is exported as ngModel.
    • We then assign the input data to our local variable street.
    • With this, we can then use street.pristine, street.valid, etc to check if the street input is dirty, and its validity.
    • We use these values to show/hide the error message.

What are the differences with deprecated template forms?

There are a few improvements in in new form compared to the deprecated:-

  1. Remove ngControl: since ngControl and ngModel behavior are quite similar (ngControl has extra validity checking features), it’s possible to combine ngControl into ngModel, additional name attribute is required in the new forms module, those that are coming from Angular 1 shouldbe familiar with this.
  2. Rename NgControlGroup to NgModelGroup: since no more ngControl, so there will be no more NgControlGroup but NgModelGroup.
  3. Exports renamed to ngModel: In deprecated form, control is exported as ngForm, it's confusing as . E.g. previously, for the name field, the syntax is #name = "ngForm", now it's #name = "ngModel".
  4. Added submitted flag to NgForm: with this improvment, we don’t need to define submitted property in our component.

For reference purpose, I've provided a live demo of the deprecated forms as well so you can see the differences.


Template forms is getting better with the latest forms module. If you are curious about what are the new form changes, you may refer to Angular form changes proposal for more details.

How about if user is requires to add password and confirm password? How could we handle custom validation in template-driven forms? You might be interested in How to Implement Custom Validator Directive (Confirm Password) in Angular 2 for this use cases.

That's it. Happy coding!

Live demo here on template-driven form with deprecated forms module (RC 4): http://plnkr.co/edit/tvALN2?p=preview

Like this article? Follow @JecelynYeen on Twitter