Skip to content

Commit 13df3bb

Browse files
authored
feat: Field support validateFirst (#71)
* inject validateFirst * test case
1 parent 42d7553 commit 13df3bb

File tree

3 files changed

+66
-10
lines changed

3 files changed

+66
-10
lines changed

src/Field.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export interface FieldProps {
6666
shouldUpdate?: ShouldUpdate;
6767
trigger?: string;
6868
validateTrigger?: string | string[] | false;
69+
validateFirst?: boolean;
6970
valuePropName?: string;
7071
onReset?: () => void;
7172
}
@@ -271,6 +272,7 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
271272
};
272273

273274
public validateRules = (options?: ValidateOptions) => {
275+
const { validateFirst } = this.props;
274276
const { triggerName } = (options || {}) as ValidateOptions;
275277
const namePath = this.getNamePath();
276278

@@ -286,7 +288,7 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
286288
});
287289
}
288290

289-
const promise = validateRules(namePath, this.getValue(), filteredRules, options);
291+
const promise = validateRules(namePath, this.getValue(), filteredRules, options, validateFirst);
290292
this.validatePromise = promise;
291293
this.errors = [];
292294

src/utils/validateUtil.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export function validateRules(
125125
value: StoreValue,
126126
rules: RuleObject[],
127127
options: ValidateOptions,
128+
validateFirst?: boolean,
128129
) {
129130
const name = namePath.join('.');
130131

@@ -179,20 +180,40 @@ export function validateRules(
179180
};
180181
});
181182

182-
const summaryPromise: Promise<string[]> = Promise.all(
183-
filledRules.map(rule => validateRule(name, value, rule, options)),
184-
).then((errorsList: string[][]): string[] | Promise<string[]> => {
185-
const errors: string[] = [].concat(...errorsList);
183+
const rulePromises = filledRules.map(rule => validateRule(name, value, rule, options));
186184

187-
if (!errors.length) {
188-
return [];
189-
}
185+
const summaryPromise: Promise<string[]> = validateFirst
186+
? finishOnFirstFailed(rulePromises)
187+
: finishOnAllFailed(rulePromises).then((errors: string[]): string[] | Promise<string[]> => {
188+
if (!errors.length) {
189+
return [];
190+
}
190191

191-
return Promise.reject<string[]>(errors);
192-
});
192+
return Promise.reject<string[]>(errors);
193+
});
193194

194195
// Internal catch error to avoid console error log.
195196
summaryPromise.catch(e => e);
196197

197198
return summaryPromise;
198199
}
200+
201+
async function finishOnAllFailed(rulePromises: Promise<string[]>[]): Promise<string[]> {
202+
return Promise.all(rulePromises).then((errorsList: string[][]): string[] | Promise<string[]> => {
203+
const errors: string[] = [].concat(...errorsList);
204+
205+
return errors;
206+
});
207+
}
208+
209+
async function finishOnFirstFailed(rulePromises: Promise<string[]>[]): Promise<string[]> {
210+
return new Promise(resolve => {
211+
rulePromises.forEach(promise => {
212+
promise.then(errors => {
213+
if (errors.length) {
214+
resolve(errors);
215+
}
216+
});
217+
});
218+
});
219+
}

tests/validate.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,5 +325,38 @@ describe('Form.Validate', () => {
325325

326326
errorSpy.mockRestore();
327327
});
328+
329+
it('validateFirst', async () => {
330+
let form;
331+
const wrapper = mount(
332+
<div>
333+
<Form
334+
ref={instance => {
335+
form = instance;
336+
}}
337+
>
338+
<InfoField
339+
name="username"
340+
validateFirst
341+
rules={[
342+
// Follow promise will never end
343+
{ validator: () => new Promise(() => null) },
344+
{ required: true },
345+
]}
346+
/>
347+
</Form>
348+
</div>,
349+
);
350+
351+
await changeValue(wrapper, '');
352+
matchError(wrapper, true);
353+
expect(form.getFieldError('username')).toEqual(["'username' is required"]);
354+
expect(form.getFieldsError()).toEqual([
355+
{
356+
name: ['username'],
357+
errors: ["'username' is required"],
358+
},
359+
]);
360+
});
328361
});
329362
/* eslint-enable no-template-curly-in-string */

0 commit comments

Comments
 (0)