angulartypescriptforms

Form array Angular


I'm having a hard time integrating this form with the html. can you help me? I've tried in some ways but I couldn't connect because I'm using FormArray. I made the form but to access the controls in the html is very complicated. I need it to be form Array, because this will have several arrays with categories. I need it to be form Array, because this will have several arrays with categories.

Form in Component TS

  testeForm: FormGroup = this.fb.group({
    feedstock: this.fb.array([
      this.addFeedStockArray()
    ])
  });
  
  
    addFeedStockArray(): FormGroup {
    return this.fb.group({
      category: "",
      position: "",
      feedstockOptions: this.fb.array([
        this.addFeedStockOptions()
      ]),
   })
 }
  
  
    addFeedStockOptions(): FormGroup {
     return this.fb.group({
      name: '',
      code: '',
      price: {
        amount: '',
        currency: ['BRL'],
      }
    })
  }
  
  
  addfeedStockClick(): void {
    (<FormArray>this.testeForm.get('feedstock')).push(this.addFeedStockOptions());
  }
              <div [formGroup]="testeForm" style="margin-left: 40px">
                <div class="second-column row" formArrayName="feedstock" >
                  <div class="row" [formGroupName]="i" *ngFor="let feedstock of feedstock.get('feedstockOptions')?.controls; let i = index">
                    <div class="form-group col">
                        <label>
                          NOME:
                        </label>
                        <input class="form-control"
                              placeholder="--" formControlName="name" >
                    </div>
                    <div class="form-group col">
                        <label>
                          CÓDIGO:
                        </label>
                        <input class="form-control"
                              placeholder="--" formControlName="code">
                    </div>
                    <div class="form-group col">
                        <label>
                          PREÇO:
                        </label>
                        <input class="form-control"
                              currencyMask
                              [options]="{ prefix: 'R$ ', thousands: '.', decimal: ',', align:'left'}"
                              min="0"
                              placeholder="R$" formControlName="price" >
                    </div>
                    <div class="form-group col">
                      <i class="material-icons close-category"  style="margin-top: 40px" (click)="removefeedStockClick(i)" >
                        close
                      </i>
                    </div>
                  </div>
                </div>
              </div>


Solution

  • I would suggest a minimal change to see if it fixes your issue

    <div [formGroup]="testeForm" style="margin-left: 40px">
      <div class="second-column row" formArrayName="feedstock" >
        <ng-container *ngFor="let feedstock of feedstock.get('feedstockOptions')?.controls; let i = index">
          <div class="row" [formGroupName]="i">
            <div class="form-group col">
              <label>NOME:</label>
              <input class="form-control" placeholder="--" formControlName="name" >
             </div>
          </div>
          ......
        </ng-container>
    

    Used an ng-container to wrap the *ngFor directive

    UPDATE

    After seeing the complete code, realized there is one larger mistake: There are 2 levels of FormArray and need to be accessed like that.

    <div [formGroup]="testeForm" style="margin-left: 40px">
      <div class="second-column row" formArrayName="feedstock" >
        <ng-container *ngFor="let fcFeedStock of testeForm.get('feedstock')?.controls; let i = index">
          <ng-container [formGroupName]="i">
            <ng-container formArrayName="feedstockOptions">
              <ng-container *ngFor="let feedstockOption of fcFeedStock.get('feedstockOptions')?.controls; let j = index">
                <div class="row" [formGroupName]="j">
                  <div class="form-group col">
                    <label>NOME:</label>
                    <input class="form-control" placeholder="--" formControlName="name" >
                  </div>
                </div>
            ......
            </ng-container>
        </ng-container>
      </ng-container>
    </div>
    

    UPDATE 2:

    Showing price > amount

    As price is a FormGroup, and amount is a FormControl:

     ...
     <div class="row" [formGroupName]="i">
        <div class="form-group col">
          <label>NOME:</label>
          <input class="form-control" placeholder="--" formControlName="name" >
         </div>
         <div formGroupName="price">
           <input formControlName="amount">
         </div>
      </div>
      ...
    

    How to add one new element to the array:

    The issue is you are confusing between the 2 FormArrays 'feedstock' and 'feedstockOptions'.

    // This function should do feedstock.push(this.addFeedStockArray())
    addfeedStockClick(): void {
      (<FormArray>this.testForm.get('feedstock')).push(this.addFeedStockArray());
    }
    

    For adding to feedstockOptions, you first need the index of the feedstock, access it's feedstockOptions, and then push to it:

    (<FormArray>(<FormArray>this.testForm.get('feedstock')).at(index).get('feedstockOptions')).push(this.addFeedStockOptions());
    

    or if you can manage to directly access the fcFeedstock, the line of code would simplify to:

    (<FormArray>fcFeedstock.get('feedstockOptions')).push(this.addFeedStockOptions())