动态表单生成之拖拽生成表单(下)

我们的动态表单,最终要实现的效果与Form.io的在线生成表单的效果类似,可以参考它的demo地址:https://codepen.io/travist/full/xVyMjo

准备工作

首先,我们在过程中会需要用到一个弹出层控件,这里引用KendoUI的Dialogs,使用下面的命令安装:

npm i --save @progress/kendo-angular-dialog

安装完成后,会提示几个可选依赖没有安装,我们继续使用命令完成安装:

npm i --save @progress/kendo-angular-buttons jquery popper.js

然后,我们将上一个列子中的动态表单的相关代码Copy过来,用于我们本次动态表单的生成,首先是HTML中的代码,我们将它放到拖拽释放区域,代码如下:

<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中的具体控件的定义后复制过来,代码如下:

formModel: DynamicFormControlModel[] = [];
formGroup: FormGroup; constructor(private formService: DynamicFormService) {
} ngOnInit() {
this.formGroup = this.formService.createFormGroup(this.formModel);
}

好,准备工作到此完成。

动态添加文本框到表单中

下面,我们来实现将文本框添加到表单中。大概流程是这样的,当我们将文本框控件拖拽到表单中时,弹出一个窗口,让用户输入文本框的Id、Label、Placeholder,然后点击保存后,我们将文本框按用户输入的属性动态的添加到表单中。

我们一步步来~

首先,定义一个弹出窗口,并定义了一些属性和方法绑定到这个窗口中,其中:

textboxWindowIsOpen属性来绑定窗口是否可见

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);

Show Demo

让我们来看看效果吧(这只是个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

kendo-ui-drag-drop.component.html

  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

kendo-ui-drag-drop.component.ts

Angular动态表单生成(八)的更多相关文章

  1. Angular动态表单生成(七)

    动态表单生成之拖拽生成表单(上) 这个功能就比较吊炸天了,之前的六篇,都是ng-dynamic-forms自带的功能,可能很多的说明官方的文档都已经写了,我只是个搬运工,而在这篇文章中,我将化身一个工 ...

  2. Angular动态表单生成(一)

    好久不写博客了,手都生了,趁着最近老大让我研究动态表单生成的时机,撸一发博客~~ 开源项目比较 老大丢给我了两个比较不错的开源的动态表单生成工具,这两个项目在github上的star数量基本持平: h ...

  3. Angular动态表单生成(五)

    动态表单生成之布局 到上面的篇章为止,我们已经把表单比较完整的生成出来了,也实现了一些验证功能,可以说,我们截止这里,就已经可以满足我们的大部分表单生成需求了~ 但是: 目前来说,我们对于表单的布局只 ...

  4. Angular动态表单生成(六)

    动态表单之根据Json生成表单 我们在实际的使用中,动态表单往往是由服务器端的一系列配置,然后返回数据给客户端,最后客户端根据数据来动态的生成表单.那么怎么像我们上面所描述的这样,生成一个可以让我们的 ...

  5. Angular动态表单生成(二)

    ng-dynamic-forms源码分析 在两个开源项目中,ng-dynamic-forms的源码相较于form.io,比较简单,所以我还勉强能看懂,下面就我自己的理解进行简单分析,若有不对的地方,请 ...

  6. Angular动态表单生成(三)

    ng-dynamic-forms实践篇(上) 定个小目标 先来定个小目标吧,我们要实现的效果: 动态生成一个表单,里面的字段如下: 字段名称 字段类型 验证 备注 姓名 text 必填,长度小于15 ...

  7. Angular动态表单生成(四)

    ng-dynamic-forms实践篇(下) 我们接着上篇,先把小目标中的所有字段都定义出来 这部分就是苦力活儿了,把KendoUiComponent中的formModel完善即可: formMode ...

  8. form-create 3.0 版本发布,好用的Vue3版本动态表单生成组件

    form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成组件.支持2个UI框架,并且支持生成任何 Vue 组件.内置20种常用表单组件和自定义组件,再复杂 ...

  9. Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)

    Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成) 动态表单生成 ElementUI官网引导 Element表单生成 Element动态增减表单,在线代码 关键配置 templa ...

随机推荐

  1. drupal7设置不含www的url跳转到含www的url

    打开drupal的.htaccess文件 找到 If your site can be accessed both with and without the 'www.' prefix 将下面对应的三 ...

  2. GADL针对矢量数据格式转换的实用工具 —— ogr2ogr

    最初,因为可爱的学弟请教如何将ESRI Shapefile文件导入Google Earth接触到了Ogr2Ogr.粗略了解之后发现,这小东西功能强大. 谷歌地球支持矢量数据的展示,前提是数据符合KML ...

  3. 网络I/O模型--06异步I/O

    异步I/O (又称为 AIO )则是采用“订阅一通知”工作模式 : 即应用程序向操作系统注册I/O监听,然后继续做自己的事情.当操作系统发生I/O事件,并且准备好数据后 , 再主动通知应用程序,触发相 ...

  4. 用flutter写一个精美的登录页面

    先看效果图: 源代码已上传到github 我们先看一下页面 , 首先这个页面,我们并没有用到AppBar,当然也就没有自带返回功能.然后下面有个Login的文字以及一条横线. 屏幕中上方是填写帐号以及 ...

  5. settimeout、setinterval区别和相互模拟

    前几天翻书,看到“避免双重求值”一节时有提到settimeout().setinterval() 建议传入函数而不是字符串以作为第一个参数,所以这里总结一下settimeout()和setinterv ...

  6. 【转】虚拟机安装Ubuntu的上网设置(有线网络和无线网络)

    虚拟机下ubuntu共享方式上网: 一. 有线网络 在有线网络的条件下,vmware的安装非常简单,上网方式几乎不用怎么设置(默认NAT模式)    如果默认情况下不能上网,则按以下步骤尝试: *** ...

  7. git pull 错误:The following untracked working tree files would be overwritten by merge

    错误描述: $ git pull origin alphaFrom https://github.com/shirley-wu/HeartTrace * branch            alpha ...

  8. leetCode题解之寻找一个数在有序数组中的范围Search for a Range

    1.问题描述 Given an array of integers sorted in ascending order, find the starting and ending position o ...

  9. 12.Spring——Web MVC框架

    1.Spring Web MVC 框架 2.Spring MVC Hello World 例子 1.Spring Web MVC 框架 Spring web         MVC 框架提供了模型-视 ...

  10. Linux 挂载

    千万不要挂载到 根目录下 也不要用 umount -fl  会死的 fdisk -l 看 能挂载的是哪个盘 格式化 mkfs.ext4 /dev/vde 创建一个文件 mkdir /testmnt 卸 ...