angular学习之动态创建表单的方法


Posted in Javascript onDecember 07, 2018

准备工作

使用ng new async-form创建一个新工程,在app.module.ts中引入ReactiveFormsModule模块并在根模块中导入

import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
 imports: [
  ReactiveFormsModule
 ]
})

构建表单元素的基类

export class QuestionBase<T> {
  value: T;//表单元素的值
  key: string;//表单元素键的名称
  label: string;//输入元素的标题
  required: boolean;//是否必输
  order: number;//排序
  controlType: string;//表单的类型 选择框/文本输入框

  constructor(options: {
    value?: T,
    key?: string,
    label?: string,
    required?: boolean,
    order?: number,
    controlType?: string
  } = {}) {
    this.value = options.value;
    this.key = options.key || '';
    this.label = options.label || '';
    this.required = !!options.required;
    this.order = options.order === undefined ? 1 : options.order;
    this.controlType = options.controlType || '';
  }
}

继承表单元素的基类

选择框元素的数据类型继承基类,设置了controlType 为'dropdown'并新增了属性options数组

import { QuestionBase } from './question-base';

export class QuestionDropdown extends QuestionBase<string>{
  controlType = "dropdown";
  options: { key: string, value: string }[] = [];

  constructor(options: {} = {}) {
    super(options);
    this.options = options["options"] || [];
  }
}

文本输入框元素的数据类型继承了基类,设置了controlType 为'textbox',新增了type属性,定义input的类型

import { QuestionBase } from './question-base';

export class QuestionTextbox extends QuestionBase<string> {
  controlType = "textbox";
  type:string;
  constructor(options:{} ={}){
    super(options);
    this.type = options["type"]||""
  }
}

生成数据

根据表单元素的派生类生成表单的数据。可以引入一个服务类,提供表单数据。

getQuestions(){
  let questions:QuestionBase<any>[]=[
   new QuestionDropdown({
    key:'brave',
    label:'Bravery Rating',
    options:[
     {key:'solid',value:'Solid'},
     {key:'great',value:'Great'},
     {key:'good',value:'Good'},
     {key:'unproven',value:'Unproven'}
    ],
    order:3
   }),
   new QuestionTextbox({
    key:'firstName',
    label:'First name',
    value:"Bombasto",
    required:true,
    order:1
   }),
   new QuestionTextbox({
    key:'emailAddress',
    label:"Email",
    type:'email',
    order:2
   })
  ];
  return questions.sort((a, b) => a.order - b.order);
 }

将数据转成FormControl类型

可以专门提供一个服务类,将表单的数据转成FormControl类型

toFormGroup(questions: QuestionBase<any>[]) {
  let group: any = {};

  questions.forEach(question => {
   group[question.key] = question.required?new FormControl(question.value||"",Validators.required)
   :new FormControl(question.value||"");
  });
  return new FormGroup(group);
 }

到这里就已经完整构建出一组FormControl 实例了。

为数据提供页面模板

<div [formGroup]="form">
 <label [attr.for]="question.key">{{question.label}}</label>
 <div [ngSwitch]="question.controlType">
  <input *ngSwitchCase="'textbox'" [formControlName]= "question.key" 
  [id]="question.key" [type]="question.type">
  <select [id]="question.key" *ngSwitchCase="'dropdown'"
   [formControlName]="question.key">
   <option *ngFor="let opt of question.options" [value]="opt.key">
    {{opt.value}}
   </option>
  </select>
 </div>
 <div class="errorMessage" *ngIf="!isValid">
  {{question.label}} is required
 </div>
</div>

通过formGroup指令绑定表单数据,ngSwitch指令来选择生成的模板,formControlName指令绑定对应的表单数据的key值

import { Component, OnInit, Input } from '@angular/core';
import {FormGroup} from '@angular/forms';

import {QuestionBase} from '../question-base';

@Component({
 selector: 'app-dynamic-form-question',
 templateUrl: './dynamic-form-question.component.html',
 styleUrls: ['./dynamic-form-question.component.less']
})
export class DynamicFormQuestionComponent implements OnInit {
 @Input() question:QuestionBase<any>;
 @Input() form :FormGroup;
 get isValid(){
  return this.form.controls[this.question.key].valid;
 }
 constructor() { }

 ngOnInit() {
 }

}

表单组件需要两个输入,form和question,form来获取对应表单的键值是否校验成功,question来渲染对应表单输入元素。使用app-dynamic-form-question标签来使用组件

引用表单组件

<div *ngFor="let question of questions" class="form-row">
   <app-dynamic-form-question [question]="question" [form]="form"></app-dynamic-form-question>
  </div>

获取到questions数据后,通过*ngFor指令来渲染单个表单组件。

结束

到这里就完成了动态创建表单的功能,以这种方式来创建表单,我们只需要开始时构建出指定的单个输入框或者其他表单元素的样式之后,通过改变数据来控制表单的内容,便于后期维护。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Js之软键盘实现(js源码)
Jan 30 Javascript
JavaScript回调(callback)函数概念自我理解及示例
Jul 04 Javascript
javascript 小数取整简单实现方式
May 30 Javascript
php+js实现倒计时功能
Jun 02 Javascript
JavaScript实现的简单拖拽效果
Jun 01 Javascript
jQuery使用animate实现ul列表项相互飘动效果示例
Sep 16 Javascript
推荐三款日期选择插件(My97DatePicker、jquery.datepicker、Mobiscroll)
Apr 21 jQuery
详解ES6之用let声明变量以及let loop机制
Jul 15 Javascript
vue.js2.0 实现better-scroll的滚动效果实例详解
Aug 13 Javascript
layer弹出子iframe层父子页面传值的实现方法
Nov 22 Javascript
Vue实现导航栏的显示开关控制
Nov 01 Javascript
Vue中axios拦截器如何单独配置token
Dec 27 Javascript
JavaScript栈和队列相关操作与实现方法详解
Dec 07 #Javascript
微信小程序实现两边小中间大的轮播效果的示例代码
Dec 07 #Javascript
vue webpack打包后图片路径错误的完美解决方法
Dec 07 #Javascript
详解在create-react-app使用less与antd按需加载
Dec 06 #Javascript
vant(ZanUi)结合async-validator实现表单验证的方法
Dec 06 #Javascript
使用react render props实现倒计时的示例代码
Dec 06 #Javascript
微信小程序冒泡事件及其阻止方法实例分析
Dec 06 #Javascript
You might like
PHP操作XML作为数据库的类
2010/12/19 PHP
PHP将XML转数组过程详解
2013/11/13 PHP
Thinkphp框架+Layui实现图片/文件上传功能分析
2020/02/07 PHP
非常有用的40款jQuery 插件推荐(系列二)
2011/12/25 Javascript
原生JS实现表单checkbook获取已选择的值
2013/07/21 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
Javascript变量作用域详解
2013/12/06 Javascript
基于NodeJS的前后端分离的思考与实践(二)模版探索
2014/09/26 NodeJs
Javascript的闭包详解
2014/12/26 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
JavaScript中定时控制Throttle、Debounce和Immediate详解
2016/11/17 Javascript
Vue实现双向绑定的方法
2016/12/22 Javascript
基于vue-cli配置lib-flexible + rem实现移动端自适应
2017/12/26 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
2018/01/21 Javascript
Vue-cli Eslint在vscode里代码自动格式化的方法
2018/02/23 Javascript
jquery判断滚动条距离顶部的距离方法
2018/09/05 jQuery
详解如何在vscode里面调试js和node.js的方法步骤
2018/12/24 Javascript
Vue项目引发的「过滤器」使用教程
2019/03/12 Javascript
[54:45]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 Optic vs OG
2018/04/02 DOTA
解决python2.7用pip安装包时出现错误的问题
2017/01/23 Python
Python实现字符串与数组相互转换功能示例
2017/09/22 Python
matplotlib中legend位置调整解析
2017/12/19 Python
PyQt5 QTable插入图片并动态更新的实例
2019/06/18 Python
python3 线性回归验证方法
2019/07/09 Python
Python实现二叉搜索树BST的方法示例
2019/07/30 Python
解决Pytorch 训练与测试时爆显存(out of memory)的问题
2019/08/20 Python
基于python2.7实现图形密码生成器的实例代码
2019/11/05 Python
StubHub意大利:购买和出售全球演唱会和体育赛事门票
2017/11/21 全球购物
捷克鲜花配送:Florea.cz
2018/10/29 全球购物
.NET笔试题(20个问题)
2016/02/02 面试题
日本语毕业生自荐信
2014/02/01 职场文书
小班下学期评语
2014/05/04 职场文书
学校运动会霸气口号
2014/06/07 职场文书
教师见习报告范文
2014/11/03 职场文书
何时使用Map来代替普通的JS对象
2021/04/29 Javascript
【海涛解说】暗牧也疯狂,牛蛙成配角
2022/04/01 DOTA