The Forms System provides infrastructure for creating and managing forms in Angular applications. It handles user input, validation, state tracking, and synchronization between TypeScript models and HTML form elements. Angular offers three primary approaches:
This document covers the high-level architecture and how these systems relate. For deep dives, see the child pages.
The forms system is built on a shared foundation of control abstractions and value accessors that bridge the gap between the framework and the DOM.
The following diagram maps high-level form concepts to their specific implementation classes and runtime instructions.
Sources: packages/forms/src/model/abstract_model.ts25-109 packages/forms/signals/src/api/structure.ts51-172 packages/core/src/render3/instructions/control.ts41-88
In traditional forms, AbstractControl is the base class for form controls, groups, and arrays packages/forms/src/model/abstract_model.ts25-109 It tracks:
VALID, INVALID, PENDING, or DISABLED packages/forms/src/model/abstract_model.ts44-86pristine/dirty and touched/untouched status, with corresponding change events packages/forms/src/model/abstract_model.ts119-147Observable emitting detailed events (e.g., ValueChangeEvent, StatusChangeEvent) packages/forms/src/model/abstract_model.ts93-163This hierarchy underpins both template-driven and reactive forms and provides the integration point for form rendering and validation.
For details on the control hierarchy and rendering model, see Forms Architecture.
The new signal-based forms introduce the FieldState interface and FieldNode class, exposing form data and metadata as signals instead of Observables packages/forms/signals/src/field/node.ts73-202 packages/forms/signals/src/api/types.ts130-192
Key characteristics:
value property is a WritableSignal<unknown>, allowing reactive reads and writes with fine-grained change detection packages/forms/signals/src/field/node.ts163-165valid, invalid, pending represent the validation status derived from an internal ValidationState packages/forms/signals/src/field/validation.ts150-173dirty, touched, errors, and more, for up-to-date UI feedback packages/forms/signals/src/field/node.ts195-201Navigation of the form tree uses a dynamic Proxy (the fieldProxy), enabling intuitive property reads to access nested fields (e.g., myForm.user.email()) packages/forms/signals/src/field/node.ts88-91
| Feature | Template-Driven | Reactive | Signal Forms (Experimental) |
|---|---|---|---|
| Model Creation | Implicit (Directives) | Explicit (TypeScript) | Explicit (Signals function) |
| Data Flow | Asynchronous | Observable streams | Fine-grained reactive signals |
| Validation | Directive-based | Validator functions | Schema-based logic and rules |
| Type Safety | Low | Improved (since v14) | High (via type inference) |
| Integration Complexity | Low | Medium | New but growing ecosystem |
This is ideal for simple forms, relying on directives like NgForm and NgModel to implicitly create and manage form controls in templates. It suits developers who prefer minimal explicit form model code.
For details, see Template-Driven Forms.
Reactive Forms define the form model explicitly using FormControl, FormGroup, and FormBuilder packages/forms/src/model/form_group.ts1-50
Signal Forms represent a new paradigm. They wrap a reactive data model with the form() function, use schemas to define validation and logic declaratively, and expose the entire form tree as reactive signals packages/forms/signals/src/api/structure.ts51-172 Signal Forms support advanced features like:
debounce, disabled, hidden schema rules for form logic control packages/forms/signals/src/api/types.ts97-105
Async validation using Resource factories goldens/public-api/forms/signals/index.api.md47-54
A compatibility layer (CompatFieldState) enables interoperation with traditional AbstractControl-based components goldens/public-api/forms/signals/index.api.md70-73
For details, see Reactive Forms and Signal Forms.
The Angular rendering engine integrates forms through specific instructions that initialize and update form controls at runtime:
ɵɵcontrolCreate() is called during the creation pass to initialize control directives and their bindings.
ɵɵcontrolUpdate() is called to keep the control state in sync during change detection cycles.
These APIs handle conditionally setting up native or custom form controls, and interact with ControlValueAccessor implementations to manage data flow between form controls and UI elements packages/core/src/render3/instructions/control.ts41-89
This illustrates how Angular's runtime instructions bridge the conceptual form model with the DOM and control bindings.
Sources: packages/core/src/render3/instructions/control.ts1-88 packages/forms/src/model/abstract_model.ts1-100
Validation is handled declaratively using schemas and logic nodes that attach rules to parts of the form tree goldens/public-api/forms/signals/index.api.md117-129
Validation Results: Validation errors conform to types that may specify which field tree node they belong to, enabling targeted feedback packages/forms/signals/src/api/types.ts138-185
Async Validation: Validator factories produce resources representing asynchronous validation state goldens/public-api/forms/signals/index.api.md47-54 packages/forms/signals/src/api/types.ts180-190
Metadata Keys: Developers can create and attach custom metadata keys to fields for UI state and other purposes using createMetadataKey functions goldens/public-api/forms/signals/index.api.md85-94
Validation state is aggregated inside FieldValidationState, tracking synchronous and asynchronous errors, pending states, and combined validity status packages/forms/signals/src/field/validation.ts150-173
The Angular Forms System offers multiple form development strategies optimized for different scenarios:
These approaches share a common runtime foundation enabling maintenance of state, validation, and synchronization with the DOM, backed by carefully designed abstractions and infrastructure.
For comprehensive technical details, visit the following child pages:
Sources: Combined from all cited files above.
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.