2

I have an ng-container that describes all of my possible form field templates, essentially on a large switch statement depending on the field's metadata:

<ng-template #dynamicFormField let-field="inputField">
  <div *ngIf="field.dataTypeName == 'ShortText'">
    <mat-form-field class="col-md-6">
      <input matInput type="text" [placeholder]="field.attributeLabel" [formControlName]="field.attributeName">
    </mat-form-field>
  </div>

  <div *ngIf="field.dataTypeName == 'LongText'">
    <mat-form-field class="col-md-12">
      <input matInput type="text" [placeholder]="field.attributeLabel" [formControlName]="field.attributeName">
    </mat-form-field>
  </div>

  <div *ngIf="field.dataTypeName == 'Number'">
    <mat-form-field>
      <input matInput type="number" [placeholder]="field.attributeLabel" [formControlName]="field.attributeName">
    </mat-form-field>
  </div>
<ng-template>

I have a base formgroup, then one property of the form group is a form array, each element of which with its own formgroup. For example, the data model looks something like this:

{
  name: 'Article Name',
  description: 'Some description of the article',
  sections: [
    {
      sectionName: 'Rich text section',
      sectionContent: 'Some rich text'
    },
    {
      sectionName: 'Second section',
      sectionContent: 'Some rich text'
    }
  ]
}

where each of these fields has corresponding metadata describing its form properties.

I want to be able to reuse the input switch statement in both the base formgroup as well as the formgroups within the form array. However, the inside of the ng-container cannot access the formgroup specified by the formarray's formGroupName input:

<div *ngFor="let field of this.sectionTypeSchemas[section.value.sectionTypeId]">
  <div *ngIf="field.isVisible != false" formGroupName="{{i}}">
    <ng-container *ngTemplateOutlet="dynamicFormField;context:{ inputField:field }"></ng-container>
  </div>
</div>

The error I am running into is basically that the Angular cannot find the controls that are inside of the formarray's FormGroups (i.e. sectionName from data model), although there is no issue in finding the controls corresponding the base formgroup controls (name and description from the data model). Is there a way I can manually pass the formgroup reference to the ng-container? A short example can be seen here.

Joe H
  • 107
  • 1
  • 7
  • Why dont you use an extra component with @Input() Decorator for this? – MullisS Mar 26 '19 at 13:29
  • @MullisS I tried but there's still no way to explicitly pass a formgroup reference to it. You run into the same context errors. – Joe H Mar 26 '19 at 13:35
  • Could you make a minimum example on stackblitz? – MullisS Mar 26 '19 at 13:36
  • @MullisS Sure check it out here: [link](https://stackblitz.com/edit/angular-czcwgu). As you can see, the fields render, but can't find the formcontrols associated with them. – Joe H Mar 26 '19 at 14:03
  • 1
    Even the answer of Erbenskönig is correct, you should bether write a component for that, since you want your component not to know the form structure of the form. Take a look of this: https://stackblitz.com/edit/angular-u7ppe4?file=src%2Fapp%2Fapp.component.ts – MullisS Mar 26 '19 at 15:36

1 Answers1

4

First of all I would probably go with a subcomponent rather than the ng-template as it was suggested in the comments above, too.

Nevertheless, there are two things that needs to be fixed in order to get your example working

Using FormControls inside another component or ng-template

Everytime you use a formControl of a formGroup inside a ng-template, you need to make sure you add a tag having the formGroup binding as well inside your ng-template, if the form-tag is placed outside the ng-template.

In your case there is something special, because the formGroup inside your ng-template is actually a subFormGroup - the formGroup for each formArrayItem

FormArray binding

If you are binding to a formArray you need to keep in mind, that you need the formArrayName on the outside control as well as the binding to the index. Please have a look here for further explanation: FormArray binding

One more thing

You have a typo inside you stackblitz: secitonHeader rather than sectionHeader.


Here is a working : stackblitz

Community
  • 1
  • 1
Erbsenkoenig
  • 1,584
  • 14
  • 18
  • I have a similar issue here https://stackoverflow.com/questions/56806982/error-during-dynamic-form-creation-from-json-cannot-find-control-with-name-dat. Can you see if you have any solution for nested reactive forms. The link has the stackblitz attached – Vikhyath Maiya Jun 28 '19 at 15:24
  • Is there any official statement on "Everytime you use a formControl of a formGroup inside a ng-template, you need to make sure you add a tag having the formGroup binding"? - the same applies for [formGroupName] too. I wanted some reusable components where sometimes there is a nested group, sometimes not, and it just doesn't work which is frustrating. – Adam Marshall Sep 06 '19 at 09:07
  • 1
    I found that if the formControl is inside a ng-template or a different component to have a reusable component, you need to pass in the formGroup and add it to a surrounding element, like a div. I am not too sure whether there is an official statement. I'll have a look at this. I don't understand your problem though. Maybe open a new question (and provide a stackblitz or jsfiddle) and I'll have a look at it. – Erbsenkoenig Sep 09 '19 at 06:58