Skip to content

Commit

Permalink
feat: 选项类的组件 autoFill 支持配置 initAutoFill 属性 Close: #9391 (#9547)
Browse files Browse the repository at this point in the history
  • Loading branch information
2betop authored Jan 31, 2024
1 parent 5a49c43 commit 41d3b12
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 10 deletions.
10 changes: 10 additions & 0 deletions docs/zh-CN/components/form/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,16 @@ order: 2
}
```

**初始不填充**

从 3.1.0 版本开始,表单初始化时,选项有值时也会执行「自动填充」逻辑,从版本 6.1.0 版本开始 可以通过 `initAutoFill` 配置成 `false` 来关闭。

`initAutoFill` 有三种值分别如下,默认为 `fillIfNotSet`

- `fillIfNotSet` 如果目标值不存在则填充,如果目标值存在则不填充。
- `true` 总是填充,如果目标值存在则覆盖。
- `false` 总是不填充,如果目标值存在则不填充。

## 控制选项高度

> 1.10.0 及以上版本
Expand Down
47 changes: 37 additions & 10 deletions packages/amis-core/src/renderers/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import isPlainObject from 'lodash/isPlainObject';
import {normalizeOptions} from '../utils/normalizeOptions';
import {optionValueCompare} from '../utils/optionValueCompare';
import type {Option} from '../types';
import {resolveEventData} from '../utils';
import {deleteVariable, resolveEventData} from '../utils';

export {Option};

Expand Down Expand Up @@ -203,6 +203,12 @@ export interface FormOptionsControl extends FormBaseControl {
autoFill?: {
[propName: string]: string;
};

/**
* @default fillIfNotSet
* 初始化时是否把其他字段同步到表单内部。
*/
initAutoFill?: boolean | 'fillIfNotSet';
}

export interface OptionsBasicConfig extends FormItemBasicConfig {
Expand Down Expand Up @@ -303,6 +309,7 @@ export function registerOptionsControl(config: OptionsConfig) {
placeholder: 'Select.placeholder',
resetValue: '',
deleteConfirmText: 'deleteConfirm',
initAutoFill: 'fillIfNotSet',
...Control.defaultProps
};
static propsList: any = (Control as any).propsList
Expand All @@ -314,6 +321,7 @@ export function registerOptionsControl(config: OptionsConfig) {

input: any;
mounted = false;
initedFilled = false;

constructor(props: OptionsProps) {
super(props);
Expand Down Expand Up @@ -356,16 +364,27 @@ export function registerOptionsControl(config: OptionsConfig) {
JSON.stringify(formItem.getSelectedOptions(formItem.tmpValue)),
() =>
this.mounted &&
this.initedFilled &&
this.syncAutoFill(formItem.getSelectedOptions(formItem.tmpValue))
)
);

if (
options &&
formItem.tmpValue &&
formItem.getSelectedOptions(formItem.tmpValue).length
) {
this.syncAutoFill(formItem.getSelectedOptions(formItem.tmpValue));
if (formInited || !addHook) {
this.initedFilled = true;
this.props.initAutoFill !== false &&
this.syncAutoFill(
formItem.getSelectedOptions(formItem.tmpValue),
this.props.initAutoFill === 'fillIfNotSet'
);
} else if (addHook) {
addHook(() => {
this.initedFilled = true;
this.props.initAutoFill !== false &&
this.syncAutoFill(
formItem.getSelectedOptions(formItem.tmpValue),
this.props.initAutoFill === 'fillIfNotSet'
);
}, 'init');
}

// 默认全选。这里会和默认值\回填值逻辑冲突,所以如果有配置source则不执行默认全选
Expand Down Expand Up @@ -530,7 +549,7 @@ export function registerOptionsControl(config: OptionsConfig) {
}
}

syncAutoFill(selectedOptions: Array<any>) {
syncAutoFill(selectedOptions: Array<any>, skipIfExits = false) {
const {autoFill, multiple, onBulkChange, data} = this.props;
const formItem = this.props.formItem as IFormItemStore;
// 参照录入|自动填充
Expand Down Expand Up @@ -579,13 +598,21 @@ export function registerOptionsControl(config: OptionsConfig) {

Object.keys(autoFill).forEach(key => {
const keys = keyToPath(key);
let value = getVariable(toSync, key);

if (skipIfExits) {
const originValue = getVariable(data, key);
if (typeof originValue !== 'undefined') {
value = originValue;
}
}

setVariable(result, key, value);

// 如果左边的 key 是一个路径
// 这里不希望直接把原始对象都给覆盖没了
// 而是保留原始的对象,只修改指定的属性
if (keys.length > 1 && isPlainObject(tmpData[keys[0]])) {
const value = getVariable(toSync, key);

// 存在情况:依次更新同一子路径的多个key,eg: a.b.c1 和 a.b.c2,所以需要同步更新data
setVariable(tmpData, key, value);
result[keys[0]] = tmpData[keys[0]];
Expand Down
203 changes: 203 additions & 0 deletions packages/amis/__tests__/renderers/Form/autoFill.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,206 @@ test('Form:options:autoFill:validation', async () => {
expect(screen.queryByText(validationMsg1)).not.toBeInTheDocument();
expect(screen.queryByText(validationMsg2)).not.toBeInTheDocument();
});

test('6. AutoFill initAutoFill fillIfNotSet', async () => {
const onSubmit = jest.fn();
const {debug, container, getByText, findByText} = render(
amisRender(
{
type: 'page',
body: [
{
type: 'form',
title: 'The form',
controls: [
{
type: 'hidden',
name: 'aId',
value: 123
},
{
type: 'hidden',
name: 'bId'
},
{
type: 'radios',
name: 'a',
autoFill: {
aValue: '${value}',
aLabel: '${label}',
aId: '${id}',
bId: '${id}'
},
value: 'a',
options: [
{
label: 'OptionA',
value: 'a',
id: 233
},
{
label: 'OptionB',
value: 'b'
}
]
}
],
submitText: 'Submit'
}
]
},
{
onSubmit: onSubmit
},
makeEnv()
)
);

await wait(200);
fireEvent.click(getByText(/Submit/));
await wait(200);

expect(onSubmit).toBeCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toMatchObject({
aId: 123,
a: 'a',
aValue: 'a',
aLabel: 'OptionA',
bId: 233
});
});

test('7. AutoFill initAutoFill false', async () => {
const onSubmit = jest.fn();
const {debug, container, getByText, findByText} = render(
amisRender(
{
type: 'page',
body: [
{
type: 'form',
title: 'The form',
controls: [
{
type: 'hidden',
name: 'aId',
value: 123
},
{
type: 'hidden',
name: 'bId'
},
{
type: 'radios',
name: 'a',
autoFill: {
aValue: '${value}',
aLabel: '${label}',
aId: '${id}',
bId: '${id}'
},
initAutoFill: false,
value: 'a',
options: [
{
label: 'OptionA',
value: 'a',
id: 233
},
{
label: 'OptionB',
value: 'b'
}
]
}
],
submitText: 'Submit'
}
]
},
{
onSubmit: onSubmit
},
makeEnv()
)
);

await wait(200);
fireEvent.click(getByText(/Submit/));
await wait(200);

expect(onSubmit).toBeCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toMatchObject({
aId: 123,
a: 'a'
});
});

test('8. AutoFill initAutoFill true', async () => {
const onSubmit = jest.fn();
const {debug, container, getByText, findByText} = render(
amisRender(
{
type: 'page',
body: [
{
type: 'form',
title: 'The form',
controls: [
{
type: 'hidden',
name: 'aId',
value: 123
},
{
type: 'hidden',
name: 'bId'
},
{
type: 'radios',
name: 'a',
autoFill: {
aValue: '${value}',
aLabel: '${label}',
aId: '${id}',
bId: '${id}'
},
initAutoFill: true,
value: 'a',
options: [
{
label: 'OptionA',
value: 'a',
id: 233
},
{
label: 'OptionB',
value: 'b'
}
]
}
],
submitText: 'Submit'
}
]
},
{
onSubmit: onSubmit
},
makeEnv()
)
);

await wait(200);
fireEvent.click(getByText(/Submit/));
await wait(200);

expect(onSubmit).toBeCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toMatchObject({
aId: 233,
a: 'a',
aValue: 'a',
aLabel: 'OptionA',
bId: 233
});
});
1 change: 1 addition & 0 deletions packages/amis/__tests__/renderers/Form/options.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ test('options:autoFill-merge', async () => {
makeEnv({})
)
);
await wait(200);

fireEvent.click(getByText('选项1'));
await wait(300);
Expand Down

0 comments on commit 41d3b12

Please sign in to comment.