【问题标题】:Dynamic form using *ngFor and submitting values from it使用 *ngFor 并从中提交值的动态表单
【发布时间】:2019-05-11 12:29:13
【问题描述】:

我有一个 stackblitz 作为指导。

我想显示我单击“编辑”按钮的材料卡列表,我可以在其中编辑文本字段,当我单击“保存”图标时,它当然会通过触发功能等来保存.

然而,我正在努力掌握这一切在 Angular 中的工作原理以及我的应用的 Material 特性。

html

<form id="myForm" [formGroup]="thisIsMyForm">
  <mat-card [formGroup]="x" *ngFor="let x of data; let i = index">
    <mat-form-field>
      <label for="{{x.name}}">Name</label>
      <input formControlName="name" id="{{x.name}}" matInput value="{{x.name}}">
    </mat-form-field>
    <mat-form-field>
      <label for="{{x.type}}">Type</label>
      <input formControlName="type" id="{{x.type}}" matInput value="{{x.type}}"/>
    </mat-form-field>
  </mat-card>
</form>

ts

import { Component, ViewChild } from '@angular/core';
import {MatSnackBar} from '@angular/material';
import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  thisIsMyForm: FormGroup

  data = [
    {name:"one", type:"one"},
    {name:"two", type:"two"},
    {name:"three", type:"three"},
  ];

  constructor(private formBuilder: FormBuilder) {}

  onSubmit() {
    // Here I would like to be able to access the values of the 'forms'
  }

}

【问题讨论】:

  • 因为它是ngFor,您可以使用FormArrayQuerySelector 来执行此操作。选择权在你。
  • @JacopoSciampi 你能指导我举个例子吗?
  • 我会做一个stackblitz

标签: html angular typescript angular-material


【解决方案1】:

您肯定正在深入研究,尝试在 *ngFor 范围内构建动态响应式表单是一项挑战。我会尽我所能引导你完成它。

您需要为控件创建一个数组,在您的构造函数中使用this.formBuild.array([]) 将您的表单设置formArrayName 创建为一个空数组...随意调用它,我只是使用formArrayName 进行演示。

使用空数组调用this.buildForm() 实例化表单后

constructor(private formBuilder: FormBuilder) {
    this.thisIsMyForm = new FormGroup({
      formArrayName: this.formBuilder.array([])
    })

    this.buildForm();
  }

在您的buildForm() 中迭代您的data[] 并为每个索引推送控件,同时分配默认值和禁用的默认状态。

 buildForm() {
    const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;

    Object.keys(this.data).forEach((i) => {
      controlArray.push(
        this.formBuilder.group({
          name: new FormControl({ value: this.data[i].name, disabled: true }),
          type: new FormControl({ value: this.data[i].type, disabled: true })
        })
      )
    })

    console.log(controlArray)
  }

请注意: console.log(controlArray.controls) 会产生以下输出...每个索引是一个 FormGroup 有两个控件 nametype

0: FormGroup
1: FormGroup
2: FormGroup

在您的 html 中,您需要建立一个模仿您刚刚创建的 thisIsMyForm 的容器层次结构。

  • 家长:thisIsMyForm
  • 孩子:formArrayName
  • 孙子:i as formGroupName

grandchild 很重要,因为它与上一步中controlArray.controls 的控制台日志匹配

<form id="myForm" [formGroup]="thisIsMyForm">
    <div [formArrayName]="'formArrayName'">
        <mat-card *ngFor="let x of data; let i = index">
            <div [formGroupName]="i">

根据控件禁用状态创建编辑和保存按钮

   <button *ngIf="formControlState(i)" (click)="toggleEdit(i)">Enable Edit</button>
    <button *ngIf="!formControlState(i)" (click)="toggleEdit(i)">Save</button>

在组件中创建方法以接收索引作为参数并处理隐藏按钮和切换输入字段启用和禁用状态的逻辑。

toggleEdit(i) {
    const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
    if(controlArray.controls[i].status === 'DISABLED'){
      controlArray.controls[i].enable()
    }else{
      controlArray.controls[i].disable()
    }
  }

  formControlState(i){
     const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
     return controlArray.controls[i].disabled
  }

提交按钮时,console.log 的表单值...当任何输入 formControls 处于启用状态时,也禁用按钮。

<button [disabled]="thisIsMyForm.get('formArrayName').enabled" (click)="onSubmit()">Submit Form</button>

onSubmit() {
    // Here I would like to be able to access the values of the 'forms'
    console.log(this.thisIsMyForm.value)
  }

堆栈闪电战

https://stackblitz.com/edit/dynamic-form-ngfor-otbuzn?embed=1&file=src/app/app.component.ts

【讨论】:

  • 请注意,stackblitz 上有一个错字。它说“formrControlState”而不是“formControlState”。这个帖子也超级有用!非常感谢!
  • @GrantCurell 不错!它已得到纠正。没有什么比复制和粘贴错别字更好的了。没问题,很高兴您发现这些信息对您有所帮助。
【解决方案2】:

使用QueryList

您的 html(这是一个示例):

<ng-container *ngFor="let x of data; let i = index">
  <div class="ctr">
    <span #names class="item">{{x.name}}</span>
    <span #types class="item">{{x.type}}</span>
    <span class="button" (click)="showData(i)">Show data</span>
  </div>

</ng-container>

<h2>Selected values: </h2>
Selected name: {{selectedName}} <br>
Selected type: {{selectedType}}

一些css只是为了样式

.ctr{
  display: flex;
  flex-direction: row;
  margin-bottom: 20px;
}

.item{
  margin-right:40px;
}

.button{
  border: 1px solid black;
  padding: 2px 5px 2px 5px;
  cursor: pointer;
}

组件:

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChildren('names') names:QueryList<any>;
  @ViewChildren('types') types:QueryList<any>;

  selectedName: string;
  selectedType: string;

  data = [
    {name:"one", type:1},
    {name:"two", type:2},
    {name:"three", type:3},
  ];

  showData(index){
    let namesArray = this.names.toArray();
    let typesArray = this.types.toArray();

    this.selectedName = namesArray[index].nativeElement.innerHTML;
    this.selectedType = typesArray[index].nativeElement.innerHTML;
  }
}

工作堆栈闪电战:https://stackblitz.com/edit/angular-j2n398?file=src%2Fapp%2Fapp.component.ts

【讨论】:

  • 如何使用它从form 提交数据?
  • 我想我在看了你更多的闪电战之后我已经掌握了它,但是如果我遇到任何问题,我会给你一个嗡嗡声:-)
  • 我不熟悉如何使用FormArray 做得“好”,因为我不太喜欢它。但是几个月前我试图理解它,这个链接对我很有帮助:stackblitz.com/edit/wr-angular-nested-form-array
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2013-07-07
相关资源
最近更新 更多