搜索下拉框
- github: github.com/easy-page/e…
- 文档站官网:easy-page.github.io/easy-page-d…
- 文档站 github: github.com/easy-page/e…
在表单中,下拉框的处理也是一个比较复杂的场景,它复杂在:
- 可以基于搜索,去获取下拉框选项数据。
- 在编辑的时,需要进行回填,之前基于关键词搜索的选项,在回填时,查询选项或还需再查询一次。
- 回填时,基于回填的选项里额外的信息,做相关提示信息展示。
案例
上述描述,可能有点云里雾里,我们可以通过下述例子来感受其复杂:
- 创建一个下拉框
import { Empty, SelectEffectType, SelectState, UI_COMPONENTS, nodeUtil, } from '@easy-page/antd-ui'; import type { DefaultOptionType } from 'antd/es/select'; type GoodState = SelectState<number, { mark: string }>; export const goods = nodeUtil.createField< GoodState, { goods: GoodState }, Empty, SelectEffectType<{ mark: string }> >( 'goods', '商品', { /** 默认选中一个选项的 id **/ value: { choosed: 1 }, required: true, mode: 'single', }, { ui: UI_COMPONENTS.SELECT, select: { /** 下拉框 antd 的一些配置,便于后续做搜索功能 **/ showSearch: true, notFoundContent: null, filterOption: false, }, } );
- 增加
action
副作用加载数据。- 初始化时,加载默认查询选项;如果查询选项中不包含默认选中的选项,则基于 ID 查询该选项;合并查询结果并返回。
- 在搜索时,基于关键词,查询选项;同理如果查询的选项中不包含已选择选项,则继续查询一次。
export const goods = nodeUtil.createField< GoodState, { goods: GoodState }, Empty, SelectEffectType<{ mark: string }> >( 'goods', '商品', { ... actions: [ { /** 监听自身 value 的变化,感知 keyword 变化,执行副作用。 **/ effectedKeys: ['goods'], /** 初始化执行 */ initRun: true, /** 初始化查询选中数据 */ action: async ({ value, initRun }) => { /** 只有初始化时,或者存在关键词时才做查询 **/ if (initRun || value.keyword !== undefined) { /** 查询选项 */ const options = (await searchByKeywords(value.keyword)) || []; const hasChoosed = options.find((x) => x.value === value.choosed); if (value.choosed && !hasChoosed) { /** 选择的选项不在查询的列表中,单独搜索选中选项 */ const choosed = await searchById(value.choosed); return { fieldValue: { ...value, options: [choosed, ...options], keyword: undefined, }, }; } return { fieldValue: { ...value, options, keyword: undefined } }; } return {}; }, }, ], }, ... );
改进
从上面示例的:action
中可见其复杂程度,当然这样的逻辑,我们可以抽象到底层基础组件。这样我们的 action
逻辑就会变成:
import { searchAction } from '@easy-page/antd-ui';
export const goods = nodeUtil.createField<
GoodState,
{ goods: GoodState },
Empty,
SelectEffectType<{ mark: string }>
>(
'goods',
'商品',
{
...
actions: [
{
...
action: async ({ value, initRun }) => {
return searchAction<number, { mark: string }>({
async searchByChoosed(choosed) {
const result = await searchById(choosed);
return result ? [result] : [];
},
async searchByKeyword(keyword) {
const result = await searchByKeywords(keyword);
return result || [];
},
initRun,
value,
});
},
},
],
},
...
);
Demo
我们来看看此时的实际效果: