// Tutorial //

How to Deal with Different Form Controls in Angular 2

Draft updated on Invalid Date
Default avatar
By Jecelyn Yeen
Developer and author at DigitalOcean.
How to Deal with Different Form Controls in Angular 2

This tutorial is out of date and no longer maintained.

Introduction

In this tutorial we will explore the way to bind these few types of controls to our form: text, number, radio, select (primitive type), select (object), multiple select, checkbox (boolean), and checkbox (toggle value).

Feel free to skip some of the control types (as some of them are really simple).

If you are new to Angular 2 forms, do refer to these articles for basics.

View Angular 2 - Different form controls (final) scotch on plnkr

We will build a form to capture user information based on these interfaces.

user.interface.ts
export interface User {
  name: string; // text
  age?: number; // number
  language?: string; // radio
  role?: string; // select (primitive)
  theme?: Theme; // select (object)
  topics?: string[]; // multiple select
  isActive?: boolean; // checkbox
  toggle?: string; // checkbox toggle either 'toggled' or 'untoggled'
}
theme.interface.ts
export interface Theme {
  display: string;
  backgroundColor: string;
  fontColor: string;
}

Here is how the UI will look:

Angular 2 Form Controls

App Setup

Here’s our file structure:

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

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

  1. 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';

@NgModule({
  imports:      [ BrowserModule, FormsModule ], // import forms module
  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';
import { Theme } from './theme.interface';

@Component({
  moduleId: module.id,
  selector: 'my-app',
  templateUrl: 'app.component.html',
  directives: []
})
export class AppComponent implements OnInit {
  public user: User;
  /* standing data goes here*/
  ...
  /* end standing data */
  ngOnInit() {
    // initialize user model here
  }
  public save(isValid: boolean, f: User) {
    console.log(f);
  }
}

Standing Data

We need to include some data for setup as well:

app.component.ts
...

/* standing data goes here*/
public languages = [
  { value: 'en', display: 'English' },
  { value: 'es', display: 'Spanish' }
];
public roles = [
  { value: 'admin', display: 'Administrator' },
  { value: 'guest', display: 'Guest' },
  { value: 'custom', display: 'Custom' }
];
public themes: Theme[] = [
  { backgroundColor: 'black', fontColor: 'white', display: 'Dark' },
  { backgroundColor: 'white', fontColor: 'black', display: 'Light' },
  { backgroundColor: 'grey', fontColor: 'white', display: 'Sleek' }
];
public topics = [
  { value: 'game', display: 'Gaming' },
  { value: 'tech', display: 'Technology' },
  { value: 'life', display: 'Lifestyle' },
];
public toggles = [
  { value: 'toggled', display: 'Toggled' },
  { value: 'untoggled', display: 'UnToggled' },
];
/* end standing data */

...

Initialize model

Then, we need to initialize our user model:

app.component.ts
...

ngOnInit() {
  // initialize user model here
  this.user = {
    name: '',
    language: this.languages[0].value, // default to English
    role: null,
    theme: this.themes[0], // default to dark theme
    isActive: false,
    toggle: this.toggles[1].value, // default to untoggled
    topics: [this.topics[1].value] // default to Technology
  }
}
...

The HTML View

This is how our HTML view will look like.

app.component.html
<form #f="ngForm" novalidate>

  <!-- We'll add our form controls here -->

  <button type="submit" (click)="save(f.value, f.valid)">Submit</button>
</form>

Implementation

Let’s start to look into each type of control.

1. Text

Getting text input is very straightforward. You need the name attribute, and ngModel.

app.component.html
...
<div>
  <label>Name</label>
  <input type="text" name="name" [(ngModel)]="user.name">
</div>

...

2. Number

Getting number input is also very straightforward.

app.component.html
...
<div>
  <label>Age</label>
  <input type="number" name="age" [(ngModel)]="user.age">
</div>

...

3. Radio

Binding radio input is not that easy prior Angular RC 2. With the new form in RC 3 onward, we can directly bind to ngModel, bind the value property.

We have this list of preferred languages:

app.component.ts
public languages = [
  { value: 'en', display: 'English' },
  { value: 'es', display: 'Spanish' }
];

When select, we want only the value Hammerhead or Great White Shark.

app.component.html
...
<div>
  <label>Language</label>
  <div *ngFor="let language of languages">
    <label>
    <input type="radio" name="language" [(ngModel)]="user.language"
    [value]="language.value">
    {{language.display}}
    </label>
  </div>
</div>
...

4. Select (Primitive type)

You can bind select to ngModel. Loop through your option list, set the value property.

We have a list of roles:

app.component.ts

public roles = [
  { value: 'admin', display: 'Administrator' },
  { value: 'guest', display: 'Guest' },
  { value: 'custom', display: 'Custom' }
];

When value selected, we expected it to return string value admin, guest, or custom. Here’s how your HTML will look like.

app.component.html
...
<div>
  <label>Role</label>
  <select name="role" [(ngModel)]="user.role">
    <option *ngFor="let role of roles" [value]="role.value">
    {{role.display}}
    </option>
  </select>
</div>
...

5. Select (object)

Similar to the last example, but this time, instead of a simple type, we want the whole object when it’s selected.

Here is the list of themes:

app.component.ts
public themes: Theme[] = [
  { backgroundColor: 'black', fontColor: 'white', display: 'Dark' },
  { backgroundColor: 'white', fontColor: 'black', display: 'Light' },
  { backgroundColor: 'grey', fontColor: 'white', display: 'Sleek' }
];

When selected, for example Light theme, we expect { backgroundColor: 'white', fontColor: 'black', display: 'Light' } to be returned. Instead of binding to the value property, we bind to ngValue property.

app.component.html
...
<div>
  <label>Theme</label>
  <select name="theme" [(ngModel)]="user.theme">
    <option *ngFor="let theme of themes" [ngValue]="theme">
      {{theme.display}}
    </option>
  </select>
</div>

...

6. Multiple select

We can select more than 1 topics. E.g. when selecting game and tech, it should return ['game', 'tech'].

app.component.ts
public topics = [
  { value: 'game', display: 'Gaming' },
  { value: 'tech', display: 'Technology' },
  { value: 'life', display: 'Lifestyle' },
];

Similar to select, but this time our model is array of string.

app.component.html
...
<div>
  <label>Topics</label>
  <select multiple name="topics" [(ngModel)]="user.topics">
    <option *ngFor="let topic of topics" [value]="topic.value">
      {{topic.display}}
    </option>
  </select>
</div>
...

7. Checkbox (boolean)

By default, checkboxes return boolean. Bind ngModel and define the name attribute as usual.

app.component.html
...
<div>
  <label>
    <input type="checkbox" name="isActive"  [(ngModel)]="user.isActive">
    Is Active
  </label>
</div>

...

8. Checkbox (Toggle value)

In this case, we want to display a checkbox. Instead of boolean, we expecting value. When checked, it should return toggled, else return value untoggled.

This is the list of toggles:

app.component.ts
public toggles = [
  { value: 'toggled', display: 'Toggled' },
  { value: 'untoggled', display: 'UnToggled' },
];

First, we define a hidden input to bind to the real model. Then we create the checkbox input, handle the checked property and change event. Change event fire every time value change, and it has $event that we can read from.

In our case, we read the $event.target.checked to find out if the checkbox is checked, then update model value accordingly.

app.component.html
...
<div>
  <input type="hidden" name="toggle" [(ngModel)]="user.toggle">
  <div>
    <label>
      <input type="checkbox"
        [checked]="user.toggle === toggles[0].value"
        (change)="$event.target.checked? (user.toggle =  toggles[0].value) : (user.toggle = toggles[1].value)">
      {{ toggles[0].display }}
    </label>
  </div>
</div>

...

Tips during development

During development, it’s good that you can visualize the value. Angular provided a very useful json Pipe.

app.component.html
...
<pre>{{your_form or control_name | json }}</pre>

...

Conclusion

That’s it. Hope it helps your journey in Angular 2. Happy coding!


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment