【问题标题】:Angular 2: Using dynamic inputs in reactive formsAngular 2:以反应形式使用动态输入
【发布时间】:2016-10-07 05:43:16
【问题描述】:

我有一个 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)以使用自定义字段的“ID”获取值。

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

一定有办法将这些动态表单集成到 Angular 中,以便我可以将它们与控制组和验证规则一起使用?

【问题讨论】:

    标签: forms angular


    【解决方案1】:

    是的,确实有。查看Angular 2's Dynamic Forms。它的基本要点是您创建类(问题),它为您希望访问的每种类型的表单控件定义了选项。因此,例如,作为最终结果,您可能会得到如下结果:

    private newInput;
    
    constructor(){
        // typically you would get your questions from a service/back-end.
    
        this.newInput = new NumberQuestion({
            key: 'amount',
            label: 'Cash Back',
            value: 21,
            required: true,
            max: 1000,
            min: 10
        });
    }
    
    ngOnInit(){
        let control = this.newInput.required ? 
            new FormControl(this.newInput.value, Validators.required)
            : new FormControl(this.newInput.value);
    
        this.form.addControl(this.newInput.key, control);
    }
    

    【讨论】:

    • 太棒了!非常感谢。
    • 但是如何处理日期选择器?就我而言,我需要根据从服务器接收到的“日期”类型显示日期选择器控件。
    • 您可以使用angular2 DatePipe 和/或您可以使用LoDash 或类似方法将日期转换为字符串?
    【解决方案2】:

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

    【讨论】:

    • 如果您想要一个 FormControls 的 FormArray,每个都有自己的名称,而不是使用索引遍历它们,该怎么办?如果您想要从 API 检索到的自定义字段数组而不是电子邮件地址数组,该怎么办?
    【解决方案3】:

    另请参阅此处的示例。评论很好,所以很容易理解希望。 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 -->
    

    【讨论】:

      猜你喜欢
      • 2018-11-10
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2017-11-27
      • 2018-10-10
      • 2020-07-04
      • 1970-01-01
      • 2017-06-03
      相关资源
      最近更新 更多