如何在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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章