咱們的動態表單,最終要實現的效果與Form.io的在線生成表單的效果相似,能夠參考它的demo地址:https://codepen.io/travist/full/xVyMjocss
首先,咱們在過程當中會須要用到一個彈出層控件,這裏引用KendoUI的Dialogs,使用下面的命令安裝:html
npm i --save @progress/kendo-angular-dialog
安裝完成後,會提示幾個可選依賴沒有安裝,咱們繼續使用命令完成安裝:jquery
npm i --save @progress/kendo-angular-buttons jquery popper.js
而後,咱們將上一個列子中的動態表單的相關代碼Copy過來,用於咱們本次動態表單的生成,首先是HTML中的代碼,咱們將它放到拖拽釋放區域,代碼以下:npm
<div class="col-md-8">
<h4>請將表單元素拖拽到這裏</h4>
<div style="min-height: 300px;background-color: #EDEDEE" droppable (onDrop)="onDropToForm($event)">
<form [formGroup]="formGroup" class="k-form">
<dynamic-kendo-form [group]="formGroup"
[model]="formModel"
>
</dynamic-kendo-form>
</form>
</div>
</div>
而後,咱們咱們將Component中的相關代碼刪掉FormModel中的具體控件的定義後複製過來,代碼以下:app
formModel: DynamicFormControlModel[] = []; formGroup: FormGroup; constructor(private formService: DynamicFormService) { } ngOnInit() { this.formGroup = this.formService.createFormGroup(this.formModel); }
好,準備工做到此完成。ide
下面,咱們來實現將文本框添加到表單中。大概流程是這樣的,當咱們將文本框控件拖拽到表單中時,彈出一個窗口,讓用戶輸入文本框的Id、Label、Placeholder,而後點擊保存後,咱們將文本框按用戶輸入的屬性動態的添加到表單中。ui
咱們一步步來~this
首先,定義一個彈出窗口,並定義了一些屬性和方法綁定到這個窗口中,其中:spa
textboxWindowIsOpen屬性來綁定窗口是否可見code
closeTextboxWindow方法用於關閉窗口
saveTextBox方法用於用戶點擊保存按鈕後的動態添加控件到表單的相關事件處理
Id,Label,Placeholder文本框均與txtBox的相關屬性綁定,txtBox屬性的類型爲DynamicInputModel,即ng-dynamic-forms中定義的文本框的類型。
<kendo-window title="請輸入表單元素屬性" *ngIf="textboxWindowIsOpen" (close)="closeTextboxWindow()"
[minWidth]="250" [width]="450">
<form class="k-form">
<label class="k-form-field">
<span>ID</span>
<input class="k-textbox" placeholder="Text Box Id" name="id" [(ngModel)]="txtBox.id"/>
</label>
<label class="k-form-field">
<span>Label</span>
<input class="k-textbox" placeholder="Text Box Label" name="label" [(ngModel)]="txtBox.label"/>
</label>
<label class="k-form-field">
<span>Placeholder</span>
<input class="k-textbox" placeholder="Text Box Placeholder" name="placeholder" [(ngModel)]="txtBox.placeholder"/>
</label>
<div class="text-right">
<button type="button" class="k-button" (click)="closeTextboxWindow()">關閉</button>
<button type="button" class="k-button k-primary" (click)="saveTextBox()">保存</button>
</div>
</form>
</kendo-window>
而後讓咱們來看看最終ts代碼中邏輯的實現吧:
首先是屬性的定義:
textboxWindowIsOpen = false; txtBox: DynamicInputModel = new DynamicInputModel({});
其次當文本框控件拖拽到表單區域時,由上篇中提到的onDrop時間的觸發來打開上面定義的window:
onDropToForm(event) { switch (event.dragData.type) { case 'TextBox': this.openTextboxWindow(); break; default: break; } }
打開和關閉window的方法其實就是修改了以下textboxWindowIsOpen屬性的值:
openTextboxWindow() { this.textboxWindowIsOpen = true; } closeTextboxWindow() { this.textboxWindowIsOpen = false; }
最後,當用戶點擊保存時,動態添加文本框到表單中:
saveTextBox() { const newTxtbox = new DynamicInputModel({ id: this.txtBox.id, label: this.txtBox.label, placeholder: this.txtBox.placeholder }); this.formModel.push(newTxtbox); this.formGroup = this.formService.createFormGroup(this.formModel); this.closeTextboxWindow(); }
保存的這段代碼中,有兩個點須要注意:
1.不能直接將咱們定義的txtBox屬性push到formModel中,由於txtBox是對象,爲引用類型,而咱們的txtBox是一個公用的對象,若是直接push該對象,則後續該對象發生變化,formModel中的該對象也會跟着變。
2.push完成後,必須再次使用formService建立表單,這裏的緣由我也沒有找到,不這樣作會報錯~
this.formGroup = this.formService.createFormGroup(this.formModel);
讓咱們來看看效果吧(這只是個Demo,有很是明顯的Bug還請你們見諒)
另外,對於其餘的控件,其實原理都是同樣的,只是在彈出的窗口中的屬性不一樣而已,這裏提供給你們思路,若是我把這些元素都實現了,我會放出來給你們~
拖拽相關的全部代碼打包以下:
1 <div style="padding:20px;"> 2 <div class="row" style="margin-top:20px;border: 1px solid;padding:10px;"> 3 <div class="col-md-4"> 4 <ul class="list-group"> 5 <li class="list-group-item" draggable [dragData]="{type:'TextBox'}">TextBox</li> 6 <li class="list-group-item" draggable [dragData]="{type:'Select'}">Select</li> 7 <li class="list-group-item" draggable [dragData]="{type:'TextArea'}">TextArea</li> 8 <li class="list-group-item" draggable [dragData]="{type:'Password'}">Password</li> 9 <li class="list-group-item" draggable [dragData]="{type:'Number'}">Number</li> 10 </ul> 11 </div> 12 <div class="col-md-8"> 13 <h4>請將表單元素拖拽到這裏</h4> 14 15 <div style="min-height: 300px;background-color: #EDEDEE" droppable (onDrop)="onDropToForm($event)"> 16 <form [formGroup]="formGroup" class="k-form"> 17 <dynamic-kendo-form [group]="formGroup" 18 [model]="formModel" 19 > 20 21 </dynamic-kendo-form> 22 </form> 23 </div> 24 </div> 25 </div> 26 </div> 27 28 <kendo-window title="請輸入表單元素屬性" *ngIf="textboxWindowIsOpen" (close)="closeTextboxWindow()" 29 [minWidth]="250" [width]="450"> 30 31 <form class="k-form"> 32 33 <label class="k-form-field"> 34 <span>ID</span> 35 <input class="k-textbox" placeholder="Text Box Id" name="id" [(ngModel)]="txtBox.id"/> 36 </label> 37 <label class="k-form-field"> 38 <span>Label</span> 39 <input class="k-textbox" placeholder="Text Box Label" name="label" [(ngModel)]="txtBox.label"/> 40 </label> 41 <label class="k-form-field"> 42 <span>Placeholder</span> 43 <input class="k-textbox" placeholder="Text Box Placeholder" name="placeholder" [(ngModel)]="txtBox.placeholder"/> 44 </label> 45 46 <div class="text-right"> 47 <button type="button" class="k-button" (click)="closeTextboxWindow()">關閉</button> 48 <button type="button" class="k-button k-primary" (click)="saveTextBox()">保存</button> 49 </div> 50 </form> 51 52 </kendo-window> 53
1 import {Component, OnInit} from '@angular/core'; 2 import {DynamicFormControlModel, DynamicFormService, DynamicInputModel} from "@ng-dynamic-forms/core"; 3 import {FormGroup} from "@angular/forms"; 4 5 @Component({ 6 selector: 'app-kendo-ui-drag-drop', 7 templateUrl: './kendo-ui-drag-drop.component.html', 8 styleUrls: ['./kendo-ui-drag-drop.component.css'] 9 }) 10 export class KendoUiDragDropComponent implements OnInit { 11 12 textboxWindowIsOpen = false; 13 txtBox: DynamicInputModel = new DynamicInputModel({}); 14 formModel: DynamicFormControlModel[] = []; 15 formGroup: FormGroup; 16 17 constructor(private formService: DynamicFormService) { 18 } 19 20 21 ngOnInit() { 22 this.formGroup = this.formService.createFormGroup(this.formModel); 23 } 24 25 onDropToForm(event) { 26 switch (event.dragData.type) { 27 case 'TextBox': 28 this.openTextboxWindow(); 29 break; 30 default: 31 break; 32 } 33 } 34 35 openTextboxWindow() { 36 this.textboxWindowIsOpen = true; 37 } 38 39 closeTextboxWindow() { 40 this.textboxWindowIsOpen = false; 41 } 42 43 saveTextBox() { 44 const newTxtbox = new DynamicInputModel({ 45 id: this.txtBox.id, 46 label: this.txtBox.label, 47 placeholder: this.txtBox.placeholder 48 }); 49 50 this.formModel.push(newTxtbox); 51 this.formGroup = this.formService.createFormGroup(this.formModel); 52 this.closeTextboxWindow(); 53 } 54 } 55