Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular forms: best practise for complex nested reactive forms and validation at root component

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:

  • Control Value Accessor: the concept is perfect, the logic is split perfectly among the children without the parent having to concern about it, but the CON is that the children controllers are not exposed and I can't markAsTouched all the sub forms to show the respective errors
  • Control Container: This approach seems to be needing all of the controls to be defined at the parent level, but being a very big form, it seems really counterproductive and not really solving my problem.

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

like image 252
user3353167 Avatar asked Feb 22 '26 16:02

user3353167


2 Answers

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.

Parent component rules:

  • stateful
  • creates and holds form definition
  • emits form state (value, valid, pristine) on every form change
  • holds custom validation logic

Children components rules:

  • stateless
  • receives form parts (nested FormGroups) from parent
  • no custom validation logic

In above scenario children components are "reusable views" without any validation logic. It will always comes from parent.

How to pass form parts to children components`?

You can pass nested FormGroups in following ways:

  • through Input (https://github.com/p-programowanie/angular-forms/tree/forms-form-group)
  • through ControlContainer and constructor injection (https://github.com/p-programowanie/angular-forms/tree/forms-control-container)
  • through ControlContainer and viewProvider injection (https://github.com/p-programowanie/angular-forms/tree/forms-control-container-provider)

ControlValueAccessor

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.

Business logic out of component

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)

like image 101
Karol T Avatar answered Feb 25 '26 04:02

Karol T


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.

like image 41
IAfanasov Avatar answered Feb 25 '26 06:02

IAfanasov