Angular offers two approaches to handling forms. Template-driven forms use directives like ngModel in the template and are simpler for basic forms, while reactive forms use FormGroup and FormControl in the component class, offering more control, easier testing, and better handling of dynamic or complex forms. Reactive forms require importing ReactiveFormsModule. A reactive form is created by instantiating a FormGroup that contains FormControl instances, each with a default value and an optional array of Validators. The form is bound in the template with [formGroup] and individual inputs with formControlName.
FormBuilder is an injectable service that provides shorthand syntax for creating FormGroup, FormControl, and FormArray instances, using array notation to specify initial values and validators. Since Angular 14, FormBuilder.nonNullable produces typed, non-nullable controls where initial values are required and reset() restores them. FormArray manages a dynamic list of FormControls or FormGroups, useful for repeating form sections whose count changes, with methods like push() and removeAt(). FormRecord is similar to FormGroup but supports dynamic keys, useful when the field set is not known at compile time. Typed reactive forms infer control types automatically, so this.form.controls.name.value is correctly typed as string rather than any, with FormControl<string | null> for nullable cases.
Validators can be composed in arrays and applied to controls, and errors from all validators are aggregated on the control's errors property. Cross-field validators receive the full AbstractControl (typically a FormGroup) and validate across fields, for example checking that password and confirm match. Async validators return an Observable or Promise that resolves to validation errors, ideal for server-side checks like unique email validation; call updateValueAndValidity() to re-run them. The updateOn option changes when a control's value is updated and validated, with options of 'change' (the default), 'blur', or 'submit'. Reactive forms track control state with flags: markAsDirty and markAsPristine for user-interaction tracking, and markAsTouched and markAsUntouched for focus tracking, both used to control when error messages appear. valueChanges emits the new value whenever the form value changes, while statusChanges emits the new VALID, INVALID, PENDING, or DISABLED status when validation state changes.