Angular:在(更改)事件上添加动态生成的输入字段数据时出现问题

Angular: Issue in adding dynamically generated input field data on the (change) event

我有一个功能,我需要在单击按钮时发送动态生成的输入字段。

为了更好地理解,我在 stackblitz 上重现了这个问题。

在该应用程序中,当我输入 resourceQuantity 时,会动态生成 resourceId 字段。 我的问题是单独识别这些字段并单击一次按钮将它们发送到服务器端。

This 我在 stackblitz 上找到的解决方案是相似的,但在我的问题中,我没有删除或添加按钮点击,而是 (change) 事件。

这里是 HTML 代码:

<mat-form-field>
    <input  matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/> 
</mat-form-field><br/><br/>
<div>
    <ul>
        <li *ngFor="let item of counter(resourceQuantity)">
            <input  matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/> 
        </li>       
    </ul>
</div>

这里是 TS 代码:

  ngOnInit() {
    this.form = new FormGroup({
            'employeeId': new FormControl(null, {validators: [Validators.required]}),
            'employeeName': new FormControl(null, {validators: [Validators.required]}),
            'resourceQuantity': new FormControl(null, {validators: [Validators.required]}),
            'resourceId': new FormControl(null, {validators: [Validators.required]})
    });
  }

  somethingChanged() {
      console.log(this.resourceQuantity);
  }

  counter(i: number) {
      return new Array(i);
  }

请告诉我解决我的问题的最佳方法。谢谢。

这里是 formArray 的完美用例...唯一的区别是您需要根据在 resourceQuantity 中输入的值添加 formControls场.

相关HTML:

<mat-card>
    <form [formGroup]="form" (submit)="add()">
        <mat-form-field>
            <input matInput type="number" formControlName="employeeId" placeholder="Enter Employee Id" (change)='updateFormString()'/>
      </mat-form-field><br/><br/>
      <mat-form-field>
            <input matInput formControlName="employeeName" placeholder="Enter Employee Name" (change)='updateFormString()'/>
      </mat-form-field><br/><br/>
      <mat-form-field>
            <input  matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/> 
        </mat-form-field><br/><br/>
           <!--
             <div>
                <ul>
                    <li *ngFor="let item of counter(resourceQuantity)">
                        <input  matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/> 
                    </li>       
                </ul>
            </div>
            -->
        <div fxLayout>
            <div>
                <button
                    mat-raised-button
                    color="accent" [disabled] = "form.invalid">Save
                </button>
            </div>
        </div>

        <div formArrayName='resourceId'>
          <br/>
          <div *ngFor='let item of resourceId.controls; let i = index'>
            <input type='text' [formControlName]="i" >
          </div>
        </div>

    </form>
</mat-card>

{{formString}}

相关TS:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormArray, FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  form: FormGroup;
  resourceQuantity: any;
  formString: string;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.form = this.fb.group({
      'employeeId': new FormControl(null, { validators: [Validators.required] }),
      'employeeName': new FormControl(null, { validators: [Validators.required] }),
      'resourceQuantity': new FormControl(null, { validators: [Validators.required] }),
      //'resourceId': new FormControl(null, {validators: [Validators.required]}),
      resourceId: this.fb.array([
        this.fb.control('test entry default')
      ])
    });
  }

  updateFormString() {
    this.formString = JSON.stringify(this.form.value);
  }

  somethingChanged() {
    for (var i = 1; i < this.resourceQuantity; i++) {
      this.addResource();
    }
    this.updateFormString();
  }

  get resourceId() {
    return this.form.get('resourceId') as FormArray;
  }

  addResource() {
    this.resourceId.push(this.fb.control('test entry additional'));
  }

  counter(i: number) {
    return new Array(i);
  }
}

工作stackblitz available here

您应该使用 FormArray 来解决这个问题。 StackBlitz Demo

1.Change 你的 resourceIdFormControlFormArray 如下。

 'resourceId': new FormArray([])

2.Change 你的 counter 方法根据 资源数量 在你的 FormArray 中推送 FormControl,这个方法调用当 资源数量 中的更改事件触发时。它从 FormGroup 获取 resourceQuantity 值,然后清除 FormArray 值。之后,它循环遍历索引以动态创建 FormControl 并将其推入 FormArray

counter() {
    const index = parseInt(this.form.value.resourceQuantity);
    (this.form.controls.resourceId as FormArray).clear();
    for(let i = 0; i < index; i++) {
      const formControl = new FormControl();
      (this.form.controls.resourceId as FormArray).push(formControl);
    }
}

3.use getters 轻松访问控件

  get formControls(): any {
    return this.form.controls;
  }

  get resourceIDControls(): any {
    return this.form.controls.resourceId['controls'];
  }

4.Change 您的 HTML 循环 FormArray 并动态设置 FormControlName

<div formArrayName="resourceId">
     <ul>
         <li *ngFor="let item of resourceIDControls; let i = index">
             <input  matInput type="number" placeholder="Enter Resource Number" [formControlName]="i"/> 
         </li>       
     </ul>
 </div>

避免同时使用 ngModelformControl。您可以在组件中使用 formArray 和 getter 函数来获得结果。

编辑:我编辑了我的代码以反映您通过在 resourceQuantity formControl 上订阅 valueChanges 并生成formArray 当它检测到变化时。这会实时创建资源。

注意:不要忘记从valueChanges以防止内存泄漏。我已更新我的 Stackblitz 以显示相同内容。

这是 StackBlitz

上的一个工作示例

我还将设置我的员工模型以包含资源数组;

import { Resource } from './resource.model';

export interface Employee {
    employeeId: number;
    employeeName: string;
    resourceQuantity: number;
    resourceIds: Resource[];
}

那么你的资源只需要一个id:

export interface Resource {
    resourceId: number;
}