首页 文章

如何在Angular 2中动态添加和删除表单字段

提问于
浏览
44

我正在尝试在用户单击添加按钮时动态添加输入字段,并且对于每个表单字段必须有一个删除按钮,当用户单击表单字段必须删除时,我需要使用Angular 2来实现此目的,如我是Angular 2的新手,请帮我完成它

我试过了什么

我创建了一组字段(3个选择框和1个文本框),创建了一个名为添加字段的按钮,但我已经在角度1.x中尝试了它的工作正常但是在角度2我不知道如何完成它,这是我全部工作的link

app/app.component.ts
 import {
    Component
  }
from '@angular/core';
  @Component({
    selector: 'my-app',
    template: `
    <h1>{{title}}</h1>
    <div class="container">
    <button class="btn btn-success bt-sm">add</button>
    <form role="form" calss="form-inline">
    <div class="form-group col-xs-3">
    <label>Select State:</label>
    <select class="form-control" [(ngModel)]="rules.State" id="sel1">
            <option>State1</option>
            <option>State2</option>
            <option>State3</option>
            <option>State4</option>
</select>
     </div>
    <div class="form-group col-xs-3">
<label>Rule:</label>
     <input type="text" data-toggle="modal" data-target="#myModal" class="form-                   control">
    </div>
<div class="form-group col-xs-3">
<label>Pass State :</label>
    <select class="form-control" [(ngModel)]="rules.pass">
    <option>State1</option>
    <option>State2</option>
    <option>State3</option>
    <option>State4</option>
</select>
 </div>
 <div class="form-group col-xs-3">
    <label>Fail State:</label>
        <select class="form-control" [(ngModel)]="rules.fail">
        <option>State1</option>
        <option>State2</option>
        <option>State3</option>
     <option>State4</option>
     </select>
         </div>
    </form>
     </div>
 <div class="modal fade" id="myModal" role="dialog">
      <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                     <button type="button" class="close" data-dismiss="modal">&times    </button>
                    <h4 class="modal-title">Rules Configuration</h4>
                </div>
                <div class="modal-body">
                 <p>Rules</p>
                </div>
                 <div class="modal-footer">
                 <button type="button" class="btn btn-default" data-  dismiss="modal">Close</button>
                </div>
             </div>

                </div>
                 </div>
`
    })
    export class AppComponent {
            title = 'Rule Engine Demo';
          rules: Rules = {
                  State: '',
                  pass: '',
                 fail: ''
                };

1 回答

  • 124

    这已经晚了几个月,但我想我会根据this here tutorial提供我的解决方案 . 它的要点是,一旦改变了接近表单的方式,它就会更容易管理 .

    首先,使用 ReactiveFormsModule 代替普通 FormsModule 或者除了正常 FormsModule 之外 . 使用反应式表单,您可以在组件/服务中创建表单,然后将其插入页面而不是生成表单本身的页面 . 它更容易测试,更灵活,而且我可以告诉最好的方法来制作很多非平凡的形式 .

    从概念上讲,最终结果看起来有点像这样:

    • 您有一个基础 FormGroup ,其中包含整个表单所需的 FormControl 个实例 . 例如,在我链接到的教程中,假设您需要一个表单,用户可以在其中输入一次名称,然后输入任意数量的地址 . 所有一次性字段输入都将在此基本表单组中 .

    • FormGroup 实例中,将有一个或多个 FormArray 实例 . FormArray 基本上是一种将多个控件组合在一起并迭代它们的方法 . 您还可以在数组中放置多个 FormGroup 实例,并将这些实例与"mini-forms"嵌套在较大的表单中 .

    • 通过在动态 FormArray 中嵌套多个 FormGroup 和/或 FormControl 实例,您可以控制有效性并将表单管理为由多个动态部分组成的一个大的反应部分 . 例如,如果要在允许用户提交之前检查每个输入是否有效,则一个子表单的有效性将为"bubble up"到顶级表单,整个表单将变为无效,从而可以轻松管理动态输入 .

    • 本质上, FormArray 是数组接口的包装器,但对于表单部分,您可以随时推送,弹出,插入和删除控件,而无需重新创建表单或进行复杂的交互 .

    如果我链接到的教程发生故障,这里有一些示例代码可以自己实现(我的示例使用TypeScript)来说明基本思想:

    Base Component code:

    import { Component, Input, OnInit } from '@angular/core';
    import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
    
    @Component({
      selector: 'my-form-component',
      templateUrl: './my-form.component.html'
    })
    export class MyFormComponent implements OnInit {
        @Input() inputArray: ArrayType[];
        myForm: FormGroup;
    
        constructor(private fb: FormBuilder) {}
        ngOnInit(): void {
            let newForm = this.fb.group({
                appearsOnce: ['InitialValue', [Validators.required, Validators.maxLength(25)]],
                formArray: this.fb.array([])
            });
    
            const arrayControl = <FormArray>newForm.controls['formArray'];
            this.inputArray.forEach(item => {
                let newGroup = this.fb.group({
                    itemPropertyOne: ['InitialValue', [Validators.required]],
                    itemPropertyTwo: ['InitialValue', [Validators.minLength(5), Validators.maxLength(20)]]
                });
                arrayControl.push(newGroup);
            });
    
            this.myForm = newForm;
        }
        addInput(): void {
            const arrayControl = <FormArray>this.myForm.controls['formArray'];
            let newGroup = this.fb.group({
    
                /* Fill this in identically to the one in ngOnInit */
    
            });
            arrayControl.push(newGroup);
        }
        delInput(index: number): void {
            const arrayControl = <FormArray>this.myForm.controls['formArray'];
            arrayControl.removeAt(index);
        }
        onSubmit(): void {
            console.log(this.myForm.value);
            // Your form value is outputted as a JavaScript object.
            // Parse it as JSON or take the values necessary to use as you like
        }
    }
    

    Sub-Component Code :(每个新输入字段一个,以保持清洁)

    import { Component, Input } from '@angular/core';
    import { FormGroup } from '@angular/forms';
    
    @Component({
        selector: 'my-form-sub-component',
        templateUrl: './my-form-sub-component.html'
    })
    export class MyFormSubComponent {
        @Input() myForm: FormGroup; // This component is passed a FormGroup from the base component template
    }
    

    Base Component HTML

    <form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
        <label>Appears Once:</label>
        <input type="text" formControlName="appearsOnce" />
    
        <div formArrayName="formArray">
            <div *ngFor="let control of myForm.controls['formArray'].controls; let i = index">
                <button type="button" (click)="delInput(i)">Delete</button>
                <my-form-sub-component [myForm]="myForm.controls.formArray.controls[i]"></my-form-sub-component>
            </div>
        </div>
        <button type="button" (click)="addInput()">Add</button>
        <button type="submit" [disabled]="!myForm.valid">Save</button>
    </form>
    

    Sub-Component HTML

    <div [formGroup]="form">
        <label>Property One: </label>
        <input type="text" formControlName="propertyOne"/>
    
        <label >Property Two: </label>
        <input type="number" formControlName="propertyTwo"/>
    </div>
    

    在上面的代码中,我基本上有一个表示表单基础的组件,然后每个子组件在位于 FormGroup 基地内的 FormArray 内管理自己的 FormGroup 实例 . 基本模板将子组传递给子组件,然后您可以动态处理整个表单的验证 .

    此外,这使得通过从表单中策略性地插入和删除组件来重新排序组件变得微不足道 . 它(似乎)使用任何数量的输入,因为它们不与名称冲突(据我所知,模板驱动形式的一大缺点)并且您仍然保留了相当多的自动验证 . 这种方法唯一的“缺点”是,除了编写更多代码之外,还必须重新学习表单的工作方式 . 但是,随着您的继续,这将为更大,更动态的形式提供可能性 .

    如果您有任何疑问或想要指出一些错误,请继续 . 我刚刚根据我上周所做的事情输入了上面的代码,其名称已更改,其他misc也是如此 . 属性遗漏,但它应该是直截了当的 . 上面代码和我自己的代码之间唯一的主要区别是我将所有表单构建移动到一个单独的服务,该服务从组件中调用,因此它不那么混乱 .

相关问题