Search code examples
angularangular-forms

Angular ReactiveForm with recursive template doesn't recognize parent formGroup directive


In my app I construct formGroups dynamically from a config object that looks like this:

const formElements: FormElementInterface[] = [
 {
   type: 'formControl',
   defaultIsArray: false,
   defaultValue: 'Apfel',
   formControlName: 'fruits',
   htmlTag: 'mat-input',
   inputIype: 'text'
  } as InputFormControlInterface,
];

The FormElementInterface[] consists either of formControlobjects or formGroupobjects. The latter can contain formControls or more formGroups.

Constructing the actual formGroup, which is called completeForm as you will see in the template, went smoothly, but inside the template I met some problem and got this error:

formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class)

This is an excerpt from my template:

<form [formGroup]="completeForm">
 <div *ngFor="let formElement of forms">
  <ng-container
    *ngTemplateOutlet="formElement.type === 'formGroup' ? formGroup : formControl; context:{$implicit: formElement}">
  </ng-container>
 </div>
</form>

<ng-template #formControl let-formElement>
  <span [ngSwitch]="formElement.htmlTag">
    <div *ngSwitchCase="'mat-input'">
      <mat-form-field class="example-full-width">
        <input matInput [value]="formElement.defaultValue" formControlName="fruits">
      </mat-form-field>
    </div>
  </span>
</ng-template>

As you can see formGroup is set. Are the ng-template interfering?


Solution

  • I found the solution: due to the ng-template formControlName isnt sufficient since ng-template kinda messes up the hierarchy in the template. Therefore the path to the formControl inside the formGroup must be provided like so:

    <input matInput [value]="formElement.defaultValue" [formControl]="getFormControl(formElement.formControlName)">