Skip to content

Commit b6a8946

Browse files
authored
feat: Form support validateTrigger (#130)
* feat: Form support validateTrigger * test case * back of test case
1 parent 674f5bf commit b6a8946

File tree

4 files changed

+73
-34
lines changed

4 files changed

+73
-34
lines changed

src/Field.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,17 @@ export interface FieldState {
8383
}
8484

8585
// We use Class instead of Hooks here since it will cost much code by using Hooks.
86-
class Field extends React.Component<InternalFieldProps, FieldState> implements FieldEntity {
86+
class Field extends React.Component<InternalFieldProps, FieldState, InternalFormInstance>
87+
implements FieldEntity {
8788
public static contextType = FieldContext;
8889

8990
public static defaultProps = {
9091
trigger: 'onChange',
91-
validateTrigger: 'onChange',
9292
valuePropName: 'value',
9393
};
9494

95+
context: InternalFormInstance;
96+
9597
public state = {
9698
resetCount: 0,
9799
};
@@ -391,6 +393,10 @@ class Field extends React.Component<InternalFieldProps, FieldState> implements F
391393
valuePropName,
392394
getValueProps,
393395
} = this.props;
396+
397+
const mergedValidateTrigger =
398+
validateTrigger !== undefined ? validateTrigger : this.context.validateTrigger;
399+
394400
const namePath = this.getNamePath();
395401
const { getInternalHooks, getFieldsValue }: InternalFormInstance = this.context;
396402
const { dispatch } = getInternalHooks(HOOK_MARK);
@@ -434,7 +440,7 @@ class Field extends React.Component<InternalFieldProps, FieldState> implements F
434440
};
435441

436442
// Add validateTrigger
437-
const validateTriggerList: string[] = toArray(validateTrigger || []);
443+
const validateTriggerList: string[] = toArray(mergedValidateTrigger || []);
438444

439445
validateTriggerList.forEach((triggerName: string) => {
440446
// Wrap additional function of component, so that we can get latest value from store

src/Form.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface FormProps extends BaseFormProps {
2929
onFieldsChange?: Callbacks['onFieldsChange'];
3030
onFinish?: Callbacks['onFinish'];
3131
onFinishFailed?: Callbacks['onFinishFailed'];
32+
validateTrigger?: string | string[] | false;
3233
}
3334

3435
const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
@@ -40,6 +41,7 @@ const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
4041
children,
4142
component: Component = 'form',
4243
validateMessages,
44+
validateTrigger = 'onChange',
4345
onValuesChange,
4446
onFieldsChange,
4547
onFinish,
@@ -122,10 +124,16 @@ const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
122124
prevFieldsRef.current = fields;
123125
}, [fields, formInstance]);
124126

127+
const formContextValue = React.useMemo(
128+
() => ({
129+
...(formInstance as InternalFormInstance),
130+
validateTrigger,
131+
}),
132+
[formInstance, validateTrigger],
133+
);
134+
125135
const wrapperNode = (
126-
<FieldContext.Provider value={formInstance as InternalFormInstance}>
127-
{childrenNode}
128-
</FieldContext.Provider>
136+
<FieldContext.Provider value={formContextValue}>{childrenNode}</FieldContext.Provider>
129137
);
130138

131139
if (Component === false) {

src/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ export type InternalFormInstance = Omit<FormInstance, 'validateFields'> & {
184184
*/
185185
prefixName?: InternalNamePath;
186186

187+
validateTrigger?: string | string[] | false;
188+
187189
/**
188190
* Form component should register some content into store.
189191
* We pass the `HOOK_MARK` as key to avoid user call the function.

tests/validate.test.js

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -250,40 +250,63 @@ describe('Form.Validate', () => {
250250
await timeout();
251251
expect(form.getFieldError('test')).toEqual(["'test' is required"]);
252252
});
253-
});
254253

255-
it('change validateTrigger', async () => {
256-
let form;
254+
it('change validateTrigger', async () => {
255+
let form;
257256

258-
const Test = ({ init = false }) => (
259-
<Form
260-
ref={instance => {
261-
form = instance;
262-
}}
263-
>
264-
<Field
265-
name="title"
266-
validateTrigger={init ? 'onChange' : 'onBlur'}
267-
rules={[
268-
{ required: true, message: 'Title is required' },
269-
{ min: 3, message: 'Title should be 3+ characters' },
270-
]}
257+
const Test = ({ init = false }) => (
258+
<Form
259+
ref={instance => {
260+
form = instance;
261+
}}
271262
>
272-
<Input />
273-
</Field>
274-
</Form>
275-
);
263+
<Field
264+
name="title"
265+
validateTrigger={init ? 'onChange' : 'onBlur'}
266+
rules={[
267+
{ required: true, message: 'Title is required' },
268+
{ min: 3, message: 'Title should be 3+ characters' },
269+
]}
270+
>
271+
<Input />
272+
</Field>
273+
</Form>
274+
);
276275

277-
const wrapper = mount(<Test />);
276+
const wrapper = mount(<Test />);
278277

279-
getField(wrapper).simulate('blur');
280-
await timeout();
281-
expect(form.getFieldError('title')).toEqual(['Title is required']);
278+
getField(wrapper).simulate('blur');
279+
await timeout();
280+
expect(form.getFieldError('title')).toEqual(['Title is required']);
282281

283-
wrapper.setProps({ init: true });
284-
await changeValue(getField(wrapper), '1');
285-
expect(form.getFieldValue('title')).toBe('1');
286-
expect(form.getFieldError('title')).toEqual(['Title should be 3+ characters']);
282+
wrapper.setProps({ init: true });
283+
await changeValue(getField(wrapper), '1');
284+
expect(form.getFieldValue('title')).toBe('1');
285+
expect(form.getFieldError('title')).toEqual(['Title should be 3+ characters']);
286+
});
287+
288+
it('form context', async () => {
289+
const wrapper = mount(
290+
<Form validateTrigger="onBlur">
291+
<InfoField name="test" rules={[{ required: true }]} />
292+
</Form>,
293+
);
294+
295+
// Not trigger validate since Form set `onBlur`
296+
await changeValue(getField(wrapper), '');
297+
matchError(wrapper, false);
298+
299+
// Trigger onBlur
300+
wrapper.find('input').simulate('blur');
301+
await timeout();
302+
wrapper.update();
303+
matchError(wrapper, true);
304+
305+
// Update Form context
306+
wrapper.setProps({ validateTrigger: 'onChange' });
307+
await changeValue(getField(wrapper), '1');
308+
matchError(wrapper, false);
309+
});
287310
});
288311

289312
describe('validate only accept exist fields', () => {

0 commit comments

Comments
 (0)