Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
348 views
in Technique[技术] by (71.8m points)

angular5 - Add item in dynamic reactive form in Angular

I am trying to build a nested reactive form in Angular 5. I am able to push items at one level, but unable to push item at second level.

ngOnInit() {
 this.orderForm = this.formBuilder.group({
  customerName: '',
  email: '',
  items: this.formBuilder.array([this.createItem()])
});
}

 createItem(): FormGroup {
    return this.formBuilder.group({
      name: 'a',
      description: 'b',
      price: 'c',
      //subItems: this.formBuilder.array([this.createSubItem()])
    });
 }

 //createSubItem(): FormGroup {
    //return this.formBuilder.group({
      //subname: 'abc'
    //});
 //}

 addItem(): void {
    this.items = this.orderForm.get('items') as FormArray;
    //this.subItems = this.items.get('subItems') as FormArray;
    //this.subItems.push(this.createSubItem());
    this.items.push(this.createItem());
 }

In the above code the uncommented code is working fine with push. I have further subItems inside items, and commented code is the one I am trying to achieve, but it is not working.

Can any body show me how to achieve this?

For uncommented code, I am showing data in html like this and it is working well. If any body have solution at code level, please also tell me how to update html for nested items as well.

<form [formGroup]="orderForm">
<div formArrayName="items" *ngFor="let item of orderForm.get('items').controls; let i = index;">
    <div [formGroupName]="i">
      <input formControlName="name" placeholder="Item name">
      <input formControlName="description" placeholder="Item description">
      <input formControlName="price" placeholder="Item price">
    </div>
  </div>
  <input type="button" value="sldkj" (click)="addItem()">
</form>

SOLUTION:

First of all I managed to pre-populate values like this.

 obj = [
    {
      'name': "umair",
      'description': "desc1",
      'subItems': [
        {
          'subname': 'value'
        },
        {
          'subname': 'value2'
        },
        {
          'subname': 'value3'
        }
      ]
    },
    {
      'name': "ali",
      'description': "desc2",
      'subItems': [
        {
          'subname': 'valu4'
        },
        {
          'subname': 'value5'
        },
        {
          'subname': 'value6'
        }
      ]
    }
  ]

  ngOnInit() {
    this.createForm(this.obj);
    console.log(this.orderForm);
  }

  createForm(obj) {
    var arr = [];
    for (var i = 0; i < obj.length; i++) {
      arr.push(this.createItem(obj[i]));
    }
    this.orderForm = this.formBuilder.group({
      items: this.formBuilder.array(arr)
    });
  }

  createItem(obj): FormGroup {
    var subArr = [];
    for (var i = 0; i < obj.subItems.length; i++) {
      subArr.push(this.createSubItem(obj.subItems[i]));
    }
    return this.formBuilder.group({
      name: obj.name,
      description: obj.description,
      subItems: this.formBuilder.array(subArr)
    });
  }

  createSubItem(subItem): FormGroup {
    return this.formBuilder.group({
      subname: subItem.subname
    });
  }

After help in 'marked' answer below, I managed to add subitem and populate in html like below.

 <form [formGroup]="orderForm">
  <!-- <label>{{item.get('name').value}}</label> -->
  <div formArrayName="items" *ngFor="let item of orderForm.controls.items.controls; let i = index;">
    <div formGroupName="{{i}}">
      <!-- <label>{{item.get('name').value}}</label> -->
      <input formControlName="name" placeholder="Item name">
      <input formControlName="description" placeholder="Item description">

      <input type="button" value="subAdd" (click)="addSubItems(i)">

      <div formArrayName="subItems" *ngFor="let subItem of item.controls.subItems.controls; let idx = index;">
        <div formGroupName="{{idx}}">
          <!-- <label>{{subItem.get('subname').value}}</label> -->
          <input formControlName="subname" placeholder="Item name">
        </div>
      </div>

    </div>
  </div>
</form>

code

addSubItems(_index: any): void {
    var a = this.orderForm['controls']['items']['controls'][_index] as FormGroup;
    this.subItems = a.get('subItems') as FormArray;
    var newSubItem = {
      'subname': 'value6'
    }
    this.subItems.push(this.createSubItem(newSubItem));
  }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

So first let start with understanding what you do.

You make a formarray in formarray. So this mean it have two loops. So you have to *ngFor the first and *ngFor the second. In the end this means you have an index i for your items and and j for your subItems. Then you can add addSubItems(i) for pushing your subItems.

Your html should look something like this:

<form [formGroup]="orderForm">
  <div formArrayName="items">
     <div *ngFor="let arrays of orderForm.controls.items.controls; let i = index;">
        <div formGroupName="{{i}}">
          <input formControlName="name" placeholder="Item name">
          <input formControlName="description" placeholder="Item description">
          <input formControlName="price" placeholder="Item price">
          <input type="button" value="subAdd" (click)="addSubItems(i)"> <-- here your button -->
          <div formArrayName="subItems">
             <div *ngFor="let item of arrays.controls.subItems.controls; let j = index;">
                <div formGroupName="{{j}}">
                   <input formControlName="subname" placeholder="Item subname">

Your addSubItems should look something like:

 addSubItems(_index: any): void {
    this.item = this.orderForm['controls']['items']['controls'][_index] as FormGroup;
    this.subItems = this.item.get('subItems') as FormArray;
    this.subItems.push(this.createSubItem());

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...