Structure Wrappers
Angular Signal Forms work best when every relevant part of the form tree is represented by a stable node.
Most domain models naturally fit this structure:
interface Address { street: string; city: string;}However, some common domain concepts do not map naturally to a form tree.
Examples include:
- Optional nested objects
- Dynamic form sections
- Collections that require their own metadata
- Structures that need form-specific state
To address these scenarios, ngx-signal-schema provides Structure Wrappers.
Structure wrappers transform domain types into form-friendly representations without changing their business meaning.
The Problem
Section titled “The Problem”Consider an optional invoice recipient:
interface Order { invoiceRecipient: InvoiceRecipient | null;}From a domain perspective, this is perfectly valid.
However, a form faces a challenge:
invoiceRecipient├── street├── city└── countryWhen the value becomes null, the entire subtree disappears.
This makes it difficult to:
- apply rules
- manage visibility
- enable or disable sections
- attach metadata
- build predictable form structures
Stable Form Trees
Section titled “Stable Form Trees”A common pattern throughout this library is:
Domain Model ↓Structure Wrapper ↓Form ModelInstead of removing parts of the form tree entirely, structure wrappers keep a stable node and move the optionality or collection behavior into the wrapper itself.
This allows Angular Signal Forms to operate on a predictable structure.
OptionalBlock
Section titled “OptionalBlock”OptionalBlock<T> represents optional object structures.
Instead of:
invoiceRecipient: InvoiceRecipient | nullthe form model becomes:
invoiceRecipient: OptionalBlock<InvoiceRecipient>Conceptually:
{ meta: { enabled: boolean; };
data: InvoiceRecipient;}The object tree always exists.
Whether the value should be considered present is controlled by the wrapper metadata.
This makes it possible to:
- show and hide sections
- enable and disable sections
- apply validators
- keep a stable form structure
without constantly creating and removing subtrees.
Example
Section titled “Example”invoiceRecipient.meta.enabled = false;The form section still exists structurally, but can be treated as absent when mapped back to the domain model.
When to Use Structure Wrappers
Section titled “When to Use Structure Wrappers”Structure wrappers are useful when:
- object trees are optional (
OptionalBlock) - form sections appear and disappear dynamically
- metadata must exist alongside domain data
- stable form structures are preferred over constantly changing trees
For simple forms and flat data structures, they are usually unnecessary.
Design Principle
Section titled “Design Principle”Structure wrappers follow a simple idea:
Keep the form tree stable.Move structural behavior into explicit wrapper types.This makes complex forms easier to compose, validate and maintain while preserving the intent of the original domain model.