- 首页
- 其他开发
- 如何在 Angular 2 中动态添加和删除表单字段
如何在 Angular 2 中动态添加和删除表单字段
[英] How to dynamically add and remove form fields in Angular 2
本文介绍了如何在 Angular 2 中动态添加和删除表单字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试在用户单击添加按钮时动态添加输入字段,并且对于每个表单字段都必须有一个删除按钮,当用户单击必须删除表单字段时,我需要使用 Angular 实现这一点2、由于我是 Angular 2 的新手,请帮助我完成它
我的尝试
我创建了一组字段(3 个选择框和 1 个文本框),创建了一个名为添加字段的按钮,但我在 angular 1.x 中尝试过它工作正常,但在 angular 2 中我不知道如何要完成它,这是我全部工作的链接
app/app.component.ts进口 {成分}来自'@angular/core';@成分({选择器:'我的应用',模板:`<h1>{{title}}</h1><div class="容器"><button class="btn btn-success bt-sm">add</button><form role="form" calss="form-inline"><div class="form-group col-xs-3"><label>选择状态:</label><select class="form-control" [(ngModel)]="rules.State" id="sel1"><option>State1</option><option>State2</option><option>State3</option><option>State4</option></选择>
<div class="form-group col-xs-3"><label>规则:</label><input type="text" data-toggle="modal" data-target="#myModal" class="form-control">
<div class="form-group col-xs-3"><label>通过状态:</label><select class="form-control" [(ngModel)]="rules.pass"><option>State1</option><option>State2</option><option>State3</option><option>State4</option></选择>
<div class="form-group col-xs-3"><label>失败状态:</label><select class="form-control" [(ngModel)]="rules.fail"><option>State1</option><option>State2</option><option>State3</option><option>State4</option></选择>
</表单>
<div class="modalfade" id="myModal" role="dialog"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal">× </button><h4 class="modal-title">规则配置</h4>
<div class="modal-body"><p>规则</p>
<div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
`})导出类 AppComponent {title = '规则引擎演示';规则:规则 = {状态: '',经过: '',失败: ''};
解决方案
这已经晚了几个月,但我想我会根据 本教程.其要点是,一旦您改变处理表单的方式,管理起来就会容易得多.
首先,使用ReactiveFormsModule
代替普通的FormsModule
或与其一起使用.使用响应式表单,您可以在组件/服务中创建表单,然后将它们插入页面而不是页面生成表单本身.这是更多的代码,但它更易于测试,更灵活,据我所知,这是制作大量非平凡形式的最佳方法.
最终结果看起来有点像这样,概念上:
您有一个基本的 FormGroup
以及整个表单所需的任何 FormControl
实例.例如,在我链接的教程中,假设您需要一个表单,用户可以在其中输入一次姓名,然后输入任意数量的地址.所有一次性字段输入都将在此基本表单组中.
在那个 FormGroup
实例中会有一个或多个 FormArray
实例.FormArray
基本上是一种将多个控件组合在一起并对其进行迭代的方法.您还可以在数组中放置多个 FormGroup
实例,并将它们用作嵌套在较大表单中的本质上的迷你表单".
通过在动态 FormArray
中嵌套多个 FormGroup
和/或 FormControl
实例,您可以控制有效性并将表单管理为一个,由几个动态部分组成的大型反应片.例如,如果你想在允许用户提交之前检查每一个输入是否有效,一个子表单的有效性会冒泡"到顶级表单,整个表单变得无效,这样很容易管理动态输入.
由于 FormArray
本质上是数组接口的包装器,但对于表单块,您可以随时推送、弹出、插入和删除控件,而无需重新创建表单或进行复杂的交互.
如果我链接的教程失败了,这里有一些示例代码,您可以自己实现(我的示例使用 TypeScript)来说明基本思想:
基本组件代码:
import { Component, Input, OnInit } from '@angular/core';从@angular/forms"导入 { FormArray, FormBuilder, FormGroup, Validators };@成分({选择器:'我的表单组件',templateUrl: './my-form.component.html'})导出类 MyFormComponent 实现 OnInit {@Input() inputArray: ArrayType[];我的表格:表格组;构造函数(私有 fb:FormBuilder){}ngOnInit(): 无效 {让 newForm = this.fb.group({出现一次:['InitialValue', [Validators.required, Validators.maxLength(25)]],formArray: this.fb.array([])});const arrayControl = <FormArray>newForm.controls['formArray'];this.inputArray.forEach(item => {让 newGroup = this.fb.group({itemPropertyOne: ['InitialValue', [Validators.required]],itemPropertyTwo: ['InitialValue', [Validators.minLength(5), Validators.maxLength(20)]]});arrayControl.push(newGroup);});this.myForm = newForm;}添加输入():无效{const arrayControl = <FormArray>this.myForm.controls['formArray'];让 newGroup = this.fb.group({/* 填写与 ngOnInit 中相同的内容 */});arrayControl.push(newGroup);}delInput(索引:数字):无效{const arrayControl = <FormArray>this.myForm.controls['formArray'];arrayControl.removeAt(index);}onSubmit(): void {console.log(this.myForm.value);//您的表单值作为 JavaScript 对象输出.//将其解析为 JSON 或根据需要采用必要的值}}
子组件代码:(每个新输入字段一个,以保持整洁)
import { Component, Input } from '@angular/core';从@angular/forms"导入{FormGroup};@成分({选择器:我的表单子组件",templateUrl: './my-form-sub-component.html'})导出类 MyFormSubComponent {@Input() myForm: FormGroup;//该组件从基础组件模板中传递了一个 FormGroup}
基本组件 HTML
子组件 HTML
<label>属性一:</label><input type="text" formControlName="propertyOne"/><label >属性二:</label><input type="number" formControlName="propertyTwo"/>
在上面的代码中,我基本上有一个代表表单基础的组件,然后每个子组件在位于基础 FormGroup
.基本模板将子组传递给子组件,然后您可以动态处理整个表单的验证.
此外,这使得通过有策略地从表单中插入和删除组件来重新排序组件变得微不足道.它适用于(似乎)任意数量的输入,因为它们与名称不冲突(据我所知,模板驱动表单的一个很大缺点)并且您仍然保留了几乎自动验证.这种方法的唯一缺点"是,除了编写更多代码之外,您还必须重新学习表单的工作原理.但是,随着您的进行,这将为更大、更动态的表单开辟可能性.
如果您有任何问题或想指出一些错误,请继续.我只是根据我上周自己做的事情输入了上面的代码,名称已更改和其他杂项.属性被遗漏了,但它应该是直截了当的.上面的代码和我自己的代码之间的唯一主要区别是,我将所有的表单构建移到了从组件调用的单独服务中,因此它不那么混乱.
I'm trying to add input fields dynamically while the user clicks the add button and for each form field there must be a remove button, when the user clicks that the form fields must be removed, I need to achieve this using Angular 2, as I'm new to Angular 2 please help me to complete it
What I have tried
I have created a set of fields (3 select box and 1 text box), created a button called add fields, but I have tried it in angular 1.x its working fine but in angular 2 I don't know how to complete it, this is link of my full work
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">× </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: ''
};
解决方案
This is a few months late but I thought I'd provide my solution based on this here tutorial. The gist of it is that it's a lot easier to manage once you change the way you approach forms.
First, use ReactiveFormsModule
instead of or in addition to the normal FormsModule
. With reactive forms you create your forms in your components/services and then plug them into your page instead of your page generating the form itself. It's a bit more code but it's a lot more testable, a lot more flexible, and as far as I can tell the best way to make a lot of non-trivial forms.
The end result will look a little like this, conceptually:
You have one base FormGroup
with whatever FormControl
instances you need for the entirety of the form. For example, as in the tutorial I linked to, lets say you want a form where a user can input their name once and then any number of addresses. All of the one-time field inputs would be in this base form group.
Inside that FormGroup
instance there will be one or more FormArray
instances. A FormArray
is basically a way to group multiple controls together and iterate over them. You can also put multiple FormGroup
instances in your array and use those as essentially "mini-forms" nested within your larger form.
By nesting multiple FormGroup
and/or FormControl
instances within a dynamic FormArray
, you can control validity and manage the form as one, big, reactive piece made up of several dynamic parts. For example, if you want to check if every single input is valid before allowing the user to submit, the validity of one sub-form will "bubble up" to the top-level form and the entire form becomes invalid, making it easy to manage dynamic inputs.
As a FormArray
is, essentially, a wrapper around an array interface but for form pieces, you can push, pop, insert, and remove controls at any time without recreating the form or doing complex interactions.
In case the tutorial I linked to goes down, here some sample code you can implement yourself (my examples use TypeScript) that illustrate the basic ideas:
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: (one for each new input field, to keep things clean)
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>
In the above code I basically have a component that represents the base of the form and then each sub-component manages its own FormGroup
instance within the FormArray
situated inside the base FormGroup
. The base template passes along the sub-group to the sub-component and then you can handle validation for the entire form dynamically.
Also, this makes it trivial to re-order component by strategically inserting and removing them from the form. It works with (seemingly) any number of inputs as they don't conflict with names (a big downside of template-driven forms as far as I'm aware) and you still retain pretty much automatic validation. The only "downside" of this approach is, besides writing a little more code, you do have to relearn how forms work. However, this will open up possibilities for much larger and more dynamic forms as you go on.
If you have any questions or want to point out some errors, go ahead. I just typed up the above code based on something I did myself this past week with the names changed and other misc. properties left out, but it should be straightforward. The only major difference between the above code and my own is that I moved all of the form-building to a separate service that's called from the component so it's a bit less messy.
这篇关于如何在 Angular 2 中动态添加和删除表单字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文