Skip to content

Commit 9ea5929

Browse files
feat: support validate recursive (#226)
* feat: support validate recursive * Update src/interface.ts Co-authored-by: 二货机器人 <[email protected]> * Update src/useForm.ts Co-authored-by: 二货机器人 <[email protected]> * Update src/useForm.ts Co-authored-by: 二货机器人 <[email protected]> * prettier all code Co-authored-by: 二货机器人 <[email protected]>
1 parent 82f005d commit 9ea5929

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

src/interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ export interface FieldError {
119119
export interface ValidateOptions {
120120
triggerName?: string;
121121
validateMessages?: ValidateMessages;
122+
/**
123+
* Recursive validate. It will validate all the name path that contains the provided one.
124+
* e.g. ['a'] will validate ['a'] , ['a', 'b'] and ['a', 1].
125+
*/
126+
recursive?: boolean;
122127
}
123128

124129
export type InternalValidateFields = (

src/useForm.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,13 +712,27 @@ export class FormStore {
712712
namePathList.push(field.getNamePath());
713713
}
714714

715+
/**
716+
* Recursive validate if configured.
717+
* TODO: perf improvement @zombieJ
718+
*/
719+
if (options?.recursive && provideNameList) {
720+
const namePath = field.getNamePath();
721+
if (
722+
// nameList[i] === undefined 说明是以 nameList 开头的
723+
// ['name'] -> ['name','list']
724+
namePath.every((nameUnit, i) => nameList[i] === nameUnit || nameList[i] === undefined)
725+
) {
726+
namePathList.push(namePath);
727+
}
728+
}
729+
715730
// Skip if without rule
716731
if (!field.props.rules || !field.props.rules.length) {
717732
return;
718733
}
719734

720735
const fieldNamePath = field.getNamePath();
721-
722736
// Add field validate rule in to promise list
723737
if (!provideNameList || containsNamePath(namePathList, fieldNamePath)) {
724738
const promise = field.validateRules({

tests/validate.test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable no-template-curly-in-string */
22
import React from 'react';
33
import { mount } from 'enzyme';
4+
import { act } from 'react-dom/test-utils';
45
import Form, { Field, useForm } from '../src';
56
import InfoField, { Input } from './common/InfoField';
67
import { changeValue, matchError, getField } from './common';
@@ -686,5 +687,40 @@ describe('Form.Validate', () => {
686687
expect(failedTriggerTimes).toEqual(1);
687688
expect(passedTriggerTimes).toEqual(1);
688689
});
690+
691+
it('validate support recursive', async () => {
692+
let form;
693+
const wrapper = mount(
694+
<div>
695+
<Form
696+
ref={instance => {
697+
form = instance;
698+
}}
699+
>
700+
<InfoField name={['username', 'do']} rules={[{ required: true }]} />
701+
<InfoField name={['username', 'list']} rules={[{ required: true }]} />
702+
</Form>
703+
</div>,
704+
);
705+
706+
wrapper
707+
.find('input')
708+
.at(0)
709+
.simulate('change', { target: { value: '' } });
710+
await act(async () => {
711+
await timeout();
712+
});
713+
wrapper.update();
714+
715+
try {
716+
const values = await form.validateFields(['username'], { recursive: true });
717+
expect(values.username.do).toBe('');
718+
} catch (error) {
719+
expect(error.errorFields.length).toBe(2);
720+
}
721+
722+
const values = await form.validateFields(['username']);
723+
expect(values.username.do).toBe('');
724+
});
689725
});
690726
/* eslint-enable no-template-curly-in-string */

0 commit comments

Comments
 (0)