Template-Driven Forms
Relevant source files
- goldens/public-api/forms/index.api.md
- packages/compiler/src/typecheck/ops/signal_forms.ts
- packages/forms/signals/src/controls/interop_ng_control.ts
- packages/forms/signals/src/directive/control_custom.ts
- packages/forms/signals/src/directive/control_cva.ts
- packages/forms/signals/src/directive/control_native.ts
- packages/forms/signals/src/directive/form_field.ts
- packages/forms/signals/src/directive/input_validity_monitor.ts
- packages/forms/signals/src/directive/native.ts
- packages/forms/signals/test/web/form_field.spec.ts
- packages/forms/signals/test/web/input_validity_monitor.spec.ts
- packages/forms/signals/test/web/interop.spec.ts
- packages/forms/signals/test/web/number_input.spec.ts
- packages/forms/signals/test/web/test_input_validity_monitor.ts
- packages/forms/src/directives.ts
- packages/forms/src/directives/abstract_control_directive.ts
- packages/forms/src/directives/native.ts
- packages/forms/src/directives/ng_control.ts
- packages/forms/src/directives/ng_control_status.ts
- packages/forms/src/directives/ng_form.ts
- packages/forms/src/directives/ng_model.ts
- packages/forms/src/directives/reactive_directives/abstract_form.directive.ts
- packages/forms/src/directives/reactive_directives/form_control_directive.ts
- packages/forms/src/directives/reactive_directives/form_control_name.ts
- packages/forms/src/directives/reactive_directives/form_group_directive.ts
- packages/forms/src/directives/reactive_directives/form_group_name.ts
- packages/forms/src/directives/reactive_errors.ts
- packages/forms/src/directives/shared.ts
- packages/forms/src/directives/validators.ts
- packages/forms/src/form_builder.ts
- packages/forms/src/forms.ts
- packages/forms/src/model/abstract_model.ts
- packages/forms/src/model/form_array.ts
- packages/forms/src/model/form_control.ts
- packages/forms/src/model/form_group.ts
- packages/forms/src/validators.ts
- packages/forms/test/BUILD.bazel
- packages/forms/test/directives_spec.ts
- packages/forms/test/form_array_spec.ts
- packages/forms/test/form_builder_spec.ts
- packages/forms/test/form_control_spec.ts
- packages/forms/test/form_group_spec.ts
- packages/forms/test/reactive_integration_spec.ts
- packages/forms/test/template_integration_spec.ts
- packages/forms/test/typed_integration_spec.ts
- packages/forms/test/util.ts
- packages/forms/test/validators_spec.ts
- packages/forms/test/value_accessor_integration_spec.ts
Purpose and Scope
This document describes Angular's template-driven forms system, which provides a declarative approach to building forms using directives in templates. Template-driven forms automatically create FormControl and FormGroup instances behind the scenes based on template directives, contrasting with the explicit model creation in reactive forms.
This page focuses on the directives and mechanisms specific to template-driven forms: NgForm, NgModel, NgModelGroup, and their interaction with control value accessors and validators. For the underlying form control architecture shared by both approaches, see 8.1 Forms Architecture For reactive forms and signal-based forms, see 8.3 Reactive Forms and Signal Forms
System Architecture
Template-driven forms operate through a set of directives that detect form elements in templates and automatically instantiate form control objects. The system builds a model-driven structure implicitly from the template markup.
Template to Model Mapping
Sources: packages/forms/src/directives/ng_form.ts1-20 packages/forms/src/directives/ng_model.ts1-20 packages/forms/src/directives/ng_model_group.ts1-20
NgForm Directive
The NgForm directive is the cornerstone of template-driven forms. It automatically attaches to <form> elements and creates a FormGroup instance to manage all controls within the form.
Automatic Form Detection and Provider Chain
The NgForm directive has a selector that matches both form tags and ngForm attributes packages/forms/src/directives/ng_form.ts68 When Angular encounters a <form> tag, it automatically creates an NgForm directive instance unless the form has the ngNoForm attribute or is already bound to a formGroup packages/forms/src/directives/ng_form.ts68
Key responsibilities:
- Creates and manages the root
FormGroupinstance packages/forms/src/directives/ng_form.ts114 - Provides itself as a
ControlContainerto child directives packages/forms/src/directives/ng_form.ts71 - Handles form submission events and prevents default browser behavior packages/forms/src/directives/ng_form.ts197-202
- Exposes form-level status via the
AbstractControlhierarchy packages/forms/src/model/abstract_model.ts95-108
Sources: packages/forms/src/directives/ng_form.ts68-210 packages/forms/src/model/form_group.ts188-205
NgModel Directive
The NgModel directive creates a FormControl instance for individual form fields and establishes two-way data binding between the form control and a component property.
Implicit Control Creation Lifecycle
Control Registration Requirements
- name attribute is required: When used within a form, the
nameattribute defines the key in the parentFormGrouppackages/forms/src/directives/ng_model.ts153 - Parent ControlContainer:
NgModellooks for a parentControlContainer(likeNgForm) to register its control packages/forms/src/directives/ng_model.ts241 - ControlValueAccessor:
NgModelusesselectValueAccessorto find the appropriate bridge to the DOM packages/forms/src/directives/shared.ts112
Sources: packages/forms/src/directives/ng_model.ts137-250 packages/forms/src/directives/shared.ts100-120
NgModelGroup Directive
The NgModelGroup directive creates nested FormGroup instances within the parent form, allowing hierarchical organization of form controls.
NgModelGroup extends AbstractFormGroupDirective and provides a new ControlContainer scope for all its children packages/forms/src/directives/ng_model_group.ts74 This allows nested data structures in the final form value packages/forms/src/model/form_group.ts58-68
Sources: packages/forms/src/directives/ng_model_group.ts70-85 packages/forms/src/model/form_group.ts188-195
Control Value Accessors (CVA)
Control Value Accessors bridge the gap between form controls (model) and native DOM elements (view). Template-driven forms automatically select the appropriate value accessor.
Built-in Accessors and Selection
Value Synchronization Flow
Sources: packages/forms/src/directives/control_value_accessor.ts15-45 packages/forms/src/directives/shared.ts100-130
Validation in Template-Driven Forms
Validation is applied via directives that provide themselves through the NG_VALIDATORS or NG_ASYNC_VALIDATORS multi-provider tokens packages/forms/src/directives/validators.ts40-45
Validator Composition
Common Validator Directives:
RequiredValidator: Checks for non-empty values packages/forms/src/directives/validators.ts120MinLengthValidator: Checks minimum string/array length packages/forms/src/directives/validators.ts250EmailValidator: Validates email format packages/forms/src/directives/validators.ts500
Sources: packages/forms/src/directives/validators.ts100-600 packages/forms/src/validators.ts20-50
Form State and Events
AbstractControl tracks state and emits events that template-driven forms expose to the UI.
Control Status and CSS Classes
The NgControlStatus directive automatically applies CSS classes to elements based on the underlying control's state packages/forms/src/directives/ng_control_status.ts38:
.ng-valid/.ng-invalidpackages/forms/src/model/abstract_model.ts44-51.ng-pristine/.ng-dirtypackages/forms/src/model/abstract_model.ts124-131.ng-touched/.ng-untouchedpackages/forms/src/model/abstract_model.ts140-147
Event Streams
Controls expose observables for tracking changes:
valueChanges: EmitsValueChangeEventwhen the value is updated packages/forms/src/model/abstract_model.ts109statusChanges: EmitsStatusChangeEventwhen validity changes packages/forms/src/model/abstract_model.ts156-163events: A unified stream of allControlEventtypes (Submit, Reset, Value, Status) packages/forms/src/model/abstract_model.ts45
Sources: packages/forms/src/model/abstract_model.ts40-188 packages/forms/src/directives/ng_control_status.ts30-60
Refresh this wiki
On this page
- Template-Driven Forms
- Purpose and Scope
- System Architecture
- Template to Model Mapping
- NgForm Directive
- Automatic Form Detection and Provider Chain
- NgModel Directive
- Implicit Control Creation Lifecycle
- Control Registration Requirements
- NgModelGroup Directive
- Control Value Accessors (CVA)
- Built-in Accessors and Selection
- Value Synchronization Flow
- Validation in Template-Driven Forms
- Validator Composition
- Form State and Events
- Control Status and CSS Classes
- Event Streams
