fumeng
fumeng

Reputation: 1830

Displaying a list of contacts in a form and allowing the user to add new ones

SOLVED: thanks to @Gourav - I just needed to add the data into my form like this:

buildFormDynamic(item: Item): FormGroup {
return this.fb.group({
  data: [item && item.data],
});

}

UPDATE: The form builder code appears correct; however, the problem seems to be that the json data isn't getting populated correctly when it first loads.

UPDATE: I'm using Angular 8 and I'm now dynamically creating my form using this mock JSON:

{
  "data": {
    "item": [
      {
        "data": "object property"
      },
      {
        "data": "object property 2",
      }
    ]
  }
}

The idea is that the form will show a contact section for all the items returned; in this case 3. Here's how I dynamically build it:

private service: ItemService;
private items: Array;
itemForm: FormGroup;

constructor(private fb: FormBuilder, private service: ItemService) 
{
  this.service = service;
}

ngOnInit() {
  this.items = this.service.getItems();
  this.createForm();
}

createForm() {
  let arr = [];

  for (let i = 0; i < this.items.data.item.length; i++) {
    arr.push(this.buildFormDynamic(this.items.data.item[i]));
  }

  this.itemForm = this.fb.group({
    itemDetails: this.fb.array(arr)
  });
}

buildFormDynamic(contact: Object): FormGroup {
  return this.fb.group({
    data: [""],
    itemId: [""]
  });
}

And here's my updated HTML:

<form [formGroup]="itemForm" >
  <div>
    <div>
      <input formControlName="isItem" type="radio" name="item" />
      <input formControlName="isNotItem" type="radio" name="item" />
    </div>
  </div>

  <div formArrayName="itemDetails"
      *ngFor="
        let contact of itemForm.controls.items.controls[i]
          .controls;
        let i = index
      ">
    <div formGroupName="{{ i }}">
    <div>
      <input formControlName="name" type="text" id="itemName" />
    </div>

    <div>
      <input formControlName="itemId" type="text" id="itemId" />
    </div>

    <div>
      <button type="button" (click)="addItem()">
        Add an Item
      </button>
    </div>

    <div>
      <button type="button">Cancel</button>
      <button type="button">Save</button>
    </div>
    </div>
  </div>
</form>

I'm not getting any errors with paths to my controls. And when I check to see if my stuff is here where I expect it:

let item of itemForm.controls.items.controls[i]
          .controls;

...it appears to be the correct path. But I'm still getting the error that "controls are undefined". Is this not the right way to do this? My FB array has 3 form groups.

enter image description here

Upvotes: 0

Views: 474

Answers (2)

Gourav Garg
Gourav Garg

Reputation: 2911

<form [formGroup]="clientProfileForm">
  <div>
    <div>
      <input formControlName="isAdmin" type="radio" name="admin" />
      <input formControlName="isNotAdmin" type="radio" name="admin" />
    </div>
  </div>

  <div formArrayName="contactDetails" *ngFor="
        let contact of clientProfileForm.controls.contactDetails.controls; let i = index
      ">
    <div formGroupName="{{ i }}">
      <div>
        <input formControlName="name" type="text" id="fullName" />
      </div>
      <div>
        <input formControlName="phone" type="number" />
        <input formControlName="phoneExt" type="number" id="phoneExt" />
      </div>
      <div>
        <input formControlName="email" type="text" id="email" />
      </div>
    </div>
  </div>
  <div>
    <div>
      <input formControlName="implementationRole" type="checkbox" name="implementationRole" />

      <input formControlName="operationsRole" type="checkbox" name="operationsRole" />
    </div>

    <div>
      <input formControlName="userId" type="text" id="userId" />
    </div>

    <div>
      <button type="button" (click)="addContact()">
        Add a contact
      </button>
    </div>

    <div>
      <button type="button">Cancel</button>
      <button type="button">Save</button>
    </div>
  </div>
</form>

If you want to access this form array in html, you should not use functions in interpolations as it can kill your application performance due to continuously calling function.

Functions in interpolation

let contact of clientProfileForm.controls.contactDetails.controls

You can simply use in html, which will not cause any issue.

This will run loop over the 3 formgroups and assign the value to controls.

<div *ngFor="
    let contact of clientProfileForm.controls.contactDetails.controls; let i = index
  ">
<div formGroupName="{{ i }}">
  <div>
    <input formControlName="name" type="text" id="fullName" />
  </div>
  <div>
    <input formControlName="phone" type="number" />
    <input formControlName="phoneExt" type="number" id="phoneExt" />
  </div>
  <div>
    <input formControlName="email" type="text" id="email" />
  </div>
</div>

Upvotes: 2

Karthik RP
Karthik RP

Reputation: 1078

Ok, I see the problem. I faced with a similar problem wihle working with dynamic forms using form array.

You need to modify your 'clientProfileForm.controls' in your template.

Add the below function in your component ts file.

    getContactControls() {
        return (this.clientProfileForm.get('contactDetails') as FormArray).controls;
    }

then modify your template file as below.

    <div formArrayName="contactDetails" *ngFor="let contact of getContactControls(); let i = index">
        ...
    </div>

Here is a working Stakblitz app.

Upvotes: 1

Related Questions