Forms
Template-driven forms (Chapter 8) put the form's structure in the HTML, with Angular inferring the model behind the scenes. Reactive forms invert that: the form is defined explicitly in the component class as an object you build and control directly, with the template just connecting to it. More setup, but the form becomes a real, inspectable, programmatically-controllable object — the better fit for complex forms, dynamic fields, and custom validation.
Building a FormGroup
A FormGroup is the whole form; each field is a FormControl with its initial value and an array of validators. Crucially, this entire structure is a plain object in the class — readable and writable from code. The validators come from Validators (required, email, minLength(8), pattern(...)) rather than being template attributes, and uses ReactiveFormsModule instead of FormsModule.
Connecting the Template
[formGroup]="loginForm" binds the template's form to the object built in the class, and each input declares which control it represents with formControlName="email". Notice there's no [(ngModel)] anywhere — the form object is the single source of truth, and the inputs simply attach to its existing controls by name. loginForm.invalid works exactly as before for the submit button.
FormBuilder — Less Boilerplate
FormBuilder — injected as a service (Chapter 6) — is a shorthand for building the same structure with less new FormGroup/new FormControl repetition: each field becomes a terse [initialValue, validators] array. It produces an identical FormGroup; it's purely the more concise and conventional way to write one, and what most real reactive-forms code uses.
Reacting to Value Changes
Every control (and the form itself) exposes a valueChanges Observable that emits each time its value changes — the core reason these are called reactive forms. This is what makes things like live-filtering, dependent fields, or debounced validation natural, in a way template-driven forms can't match cleanly. Observables are covered properly in Chapter 11; this is a first glimpse of why reactive forms unlock so much.
Programmatic Control
Because the form is a real object, it can be manipulated from code — setValue/patchValue to fill it (e.g. loading an existing record into an edit form), reset() to clear it. This programmatic control is the practical payoff of reactive forms, and the main reason they're preferred for anything beyond a simple contact form.
[(ngModel)] + FormsModule) or entirely reactive (formControlName + ReactiveFormsModule) — mixing [(ngModel)] and formControlName on controls within the same form causes confusing conflicts. Pick one approach per form: template-driven for simple cases, reactive when the extra control is genuinely needed.
| Template-driven (Ch 8) | Reactive (Ch 9) | |
|---|---|---|
| Form defined in | The template (HTML) | The component class |
| Module | FormsModule | ReactiveFormsModule |
| Binding | [(ngModel)] | formControlName |
| Validators | Template attributes | Validators in the class |
| Best for | Simple forms | Complex/dynamic forms, programmatic control |
Coding Challenges
Rebuild Chapter 8's signup form (name + email, both required, email validated) as a reactive form using FormGroup/FormControl, logging the form's value on submit and disabling the button while invalid.
📄 View solutionRewrite the same form using FormBuilder (fb.group) instead of new FormGroup/new FormControl, and add per-field validation messages reading each control's errors and touched state.
📄 View solutionBuild a reactive form with a "Fill demo data" button (using patchValue) and a "Reset" button (using reset()), plus subscribe to one field's valueChanges to log its value live as the user types.
📄 View solutionChapter 9 Quick Reference
- Reactive forms define the form in the class; require ReactiveFormsModule
- FormGroup = the whole form; FormControl = one field (initial value + validators)
- Template connects with [formGroup] and formControlName — no
ngModel - Validators (required/email/minLength/pattern) come from the class, not template attributes
- FormBuilder (
fb.group({...})) — the concise, conventional way to build the same structure - valueChanges Observable, plus setValue/patchValue/reset — programmatic power over the form
- Never mix
ngModelandformControlNameon the same form - Next chapter: routing — RouterModule, route params, and guards