Reactive forms build the entire form structure explicitly in TypeScript, then bind a template to it. This lesson covers FormGroup, FormControl, FormArray, and FormBuilder in depth.
How Reactive Forms Work
In reactive forms, you construct a tree of FormControl and FormGroup (or FormArray) instances directly in the component class, defining values and validators explicitly, then bind the template to that structure using directives like formGroup and formControlName.
Because the form's structure and validation logic live in plain TypeScript, reactive forms are straightforward to unit test without rendering any HTML at all.
FormBuilder.group() creates a FormGroup; each key maps to a FormControl, nested FormGroup, or FormArray.
[formGroup] on the <form> element binds the whole group; formControlName binds an individual field.
formGroupName binds a nested group; formArrayName binds a nested array of controls.
Values can be a plain default, or a two-element array [defaultValue, validators].
Reactive Forms Cheatsheet
The classes and directives you'll use to build and bind reactive forms.
API
Example
Purpose
FormControl
new FormControl('')
A single form field
FormGroup
new FormGroup({ name: ... })
A named collection of controls
FormArray
new FormArray([...])
A dynamic list of controls
FormBuilder
inject(FormBuilder)
Shorthand for building the structures above
[formGroup]
<form [formGroup]="form">
Bind the whole group to a form element
formControlName
<input formControlName="email">
Bind one control by key
formGroupName
<div formGroupName="address">
Bind a nested group by key
formArrayName
<div formArrayName="tags">
Bind a nested array by key
form.value
this.form.value
Current value of the whole group
form.valueChanges
this.form.valueChanges.subscribe(...)
Observable stream of value changes
Dynamic Fields With FormArray
FormArray manages a dynamic, variable-length list of controls, ideal for scenarios like "add another phone number" where the number of fields isn't known in advance.
form = this.fb.group({
phones: this.fb.array([this.fb.control('')]),
});
get phones() {
return this.form.get('phones') as FormArray;
}
addPhone() {
this.phones.push(this.fb.control(''));
}
<div formArrayName="phones">
@for (phone of phones.controls; track $index) {
<input [formControlName]="$index" />
}
</div>
<button type="button" (click)="addPhone()">Add Phone</button>
Reacting to Value Changes
Because reactive forms are built on Observables, valueChanges and statusChanges let you react to user input reactively, useful for live previews, conditional fields, or debounced search-as-you-type inputs.
Reactive forms give you precise, code-first control over updating values: setValue requires every key, patchValue allows partial updates, and reset clears the form back to its initial (or a given) state.
this.form.setValue({ email: 'a@b.com' }); // must match structure exactly
this.form.patchValue({ email: 'a@b.com' }); // partial update, other fields untouched
this.form.reset(); // clears back to initial state
Common Mistakes
Forgetting to import ReactiveFormsModule in a standalone component that uses formGroup/formControlName.
Using setValue when only updating one field, patchValue is usually what you want for partial updates.
Not unsubscribing from valueChanges subscriptions when a component using them is destroyed.
Rebuilding the entire FormGroup structure unnecessarily instead of using patchValue/reset to update existing controls.
Key Takeaways
Reactive forms build FormControl/FormGroup/FormArray structures explicitly in TypeScript.
FormBuilder is a convenient shorthand for constructing these structures.
formGroup, formControlName, formGroupName, and formArrayName bind the template to the form structure.
valueChanges and statusChanges expose the form as Observables for reactive UI updates.
Pro Tip
For forms with many fields, define a typed interface for the form's shape and use Angular's typed forms (FormGroup<MyFormShape>) so form.value and form.get() calls are fully type-checked at compile time.
You now understand reactive forms in depth. Next, focus specifically on Form Validation, applying and combining validators effectively.