1. Declare the model
Start with a component-owned form tree. field() creates leaf values and form() infers their combined object shape.
import { Component } from '@angular/core';
import { field, FormNodeDirective, form } from '@ngblocks/form-nodes';
@Component({
selector: 'app-profile-editor',
imports: [FormNodeDirective],
template: `
<label>
Name
<input [formNode]="form.name" />
</label>
<p>Current name: {{ form.name() }}</p>
`,
})
export class ProfileEditor {
form = form({
name: field(''),
age: field<number>(null),
email: field(''),
});
}
Fields infer nullability from their initial value. Use field.nullable('') when null is allowed;
this adds null to the inferred string type. See Field nullability.
For the declaration above, the inferred value is equivalent to:
type ProfileValue = {
name: string;
age: number | null;
email: string;
};
You do not need to maintain that interface separately. TypeScript derives it from the declaration.
Start from fields and let form() derive the aggregate type. Add an explicit domain type only
where it communicates a boundary or constrains a nullable/union value more precisely.
📝 Read and update values
Call nodes directly to read their committed values:
this.form(); // { name: '', age: null, email: '' }
this.form.name(); // ''
this.form.age(); // null
Use methods directly on fields and forms:
this.form.name.set('Ada');
this.form.age.update(age => (age ?? 0) + 1);
this.form.patch({
email: 'ada@example.com',
});
The model itself also works outside Angular and does not require dependency injection. The first field is already connected to a native input; next, bind the remaining fields and examine the control interaction behavior.
🔗 Related guides and reference
- Creating nodes covers every
field(),form(), nested-object, andarray()declaration shape. - Values and state explains callable values,
set(),update(),patch(), andreset(). field()reference documents nullability, options, state, and validation.form()reference documents aggregate values, children, and operations.
Continue with Step 2: Bind controls.