3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 10

User Input and Forms in Angular

Handling user input and creating forms

STANDARD

User Input and Forms in Angular

At some point, you’re going to want to collect some data from your users. That might be some text for a status update, their name and shipping address, a search term, a title for their todo list item, or anything else.

Whatever the data is, the user is going to be entering it into one of the templates in your application. We’ve already looked at a simple example of this using [(ngModel)], let’s revisit that now:

import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-home',
  template: `
    <p>I am the home page</p>
    <input [(ngModel)]="firstName" (ngModelChange)="logChange()" />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {
  firstName = 'Josh';

  logChange() {
    console.log(this.firstName);
  }
}

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    RouterModule.forChild([
      {
        path: '',
        component: HomeComponent,
      },
    ]),
  ],
  declarations: [HomeComponent],
})
export class HomeModule {}

NOTE: The FormsModule must be included in the module you are trying to access ngModel in.

I’ve extended this into a complete example now. I’ve also set up an event binding for (ngModelChange) so that you can see every time the user changes the input, that change is reflected on this.firstName.

Now we have access to some data that the user has supplied, and we can do whatever we like with it. If we wanted, we could bind to values in an object like this to get multiple values:

@Component({
  selector: 'app-home',
  template: `
    <p>I am the home page</p>
    <input [(ngModel)]="formData.firstName" (ngModelChange)="logChange()" />
    <input [(ngModel)]="formData.lastName" (ngModelChange)="logChange()" />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {
  formData = {
    firstName: '',
    lastName: '',
  };

  logChange() {
    console.log(this.formData);
  }
}

This approach works quite well for simple forms, but can become more difficult for larger/more complex forms if implemented naively. We might want to include validations on the forms to enforce certain values, react to value changes, dynamically add/remove fields, and more. The more popular approach generally is to use ReactiveForms.

I emphasised generally because there are some proponents of template driven forms that rely on using ngModel even for more complex form situations. Proponents of this approach include industry veterans who have a great deal of knowledge and experience. This is not an approach I have ever used for any substantial amount of time so I can’t speak too much to its benefits or downsides, but it is certainly a valid architectural approach and definitely not something that should be dismissed out of hand.

Nonetheless, we will be focusing on just one approach primarily: ReactiveForms.

Reactive Forms

To use ReactiveForms we will need to replace the FormsModule in our modules imports with ReactiveFormsModule. The FormsModule is what provides us with ngModel and it is possible to include both but, generally, if we are using ReactiveForms we won’t be using ngModel.

The general idea behind a reactive form is that it is made up of a FormGroup (or multiple) and within that group will be multiple FormControl instances. The group collects things together, and the individual controls are tied to a specific input. In this way, we could apply validations to a specific control and check if it is valid, and we could also apply validations to an entire group and check if the entire group is valid.

We might create a reactive form like this:

import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-home',
  template: `
    <form [formGroup]="myForm">
      <input formControlName="firstName" type="text" />
      <input formControlName="lastName" type="text" />
    </form>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {
  myForm = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
  });
}

@NgModule({
  imports: [
    CommonModule,
    ReactiveFormsModule,
    RouterModule.forChild([
      {
        path: '',
        component: HomeComponent,
      },
    ]),
  ],
  declarations: [HomeComponent],
})
export class HomeModule {}
STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).