README
Form
1. 介绍
注意!所有的回调方法都是用对象解构方式传参数的
就是这样 ⬇️
handleChange({fieldName,fieldBizData,...}){
// Your code is here.
}
该组件从平台Form组件中抽出,内置了如下平台逻辑:
- 表单联动
- 字段依赖(根据字段的值刷新某一字段的数据源)
- 表单验证
- 同步验证
- 异步验证
2. 可扩展的逻辑
2.1 表单元数据加载
2.1.1 直接提供表单元数据
当直接给overrideFormMetaData
传递表单元数据时,表单将跳过网络请求,直接使用提供的元数据。
不提供这个属性时,表单将按照popOption
中提供的数据加载数据。
2.1.2 自定义表单元数据请求地址
实现getFormViewRequestURL
方法,表单将会使用该URL请求表单元数据。
getFormViewRequestURL(){
return url
}
<Form {...otherProps} getFormViewRequestURL={getFormViewRequestURL}/>
2.1.3 使用自定义参数加载
请求表单时至少要有这四个基础的参数app
, metaObjName
, viewName
, formState
,这四个参数。当formState
需要传入id
。
表单请求时会带上additionParamsWhenLoad
里面的参数,保存时会带上additionParamsWhenSave
里面的参数。
const formViewParams = {
// id: '',
app: 'BeisenCloudStepAAA',
metaObjName: 'BeisenCloudStepAAA.liandongzhuanyong',
viewName: 'BeisenCloudStepAAA.shareddemoform2',
formState: 'create',
additionParamsWhenLoad: {
param1:'param1content',
param2:'param2content'
},
additionParamsWhenSave: {
param1:'param1content',
param2:'param2content'
},
additionHeadersWhenSave:{
header1:'header1content',
header2:'header2content'
},
httpMethodWhenSave: 'POST'
// customSaveURL: YOUR_API
}
<Form {...otherProps} formViewParams={formViewParams}/>
2.1.4 过滤(修改)表单元数据
当表单元数据从网络加载后,如果存在属性formMetaDataFilter
,会执行该方法,并将返回的元数据作为展示表单的元数据。
formMetaDataFilter({formMetaData}){
// do some change
return formMetaData
}
<Form {...otherProps} formMetaDataFilter={formMetaDataFilter} />
2.1.5 修改表单参数重新加载表单
当formViewParams
中除additionParamsWhenSave
以外任何一部分发生变化时,表单会重新加载。
可以通过实现shouldReloadFormData
方法重写判断是否重新加载表单逻辑。
2.2 过滤数据源
当表单数据源加载后,会调用dataSourceFilter
方法,该方法会传入每个DataSource
项(fieldName
、key
、dataSourceResults
),用return
的dataSourceResults
作为新的数据源。
2.3 替换组件
替换组件的优先级如下:
当渲染该字段时,会首先根据字段元数据的cmp_data.field_name
(复合表单为cmp_data.field_name_form_multi
)从extendedFieldMapByFieldName
中查询。
如果查询不到该组件,会首先根据字段元数据的cmp_type
从extendedFieldMap
中查询。
如果查询不到该组件,则会从平台标准组件的FieldMap
中查询。
如果仍然查询不到,则会默认使用单行文本
代替。
2.3.1 根据字段名替换组件
props
为字段的渲染前的props
,OriginalComponent
为
const overrideFields = {
a1: (props, OriginComponent) => {
return (
<div>
<OriginComponent {...props} />
<span>自定义自定义</span>
</div>
);
},
extdanxuansetting_100013_62398125: ()=> {
return <Hello />
}
}
<Form {...otherProps} extendedFieldMapByFieldName={overrideFields}/>
2.3.2 根据字段类型替换组件
支持传入自定义字段组件。传入字段组件需要遵照以下格式:
const overrideFields = {
FIELD_TYPE1: (props, OriginComponent) => {
return (
<div>
<OriginComponent {...props} />
<span>自定义自定义</span>
</div>
);
},
FIELD_TYPE2: ()=> {
return <Hello />
}
}
<Form {...otherProps} extendedFieldMap={overrideFields}/>
2.4 表单联动
此处将值改变时处罚联动逻辑的字段成为控制字段
。
2.4.1 设定监听字段
需要将所有的控制字段
都通过extendedFormLinkageFields
这个props传入。
这样做的目的是,当触发联动时,可以使用专门的onFormLinkage
方法处理联动逻辑,减小onChange
方法的体积。
设想一下,如果联动逻辑依赖于onChange
方法,那么在onChange
内做联动逻辑必定会使得onChange
方法非常大。尤其是涉及到链式联动逻辑时。
将联动逻辑和onChange
分开,可以得到更好的代码结构。
2.4.2 实现回调方法
实现接口方法onFormLinkage
,该方法会传入:
fieldName
发生值改变的控制字段的字段名fieldBizData
控制字段的值formBizData
当前表单(所有字段)的值fieldBizDataBeforeChange
控制字段的值改变之前的值formLinkageFunctions
表单联动操作方法集,包含的方法在2.4.3
介绍commitFormLinkage
提交表单联动操作
当进行表单联动操作后,必须调用commitFormLinkage
提交联动操作。这样做的原因是考虑到有一些联动逻辑是异步进行的,因此联动方法也应该是异步的。
请务必确保联动提交。否则,未使用commitFormLinkage
提交的联动不会生效,还会遗留在联动操作队列中,产生奇怪的问题。
这里要强调,每调用一次commitFormLinkage
,都会立刻进行联动逻辑。需要考虑数据同步(例如进行设定字段值后进行了commitFormLinkage
,但一个异步请求还没返回)和性能问题。建议有异步操作的在异步回调中使用commitFormLinkage
。
实际上,每个表单联动方法做的事情,在表单联动操作队列中添加一条联动记录(也可以认为是一条消息),当调用commitFormLinkage
时,执行联动操作队列中所有的联动逻辑。
对于设定setFieldError
和removeFieldError
这两个显示和移除字段错误信息的联动方法,由于没有传入验证器,错误信息的显示和隐藏需要手动维护。表单进行验证(且失败)时,回调方法onValidateFailed
的参数formErrors
会包含联动设置的错误。
2.4.3 表单联动操作方法
method | params | description |
---|---|---|
hideField | fieldName | 使字段fieldName隐藏 |
showField | fieldName | 使字段fieldName显示 |
presenceField | fieldName | 使字段fieldName必填 |
nonPresenceField | fieldName | 使字段fieldName非必填 |
readOnlyField | fieldName | 使字段fieldName只读 |
clearBizData | fieldName | 清空字段fieldName的值 |
setBizData | fieldName, bizData | 设置字段fieldName的值 |
setBizDataGroup | bizDataMap, fieldNamesToInvokeNextLinkageOn | 同时设置多个数据,如果有下一级联动,触发指定字段的联动 |
updateDataSource | fieldName, dataSourceResults | 更新字段fieldName的数据源 |
hideFormPart | formPartIndex | 隐藏第formPartIndex个表单区块(从0开始) |
showFormPart | formPartIndex | 显示第formPartIndex个表单区块(从0开始) |
setFieldError | fieldName, errorMessage | 使字段fieldName显示错误errorMessage |
removeFieldError | fieldName | 移除字段fieldName上的错误信息(必须是由setFieldError设定的错误信息) |
2.4.4 代码风格
**请尽量使用对象解构的方式接收参数,尽量使用switch-case来区分fieldName和fieldBizData.value的值,减少if-else的使用。**否则当逻辑较多时,过多的if-else会让代码变得非常乱。
2.5 表单验证
2.5.1 传入自定义验证器
自定义验证器function
格式为validate.js的自定义验证器格式
const extendedValidators = {
validatorName1: validateFunction1,
validatorName2: validateFunction2,
validatorName3: validateFunction3,
}
<Form {...otherProps} extendedValidators={extendedValidators} />
2.5.2 自定义字段的验证器
传入extendedFieldValidators
属性可以单独定义每个字段的验证器。替换组件的组件只能使用这种方式定义验证器。
在extendedFieldValidators
中,每个function
的参数是表单元数据带的验证器,需要返回最终决定的该字段的验证器。
const extendedFieldValidators = {
fieldName1: (originalValidators) => {
return Object.assign({},validators,{presence: {message: "^必填"}})
},
fieldName2: () => {
return Object.assign({presence: {message: "^必填"}})
}
}
<Form {...otherProps} extendedFieldValidators={extendedFieldValidators}/>
2.5.3 重写验证逻辑
实现overrideValidate
方法。
该方法的参数是表单数据formBizData
和表单元数据formMetaData
。
该方法需要返回一个Promise
,值为validate.js
的错误类型,当验证通过时,应返回可判断为false
的值(建议返回null
)。
2.5.4 在onChange中手动设定错误信息
当onChange调用时,functions
参数中有两个方法:setError(errorMessage)
和removeError()
,可以通过调用这两个方法给字段设置错误信息。
但需要注意,和联动中的设置字段错误一样,需要手动清除字段错误信息才能通过表单验证(实际上内部实现是一样的,只是绑定了fieldName)。
2.6 表单提交
2.6.1 重写表单提交逻辑
实现overrideSubmit
方法。参数是表单的数据bizData
。
2.6.2 自定义提交附带参数
见2.1.3
。
2.6.3 表单提交前
表单验证通过后,开始提交前会回调preSubmit
方法,该方法需要返回一个Promise
。当返回resolve
时,表单会继续进行提交动作,返回reject
时,会中断提交动作。
这是一个例子,通过做一个前置请求,决定是否提交数据,当这个前置请求返回错误时,弹出错误提示
export default class PreSubmitExample extends Component {
handlePreSubmit = ({ formBizData, functions }) => {
const _417 = 'https://api.simgenius.cn/simrest/ObjectData/BSDevHelper/OperationResult/4615096d-6752-495f-a32c-ceac05e5beea';
const _200 = 'https://api.simgenius.cn/simrest/ObjectData/BSDevHelper/OperationResult/6ea7ac57-14da-41bb-b59e-b60903c6db33';
return new Promise((resolve,reject)=>{
fetch(_417)
.then(r => r.json())
.then((operationResult) => {
if(operationResult.code !== 200){
this.formMethods.showTip({title:operationResult.message, infoType:'error', content:[]})
reject(operationResult)
}else {
return functions.showConfirm(operationResult.message)
}
}).then(()=>{console.log('confirm'); resolve();},()=>{console.log('cancel');reject()})
})
};
render() {
const popOptions = {
formSaveLabel: '想要一个长长的名字,很长很长的,长长长长长长长长的',
cmpContext: {
app: 'BeisenCloudDemo',
'currentViewName': 'BeisenCloudDemo_Sshitu',
'metaObjName': 'BeisenCloudDemo.123'
},
formState: 'create',
};
return (
<FormWithFooter
formMethods={f=>this.formMethods = f}
overrideFormMetaData={require('../BugFix__NOT_EXAMPLE/metadata6')}
BSGlobal={BSGlobal}
popOptions={popOptions}
preSubmit={this.handlePreSubmit}
/>
);
}
}
2.7 捕获内部事件
内部事件产生时机见下图的生命周期。
实现onImplicitEvent
方法,参数为eventName
、params
。目前params
没有参数传进来,将来传递参数仍然会通过对象解构方式传递到params
。
3. API
3.1 值类型props
name | type | default | description |
---|---|---|---|
overrideFormMetaData | MetaData | none | 当使用这个属性时,表单会直接使用提供的元数据,不再通过网络请求获取表单的元数据。 |
formLinkageFields | Array<string> | none | 扩展联动逻辑中,控制字段的字段名 |
extendedFieldMap | Dictionary |
none | 传入的自定义组件列表 |
extendedFieldMapByFieldName | Dictionary |
none | 传入的自定义组件列表 |
defaultBizData | BizData | none | 表单的初始值 |
formViewParams | Object | none | 表单的参数,其中: app, metaObjName, viewName, formState必填,编辑时需要填表单数据的id,additionParamsWhenLoad为加载时的额外参数,additionParamsWhenSave为提交时的额外参数 |
extendedValidators | Dictionary |
none | 自定义验证器 |
extendedFieldValidators | Dictionary |
none | 自定义字段的验证器 |
loadingIsFixedPosition | boolean | false | 表单加载的loading是否是fixed定位 |
3.1 function类型props
name | params | returns | description |
---|---|---|---|
onChange | fieldName, fieldBizData, formBizData, fieldBizDataBeforeChange, functions | none | 表单数据改变时的回调 |
onFormLinkage | fieldName, fieldBizData, formBizData, fieldBizDataBeforeChange, formLinkageFunctions, commitFormLinkage | undefined | 表单联动回调 |
dataSourceFilter | fieldName, key, dataSourceResults | dataSourceResults | 数据源过滤器 |
formMetaDataFilter | formMetaData | formMetaData | 过滤(修改)表单元数据 |
overrideValidate | formBizData, formMetaData | Promise<form_errors> | 自定义表单验证过程 |
onValidateFailed | formErrors | none | 表单验证失败时的回调 |
overrideSubmit | bizData | none | 自定义表单提交过程 |
preSubmit | formBizData, dataToSubmit, functions | Promise | 表单验证通过后,开始提交前的回调 |
onSubmitted | response | none | 表单提交成功后的回调 |
onSubmitFailed | Promise.reject<response> | none | 表单提交失败时的回调 |
onImplicitEvent | eventName, params | none | 隐式事件回调 |
shouldReloadFormData | prevProps, currentProps, formBizData, formErrors | boolean | 当formViewParams发生变化时,是否重新加载表单 |
3.3 methods
name | params | returns | description |
---|---|---|---|
showTip | tipOption | none | 弹出Tip |
submit | none | none | 表单提交 |
validate | none | Promise |
表单验证 |
getBizData | none | BizData | 获取表单数据 |