首页 > 其他分享 >formly-form 动态表单

formly-form 动态表单

时间:2022-12-19 18:23:04浏览次数:77  
标签:formly FormlyFieldConfig form true label key props 表单 type

动态表单库

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 protected]' };
  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允许您定义最多三个方法,这些方法将在表单构建过程中按此顺序调用:

  1. prePopulate
  2. onPopulate
  3. 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,FormlyFieldConfig,form,true,label,key,props,表单,type
From: https://www.cnblogs.com/fangdongdemao/p/16992806.html

相关文章

  • EBS挂载FORM详细步骤
    上传fmb文件编译到指定目录,具体编译到哪里,可以在applicationdeveloper职责下的应用产品->注册查看F11搜索,搜索%SECOM%,记下基本路径,下一步会用到3编译登录服务器,进......
  • go 表单
     处理表单的输入用户在表单中输入的数据会以键值的形式记录在请求的主体(body)中,然后以HTTPPOST请求的形式发送至服务器。服务器在接收浏览器发送的表单请求后,还需要......
  • 问题解决系列:NameError: name 'platform_system' is not defined
    问题场景使用 ​​pip​​​安装依赖的时候,更新之后,更新的依赖不能用。比如我将机器的​​ansible​​​版本指定安装​​2.7.11​​​版本,安装成功之后,使用命令​​ansible......
  • ffmpeg使用avformat_close_input()函数释放结构体时崩溃的问题
    先看一下我调试时,发现程序崩溃的代码位置//这是我的程序释放流上下文时的操作if(m_pAvFormatContext){if(m_iVideoStreamIndex>=0)avcodec_free_context(&m......
  • 显示一个Form中的所有内容
    如果想把上个网页<Form>..</Form>内的所有内容显示出来,有这样两种方法:231、以ForEach..In..45<%6ForEachNameInRequest.Form......
  • Transformers库之模型(Model)组件和分词器(Tokenizer)组件
    目录模型加载模型保存模型分词器分词策略加载与保存分词器编码与解码文本处理多段文本Padding操作Attentionmasks直接使用分词器编码句子对模型在之前介绍pipeline组......
  • 经典文献阅读之--Swin Transformer
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......
  • 【机器学习】李宏毅——Transformer
    Transformer具体就是属于Sequence-to-Sequence的模型,而且输出的向量的长度并不能够确定,应用场景如语音辨识、机器翻译,甚至是语音翻译等等,在文字上的话例如聊天机器人、文章......
  • @JSONField 和 @JsonFormat,前后端日期格式转换
    DTO:前端向后端接口请求时的对象。VO:后端向前端响应的对象。前端:vue后端:SpringBoot+MybatisPlus涉及的两个包:com.alibaba.fastjson.annotation.JSONField;com.......
  • #yyds干货盘点# react笔记之学习之创建表单
    前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从......