Skip to main content
Angular provides two approaches to handling user input through forms: reactive forms and template-driven forms. Both approaches capture user input events from the view, validate the input, create a form model and data model to update, and provide a way to track changes.

Choosing an Approach

Reactive Forms

Provide direct, explicit access to the underlying form object model. More robust, scalable, reusable, and testable.

Template-Driven Forms

Rely on directives in the template to create and manipulate the underlying object model. Useful for simple forms.

Key Differences

FeatureReactiveTemplate-driven
Form model setupExplicit, created in component classImplicit, created by directives
Data modelStructured and immutableUnstructured and mutable
Data flowSynchronousAsynchronous
Form validationFunctionsDirectives

Common Building Blocks

Both approaches share underlying building blocks:

FormControl

Tracks the value and validation status of an individual form control.
packages/forms/src/model/form_control.ts
const control = new FormControl('initial value');
console.log(control.value); // 'initial value'

FormGroup

Tracks the value and validity state of a group of FormControl instances.
packages/forms/src/model/form_group.ts
const form = new FormGroup({
  firstName: new FormControl('Nancy'),
  lastName: new FormControl('Drew')
});
console.log(form.value); // {firstName: 'Nancy', lastName: 'Drew'}

FormArray

Tracks the value and validity state of an array of FormControl, FormGroup, or FormArray instances.
packages/forms/src/model/form_array.ts
const arr = new FormArray([
  new FormControl('Nancy'),
  new FormControl('Drew')
]);
console.log(arr.value); // ['Nancy', 'Drew']

Form State Properties

All form controls track state that helps you understand the user interaction:
  • value: The current value of the control
  • valueChanges: Observable that emits every time the value changes
  • valid: Whether the control passes all validators
  • invalid: Whether the control fails any validators
  • errors: Object containing validation errors, or null
  • statusChanges: Observable that emits status changes
  • pristine: User has not changed the value (opposite of dirty)
  • dirty: User has changed the value
  • untouched: User has not visited the control (opposite of touched)
  • touched: User has visited the control (blur event)
  • disabled: Control is disabled and excluded from validation
  • enabled: Control is enabled

FormBuilder

The FormBuilder service provides syntactic sugar to reduce boilerplate:
packages/forms/src/form_builder.ts
import { FormBuilder } from '@angular/forms';

const fb = new FormBuilder();
const form = fb.group({
  firstName: ['Nancy'],
  lastName: ['Drew'],
  address: fb.group({
    street: [''],
    city: [''],
    state: [''],
    zip: ['']
  })
});

Data Flow

1

View to Model

User types into an input element. The input element emits an “input” event with the latest value.
2

Control Value Accessor

The ControlValueAccessor listening for events on the form input element immediately relays the new value to the FormControl instance.
3

Value Changes

The FormControl instance emits the new value through the valueChanges observable.
4

Model to View

When the component updates the FormControl value, the change flows through the ControlValueAccessor to the native form element.

Next Steps

Reactive Forms

Learn about explicit form control with reactive forms

Template-Driven Forms

Learn about template-driven forms with ngModel

Form Validation

Add validation to your forms