A lot of my existing Angular code using template-driven forms looks something like this:
Component (*.ts):
protected person: Person;
Template (*.html):
<input type="text" [(ngModel)]="person.firstName">
<input type="text" [(ngModel)]="person.lastName">
Now let's say I'd like to make such an application ready for zoneless Angular. The obvious approach would be using signals. However, the following does not work, as signals are supposed to be immutable:
Component (*.ts):
protected person = model<Person>({ firstName: '', lastName: '' });
Template (*.html):
<input type="text" [(ngModel)]="person().firstName">
<input type="text" [(ngModel)]="person().lastName">
Question:
What's the best practice with modern Angular to bind a form to an object in such a way that it will be compatible with zoneless change detection?
Signals for forms is a part of the Angular Roadmap this will be the ultimate solution to this scenario. But we have to wait for that to happen.
Signal Forms
We plan to analyze existing feedback about Angular forms and design a solution which addresses developers' requirements and uses Signals for management of reactive state.
You cannot directly bind the values (since that can be done only for the model
and not the inner values), but you can set a (ngModelChange)
that will update the inner property using update
and then use Object Destructuring
so that a new memory reference is created and the signal detects it as a change.
<input type="text" [ngModel]="person().firstName" (ngModelChange)="updateProp($event, 'firstName')">
<input type="text" [ngModel]="person().lastName" (ngModelChange)="updateProp($event, 'lastName')">
The TS Code will look like:
updateProp(value: any, propName: string) {
this.person.update((prevPerson: Person) => ({
[propName]: value,
...prevPerson,
});
}
There are other solutions using effect
or linkedSignal
, but they involve setting up individual properties and a lot of extra initialization code, so I am recommending this approach.