如何在Angular中创建复杂的动态表单?

英文 | https://medium.com/javascript-in-plain-english/how-to-create-a-complex-dynamic-form-in-angular-19a472af6060

翻译 | web前端开发(ID:web_qdkf)

表单是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">&nbsp;</div></div><div class="row">  <div class="col-md-12">&nbsp;</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">&nbsp;</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">&nbsp;</div></div><label class="cus-form-label">Product Features</label><div class="row">  <div class="col-md-12">&nbsp;</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项目中附加完整的代码示例,截图如下:

演示地址:https://stackblitz.com/edit/angular-dynamic-component-1-h6hxos

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值