diff --git a/docs/form-render/advanced-bind.md b/docs/form-render/advanced-bind.md index cb967b611..e136370e0 100644 --- a/docs/form-render/advanced-bind.md +++ b/docs/form-render/advanced-bind.md @@ -8,7 +8,7 @@ group: order: 1 --- -# bind + + + + +## 进阶 +- 对象嵌套情况, bind 要写绝对路径 +- List 组件嵌套情况,bind 路径从 List 嵌套的子节点开始写 +```jsx +import React from 'react'; +import { Button } from 'antd'; +import FormRender, { useForm } from 'form-render'; + +const delay = ms => new Promise(res => setTimeout(res, ms)); + +const schema = { + type: 'object', + properties: { + obj: { + title: '对象', + type: 'object', + description: '对象嵌套 bind 要写决定路径', + // bind: 'root', + properties: { + a: { + title: '日期', + widget: 'input', + }, + b: { + title: '日期', + widget: 'input', + }, + } + }, + obj2: { + title: '对象', + type: 'object', + description: '对象嵌套 bind 要写决定路径', + bind: 'parent', + properties: { + c: { + title: '日期', + widget: 'input', + bind: 'obj.c' + }, + d: { + title: '日期', + widget: 'input', + }, + + obj3: { + title: '对象', + type: 'object', + description: '对象嵌套 bind 要写决定路径', + bind: 'parent', + properties: { + e: { + title: '日期', + widget: 'input', + }, + f: { + title: '日期', + widget: 'input', + }, + + } + } + + } + } + } +}; + +const Demo = () => { + const form = useForm(); + const onFinish = (formData) => { + console.log(formData, 'formData'); + }; + return ( + { + form.setValues({ + d: 1, e: 1, f: 1, + obj: { + c: 3, + a:1, b:1, + }, + + + }) + } + } + /> + ); +}; + +export default Demo; + +``` diff --git a/docs/form-render/advanced-layout.md b/docs/form-render/advanced-layout.md index 354c49ee7..6c08cd0e1 100644 --- a/docs/form-render/advanced-layout.md +++ b/docs/form-render/advanced-layout.md @@ -367,3 +367,4 @@ export default () => { ); } ``` +s \ No newline at end of file diff --git a/package.json b/package.json index 89b0611b3..4fd122ddd 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "babel-plugin-no-debugger": "^0.0.1", "babel-plugin-transform-remove-console": "^6.9.4", "cross-env": "^7.0.3", - "dumi": "^2.0.2", + "dumi": "2.3.8", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", "enzyme-to-json": "^3.6.2", diff --git a/packages/form-render/src/models/bindValues.ts b/packages/form-render/src/models/bindValues.ts index 4e3c5a7fa..4df47bf0f 100644 --- a/packages/form-render/src/models/bindValues.ts +++ b/packages/form-render/src/models/bindValues.ts @@ -1,4 +1,4 @@ -import { get, set, unset } from 'lodash-es'; +import { get, set, unset, assignIn } from 'lodash-es'; import { _cloneDeep, isArray, @@ -29,24 +29,38 @@ const transformPath = (path: string) => { return result; }; -const transformValueToBind = (data: any, path: any, bind: false | string | string[]) => { +// 将 formData 数据按照 bind 配置进行转换 +const transformValuesToBind = (data: any, path: any, bind: false | string | string[], parentPath?: string) => { + // 配置 bind = false,在表单提交的时候可以将数据从 formData 中移除 if (bind === false) { unset(data, path); return; } - + + // bind: string if (typeof bind === 'string') { let value = get(data, path); - const preValue = get(data, bind); + const preValue = get(data, bind === 'parent' ? parentPath : bind); if (isObject(preValue)) { value = { ...preValue, ...value }; } - set(data, bind, value); + + // 更新数据 + if (bind === 'root' || parentPath === '#') { // 数据绑定到根节点 + assignIn(data, value) + } else if (bind === 'parent') { // 数据绑定到父节点 + set(data, parentPath, value); + } else { // 数据绑定到指定节点 + set(data, bind, value); + } + + // 移除原数据 unset(data, path); return; } - // The array is converted to multiple fields. + // bind: string[], 例如:bind: ['obj.startDate', 'obj.endDate'], + // 结果 [startDate, endDate] => {obj: { startDate, endDate }} if (isMultiBind(bind)) { const value = get(data, path); unset(data, path); @@ -58,13 +72,42 @@ const transformValueToBind = (data: any, path: any, bind: false | string | strin }); } } -} +}; + +// 按照 Bind 配置还原 formData 数据 +const transformBindToValue = (data: any, path: any, bind: false | string | string[], item?:any) => { + // bind: false 不用处理 + if (bind === false) { + return; + } -const transformBindToValue = (data: any, path: any, bind: any) => { + // bind: string if (typeof bind === 'string') { - let value = get(data, bind); + let value = get(data, bind) ; const preValue = get(data, path); - if (isObject(preValue)) { + + if (item?.children?.length > 0) { + value = { ...preValue, ...value }; + let obj = null; + if (bind === 'root' || item.parent === '#') { + obj = data; + } else if (bind === 'parent') { + obj = get(data, item.parent); + } + + item.children.forEach((item: any) => { + const list = item.split('.'); + const key = list[list.length-1]; + if (isObject(value[key])) { + value[key] = { + ...value?.[key], + ...obj?.[key] + } + } else if (!!obj) { + value[key] = obj[key]; + } + }) + } else if (isObject(preValue)) { value = { ...preValue, ...value }; } set(data, path, value); @@ -90,16 +133,16 @@ const transformBindToValue = (data: any, path: any, bind: any) => { } } - +// 转换表单数据 export const parseValuesToBind = (values: any, flatten: any) => { + // console.log(values, flatten, 'parseValuesToBind'); // No bind field exists, no processing if (!JSON.stringify(flatten).includes('bind')) { return values; } - const data = _cloneDeep(values); - const dealFieldList = (obj: any, [path, ...rest]: any, bind: any) => { + const dealFieldList = (obj: any, [path, ...rest]: any, bind: any, ) => { if (rest.length === 1) { const list = get(obj, path, []); list.forEach((item: any, index: number) => { @@ -108,7 +151,7 @@ export const parseValuesToBind = (values: any, flatten: any) => { list[index] = value; return; } - transformValueToBind(item, rest[0], bind); + transformValuesToBind(item, rest[0], bind); }); } @@ -122,22 +165,26 @@ export const parseValuesToBind = (values: any, flatten: any) => { Object.keys(flatten).forEach(key => { const bind = flatten[key]?.schema?.bind; + const parentPath = flatten[key]?.parent; if (bind === undefined) { return; } const path = transformPath(key); - isArray(path) ? dealFieldList(data, path, bind) : transformValueToBind(data, path, bind); + isArray(path) ? dealFieldList(data, path, bind) : transformValuesToBind(data, path, bind, parentPath); }); return data; }; +// 还原表单数据 export const parseBindToValues = (values: any, flatten: any) => { + console.log(values, flatten, 'parseBindToValues'); + // No bind field exists, no processing if (!JSON.stringify(flatten).includes('bind')) { return values; } - const data = _cloneDeep(values); + const dealFieldList = (obj: any, [path, ...rest]: any, bind: any) => { if (rest.length === 1) { const list = get(obj, path, []); @@ -157,15 +204,15 @@ export const parseBindToValues = (values: any, flatten: any) => { dealFieldList(value, rest, bind); } }; - + Object.keys(flatten).forEach(key => { - const bind = flatten[key]?.schema?.bind; + const item = flatten[key]; + const bind = item.schema?.bind; if (bind === undefined) { return; } const path = transformPath(key); - - isArray(path) ? dealFieldList(data, path, bind) : transformBindToValue(data, path, bind); + isArray(path) ? dealFieldList(data, path, bind) : transformBindToValue(data, path, bind, item); }); return data; diff --git a/packages/form-render/src/models/flattenSchema.ts b/packages/form-render/src/models/flattenSchema.ts index 411b90e27..fb1cccfb2 100644 --- a/packages/form-render/src/models/flattenSchema.ts +++ b/packages/form-render/src/models/flattenSchema.ts @@ -43,7 +43,6 @@ export function getSchemaFromFlatten(flatten: any, path = '#') { export function flattenSchema(_schema = {}, name?: any, parent?: any, _result?: any) { // 排序 // _schema = orderBy(_schema, item => item.order, ['asc']); - const result = _result || {}; const schema: any = _cloneDeep(_schema) || {}; @@ -79,9 +78,9 @@ export function flattenSchema(_schema = {}, name?: any, parent?: any, _result?: } if (schema.type) { - result[_name] = { parent, schema, children }; + } - + result[_name] = { parent, schema, children }; return result; } diff --git a/packages/form-render/src/widgets/listDrawer/drawerForm.tsx b/packages/form-render/src/widgets/listDrawer/drawerForm.tsx index 4cc97d871..e8775fc4c 100644 --- a/packages/form-render/src/widgets/listDrawer/drawerForm.tsx +++ b/packages/form-render/src/widgets/listDrawer/drawerForm.tsx @@ -3,21 +3,21 @@ import { Button, Drawer, Space, ConfigProvider } from 'antd'; import { translation } from '../utils'; const DrawerForm = (props: any) => { - const { children, onConfirm, onClose, DrawerProps } = props; + const { children, onConfirm, onClose, ...ret } = props; const configCtx = useContext(ConfigProvider.ConfigContext); const t = translation(configCtx); - let drawerProps: any = { ...DrawerProps, open: true }; + let extraProps: any = { ...ret, open: true }; if ((window as any).antdVersion === 'v4') { - drawerProps = { ...DrawerProps, visible: true }; + extraProps = { ...ret, visible: true }; } return ( diff --git a/packages/form-render/src/widgets/listDrawer/index.tsx b/packages/form-render/src/widgets/listDrawer/index.tsx index be6faeac2..426d21b44 100644 --- a/packages/form-render/src/widgets/listDrawer/index.tsx +++ b/packages/form-render/src/widgets/listDrawer/index.tsx @@ -238,6 +238,7 @@ const TableList: React.FC = (props: any) => { }); } + const drawerIndex = indexRef.current ?? (fields.length - 1); return (
= (props: any) => { )} {visible && ( - {renderCore({ schema: schema.items, parentPath: [fields.length - 1], rootPath: [...rootPath, fields.length - 1] })} + {renderCore({ schema: schema.items, parentPath: [drawerIndex], rootPath: [...rootPath, drawerIndex] })} )}