Skip to content

Commit

Permalink
feat: add updateSchema to form api (#4453)
Browse files Browse the repository at this point in the history
* feat: add updateSchema to form api

* chore: typo

* chore: typo
  • Loading branch information
anncwb committed Sep 21, 2024
1 parent 68dbe04 commit 60cffb0
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 6 deletions.
63 changes: 62 additions & 1 deletion packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
};
Expand Down Expand Up @@ -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(

Check failure on line 185 in packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts > updateSchema > should log an error if fieldName is missing in some items

AssertionError: expected "error" to be called with arguments: [ Array(1) ] Received: 1st error call: Array [ - "All children of the form Schema array that need to be updated must contain the `field` field", + "All items in the schema array must have a valid `fieldName` property to be updated", ] Number of calls: 1 ❯ packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts:185:29
'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');
});
});
33 changes: 32 additions & 1 deletion packages/@core/ui-kit/form-ui/src/form-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand Down
48 changes: 44 additions & 4 deletions playground/src/views/examples/form/api.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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个
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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>
Expand Down

0 comments on commit 60cffb0

Please sign in to comment.