formly-form 动态表单
动态表单库
https://github.com/ngx-formly/ngx-formly
安装
ng add @ngx-formly/schematics --ui-theme=ng-zorro-antd
@ngx-formly/ng-zorro-antd
选择UI
bootstrap
material
ng-zorro-antd
ionic
primeng
kendo
nativescript
会默认导入到Module
+ import { ReactiveFormsModule } from '@angular/forms';
+ import { FormlyModule } from '@ngx-formly/core';
+ import { FormlyBootstrapModule } from '@ngx-formly/bootstrap';
@NgModule({
imports: [
BrowserModule,
+ FormsModule,
+ ReactiveFormsModule,
// -----------
FormlyNgZorroAntdModule,
NzFormModule,
// -------
+ FormlyModule.forRoot(),
+ FormlyBootstrapModule
],
...
})
formly-form
<formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
该<formly-form>
组件是表单的主要容器
fields
:用于构建表单的字段配置。form
:允许跟踪模型值和验证状态的表单实例。model
:表格要表示的模型
form = new FormGroup({});
model = { email: 'email@gmail.com' };
fields: FormlyFieldConfig[] = [
{
key: 'email',
type: 'input',
props: {
label: 'Email address',
placeholder: 'Enter email',
required: true,
}
}
];
Name | Type | Default | Required | Description |
---|---|---|---|---|
form | FormGroup or FormArray |
new FormGroup({}) |
no | 表单实例 |
fields | FormlyFieldConfig[] |
yes | 构建表单的字段配置 | |
model | any |
yes | 表单表示的模型 | |
options | FormlyFormOptions |
no | 表格的选项 |
(modelChange)
model 值发生变量的时候触发的事件
fields
Attribute | Type | Description |
---|---|---|
key | string |
model 的键 |
id | string |
请注意,id 如果未设置,则会生成。 |
name | string |
过于的表单name才有效 |
type | string |
自定义模板 |
className | string |
自定的class样式formly-field directive. |
props | object |
任何特定于模板的选项都放在此处 |
templateOptions | object |
任何特定于模板的选项都放在此处,props 进行改用(props权重高一些) |
template | string |
自定义html 内容, 而不是type |
defaultValue | any |
model 为设置,或者为undefined , 该模型的值被分配 |
hide | boolean |
是否隐藏字段 |
hideExpression | boolean /string /function |
有条件地隐藏该字段 |
expressions | boolean /string /function |
一个对象,其中键是要在主字段配置上设置的属性,值是用于分配该属性的表达式。 |
focus | boolean |
是否获取焦点. 默认为 false . 可以用 expressions 进行设置 |
wrappers | string[] |
自定义组件里面包装label , 可以设置样式 |
parsers | function[] |
每当模型更新(通常通过用户输入)时,作为管道执行的函数数组 |
fieldGroup | FormlyFieldConfig[] |
字段组, 让高级布局更简单, 对于通过模型关联的字段进行分组 |
fieldArray | FormlyFieldConfig |
|
fieldGroupClassName | string |
formly-group 组件的class |
validation | object |
校验messages 信息的显示 |
validators | any |
特定字段设置验证规则 |
asyncValidators | any |
异步验证的内容 |
formControl | AbstractControl |
该字段的FormControl。它为您提供更多控制,如运行验证器、计算状态和重置状态。 |
modelOptions | object |
控制模型更改的有用属性的对象: debounce , updateOn |
modelOptions?: {
debounce?: { // 防抖的ms 值
default: number;
};
// https://angular.io/api/forms/AbstractControl#updateOn 触发方式
updateOn?: 'change' | 'blur' | 'submit';
};
formState
配合option
进行状态通信
NgModule 声明中声明验证函数和消息
自定义校验
// 自定义报错信息
export function IpValidatorMessage(error: any, field: FormlyFieldConfig) {
return `"${field.formControl.value}" is not a valid IP Address`;
}
// 报错规则
export function IpValidator(control: AbstractControl): ValidationErrors | null {
return /(\d{1,3}\.){3}\d{1,3}/.test(control.value) ? null : { 'ipTwo': true };
}
...
@NgModule({
imports: [
...
FormlyModule.forRoot({
validationMessages: [
{ name: 'ipTwo', message: IpValidatorMessage },
{ name: 'required', message: 'This field is required' },
],
validators: [
{ name: 'ipTwo', validation: IpValidator },
],
}),
]
})
页面上使用
{
key: 'ip',
type: 'input',
props: {
label: 'IP Address (using custom validation declared in ngModule)',
required: true,
},
validators: {
validation: ['ipTwo'],
},
// 异步校验器
asyncValidators: {
validation: ['ipAsync'],
},
},
字段声明校验函数
export function IpValidator(control: AbstractControl): ValidationErrors {
return /(\d{1,3}\.){3}\d{1,3}/.test(control.value) ? null : { 'ipTwo': true };
}
{
key: 'ip',
type: 'input',
props: {
label: 'IP Address (using custom validation through `validators.validation` property)',
required: true,
},
validators: {
validation: [IpValidator],
},
// 异步函数
asyncValidators: {
validation: [IpAsyncValidator],
},
},
在字段定义中声明验证函数和消息
{
key: 'ip',
type: 'input',
props: {
label: 'IP Address (using custom validation through `validators.expression` property)',
description: 'custom validation message through `validators.expression` property',
required: true,
},
validators: {
ip: {
// 为true 为符合报错信息
expression: (c: AbstractControl) => /(\d{1,3}\.){3}\d{1,3}/.test(c.value),
message: (error: any, field: FormlyFieldConfig) => `"${field.formControl.value}" is not a valid IP Address`,
},
},
asyncValidators: {
ip: {
expression: (c: AbstractControl) => return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(/(\d{1,3}\.){3}\d{1,3}/.test(c.value));
}, 1000);
}),
message: (error: any, field: FormlyFieldConfig) => `"${field.formControl.value}" is not a valid IP Address`,
},
},
},
在 NgModule 声明中的表单类型和消息中声明验证函数
export function IpValidator(control: AbstractControl): boolean {
return /(\d{1,3}\.){3}\d{1,3}/.test(control.value);
}
@NgModule({
imports: [
...
FormlyModule.forRoot({
validationMessages: [
{ name: 'ipTwo', message: 'This field is required' },
],
types: [
{
name: 'ipTwo',
extends: 'input',
defaultOptions: {
validators: {
ip: IpValidator // 'ip' matches the ip validation message
}
},
},
}),
]
})
形式表达式expression
{
key: 'text2',
type: 'input',
props: {
label: 'Hey!',
placeholder: 'This one is disabled if there is no text in the other input',
},
expressions: {
'props.disabled': '!model.text',
'props.disabled': (field: FormlyFieldConfig) => {
return !field.model.text;
},
},
},
条件
{
key: 'iLikeTwix',
type: 'checkbox',
props: {
label: 'I like twix',
},
expressions: {
hide: '!model.name',
hide: (field: FormlyFieldConfig) => {
return field.model?.city === "123";
},
},
}
点击
toggle(){
this.fields[0].hide = !this.fields[0].hide;
}
formState 状态
<formly-form [model]="model" [fields]="fields" [options]="options" [form]="form"></formly-form>
form = new FormGroup({});
model: any = {};
options: FormlyFormOptions = {
formState: {
disabled: true,
},
};
fields: FormlyFieldConfig[] = [
{
key: 'text',
type: 'input',
props: {
label: 'First Name',
},
expressions: {
// apply expressionProperty for disabled based on formState
'props.disabled': 'formState.disabled',
},
},
];
toggleDisabled() {
this.options.formState.disabled = !this.options.formState.disabled;
}
生命周期
hooks: {
afterContentInit: () => {},
afterViewInit: () => {},
onInit: () => {},
onChanges: () => {},
onDestroy: () => {},
},
参数
export type FormlyHookFn = (field: FormlyFieldConfig) => void;
export interface FormlyHookConfig {
onInit?: FormlyHookFn;
onChanges?: FormlyHookFn;
afterContentInit?: FormlyHookFn;
afterViewInit?: FormlyHookFn;
onDestroy?: FormlyHookFn;
}
例如
hooks:{
onInit(f: FormlyFieldConfigCache) {
f.formControl = new FormControl();
}
},
}
fieldChanges
值得监听(源码是对valueChanges
进行封装)
hooks: {
onInit(f: FormlyFieldConfigCache) {
f?.options?.fieldChanges?.subscribe(res => {
console.log(res,'ressss');
})
}
},
modelOptions: {
debounce: {default: 3000},// 防抖
updateOn: 'change'
}
自定义组件
import { Component } from '@angular/core';
import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
@Component({
selector: 'formly-field-input',
template: `
<input type="input" [formControl]="formControl" [formlyAttributes]="field">
`,
})
export class InputFieldType extends FieldType<FieldTypeConfig> {}
ngModule 注册组件
@NgModule({
declarations: [InputFieldType],
import { InputFieldType } from './intput-field.type';
@NgModule({
imports: [
FormlyModule.forRoot({
types: [
{ name: 'inputOne', component: InputFieldType },
],
}),
],
})
types 有两个属性
name:组件类型的名称。type您在字段的选项中使用它。
component:设置此类型时 Formly 应创建的组件。
页面使用
方式一, 直接把组件传递给字段使用
fields: FormlyFieldConfig[] = [
{
key: 'firstname',
type: InputFieldType,
},
];
方式二, 使用ngModule 注册的type
fields: FormlyFieldConfig[] = [
{
key: 'firstname',
type: 'inputOne',
},
];
自定义label 组件
创建一个代表扩展FieldWrapper
类的包装器的组件。
import { Component, ViewChild, ViewContainerRef } from '@angular/core';
import { FieldWrapper } from '@ngx-formly/core';
@Component({
selector: 'formly-wrapper-panel',
template: `
<div class="card">
<h3 class="card-header">Its time to party</h3>
<h3 class="card-header">{{ props.label }}</h3>
<div class="card-body">
<ng-container #fieldComponent></ng-container>
</div>
<!-- 报错的信息 -->
<ng-container *ngIf="showError">
<formly-validation-message [field]="field"></formly-validation-message>
</ng-container>
</div>
`,
})
export class PanelFieldWrapper extends FieldWrapper {
}
使用
@NgModule({
declarations: [PanelFieldWrapper],
imports: [
FormlyModule.forRoot({
wrappers: [
{ name: 'panel', component: PanelFieldWrapper },
],
}),
],
})
页面使用
方式一 直接传递组件
fields: FormlyFieldConfig[] = [
{
key: 'address',
wrappers: [PanelFieldWrapper],
props: { label: 'Address' },
fieldGroup: [{
key: 'town',
type: 'input',
props: {
required: true,
type: 'text',
label: 'Town',
},
}],
},
];
方法二:将PanelFieldWrapper
别名(在 中定义FormlyModule.forRoot
)传递给字段配置。
fields: FormlyFieldConfig[] = [
{
key: 'address',
+ wrappers: ['panel'],
props: { label: 'Address' },
fieldGroup: [{
key: 'town',
type: 'input',
props: {
required: true,
type: 'text',
label: 'Town',
},
}],
},
];
在module组合使用
@NgModule({
imports: [
FormlyModule.forRoot({
types: [
{
name: 'operator',
component: OperatorComponent, //输入框组件
wrappers: ['form-field'] //label 组件
},
],
}),
],
自定义扩展接口属性
创建了一个扩展,它定义了一个默认标签(如果它FormlyFieldConfig
本身没有定义的话)
定义接口类
*default-label-extension.ts*
import { FormlyExtension } from '@ngx-formly/core';
export const defaultLabelExtension: FormlyExtension = {
prePopulate(field): void {
if (field.props?.label) {
return;
}
field.props = {
...field.props,
label: 'Default Label'
}
},
};
FormlyExtension
允许您定义最多三个方法,这些方法将在表单构建过程中按此顺序调用:
prePopulate
onPopulate
postPopulate
注册自定义扩展
@NgModule({
imports: [
FormlyModule.forRoot({
extensions: [
{
name: 'default-label',
extension: defaultLabelExtension,
priority:1 // 优先级, 默认1
}
]
})
],
})
lazyRender 延迟加载组件
默认为true
当设置为false, 渲染字段组件并使用CSS控制其可见性。
例如
constructor(
private config: FormlyConfig,
) {
this.config.extras.lazyRender = false;
}
fields: FormlyFieldConfig[] = [
{
key: 'input',
type: 'input',
hide:true, // 设置为true,隐藏, 我们发现是通过css隐藏的
templateOptions: {
label: 'Input',
placeholder: 'Input placeholder',
required: true,
},
},
]
renderFormlyFieldElement
是否呈现渲染每项中<form-field>
组件里面的dom
默认为true
// 我们发现里面的内容都被隐藏啦
this.config.extras.renderFormlyFieldElement = false;
我们发现form-field
组件的内容会提取到外层
异步修改值
{
key: 'input',
type: 'input',
props: {
label: '测试1'
},
expressions: {
'props.label':timer(2000).pipe(
map(()=>'修改为2')
)
},
}
修改一项的值
ngOnInit(): void {
setTimeout(()=>{
this.fields[0]?.formControl?.setValue('aaaa');
console.log(this.model);
},2000)
}
key 支持括号/点的方式拿到属性
fields: FormlyFieldConfig[] = [{
key: 'name[0].age',
type: 'textarea',
className: 'flex-1',
}]
model = {name: [{age: 'sexName'}]};
下拉框
fields: FormlyFieldConfig[] = [
// 多选
{
key: 'Select',
type: 'select',
props: {
label: 'Select',
placeholder: 'Placeholder',
description: 'Description',
required: true,
options: [
{ value: 1, label: 'Option 1' },
{ value: 2, label: 'Option 2' },
{ value: 3, label: 'Option 3' },
{ value: 4, label: 'Option 4', disabled: true },
],
},
},
// 多选
{
key: 'select_multi',
type: 'select',
props: {
label: 'Select Multiple',
placeholder: 'Placeholder',
description: 'Description',
required: true,
multiple: true,
selectAllOption: 'Select All',
options: [
{ value: 1, label: 'Option 1' },
{ value: 2, label: 'Option 2' },
{ value: 3, label: 'Option 3' },
{ value: 4, label: 'Option 4', disabled: true },
],
},
},
];
单选
fields: FormlyFieldConfig[] = [
{
key: 'Radio',
type: 'radio',
props: {
label: 'Radio',
placeholder: 'Placeholder',
description: 'Description',
required: true,
options: [
{ value: 1, label: 'Option 1' },
{ value: 2, label: 'Option 2' },
{ value: 3, label: 'Option 3' },
{ value: 4, label: 'Option 4', disabled: true },
],
},
},
];
复选
fields: FormlyFieldConfig[] = [
{
key: 'Checkbox',
type: 'checkbox',
props: {
label: 'Accept terms',
description: 'In order to proceed, please accept terms',
pattern: 'true',
required: true,
},
validation: {
messages: {
pattern: 'Please accept the terms',
},
},
},
];
fields: FormlyFieldConfig[] = [
{
key: 'Textarea',
type: 'textarea',
props: {
label: 'Textarea',
placeholder: 'Placeholder',
description: 'Description',
required: true,
},
},
];
fields: FormlyFieldConfig[] = [
{
key: 'Input',
type: 'input',
props: {
label: 'Input',
placeholder: 'Placeholder',
description: 'Description',
required: true,
},
},
];
formly-form 动态表单的更多相关文章
- 解析:使用easyui的form提交表单,在IE下出现类似附件下载时提示是否保存的现象
之前开发时遇到的一个问题,使用easyui的form提交表单,在Chrome下时没问题的,但是在IE下出现类似附件下载时提示是否保存的现象. 这里记录一下如何解决的.其实这个现象不光是easyui的f ...
- Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)
Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成) 动态表单生成 ElementUI官网引导 Element表单生成 Element动态增减表单,在线代码 关键配置 templa ...
- angularjs 动态表单, 原生事件中调用angular方法
1. 原生事件中调用angular方法, 比如 input的onChange事件想调用angular里面定义的方法 - onChange="angular.element(this).sco ...
- vue 开发系列(八) 动态表单开发
概要 动态表单指的是我们的表单不是通过vue 组件一个个编写的,我们的表单是根据后端生成的vue模板,在前端通过vue构建出来的.主要的思路是,在后端生成vue的模板,前端通过ajax的方式加载后端的 ...
- 如何在.Net Core MVC中为动态表单开启客户端验证
非Core中的请参照: MVC的验证 jquery.validate.unobtrusive mvc验证jquery.unobtrusive-ajax 参照向动态表单增加验证 页面引入相关JS: &l ...
- Angular动态表单生成(八)
动态表单生成之拖拽生成表单(下) 我们的动态表单,最终要实现的效果与Form.io的在线生成表单的效果类似,可以参考它的demo地址:https://codepen.io/travist/full/x ...
- Angular动态表单生成(二)
ng-dynamic-forms源码分析 在两个开源项目中,ng-dynamic-forms的源码相较于form.io,比较简单,所以我还勉强能看懂,下面就我自己的理解进行简单分析,若有不对的地方,请 ...
- Angular动态表单生成(一)
好久不写博客了,手都生了,趁着最近老大让我研究动态表单生成的时机,撸一发博客~~ 开源项目比较 老大丢给我了两个比较不错的开源的动态表单生成工具,这两个项目在github上的star数量基本持平: h ...
- 使用easyui的form提交表单,在IE下出现类似附件下载时提示是否保存的现象
之前开发时遇到的一个问题,使用easyui的form提交表单,在Chrome下时没问题的,但是在IE下出现类似附件下载时提示是否保存的现象. 这里记录一下如何解决的.其实这个现象不光是easyui的f ...
- jquery 实现动态表单设计
只是实现了前台页面的动态表单的设计,并未实现后台绑定数据到数据库等功能.技术使用到的为jquery和bootstrap.俗话说有图有真相,先说下具体效果如下: 点击添加一个面板容器: 容器添加成功: ...
随机推荐
- Css3中自适应布局单位vh、vw
视口单位(Viewport units) 什么是视口? 在桌面端,视口指的是在桌面端,指的是浏览器的可视区域:而在移动端,它涉及3个视口:Layout Viewport(布局视口),Visual Vi ...
- PAT (Basic Level) Practice 1010 一元多项式求导 分数 25
设计函数求一元多项式的导数.(注:xn(n为整数)的一阶导数为nxn−1.) 输入格式: 以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数).数字间以空格分隔. 输出格式: ...
- 关于docker创建容器报错-docker: Error response from daemon: runtime "io.containerd.runc.v2" binary not installed
今天在对一台服务器(docker相关的业务服务器)进行OS补丁时,默认使用的 yum update -y 对所有的安装包进行了升级 升级完成后,让应用方检查确认应用及功能是否一切正常,如果不正常,严重 ...
- POJ1741 tree (点分治模板)
题目大意: 给一棵有 n 个顶点的树,每条边都有一个长度(小于 1001 的正整数).定义 dist(u,v)=节点 u 和 v 之间的最小距离.给定一个整数 k,对于每一对 (u,v) 顶点当且仅当 ...
- BZOJ2654 tree (wqs二分)
题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 一个最小生成树问题,但是我们要选need条白边,我们用g(i)表示选取i条 ...
- redis bitmap数据结构之java对等操作
在之前的文章中,我们有说过bitmap,bitmap在很多场景可以应用,比如黑白名单,快速判定,登录情况等等.总之,bitmap是以其高性能出名.其基本原理是一位存储一个标识,其他衍生知道咱就不说了, ...
- 通过QQ抓IP查询地址
使用工具: Wireshark 可以直接搜索官网获取,个人用的免费的,也可以直接在kali中也是可以直接用的.这里就不介绍怎么安装了,网上很多. 步入正题: 通过wireshark进行抓包查地址,需要 ...
- jquery+bootstrap学习笔记
最近小颖接了个私活,客户要求用jquery和bootstrap来实现业务需求,小颖总结了下在写的过程中的一下坑,来记录一下 1.动态加载html文件 switch (_domName) { case ...
- resutful的使用和增强版的swagger2
1.REST的特征 统一接口:客户和服务器之间通信的方法必须统一,RESUTFUL风格的数据元操作CRUD分别对应HTTP方法----GET用来获取数据源,POST用来新建资源,PUT用来更新资源,, ...
- 9.pygame-键盘捕获
创建英雄类 """英雄精灵""" class Hero(GameSprite): def __init__(self): # 调用父类方法, ...