feat: add updateSchema to form api (#4453)
* feat: add updateSchema to form api * chore: typo * chore: typopull/48/MERGE
parent
68dbe04bef
commit
60cffb0dec
|
@ -6,7 +6,7 @@ import { FormApi } from '../src/form-api';
|
|||
vi.mock('@vben-core/shared/utils', () => ({
|
||||
bindMethods: vi.fn(),
|
||||
createMerge: vi.fn((mergeFn) => {
|
||||
return (stateOrFn, prev) => {
|
||||
return (stateOrFn: any, prev: any) => {
|
||||
mergeFn(prev, 'key', stateOrFn);
|
||||
return { ...prev, ...stateOrFn };
|
||||
};
|
||||
|
@ -144,3 +144,64 @@ describe('formApi', () => {
|
|||
expect(isValid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSchema', () => {
|
||||
let instance: FormApi;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new FormApi();
|
||||
instance.state = {
|
||||
schema: [
|
||||
{ component: 'text', fieldName: 'name' },
|
||||
{ component: 'number', fieldName: 'age', label: 'Age' },
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
it('should update the schema correctly when fieldName matches', () => {
|
||||
const newSchema = [
|
||||
{ component: 'text', fieldName: 'name' },
|
||||
{ component: 'number', fieldName: 'age', label: 'Age' },
|
||||
];
|
||||
|
||||
instance.updateSchema(newSchema);
|
||||
|
||||
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||
expect(instance.state?.schema?.[1]?.label).toBe('Age');
|
||||
});
|
||||
|
||||
it('should log an error if fieldName is missing in some items', () => {
|
||||
const newSchema: any[] = [
|
||||
{ component: 'textarea', fieldName: 'name' },
|
||||
{ component: 'number' },
|
||||
];
|
||||
|
||||
const consoleErrorSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
instance.updateSchema(newSchema);
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'All children of the form Schema array that need to be updated must contain the `field` field',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not update schema if fieldName does not match', () => {
|
||||
const newSchema = [{ component: 'textarea', fieldName: 'unknown' }];
|
||||
|
||||
instance.updateSchema(newSchema);
|
||||
|
||||
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||
expect(instance.state?.schema?.[1]?.component).toBe('number');
|
||||
});
|
||||
|
||||
it('should not update schema if updatedMap is empty', () => {
|
||||
const newSchema: any[] = [{ component: 'textarea' }];
|
||||
|
||||
instance.updateSchema(newSchema);
|
||||
|
||||
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||
expect(instance.state?.schema?.[1]?.component).toBe('number');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ import type {
|
|||
ValidationOptions,
|
||||
} from 'vee-validate';
|
||||
|
||||
import type { FormActions, VbenFormProps } from './types';
|
||||
import type { FormActions, FormSchema, VbenFormProps } from './types';
|
||||
|
||||
import { toRaw } from 'vue';
|
||||
|
||||
|
@ -186,6 +186,37 @@ export class FormApi {
|
|||
this.stateHandler.reset();
|
||||
}
|
||||
|
||||
updateSchema(schema: Partial<FormSchema>[]) {
|
||||
const updated: Partial<FormSchema>[] = [...schema];
|
||||
const hasField = updated.every(
|
||||
(item) => Reflect.has(item, 'fieldName') && item.fieldName,
|
||||
);
|
||||
|
||||
if (!hasField) {
|
||||
console.error(
|
||||
'All items in the schema array must have a valid `fieldName` property to be updated',
|
||||
);
|
||||
return;
|
||||
}
|
||||
const currentSchema = [...(this.state?.schema ?? [])];
|
||||
|
||||
const updatedMap: Record<string, any> = {};
|
||||
|
||||
updated.forEach((item) => {
|
||||
if (item.fieldName) {
|
||||
updatedMap[item.fieldName] = item;
|
||||
}
|
||||
});
|
||||
|
||||
currentSchema.forEach((schema, index) => {
|
||||
const updatedData = updatedMap[schema.fieldName];
|
||||
if (updatedData) {
|
||||
currentSchema[index] = merge(updatedData, schema) as FormSchema;
|
||||
}
|
||||
});
|
||||
this.setState({ schema: currentSchema });
|
||||
}
|
||||
|
||||
async validate(opts?: Partial<ValidationOptions>) {
|
||||
const form = await this.getForm();
|
||||
return await form.validate(opts);
|
||||
|
|
|
@ -41,12 +41,25 @@ const [BaseForm, formApi] = useVbenForm({
|
|||
label: 'field2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'field3',
|
||||
label: 'field3',
|
||||
fieldName: 'fieldOptions',
|
||||
label: '下拉选',
|
||||
},
|
||||
],
|
||||
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||
|
@ -75,9 +88,35 @@ function handleClick(
|
|||
| 'showSubmitButton'
|
||||
| 'updateActionAlign'
|
||||
| 'updateResetButton'
|
||||
| 'updateSchema'
|
||||
| 'updateSubmitButton',
|
||||
) {
|
||||
switch (action) {
|
||||
case 'updateSchema': {
|
||||
formApi.updateSchema([
|
||||
{
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '选项3',
|
||||
value: '3',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'fieldOptions',
|
||||
},
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'labelWidth': {
|
||||
formApi.setState({
|
||||
commonConfig: {
|
||||
|
@ -181,6 +220,7 @@ function handleClick(
|
|||
<template>
|
||||
<Page description="表单组件api操作示例。" title="表单组件">
|
||||
<Space class="mb-5 flex-wrap">
|
||||
<Button @click="handleClick('updateSchema')">updateSchema</Button>
|
||||
<Button @click="handleClick('labelWidth')">更改labelWidth</Button>
|
||||
<Button @click="handleClick('resetLabelWidth')">还原labelWidth</Button>
|
||||
<Button @click="handleClick('disabled')">禁用表单</Button>
|
||||
|
|
Loading…
Reference in New Issue