Как использовать formBuilder для создания новой строки таблицы при нажатии на кнопку с проверкой и начальными значениями - PullRequest
0 голосов
/ 29 апреля 2019

Я пытаюсь использовать formBuilder и formBuilder.array, чтобы создать новую строку пользовательских вводов (Text, Number, Drown down), чтобы принять пользовательский ввод и сохранить его в Angular 7. Будучи новичком в Angular 7, я еще не могу связать HTML с объявленным массивом FormBuilder.

Я не уверен, правильно ли я делаю, но мне нужна помощь, чтобы узнать, как я могу это сделать правильно. Прилагаю скриншот, чтобы убедиться, что моя проблема понятна всем.

https://imgur.com/R5FMJjR enter image description here

Файл Component.ts

import { Component, OnInit } from '@angular/core';

import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';

import { CustomersService } from '../../services/customers.service';

import { ContractService } from '../../services/contract.service';

import {Router, ActivatedRoute} from "@angular/router"

import * as _ from 'lodash';

import {ContractDetailsClass} from "./contract-details-class";

@Component({
  selector: 'app-contract-details',
  templateUrl: './contract-details.component.html',
  styleUrls: ['./contract-details.component.scss']
})


export class ContractDetailsComponent implements OnInit {

  customersList: Object;
  locationList: Object;
  contractTypeList: Object;
  bonusDurationList: Object;
  contract: Object;
  skillLevelsList: Object;
  ratesList: Object;
  rateType = Number;
  contractDetails:  any = [];
  contractDetailsForm: FormGroup;
  submitted = false;

  constructor(private formBuilder: FormBuilder, private Customers: CustomersService, private Contract: ContractService, private route: ActivatedRoute) { }

  ngOnInit() {

    var contractId = this.route.snapshot.paramMap.get("contractId");
    this.contract = {};

    //getContractDetails
    this.Contract.getContractDetails(contractId).subscribe( data=> {
      this.contractDetails = data;
      console.log('this.contractDetails');
      if(!this.contractDetails.length){
        //If empty Add 5 rows in advance
        this.addInitialRows()
      }
    });

    // getContractTypes 
    this.Contract.getContractTypes().subscribe( data=> {
      this.contractTypeList = data;
    });

    //getSkillLevels
    this.Contract.getSkillLevels().subscribe( data=> {
      this.skillLevelsList = data;
    });
    //getRates
    this.Contract.getRates().subscribe( data=> {
      this.ratesList = data;
    });


    // bonus 
    this.bonusDurationList = [{value: 'month', name: 'Month'}, {value: 'quarter', name: 'Quarter'}, {value: 'year', name: 'Year'} ];

    this.Contract.getContract(contractId).subscribe( data=> {
      this.contract = data;
      var selectedContractType = _.find(this.contractTypeList, function(item){ return item.contracttypeid == data['contracttype'];})
      if(selectedContractType) this.contract['contractType'] = selectedContractType.cnttypename;
      var selectedBonusDuration = _.find(this.bonusDurationList , function(item){ return item.value == data['bonusduration'];})
      this.contract['bonusDuration'] = selectedBonusDuration.name;
    });

    this.contractDetailsForm =  this.formBuilder.group({
      details:this.formBuilder.array([this.addDetailsGroupToForm()])
    });
  }

  addDetailsGroupToForm(){
    return this.formBuilder.group({
      requirequantity: [''],
      contracttype: [''],
      skilllevel: ['', Validators.required],
      uom: [''],
      ratetype: ['', Validators.required],
      startquantity: [''],
      endquantity: [''],
      fixedcost: [''],
      margintype: [''],
      marginvalue: [''],
      billingcycle: [''],
      remark: [''],
    });
  }

  get details() {
    return this.contractDetailsForm.get('details') as FormArray;
  }

  addDetails() {
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
  }

  addInitialRows(){
    console.log("addInitialRows  called");
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
    this.details.push(this.formBuilder.control(''));
    console.log(this.details);
  }

  rateTypeChanged(){
    var values = this.contractDetailsForm.value
    console.log(values);
    this.rateType = values.rateType;
  }

  onSubmit(){
    var values = this.contractDetailsForm.value;
      console.log(values);
  }

}

Component.html

<div class="animated fadeIn">
    <div class="row ml_margin_top_20">
      <div class="col-lg-12">
        <div class="card">
          <form [formGroup]="contractDetailsForm" (ngSubmit)="onSubmit()">
          <div class="card-header">
           <span class="col-sm-8">Contract Details</span> 
           <span class="col-sm-4 pull-right"><button aria-pressed="true" (click)="addDetails()"  class="btn btn-primary active float-right" style="position: relative;bottom: .8em;" type="button"><span class="icon icon-plus"></span> </button></span> 
          </div>
          <div class="card-body">
            <table formArrayName="details" *ngIf="details.length > 0" class="table table-sm">
              <thead>
                <tr>
                  <th>Type Of Service</th>
                  <th>UOM</th>
                  <th>Required Quantity</th>
                  <th>Rate Type</th>
                  <th>Start Quantity</th>
                  <th>End Quantity</th>
                  <th>Fixed Cost</th>
                  <th>Margin Type</th>
                  <th>Margin Value</th>
                  <th>Billing Cycle</th>
                  <th>Remark</th>
                </tr>
              </thead>
              <tbody>
                <tr *ngFor="let detail of details.controls ; let i = index">
                  <td>
                      <ng-select [items]="skillLevelsList"
                      bindLabel="skilllevel"
                      placeholder="Select Skill"
                      [clearable] = false

                      formControlName="skilllevel"                                                                                                                                                                                                                                                                                                                                                                            
                      [ngClass]="{ 'is-invalid': submitted && f.skilllevel.errors }">
                     </ng-select>
                  </td>
                  <td >
                      <input type="text"  formControlName="uom"   class="form-control" id="uom" placeholder="Enter UOM">
                  </td>
                  <td >
                      <input type="number"  formControlName="requirequantity"   class="form-control" id="requirequantity" placeholder="Enter Quantity">
                  </td>
                  <td>
                      <ng-select [items]="ratesList"
                      bindLabel="ratetypename"
                      placeholder="Select Rate"
                      [clearable] = false

                      formControlName="ratetype"
                      [ngClass]="{ 'is-invalid': submitted && f.ratetype.errors }"
                      (change)="rateTypeChanged()">
                     </ng-select>
                     <div *ngIf="submitted && f.ratetype.errors" class="invalid-feedback">
                         <div *ngIf="f.ratetype.errors.required">Rate is required</div>
                     </div>
                  </td>
                  <td >
                      <input type="text"  formControlName="startquantity"   class="form-control" id="uom" placeholder="Start Quantity">
                  </td>
                  <td >
                      <input type="text"  formControlName="endquantity"   class="form-control" id="uom" placeholder="End Quantity">
                  </td>
                  <td >
                      <input type="number"  formControlName="fixedcost"   class="form-control" id="fixedcost" placeholder="Enter Fixed Cost">
                  </td>
                  <td >
                      <input type="text"  formControlName="margintype"   class="form-control" id="margintype" placeholder="Enter margin type">
                  </td>
                  <td >
                      <input type="text"  formControlName="marginvalue"   class="form-control" id="marginvalue" placeholder="Enter margin value">
                  </td>
                  <td >
                      <input type="text"  formControlName="billingcycle"   class="form-control" id="billingcycle" placeholder="Enter billing cycle">
                  </td>
                  <td>
                      <input type="text"  formControlName="remark"   class="form-control" id="remark" placeholder="Enter remark">
                    </td>
                  <!-- <td>
                    <span class="btn btn-primary" routerLink="/contract/edit/{{ contract.contractid}}" >Edit</span>
                  </td> -->
                </tr>
              </tbody>
            </table>
            <div *ngIf="!details.length">
              <span> To add Contract Details <a (click)="addDetails()" class="" > Click here</a></span>
            </div>
            <div *ngIf="details.length > 0" class="row float-right ml_margin_bottom_15">
                <button  class="btn btn-primary active justify-content-center">Next</button>
            </div>
          </div>

          </form>
        </div>
      </div>
      <!--/.col-->
    </div>
  </div>

1 Ответ

0 голосов
/ 29 апреля 2019

Я думаю, у вас есть небольшая путаница с formArray и Form Group.Массив формы может быть FormArray из FormControls или Form Array из FormGroups.

В Angular мы можем создать FromGroup, используя formBuilder и напрямую.

//Using formBuilder
const formGroup=this.formBuilder.group({
      requirequantity: [''],
      contracttype: [''],
      skilllevel: ['', Validators.required],
      ...
    });

//Directly
const formGroup=new FormGroup({
      requirequantity: new FormControl(''),
      contracttype: new FormControl(''),
      skilllevel: new FormControl('',Validators.required),
      ...
    });

Полезно сделать функцию, котораявернуть formGroup.Мне нравится, если данные из интерфейса делают что-то вроде

getGroup(data:any)
{
    data=data || {} as IData
    return formGroup=new FormGroup({
          requirequantity: new FormControl(data.requirequantity),
          contracttype: new FormControl(data.contracttype),
          skilllevel: new FormControl(data.skilllevel,Validators.required),
          ...
        });
}

Иначе вы можете использовать что-то вроде

getGroup(data:any)
{
    return formGroup=new FormGroup({
          requirequantity: new FormControl(data?data.requirequantity:''),
          contracttype: new FormControl(data?data.contracttype:''),
          skilllevel: new FormControl(data?data.skilllevel:'',Validators.required),
          ...
        });
}

Массив формы может быть одним из свойств FormGroup.,Это

//we can has
details:FormArray=new FormArray([])
//or a form
form=new FormGroup({
   details:new FormArray([])
  })

Посмотрите, что нам нужно, почти создайте подачу formArray с пустым массивом.

Однажды у нас есть formArray, мы можем добавить в него элементы

let data={requirequantity: 10,
          contracttype: 'A',
          skilllevel: "1.22.34f",
          ...
          }

this.details.push(getGroup(data));  //Add a formArray a formGroup

this.form.get('details').push(getGroup(null)); //Add an empty group

И .html всегда один и тот же

//If the formArray is a property of a formGroup
<!--the formGroup-->
<form *ngIf="form" [formGroup]="form">
  <!--the formArrayName-->
  <div formArrayName="details">
     <!--a *ngFor over the controls of formArray using FormGroupName-->
     <div *ngFor="let item of form.get('details').controls;let i=index"
              [formGroupName]="i" />
         <!--the input/select/radio using formControlName-->
         <input formControlName="requirequantity">
         <input formControlName="contracttype">
         ...
     </div>
  </div>
</div>

Если это непосредственно formArray

<!--as formGroup the formArray-->
<form *ngIf="form" [formGroup]="details">
     <!--a *ngFor over the controls of formArray using FormGroupName-->
     <div *ngFor="let group of form.get('details').controls;let i=index"
              [formGroupName]="group" />
         <!--the input/select/radio using formControlName-->
         <input formControlName="requirequantity">
         <input formControlName="contracttype">
         ...
     </div>
  </div>

Ну, как заметьте, обычно мы используем метод get для ссылки на formArray

get details()
{
   return this.contractDetaisForm.get('details') as FormArray
}
...