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.
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';
Following that, we need to add it to the imports array within @NgModule.
imports: [BrowserModule, ReactiveFormsModule],
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>
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('');
}
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(''),
});
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.
- Add
ReactiveFormsModuleto yourapp.module.tsimports - Create a control instance with
new FormControl() - Create a group of controls with
new FormGroup() - Connect the class's
FormGroupto the view by binding it with[FormGroup]="myFormGroupName" - After the
ReactiveFormsModuleimport, theformtag will automatically implementNgForm
You can explore the code on GitHub or check out the original article on Medium (free) if you'd like to see more.

