Skip to content

Commit 5c3cab7

Browse files
authored
feat: validate support dirty (#625)
1 parent 45b959f commit 5c3cab7

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

src/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export interface ValidateOptions {
137137
* e.g. [['a']] will validate ['a'] , ['a', 'b'] and ['a', 1].
138138
*/
139139
recursive?: boolean;
140+
/** Validate when a field is dirty (validated or touched) */
141+
dirty?: boolean;
140142
}
141143

142144
export type ValidateFields<Values = any> = {

src/useForm.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ export class FormStore {
887887
const TMP_SPLIT = String(Date.now());
888888
const validateNamePathList = new Set<string>();
889889

890-
const recursive = options?.recursive;
890+
const { recursive, dirty } = options || {};
891891

892892
this.getFieldEntities(true).forEach((field: FieldEntity) => {
893893
// Add field if not provide `nameList`
@@ -900,6 +900,11 @@ export class FormStore {
900900
return;
901901
}
902902

903+
// Skip if only validate dirty field
904+
if (dirty && !field.isFieldDirty()) {
905+
return;
906+
}
907+
903908
const fieldNamePath = field.getNamePath();
904909
validateNamePathList.add(fieldNamePath.join(TMP_SPLIT));
905910

tests/common/timeout.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
import { act } from '@testing-library/react';
2+
13
export default async (timeout: number = 10) => {
24
return new Promise<void>(resolve => {
35
setTimeout(resolve, timeout);
46
});
57
};
8+
9+
export async function waitFakeTime(timeout: number = 10) {
10+
await act(async () => {
11+
await Promise.resolve();
12+
jest.advanceTimersByTime(timeout);
13+
await Promise.resolve();
14+
});
15+
}

tests/validate.test.tsx

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Form, { Field, useForm } from '../src';
55
import type { FormInstance, ValidateMessages } from '../src/interface';
66
import { changeValue, getInput, matchError } from './common';
77
import InfoField, { Input } from './common/InfoField';
8-
import timeout from './common/timeout';
8+
import timeout, { waitFakeTime } from './common/timeout';
99

1010
describe('Form.Validate', () => {
1111
it('required', async () => {
@@ -1033,4 +1033,60 @@ describe('Form.Validate', () => {
10331033

10341034
jest.useRealTimers();
10351035
});
1036+
1037+
it('dirty', async () => {
1038+
jest.useFakeTimers();
1039+
1040+
const formRef = React.createRef<FormInstance>();
1041+
1042+
const Demo = ({ touchMessage, validateMessage }) => (
1043+
<Form ref={formRef}>
1044+
<InfoField name="touch" rules={[{ required: true, message: touchMessage }]}>
1045+
<Input />
1046+
</InfoField>
1047+
<InfoField name="validate" rules={[{ required: true, message: validateMessage }]}>
1048+
<Input />
1049+
</InfoField>
1050+
<InfoField name="noop" rules={[{ required: true, message: 'noop' }]}>
1051+
<Input />
1052+
</InfoField>
1053+
</Form>
1054+
);
1055+
1056+
const { container, rerender } = render(
1057+
<Demo touchMessage="touch" validateMessage="validate" />,
1058+
);
1059+
1060+
fireEvent.change(container.querySelectorAll('input')[0], {
1061+
target: {
1062+
value: 'light',
1063+
},
1064+
});
1065+
fireEvent.change(container.querySelectorAll('input')[0], {
1066+
target: {
1067+
value: '',
1068+
},
1069+
});
1070+
1071+
formRef.current.validateFields(['validate']);
1072+
1073+
await waitFakeTime();
1074+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[0], `touch`);
1075+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[1], `validate`);
1076+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[2], false);
1077+
1078+
1079+
// Revalidate
1080+
rerender(
1081+
<Demo touchMessage="new_touch" validateMessage="new_validate" />,
1082+
);
1083+
formRef.current.validateFields({ dirty: true });
1084+
1085+
await waitFakeTime();
1086+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[0], `new_touch`);
1087+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[1], `new_validate`);
1088+
matchError(container.querySelectorAll<HTMLDivElement>('.field')[2], false);
1089+
1090+
jest.useRealTimers();
1091+
});
10361092
});

0 commit comments

Comments
 (0)