Where to Begin: Building a Single Control

Angular gives developers two primary strategies for gathering user input: reactive forms and template-driven forms. Underneath, both of these share a single Forms API.

I'm going to construct a form using the reactive strategy, frequently described as model-driven forms.

Example Form

Previously, I published an Intro To Angular Template-driven Forms, where the identical form was created using the alternative method.

Creating the same form two different ways made the distinctions much clearer for me.

I will not dive into the underlying concepts here, but a complimentary article on Medium is available if you'd like further reading.

The Initial Step: Creating One Element

The very first action is to bring in ReactiveFormsModule. This module "exports the required infrastructure and directives for reactive forms."

So, inside app.module.ts, we should bring in the ReactiveFormsModule.

import { ReactiveFormsModule } from '@angular/forms';
Enter fullscreen mode Exit fullscreen mode

Following that, we need to add it to the imports array within @NgModule.

imports: [BrowserModule, ReactiveFormsModule],
Enter fullscreen mode Exit fullscreen mode

Step 1: The Initial Element in the Template

A standard input element within Angular forms might appear like this:

<div>
  <label for="email">Email</label>
  <input type="email" id="email" [formControl]="email" />
</div>
Enter fullscreen mode Exit fullscreen mode

This is completely standard HTML, with one key exception: [formControl]=”email".

That specific binding is made possible by the FormControlDirective, a directive that originates from the ReactiveFormsModule we imported.

Step 2: Instantiating the Control in the Class

Once FormControl is imported, we are able to create a new instance and assign it to email. According to angular.io, a FormControl "Tracks the value and validation status of an individual form control."

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
...
export class ReactiveFormComponent {
  email = new FormControl('');
}
Enter fullscreen mode Exit fullscreen mode

Here, we are using new FormControl('') to give the email control an initial value of an empty string.

The FormControl instance gives you the ability to track, modify, and perform validation on the underlying form element.

And with that, your first control is created.

Scaling Up: From One Element to a Complete Form

Using that basic element as a foundation, we can build out the following form structure:

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
...
reactiveForm = new FormGroup({
    name: new FormControl(''),
    email: new FormControl(''),
    age: new FormControl(''),
});
Enter fullscreen mode Exit fullscreen mode

Remember that in each component file where you want to instantiate a FormGroup, the import from @angular/forms is required.

A FormGroup instance has been created in the class. As per angular.io, a FormGroup "Tracks the value and validity state of a group of FormControl instances."

Property binding is the mechanism we employ to connect this FormGroup model to the template's view.

When working with forms, it's often more convenient to manage the state of the entire form at once, rather than managing individual fields. This is the same desire we have with template-driven forms.

.

The First Distinction

Looking at the form tag reveals the initial key difference from template-driven forms: there is no reference variable in use.

The Second Distinction

The use of formControlName marks another key difference.

According to angular.io, "The formControlName input provided by the FormControlName directive binds each individual input to the form control defined in FormGroup."

Nevertheless, the source of truth for the model's value resides within the form group instance.

The Third Distinction

A third notable change is that the name attribute is no longer necessary on input tags.

A Brief Wrap-Up

To recap, Angular supports two principal methods for form creation. We have concentrated on the reactive method here.

It's worth reiterating that a common Forms API underpins both strategies.

  1. Add ReactiveFormsModule to your app.module.ts imports
  2. Create a control instance with new FormControl()
  3. Create a group of controls with new FormGroup()
  4. Connect the class's FormGroup to the view by binding it with [FormGroup]="myFormGroupName"
  5. After the ReactiveFormsModule import, the form tag will automatically implement NgForm

You can explore the code on GitHub or check out the original article on Medium (free) if you'd like to see more.