Skip to content

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.

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
└── country

When 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

A common pattern throughout this library is:

Domain Model
Structure Wrapper
Form Model

Instead 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<T> represents optional object structures.

Instead of:

invoiceRecipient: InvoiceRecipient | null

the 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.

invoiceRecipient.meta.enabled = false;

The form section still exists structurally, but can be treated as absent when mapped back to the domain model.

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.

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.