Search code examples
angularangular-reactive-formsangular-dynamic-componentscontrolvalueaccessor

Angular Dynamically resolved components using nested Reactive Forms with CVA's are not working


Arrgh, Having problems with Dynamically built components using ReactiveForms.

Need to trigger and Mat-Dialog and load set of components in it - works fine. Need to build some of the components dynamically from a mapping array - works fine. Need to build nested reactive forms using CVA (control value assessor) - this is the problem.

I have a working nested form using CVA that updates the form data correctly ... Unless I build the components dynamically. If I use dynamic components they are ignored in the form updates. Not sure how to fix this. My app will be very complex network of forms, so need to figure this out!

I have used the Angular.io guide for dynamic components.

Angular.io - resolve dynamic components

and followed this guide for CVA implementation

In-Depth - using CVA's

Does anyone have any Ideas?? Had issues with Stackblitz so pushed code to gitHub

dev-dynamic-comp issue


Solution

  • Instead of using CVA use Sub -Form Component Approach to create app-content form in this way we can register our child form with parent FormGroup using ControlContainer.

    Injecting ControlContainer in child component provide access to parent FormGroup then we can add desired form control using addControl method.

    content.component.ts

    import { Component, forwardRef, OnInit } from '@angular/core';
    import { AbstractControl, ControlContainer, ControlValueAccessor, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validators } from '@angular/forms';
    
    @Component({
      selector: 'app-content',
      templateUrl: './content.component.html',
      styleUrls: ['./content.component.scss']
    })
    export class ContentComponent implements OnInit {
    
      parent:FormGroup;
      constructor(private controlContainer:ControlContainer) { }
    
      ngOnInit(): void {
        this.parent = this.controlContainer.control as FormGroup;
         this.parent.addControl('contentInfoForm',new FormGroup({
          contentNotes: new FormControl("",[Validators.required]),
          contentData: new FormControl("", [Validators.required])
        }));
      }
    }
    

    component.html

    <ng-container *ngIf="parent" [formGroup]="parent">
        <ng-container formGroupName="contentInfoForm">
            <div class="row">
                <label for="Content Notes"> Content Notes </label>
                <input type="text" formControlName="contentNotes" class="">
        </div>
                <div class="row">
                    <label for="Content Data"> Content Data </label>
                    <input type="text" formControlName="contentData" class="">
        </div>
        </ng-container>
    </ng-container>
    

    Forked Working Example