【问题标题】:Angular: Issue in adding dynamically generated input field data on the (change) eventAngular:在(更改)事件上添加动态生成的输入字段数据时出现问题
【发布时间】:2019-11-15 16:58:29
【问题描述】:

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

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

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

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

这是 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);
  }

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

【问题讨论】:

  • 你的意思是说你想要这样的东西: {empId:1, empName:"abc", resourceQuantity:2, resourceId:11, resourceId:22} ? @Rachit

标签: angular typescript angular-reactive-forms angular-forms angular-in-memory-web-api


【解决方案1】:

这里是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

【讨论】:

    【解决方案2】:

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

    1.将您的resourceIdFormControl 更改为FormArray,如下所示。

     'resourceId': new FormArray([])
    

    2.根据Resource Quantity更改counter方法,将FormControl推入FormArray,当Resource Quantity。它从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.使用getter轻松访问控件

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

    4.更改您的 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>
    

    【讨论】:

    • 谢谢@Bear。如果我输入文本,它不会实时工作。有什么解决办法吗?
    • 实时是什么意思,要不要在资源数量的按键上添加表单控件?
    • 是的!当我键入/重新键入值时,输入字段的数量应相应更改。
    • 只需将事件从 (change)="counter()" 更改为 (keypress)="counter()"
    【解决方案3】:

    避免同时使用ngModelformControl。您可以使用 formArray 以及组件中的 getter 函数来获取结果。

    编辑:我已经编辑了我的代码以反映您请求的更改,方法是在resourceQuantity formControl 上订阅valueChanges,并在检测到更改时生成formArray。这会实时创建资源。

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

    这是StackBlitz上的一个工作示例

    【讨论】:

    • 感谢@nash11,它可以工作,但是如果我单击 matInput 的上下箭头,则不会生成输入字段。
    • 再次查看 stackblitz。我已经编辑了我的代码:)
    • 非常感谢你,纳什!另外,我没有尝试数组方法,因为 resourceIds 在数据库级别应该是唯一的。所以,我制作了一个单独的表格来实现这一点。
    【解决方案4】:

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

    import { Resource } from './resource.model';
    
    export interface Employee {
        employeeId: number;
        employeeName: string;
        resourceQuantity: number;
        resourceIds: Resource[];
    }
    

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

    export interface Resource {
        resourceId: number;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-04-19
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 2021-11-13
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      相关资源
      最近更新 更多