Open
Description
When using complex forms in Angular, it could be convenient to handle the form management with a dedicated store feature.
Some commons scenarios where adding a withForm() feature to a signal store could be useful:
- cross-controls management: updating a form control on a change on another control. Using a store computed method seems relevant to handle the form update business logic.
- form processing management: after computed changes has been applied to the form, calling a store method to process the form (i.e. calling a service).
- form controls value as a signal: accessing to a store state representing the form controls values as a signal. Could be used to create new computed values or when processing the form.
- Combined with the
withSync()
feature to the form state could be saved in the localStorage
To connect the form to the store, a dedicated form directive should be used.
The approach could look like this:
In template, using the appSignalStoreForm
directive :
<div [formGroup]="myForm" appSignalStoreForm [store]="myStore" formFeatureName="mySearch">
<select formControlName="period">...</select>
<input formControlName="from">
<input formControlName="to">
...
</div>
In the component, nothing required except the store:
export class SearchComponent {
readonly myStore = inject(MyStore);
...
}
In the store, declaring the withForm
feature and the required computed
and method
:
export const MyStore = signalStore(
withForm('mySearch'),
withComputed(({ mySearchFormState }) => {
return {
// method called by the form directive to compute changes on form changes
mySearchFormComputedChanges: computed<ControlChange[]>(() => {
const changes: ControlChange[] = [];
// here is the business logic to update the form as a side effect
if (mySearchFormState().controlsMarkedAsChanged.some((control) => control === 'period')) {
if (mySearchFormState().value.period === 'current') {
changes.push({ controlName: 'from', operation: new SetValue(now()) });
...
}
}
// the list of changes the form directive will apply on the form
return changes;
}),
};
}),
withMethods((store) => ({
// method called by the directive after changes applied
handleMySearchForm() {
// using the form values representation to do something
search(store.mySearchFormState().value?.from, store.mySearchFormState().value?.to);
}
}))
Let me know if you think this is feature could be relevant for the project.