2

For a variety of reasons, I need to have a formArrayName directive applied to a div with as a child a ng-container with a ngTemplateOutlet.

Let me clarify it with HTML templates.

The following template will work

 <div formArrayName="credentials" *ngFor="let creds of forArr.controls.credentials?.controls; let i = index">
      <ng-container [formGroupName]="i">
        <input placeholder="Username" formControlName="username" />
        <input placeholder="Password" formControlName="password" />
      </ng-container>
  </div>

Whereas this one won't

<div formArrayName="credentials" *ngFor="let creds of forArr.controls.credentials?.controls; let i = index">
      <ng-container [formGroupName]="i">
        <ng-container *ngTemplateOutlet="x"></ng-container>
      </ng-container>

      <ng-template #x>
        <input placeholder="Username" formControlName="username" />
        <input placeholder="Password" formControlName="password" />
      </ng-template>

</div>

The only difference is thus that I wrap all input code in a template. A major reason I need this is that I would like to reuse the template content (with two inputs) for both FormGroupwith plain fields (Username and Password) as within Formarray's for a list of username and passwords.

NOTE I left out some code regarding [formGroup]="form"> and the internal buildup as this is irrelevant for the question. The code works just fine and all controls exists and are bound with the correct directives. I just would like to set NgTemplate's within the HTML template.

I try to reuse my templates as much as possible such that it can work within both groups as on an array within a group.

1 Answer 1

2

The issue with the template version is that you lose the syntactic sugar of formArrayName and the binding between the form group and the form control. You aren't passing context to the template, so there is no binding. If you want to use a template for your form array, you must pass enough of the form context to bind to the correct form group.

You can work around this by giving the template the form group as context.

First, create a getter for your form array so that the typing in the template is correct:

  get credArray(): FormArray {
    return this.forArr.get('credentials') as FormArray;
  }

Then, update your template:

     
<ng-container *ngTemplateOutlet="x; context: {inputFormGroup: credArray.at(i)}"></ng-container>

<ng-template #x let-inputFormGroup="inputFormGroup">
    <ng-container [formGroup]="inputFormGroup">
        <input placeholder="Username" formControlName="username" />
        <input placeholder="Password" formControlName="password" />
    </ng-container>
</ng-template>

StackBlitz here. (I used a form array example I already had, so the names are different)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.