Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit f2e2e35

Browse files
committed
Ensure validation sends modelValue if validateOn is not an updateOn event. Fixes #428
1 parent 0ecd845 commit f2e2e35

File tree

4 files changed

+62
-8
lines changed

4 files changed

+62
-8
lines changed

src/components/control-component.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,20 +227,27 @@ function createControlClass(customControlPropsMap = {}, defaultProps = {}) {
227227
return changeAction(model, getValue(value));
228228
}
229229

230-
getValidateAction(value) {
230+
getValidateAction(value, eventName) {
231231
const {
232232
validators,
233233
errors,
234234
model,
235+
modelValue,
236+
updateOn,
235237
fieldValue,
236238
} = this.props;
237239

238240
const nodeErrors = this.getNodeErrors();
239241

242+
// If it is not a change event, use the model value.
243+
const valueToValidate = containsEvent(updateOn, eventName)
244+
? value
245+
: modelValue;
246+
240247
if (validators || errors) {
241-
const fieldValidity = getValidity(validators, value);
248+
const fieldValidity = getValidity(validators, valueToValidate);
242249
const fieldErrors = merge(
243-
getValidity(errors, value),
250+
getValidity(errors, valueToValidate),
244251
nodeErrors);
245252

246253
const mergedErrors = validators
@@ -257,17 +264,24 @@ function createControlClass(customControlPropsMap = {}, defaultProps = {}) {
257264
return false;
258265
}
259266

260-
getAsyncValidateAction(value) {
267+
getAsyncValidateAction(value, eventName) {
261268
const {
262269
asyncValidators,
263270
fieldValue,
264271
model,
272+
modelValue,
273+
updateOn,
265274
} = this.props;
266275

267276
// If there are no async validators,
268277
// do not run async validation
269278
if (!asyncValidators) return false;
270279

280+
// If it is not a change event, use the model value.
281+
const valueToValidate = containsEvent(updateOn, eventName)
282+
? value
283+
: modelValue;
284+
271285
// If any sync validity is invalid,
272286
// do not run async validation
273287
const asyncValidatorKeys = Object.keys(asyncValidators);
@@ -290,12 +304,12 @@ function createControlClass(customControlPropsMap = {}, defaultProps = {}) {
290304
done(validity);
291305
};
292306

293-
validator(getValue(value), outerDone);
307+
validator(getValue(valueToValidate), outerDone);
294308
})
295309
)
296310
);
297311

298-
return value;
312+
return valueToValidate;
299313
};
300314
}
301315

@@ -419,11 +433,11 @@ function createControlClass(customControlPropsMap = {}, defaultProps = {}) {
419433

420434
if (containsEvent(validateOn, eventName)) {
421435
eventActions.push(
422-
this.getValidateAction(persistedEvent));
436+
this.getValidateAction(persistedEvent, eventName));
423437
}
424438

425439
if (containsEvent(asyncValidateOn, eventName)) {
426-
eventActions.push(this.getAsyncValidateAction(persistedEvent));
440+
eventActions.push(this.getAsyncValidateAction(persistedEvent, eventName));
427441
}
428442

429443
if (containsEvent(updateOn, eventName)) {

test/control-component-spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,43 @@ Object.keys(testContexts).forEach((testKey) => {
682682
});
683683
});
684684

685+
describe('validateOn != updateOn', () => {
686+
const initialState = {
687+
foo: 'one',
688+
};
689+
690+
const radioStore = testCreateStore({
691+
testForm: formReducer('test', initialState),
692+
test: modelReducer('test', initialState),
693+
});
694+
695+
const app = TestUtils.renderIntoDocument(
696+
<Provider store={radioStore}>
697+
<Control.radio
698+
model="test.foo"
699+
value="two"
700+
validateOn="focus"
701+
validators={{
702+
isOne: (val) => val === 'one',
703+
}}
704+
/>
705+
</Provider>
706+
);
707+
708+
const input = TestUtils.findRenderedDOMComponentWithTag(app, 'input');
709+
710+
it('should initially be valid', () => {
711+
assert.isTrue(radioStore.getState().testForm.foo.valid);
712+
});
713+
714+
it('should still be valid after focusing', () => {
715+
TestUtils.Simulate.focus(input);
716+
717+
assert.isTrue(radioStore.getState().testForm.foo.valid);
718+
assert.isTrue(radioStore.getState().testForm.foo.focus);
719+
});
720+
});
721+
685722
describe('asyncValidators and asyncValidateOn property', () => {
686723
const reducer = formReducer('test');
687724
const store = testCreateStore({

test/custom-control-component-spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ describe('custom <Control /> components', () => {
283283

284284
const input = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
285285
input.value = 'testing';
286+
287+
TestUtils.Simulate.change(input);
286288
TestUtils.Simulate.blur(input);
287289
});
288290

test/custom-field-component-spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ describe('custom <Field /> components with createFieldClass()', () => {
365365

366366
const input = TestUtils.findRenderedDOMComponentWithTag(field, 'input');
367367
input.value = 'testing';
368+
TestUtils.Simulate.change(input);
368369
TestUtils.Simulate.blur(input);
369370
});
370371
});

0 commit comments

Comments
 (0)