Skip to main content

Reactive Forms

Reactive Forms are a more programmatic way of defining forms. Therefore, they provide more control and flexibility.

Reactive Forms start with pure TypeScript.

import { FormControl } from '@angular/forms';

@Component(...)
class RecipeForm {
protected readonly titleCtrl = new FormControl<string | null>(null);
}

1. Create a FormControlโ€‹

The FormControl has all sorts of methods and properties that allow you to interact with it. Here are some examples:

class FormControl<T> {
setValue(value: T): void;
value: T;
valueChanges: Observable<T>;
valid: boolean;
dirty: boolean;
...
}

You can then bind the titleCtrl to the UI with formControl directive.

import { FormControl, ReactiveFormsModule } from '@angular/forms';

@Component({
...
imports: [ReactiveFormsModule],
template: `
<form>
<input type="text" [formControl]="titleCtrl" />
</form>
`
})
class RecipeForm {
protected readonly titleCtrl = new FormControl<string | null>(null);
}

2. Things become more interesting with FormGroup (and friends)โ€‹

You can group multiple FormControls together into a FormGroup.

Form controls are flexible

It is even possible to nest FormGroups inside each other and create dynamic forms.

import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';

@Component({
...
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="recipeForm">
<input type="text" formControlName="title" />
<input type="text" formControlName="description" />
</form>
`
})
class RecipeForm {
protected readonly recipeForm = new FormGroup({
title: new FormControl<string | null>(null),
description: new FormControl<string | null>(null),
});
}

3. Add a submit event listenerโ€‹

import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';

@Component({
...
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="recipeForm" (ngSubmit)="createRecipe()">
<input type="text" formControlName="title" />
<input type="text" formControlName="description" />
</form>
`
})
class RecipeForm {
protected readonly recipeForm = new FormGroup({
title: new FormControl<string | null>(null),
description: new FormControl<string | null>(null),
});

createRecipe() {
console.log(this.recipeForm.value);
// ^ { title: 'Babaganoush', description: 'Smoky eggplant dip.' }

this.recipeForm.reset();
}
}
Prefer ngSubmit to submit

While things might seem to work well with submit event, it is better to use ngSubmit as they are not triggered exactly at the same time.
Angular listens to submit events and triggers the ngSubmit after doing some important internal work such as updating the model.

Additional Resourcesโ€‹

Pragmatic Angular Testing
๐Ÿ‘จ๐Ÿปโ€๐Ÿณ Let's cook some tests โ†’

๐Ÿ’ฐ 80โ‚ฌ ยท 170โ‚ฌ ยท Lifetime access

Learn how to write reliable tests that survive upgrades and refactorings.