The last part briefly introduced formilyjs and built a form designer based on it, and realized the dynamic design and preview function of the form. This video will introduce some advanced configurations of the form designer, so that they can be better used in our node editing and connection. line editing.
designable advanced configuration
Request and custom data injection
Generally speaking, the requests of our pages are uniformly encapsulated. How do we inject our encapsulated requests or existing data sources into our form designer when using them:
The SchemaField component is a component specially used for parsing JSON-Schema to dynamically render forms. When using createSchemaField
we can pass in scope
to inject the link into the global scope:
import { FC, Ref, useEffect, useImperativeHandle, useState } from 'react';
import { Modal } from 'antd';
import {
FormItem,
Input,
Form,
Submit,
ArrayBase,
ArrayCards,
ArrayCollapse,
ArrayItems,
ArrayTable,
ArrayTabs,
BaseItem,
Cascader,
Checkbox,
DatePicker,
Editable,
FormButtonGroup,
FormCollapse,
FormGrid,
FormTab,
GridColumn,
NumberPicker,
Password,
PreviewText,
Radio,
Reset,
Select,
SelectTable,
Space,
Switch,
TimePicker,
Transfer,
TreeSelect,
Upload,
} from '@formily/antd';
import api from '@/api';
import { createSchemaField } from '@formily/react';
import { LgetItem } from '@/utils/storage';
import { createForm } from '@formily/core';
interface PreviewProps {
previewRef: Ref<{ setVisible: (flag: boolean) => void }>;
modalConfig: { [key: string]: any };
}
const SchemaField = createSchemaField({
components: {
Input,
ArrayBase,
ArrayCards,
ArrayCollapse,
ArrayItems,
ArrayTable,
ArrayTabs,
BaseItem,
Cascader,
Checkbox,
DatePicker,
Editable,
Form,
FormButtonGroup,
FormCollapse,
FormGrid,
FormItem,
FormTab,
GridColumn,
NumberPicker,
Password,
PreviewText,
Radio,
Reset,
Select,
SelectTable,
Space,
Submit,
Switch,
TimePicker,
Transfer,
TreeSelect,
Upload,
},
scope: {
$fetch: api,
selectList: [{ label: 'aaa', value: 'aaa' }, { label: 'bbb', value: 'bbb' }]
}
});
const Preview: FC<PreviewProps> = ({ previewRef, modalConfig }) => {
const [visible, setVisible] = useState(false);
useImperativeHandle(previewRef, () => ({
setVisible,
}));
const [params, setParams] = useState({});
const normalForm = createForm({});
useEffect(() => {
if (modalConfig && visible) {
const playgroundList = LgetItem('playgroundList') || [];
const data = playgroundList.find((s) => s.id === modalConfig.id);
setParams(data?.params || {});
}
}, [modalConfig, visible]);
const handleCancel = () => {
setVisible(false);
};
return (
<Modal
title="模板预览"
visible={visible}
onCancel={handleCancel}
footer={null}
>
<Form form={normalForm} onAutoSubmit={console.log} {...params.form}>
<SchemaField schema={params.schema} />
<Submit block>保存</Submit>
</Form>
</Modal>
);
};
export default Preview;
When using the form designer, you can use the injected scope
value. For example, we prepare a json, select a drop-down control, configure the corresponding device, and then obtain the json through our injected request to display the corresponding drop-down value:
$effect(() => {
$self.loading = true
$fetch({
url: '/getSelectList',
method: 'get',
params: {}
}).then(res => {
$self.loading = false
// 当返回值不是label和value时转化一下
$self.dataSource = res.map(s => ({ label: res.name, value: res.id }))
}).catch(() => {
$self.loading = false
})
}, [])
Here $fetch
is the request we injected
Form configuration
- The key submitted by the form is the field identifier, which can be customized and modified. The default is a random string.
- The title is the label of the form form
For custom search, such as select, you need to configure the form format in the filter under component properties to support label search
(inputValue, option) => { return option.label.indexOf(inputValue) !== -1; }
- If the same configuration in the responder rule as the external configuration is configured, such as component properties, then the external configuration in the responder rule will be overwritten (the external component properties will fail)
Advanced configuration
The advanced configuration is in the responder rules. Here, it mainly describes some functions that cannot be realized by ordinary configuration, such as common linkage, dynamic value and other scenarios.
-
$self
is the currently selected form object -
$form
is the form object -
$deps
is the dependency object (the source field needs to be configured in the dependency field above) -
$observable
declare an observable -
$effect
and react'suseEffect
use something like -
$values
is the submitted form object
Dynamic enumeration value, if we have a select control, the value of this control is returned by the interface
$effect(() => { $self.loading = true $fetch({ url: '/getSelectList', method: 'get', params: {} }).then(res => { $self.loading = false // 当返回值不是label和value时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id })) }).catch(() => { $self.loading = false }) }, [])
Linkage changes the enumeration value. For example, we have two choices. The first choice is
mechanism
organization. The first choice isuser
personnel. select will obtain the list of personnel under the organization from the interface according to the value of the first select. This is a relatively common linkage selection function, so how do we implement it in the form designer (the implementation method is not unique, here is the ideas).// 第一个select,我们监听mechanism的变化,flag主要应用为跳过初次渲染(保证反显正常展示),当mechanism改版(即手动选值)后,清空user的取值。 $effect(() => { $self.loading = true $fetch({ url: '/getMechanismList', method: 'get', params: {} }).then(res => { $self.loading = false // 当返回值不是label和value时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id })) }).catch(() => { $self.loading = false }) }, []) const state = $observable({ flag: false }); $effect(() => { if (state.flag) { $form.reset('user'); } state.flag = true; }, [$self.value])
When
mechanism
changes, clear theuser
list and initiate a request to get theuser
list$effect(() => { $self.dataSource = [] if ($deps.mechanism) { $self.loading = true $fetch({ url: '/getSelectList', method: 'get', params: { mechanism: $deps.mechanism } }).then(res => { $self.loading = false // 当返回值不是label和value时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id })) }).catch(() => { $self.loading = false }) } }, [$deps.mechanism])
Small scale chopper
We use mock data to simply do a linkage
// mock/api.ts
export default {
'GET /api/mechanism': [
{
value: '1',
label: '机构1',
},
{
value: '2',
label: '机构2',
},
],
'GET /api/users': (req, res) => {
// 添加跨域请求头
const query: any = req.query;
const user: any = {
'1': [
{
value: '1-1',
label: '机构1-人员1',
},
{
value: '1-2',
label: '机构1-人员2',
},
],
'2': [
{
value: '2-1',
label: '机构2-人员1',
},
{
value: '2-2',
label: '机构2-人员2',
},
],
};
res.send(user[query.id]);
},
};
We define two mock interfaces, mechanism
and users
, the former returns a list of institutions, the latter returns the corresponding list according to the id of the former, and then we preview the pop-up window in the previous issue In the injection request, here we directly use the one provided by umi request
.
// Preview.tsx
import { request } from 'umi';
...
const SchemaField = createSchemaField({
components: ...,
scope: {
$fetch: request,
},
});
Finally we add the request in the form design
// mechanism
$effect(() => {
$self.loading = true
$fetch("/api/mechanism", {})
.then((res) => {
$self.loading = false
// 当返回值不是label和value时转化一下
$self.dataSource = res
})
.catch(() => {
$self.loading = false
})
}, [])
// users
$effect(() => {
$self.dataSource = []
if ($deps.mechanism) {
$self.loading = true
$fetch("/api/users", {
params: {
id: $deps.mechanism,
},
})
.then((res) => {
$self.loading = false
// 当返回值不是label和value时转化一下
$self.dataSource = res
})
.catch(() => {
$self.loading = false
})
}
}, [$deps.mechanism])
Finally, go to the form template to preview:
Well, the functions introduced in this article have been implemented, then in the next article, we will associate the editing function of process visualization with our form template. Modifying the form template can modify the attribute editing of nodes or connections to achieve real The dynamic attribute editing effect of , please look forward to it.
Address of this article: link
This article github address: link
github demo address: link
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。