mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: 表单项校验变更为顺序校验模式 (#6553)
* feat: 表单项校验不再校验全部规则,改为顺序校验模式; 自定义校验 addRule 增加灵活展示错误信息特性。 * doc: 表单项校验不再校验全部规则,改为顺序校验模式 * doc: 自定义校验 addRule 增加灵活展示错误信息特性 * test: 表单验证规则改为顺序校验,不再全部校验,测试用例变更 --------- Co-authored-by: jinye <jinye@baidu.com>
This commit is contained in:
parent
5b0171032a
commit
d4c931cb85
@ -1087,7 +1087,7 @@ order: 1
|
||||
}
|
||||
```
|
||||
|
||||
同样也可以配置多个格式校验
|
||||
同样也可以配置多个格式校验,按顺序进行校验,中途校验不通过就会终止
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
@ -1102,6 +1102,7 @@ order: 1
|
||||
"isNumeric": true,
|
||||
"minimum": 10
|
||||
},
|
||||
"validateOnChange": true,
|
||||
"description": "请输入数字类型文本"
|
||||
}
|
||||
]
|
||||
|
@ -8,6 +8,8 @@ title: 扩展现有组件
|
||||
|
||||
如果默认的表单检测规则不满足需求,还可以通过代码的方式扩展。
|
||||
|
||||
### 普通用法
|
||||
|
||||
JSSDK 中的用法:
|
||||
|
||||
```javascript
|
||||
@ -23,8 +25,10 @@ amisLib.addRule(
|
||||
value === '天津' ||
|
||||
value === '重庆'
|
||||
) {
|
||||
// return true 表示校验通过
|
||||
return true;
|
||||
}
|
||||
// return false 表示校验不通过,会进行错误提示
|
||||
return false;
|
||||
},
|
||||
// 出错时的报错信息
|
||||
@ -46,6 +50,57 @@ amisLib.addRule(
|
||||
import {addRule} from 'amis';
|
||||
```
|
||||
|
||||
### 更加灵活的提示错误
|
||||
|
||||
> `2.9.1` 及以上版本
|
||||
|
||||
如果想在一个验证函数里根据不同情况提示不同的错误信息,需要返回固定格式的结果:
|
||||
|
||||
```js
|
||||
{
|
||||
error: true,
|
||||
msg: '错误信息'
|
||||
}
|
||||
```
|
||||
|
||||
注意,当返回对象时,`error`必须为`true` 才会判定为错误:
|
||||
|
||||
具体用法如下:
|
||||
|
||||
```javascript
|
||||
let amisLib = amisRequire('amis');
|
||||
amisLib.addRule(
|
||||
// 校验名
|
||||
'isZXS',
|
||||
// 校验函数,values 是表单里所有表单项的值,可用于做联合校验;value 是当前表单项的值
|
||||
(values, value) => {
|
||||
if (value === '新加坡') {
|
||||
// 校验不通过,提示:该地区不在国内
|
||||
return {
|
||||
error: true,
|
||||
msg: '该地区不在国内'
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
value === '北京' ||
|
||||
value === '上海' ||
|
||||
value === '天津' ||
|
||||
value === '重庆'
|
||||
) {
|
||||
// return true 表示校验通过
|
||||
return true;
|
||||
}
|
||||
|
||||
// 校验不通过,提示:输入的不是直辖市
|
||||
return {
|
||||
error: true,
|
||||
msg: '输入的不是直辖市'
|
||||
};
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## 同时支持多种类型编辑
|
||||
|
||||
在表单编辑中,每个 name 一般对应一种类型,如果这个 name 有多种类型,比如下面的例子中 id 的值有可能是字符串,也有可能是数字,但 type 只能设置为一种类型,这种情况如何处理?
|
||||
|
@ -99,7 +99,10 @@ export interface ValidateFn {
|
||||
arg3?: any,
|
||||
arg4?: any,
|
||||
arg5?: any
|
||||
): boolean;
|
||||
): boolean | {
|
||||
error: boolean;
|
||||
msg?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const validations: {
|
||||
@ -515,10 +518,14 @@ export function validate(
|
||||
msg: string;
|
||||
}> = [];
|
||||
|
||||
rules &&
|
||||
Object.keys(rules).forEach(ruleName => {
|
||||
|
||||
if (rules) {
|
||||
const ruleNames = Object.keys(rules);
|
||||
const length = ruleNames.length;
|
||||
for (let index = 0; index < length; index++) {
|
||||
const ruleName = ruleNames[index];
|
||||
if (!rules[ruleName] && rules[ruleName] !== 0) {
|
||||
return;
|
||||
continue;
|
||||
} else if (typeof validations[ruleName] !== 'function') {
|
||||
throw new Error('Validation `' + ruleName + '` not exists!');
|
||||
}
|
||||
@ -534,17 +541,31 @@ export function validate(
|
||||
return item;
|
||||
});
|
||||
|
||||
if (!fn(values, value, ...args)) {
|
||||
let validateRes = fn(values, value, ...args);
|
||||
|
||||
// addRule 允许返回
|
||||
// {error: true, msg: '错误提示'}
|
||||
// 格式的信息来灵活展示错误
|
||||
let fnResErrorMsg = '';
|
||||
if (
|
||||
typeof validateRes === 'object' &&
|
||||
validateRes.error === true
|
||||
) {
|
||||
fnResErrorMsg = validateRes?.msg ?? '';
|
||||
}
|
||||
|
||||
if (!validateRes || fnResErrorMsg) {
|
||||
let msgRuleName = ruleName;
|
||||
if (Array.isArray(value)) {
|
||||
msgRuleName = `${ruleName}Array`;
|
||||
}
|
||||
|
||||
errors.push({
|
||||
return [{
|
||||
rule: ruleName,
|
||||
msg: filter(
|
||||
__(
|
||||
(messages && messages[ruleName]) ||
|
||||
fnResErrorMsg ||
|
||||
validateMessages[msgRuleName] ||
|
||||
validateMessages[ruleName]
|
||||
),
|
||||
@ -552,9 +573,10 @@ export function validate(
|
||||
...[''].concat(args)
|
||||
}
|
||||
)
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
@ -143,35 +143,36 @@ describe('InputGroup with validationConfig', () => {
|
||||
expect(errorDom?.childElementCount).toStrictEqual(2);
|
||||
});
|
||||
|
||||
test('InputGroup with validationConfig: delimiter', async () => {
|
||||
const delimiter = '@@';
|
||||
const {container} = setup({validationConfig: {delimiter}});
|
||||
const child1 = container.querySelector(
|
||||
'input[name=child1]'
|
||||
) as HTMLInputElement;
|
||||
const child2 = container.querySelector(
|
||||
'input[name=child2]'
|
||||
) as HTMLInputElement;
|
||||
fireEvent.change(child1, {target: {value: 'amis'}});
|
||||
await wait(500);
|
||||
// v2.9.1 改为顺序校验后,不会同时输出多条校验错误消息,所以也不会用到分隔符
|
||||
// test('InputGroup with validationConfig: delimiter', async () => {
|
||||
// const delimiter = '@@';
|
||||
// const {container} = setup({validationConfig: {delimiter}});
|
||||
// const child1 = container.querySelector(
|
||||
// 'input[name=child1]'
|
||||
// ) as HTMLInputElement;
|
||||
// const child2 = container.querySelector(
|
||||
// 'input[name=child2]'
|
||||
// ) as HTMLInputElement;
|
||||
// fireEvent.change(child1, {target: {value: 'amis'}});
|
||||
// await wait(500);
|
||||
|
||||
const submitBtn = screen.getByRole('button', {name: 'Submit'});
|
||||
fireEvent.click(submitBtn);
|
||||
await wait(500);
|
||||
// const submitBtn = screen.getByRole('button', {name: 'Submit'});
|
||||
// fireEvent.click(submitBtn);
|
||||
// await wait(500);
|
||||
|
||||
screen.debug(container);
|
||||
// screen.debug(container);
|
||||
|
||||
expect(
|
||||
container.querySelector('*[class*="InputGroup-validation--full"]')
|
||||
).toBeInTheDocument();
|
||||
// expect(
|
||||
// container.querySelector('*[class*="InputGroup-validation--full"]')
|
||||
// ).toBeInTheDocument();
|
||||
|
||||
const errorDom = container.querySelector('*[class*="Form-feedback"]');
|
||||
expect(errorDom?.childElementCount).toStrictEqual(1);
|
||||
// const errorDom = container.querySelector('*[class*="Form-feedback"]');
|
||||
// expect(errorDom?.childElementCount).toStrictEqual(1);
|
||||
|
||||
const child1ErrorText = errorDom?.childNodes[0]
|
||||
? errorDom.childNodes[0].textContent
|
||||
: '';
|
||||
// const child1ErrorText = errorDom?.childNodes[0]
|
||||
// ? errorDom.childNodes[0].textContent
|
||||
// : '';
|
||||
|
||||
expect(child1ErrorText).toEqual(expect.stringMatching(delimiter));
|
||||
});
|
||||
// expect(child1ErrorText).toEqual(expect.stringMatching(delimiter));
|
||||
// });
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {validate, str2rules} from '../../src';
|
||||
import {validate, str2rules, addRule} from '../../src';
|
||||
|
||||
test('validation:isRequired valid', () => {
|
||||
expect(
|
||||
@ -718,10 +718,6 @@ test('validation:multipleRules invalid', () => {
|
||||
{
|
||||
rule: 'isUrl',
|
||||
msg: 'validate.isUrl'
|
||||
},
|
||||
{
|
||||
rule: 'isInt',
|
||||
msg: 'validate.isInt'
|
||||
}
|
||||
]);
|
||||
});
|
||||
@ -831,10 +827,6 @@ test('validation:multipleMatchRegexp invalid', () => {
|
||||
{
|
||||
rule: 'matchRegexp1',
|
||||
msg: '请输入abc开头的好么'
|
||||
},
|
||||
{
|
||||
rule: 'matchRegexp2',
|
||||
msg: '请输入123结尾的好么'
|
||||
}
|
||||
]);
|
||||
});
|
||||
@ -874,10 +866,6 @@ test('validation:multipleMatchRegexp:noSlash invalid', () => {
|
||||
{
|
||||
rule: 'matchRegexp1',
|
||||
msg: '请输入abc开头的好么'
|
||||
},
|
||||
{
|
||||
rule: 'matchRegexp2',
|
||||
msg: '请输入123结尾的好么'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user