Angular 2:在反应形式中使用动态输入

时间:2016-10-07 05:43:16

标签: forms angular

我有一个角度2的应用程序,在整个应用程序中大量使用表单。大多数表单是使用Angular中的反应形式模块构建的,但我正在使用的API也有很多动态字段"。

例如,"后端"允许用户为某些帖子/页面创建自定义字段,我也希望用户能够在我的Angular 2应用程序中使用它们。

示例

API为我提供了一个如下所示的JSON列表:

{
    "id": "the-custom-field-id",
    "label": "The input label",
    "min": 4,
    "max": 8,
    "value": "The current value of the custom field"
},
...

现在,我在一个observable中获取自定义字段列表,并使用ngfor循环它们并为每个条目生成表单元素,如下所示:

<div *ngFor="let cf of _customFields" class="form-group">

    <label>{{cf.label}}</label>

    <input id="custom-field-{{cf.id}}" type="text" class="form-control" value="{{cf.value}}">

</div>

然后在提交时,我进入DOM(使用jQuery)以使用&#34; ID&#34;来获取值。自定义字段。

这很丑陋,违背了不混合使用jQuery和Angular的想法。

必须有一种方法将这些动态表单集成到Angular中,所以我可以将它们与控制组和验证规则一起使用吗?

3 个答案:

答案 0 :(得分:4)

是的,的确有。查看Angular 2's Dynamic Forms。它的基本要点是你创建类(问题),它定义了你想要访问的每种表单控件的选项。例如,作为最终结果,您可以拥有类似的内容:

<?php
if(count($_POST) > 0){ // if you have some value in AJAX request
  if($_POST['Action'] == 'IMPLODEARRAY'){ // your condition
    print_r($_POST['options']); // get all checkbox value.
  }
}
?>

答案 1 :(得分:1)

要创建动态添加字段的表单,您需要在表单内使用FormArray,并在运行时添加自定义元素。以下是如何动态添加输入字段以允许用户通过单击“添加电子邮件:https://github.com/Farata/angular2typescript/blob/master/chapter7/form-samples/app/02_growable-items-form.ts

”按钮向表单输入多封电子邮件的示例

答案 2 :(得分:-1)

另见我的例子。好评如此容易理解希望。 https://stackblitz.com/edit/angular-reactive-form-sobsoft

所以这就是我们在app.component.ts

中使用动态字段所需要的
ngOnInit () {
  // expan our form, create form array this._fb.array
  this.exampleForm = this._fb.group({
      companyName: ['', [Validators.required,
                         Validators.maxLength(25)]],
      countryName: [''],
      city: [''],
      zipCode: [''],
      street: [''],
      units: this._fb.array([
         this.getUnit()
      ])
    });
 }

     /**
       * Create form unit
       */
      private getUnit() {
        const numberPatern = '^[0-9.,]+$';
        return this._fb.group({
          unitName: ['', Validators.required],
          qty: [1, [Validators.required, Validators.pattern(numberPatern)]],
          unitPrice: ['', [Validators.required, Validators.pattern(numberPatern)]],
          unitTotalPrice: [{value: '', disabled: true}]
        });
      }

      /**
       * Add new unit row into form
       */
      private addUnit() {
        const control = <FormArray>this.exampleForm.controls['units'];
        control.push(this.getUnit());
      }

      /**
       * Remove unit row from form on click delete button
       */
      private removeUnit(i: number) {
        const control = <FormArray>this.exampleForm.controls['units'];
        control.removeAt(i);
      }

现在使用HTML:

<!-- Page form start -->
  <form [formGroup]="exampleForm" novalidate >

    <div fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="3.5%" fxLayoutAlign="left" >

      <!-- Comapny name input field -->
      <mat-form-field class="example-full-width" fxFlex="75%"> 
        <input matInput placeholder="Company name" formControlName="companyName" required>
        <!-- input field hint -->
        <mat-hint align="end">
          Can contain only characters. Maximum {{exampleForm.controls.companyName.value.length}}/25
        </mat-hint>
        <!-- input field error -->
        <mat-error *ngIf="exampleForm.controls.companyName.invalid">
          This field is required and maximmum alowed charactes are 25
        </mat-error>
      </mat-form-field>

      <!-- Country input field -->
      <mat-form-field class="example-full-width" > 
        <input matInput placeholder="Country" formControlName="countryName">
        <mat-hint align="end">Your IP country name loaded from freegeoip.net</mat-hint>
      </mat-form-field>

    </div>

    <div fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="3.5%" fxLayoutAlign="center" layout-margin>

      <!-- Street input field -->
      <mat-form-field class="example-full-width">
        <input matInput placeholder="Street" fxFlex="75%" formControlName="street">
      </mat-form-field>

      <!-- City input field -->
      <mat-form-field class="example-full-width" > 
        <input matInput placeholder="City" formControlName="city">
        <mat-hint align="end">City name loaded from freegeoip.net</mat-hint>
      </mat-form-field>

      <!-- Zip code input field -->
      <mat-form-field class="example-full-width" fxFlex="20%"> 
        <input matInput placeholder="Zip" formControlName="zipCode">
        <mat-hint align="end">Zip loaded from freegeoip.net</mat-hint>
      </mat-form-field>

  </div>
  <br>

  <!-- Start form units array with first row must and dynamically add more -->
  <mat-card formArrayName="units">
    <mat-card-title>Units</mat-card-title>
    <mat-divider></mat-divider>

    <!-- loop throught units -->
    <div *ngFor="let unit of exampleForm.controls.units.controls; let i=index">

      <!-- row divider show for every nex row exclude if first row -->
      <mat-divider *ngIf="exampleForm.controls.units.controls.length > 1 && i > 0" ></mat-divider><br>

      <!-- group name in this case row index -->
      <div [formGroupName]="i">
        <div fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="3.5%" fxLayoutAlign="center">

          <!-- unit name input field -->
          <mat-form-field  fxFlex="30%"> 
            <input matInput placeholder="Unit name" formControlName="unitName" required>              
          </mat-form-field>

          <!-- unit quantity input field -->
          <mat-form-field  fxFlex="10%"> 
            <input matInput placeholder="Quantity" type="number" formControlName="qty" required>
          </mat-form-field>

          <!-- unit price input field -->
          <mat-form-field  fxFlex="20%"> 
            <input matInput placeholder="Unit price" type="number" formControlName="unitPrice" required>
          </mat-form-field>

          <!-- unit total price input field, calculated and not editable -->
          <mat-form-field > 
            <input matInput placeholder="Total sum" formControlName="unitTotalPrice">
          </mat-form-field>

          <!-- row delete button, hidden if there is just one row -->
          <button mat-mini-fab color="warn" 
                  *ngIf="exampleForm.controls.units.controls.length > 1" (click)="removeUnit(i)">
              <mat-icon>delete forever</mat-icon>
          </button>
        </div>
      </div>
    </div>

    <!-- New unit button -->
    <mat-divider></mat-divider>
    <mat-card-actions>
      <button mat-raised-button (click)="addUnit()">
        <mat-icon>add box</mat-icon>
        Add new unit
      </button>
    </mat-card-actions>
  </mat-card> <!-- End form units array -->    
  </form> <!-- Page form end -->