如何在Angular中创建复杂的动态表单?
WEB前端开发社区 昨天
表单是Web应用程序中非常重要的部分。有时我们会遇到一个情况,即form元素是静态的并且定义明确。有时,Web应用程序开发会从静态形式扩展到动态形式。动态表单没有静态字段。
动态表单和控件可以基于某些事件生成。在本文中,我们将基于单击加号生成控件。单击减号按钮将其删除。
这是一种类似于芯片的结构,其中我们具有加号和减号按钮来添加和删除文本字段。在本文中,我们以产品为例。
角度设计
Angular支持两种动态控制设计。
模板驱动-在模板驱动的表单中,可以更好地控制角度模板。该模板非常强大,并且具有Angular框架内置的大多数功能。我们只需要手工设计出干净整洁的HTML。我自由也正在使用这种方法。
反应形式-同样非常强大,大多数控件位于组件中。需要Formbuilder来构建表单。
构建动态组件
我们正在构建产品组件。该产品具有产品名称和产品代码。该产品还有另一个可选参数,即产品功能。产品功能部件包含功能部件名称,功能部件添加日期和功能部件说明。
这些功能可以随时添加。我们要添加的功能数量没有限制。如下所示:
模型设计
创建界面产品功能并将其传递到产品界面。产品界面采用了诸如数组之类的产品功能。下面是数据模型。
export interface productFeatures{ featureName:string, featureAddedDate:string, featureDescription?:string}export interface Product<productFeatures> { id: number | null; productName: string; productCode: string; description?: string; productFeatures?: productFeatures[];} export const products: Product<productFeatures>[] = [ { id: 1, productName: 'Netgear Cable Modem', productCode: 'CM700', description: 'Netgear Cable Modem compatible with all cables', productFeatures: [{ featureName:"", featureAddedDate:"", featureDescription:"" }] }, ];
接着就是创建一个子组件。是的,我在这里创建一个子组件。因为在大多数企业应用程序中,我们应该创建一小组组件。
<app-product-feature> </ app-product-feature>
我们必须将数据从子组件传递到父组件。因此,这里定义了parentProductFields函数,该函数将数据设置为父组件。
<app-product-feature(parentProductFields)=“ parentProductFields($ event)”> </ app-product-feature>
在父组件中创建方法parentProduct。此方法将设置this.productField,其类型为Product <productFeatures>。
productField: Product<productFeatures> = {} as Product<productFeatures>;parentProductFields(value) {console.log(`calling hour recieved from parent is ${JSON.stringify(value)}`)this.productField = value;}
现在,在目录product下创建子组件产品功能。将父产品字段定义为@Output属性。parentProductFields的类型为Product <productFeatures>。
@Output() parentProductFields = new EventEmitter<Product<productFeatures>>()
用初始数据初始化。在这里,产品ID初始化为1,其余字段初始化为空。每当添加新功能时,产品功能数组都会包含一个对象,我们将在功能数组中推送一个新功能对象。
productField: Product<productFeatures> = {id: 1,productName: '’,productCode: '’,description: '’,productFeatures: [{featureName:””,featureAddedDate:””,featureDescription:””}]}
完整的产品组件将如下所示。
import { Component, Input, Output,EventEmitter } from '@angular/core';import {Product,productFeatures} from './product';@Component({ selector: 'app-product-feature', templateUrl: "./product-feature.component.html"})export class ProductFeatureComponent {@Input() childProductField: Product<productFeatures>;@Output() parentProductFields = new EventEmitter<Product<productFeatures>>(); productField: Product<productFeatures> = { id: 1, productName: '', productCode: '', description: '', productFeatures: [{ featureName:"", featureAddedDate:"", featureDescription:"" }] }addNewProdField(index: number): void {let prod: productFeatures = {"featureName": "","featureAddedDate": "","featureDescription": "" } ;this.productField.productFeatures.push(prod);console.log(`In method addNewProdField field index is ${index} and field is ${JSON.stringify(JSON.stringify( this.productField))}`);this.parentProductFields.emit(this.productField); } removeNewProdField(index: number): void {this.productField.productFeatures.splice(index, 1);console.log(`In method addNewProdField field index is ${index}`);this.parentProductFields.emit(this.productField); }}
现在开始写HTML结构。在HTML产品名称中,产品代码为文本框。产品功能是我们迭代以生成动态组件的动态表。
<tbody><ng-template ngFor let-prod [ngForOf]=”productField.productFeatures” let-i=”index”><tr><td><!-- Product feature here --><td></tr></ng-template></tbody>
在开发此控件时,发现了一件重要的事情。你必须为每个控件动态创建ID。否则,将创建该控件的相同深层副本。
<td><input class=”form-control minimal” id=”{{featureAddedDate + prod}}”[(ngModel)]=”prod.featureAddedDate”></td>
完整的HTML文件如下所示。
<h5>Product component</h5><div class="row"> <div class="col-md-12"> </div></div><div class="row"> <div class="col-md-12"> </div></div><div class="row required-field"> <div class="col-md-4"> <label class="cus-form-label">Product Name</label> <input class="form-control minimal" id="productName" [(ngModel)]="productField.productName"> </div></div><div class="row"> <div class="col-md-12"> </div></div><div class="row required-field"> <div class="col-md-4"> <label class="cus-form-label">Product Code</label> <input class="form-control minimal" id="productCode" [(ngModel)]="productField.productCode"> </div></div><div class="row"> <div class="col-md-12"> </div></div><label class="cus-form-label">Product Features</label><div class="row"> <div class="col-md-12"> </div></div><table class="col-lg-8" id="callingHours-id" style="background-color: white;"> <thead> <tr> <th class="bordered-cell" style="width: 30%;">Feature Name</th> <th class="bordered-cell">Feature Date</th> <th class="bordered-cell">Feature Description</th> </tr> </thead> <tbody> <ng-template ngFor let-prod [ngForOf]="productField.productFeatures" let-i="index"> <tr> <td> <input class="form-control minimal" id="{{name + prod}}" [(ngModel)]="prod.featureName"> </td> <td> <input class="form-control minimal" id="{{featureAddedDate + prod}}" [(ngModel)]="prod.featureAddedDate"> </td> <td> <input class="form-control minimal" id="{{featureDescription + prod}}" [(ngModel)]="prod.featureDescription"> </td> <td> <ng-container> <button id="{{'remoeMinus' +i}}" class="btn btn-xs btn-danger" (click)="removeNewProdField(i)"> <i class="fa fa-minus"></i> </button> </ng-container> <ng-container> <button id="{{'addrec'+ i }}" class="btn btn-xs btn-primary" (click)="addNewProdField(i)"> <i class="fa fa-plus"></i> </button> </ng-container> </td> </tr> </ng-template> </tbody></table>
添加产品功能
要添加新产品功能,请添加以下代码。此方法向this.productField.productFeatures添加新功能产品
addNewProdField(index: number): void {let prod: productFeatures = {“featureName”: “”,“featureAddedDate”: “”,“featureDescription”: “”} ;this.productField.productFeatures.push(prod);console.log(`In method addNewProdField field index is ${index} and field is ${JSON.stringify(JSON.stringify( this.productField))}`);this.parentProductFields.emit(this.productField);}
删除产品功能
要删除产品功能,请从this.productField.productFeatures中拼接产品索引。
removeNewProdField(index: number): void {this.productField.productFeatures.splice(index, 1);console.log(`In method addNewProdField field index is ${index}`);this.parentProductFields.emit(this.productField);}
要显示子组件数据中的更改,请在父组件HTML中添加以下行。
<pre>{{productField | json}}</ pre>
现在,你可以看到添加的字段的JSON数据。
{ "id": 1, "productName": "Netgear Wireless Router", "productCode": "NG123", "description": "", "productFeatures": [ { "featureName": "capacity", "featureAddedDate": "05/01/2020", "featureDescription": "123" }, { "featureName": "range", "featureAddedDate": "05/01/2020", "featureDescription": "123" } ]}
总结
同样,我们可以将示例扩展为多个产品。创建产品数组并使用* ngFor循环进行显示。在这种情况下,我们应该有两个索引。
产品的一个索引和其他产品功能。产品索引将有助于添加到产品阵列中,而功能索引将有助于添加/删除产品功能。
在stackblitz项目中附加完整的代码示例,截图如下: