Reputation: 892
I've been struggling for a few days to find a good pattern for my use case. I have a very complex reactive form, full of nested components, some fields are required, some fields may appear given certain conditions, etc... and this is creating a huge problem maintaining the code. The approach I used so far it passing the formControl to the children components and populate from there, but things started getting really hard to debug given the size of the form. A must for this form is that on submit of the whole form, a validation of all the nested fields is performed, and markAsTouched any field that is required but hasn't been inserted. I have been exploring 2 approaches but none of the 2 seems to be of any help:
I wonder if anyone has any experience with such forms and able to provide some guidance on what are the best practises in this case. I have made a very simple stackblitz with just one sub child using Control Container, unfortunately I wasn't able to make it run https://stackblitz.com/edit/angular-ivy-axbgr5
Upvotes: 13
Views: 6516
Reputation: 1126
Complex forms in Angular can be a big trouble. From my experience the best approach is to create a stateful parent component and many children stateless components.
Parent component needs to be dedicated for particular form. Child components can be reused everywhere many times.
FormGroups
) from parentIn above scenario children components are "reusable views" without any validation logic. It will always comes from parent.
You can pass nested FormGroups
in following ways:
Input
(https://github.com/p-programowanie/angular-forms/tree/forms-form-group)ControlContainer
and constructor injection (https://github.com/p-programowanie/angular-forms/tree/forms-control-container)ControlContainer
and viewProvider
injection (https://github.com/p-programowanie/angular-forms/tree/forms-control-container-provider)In my opinion using ControlValueAccessor
for creating form parts is not a good idea. Validation logic is encapsulated inside. It is good approach for create some really hard parts like a "color picker" but not just a "customer address" with several fields.
I have also tried to move business logic out of component with following simple code:
constructor(public businessLogic: VendorBusinessLogicService) { }
ngOnInit() {
this.form = this.businessLogic.createForm(this.initialValue);
this.subscription = this.form.valueChanges.subscribe(value => {
this.businessLogic.applyBusinessLogic(value);
this.emitFormState();
});
this.emitFormState();
}
Of course the requirement is to hold form reference inside the service. To be honest I cannot see benefits of it. This service for business logic looks scary. (https://github.com/p-programowanie/angular-forms/tree/forms-separated-business-logic)
Upvotes: 16
Reputation: 4993
I found it is best to create one dedicated service with all the form logic and structure. All the validations, dependencies, subscriptions, filling in the form groups and array are there. This way it is really easy to test the form parts and reuse them.
Upvotes: 2