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

Commit d2d2fd1

Browse files
committed
Reversing premature setSubmitted flagging actions and correctly computing form-level validity after async validation. Fixes #246
1 parent 315da98 commit d2d2fd1

File tree

3 files changed

+64
-12
lines changed

3 files changed

+64
-12
lines changed

src/actions/field-actions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ const submit = (model, promise, options = {}) => dispatch => {
130130
}).catch(error => {
131131
dispatch(batchActions.batch(model, [
132132
setSubmitFailed(model),
133-
errorsAction(model, error, { errors: true }),
133+
errorsAction(model, error),
134134
]));
135135
});
136136

src/components/form-component.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ class Form extends Component {
5050
modelValue,
5151
} = this.props;
5252

53-
if (!formValue) {
54-
return;
55-
}
53+
if (!formValue) return;
5654

5755
if (!validators && !errors && (modelValue !== nextProps.modelValue)) {
5856
if (!formValue.valid) {
@@ -104,11 +102,18 @@ class Form extends Component {
104102
return fieldErrors;
105103
});
106104

105+
const fieldsErrors = merge(
106+
invertValidity(fieldsValidity),
107+
fieldsErrorsValidity
108+
);
109+
110+
// Compute form-level validity
111+
if (!fieldsValidity.hasOwnProperty('') && !fieldsErrorsValidity.hasOwnProperty('')) {
112+
fieldsErrors[''] = false;
113+
}
114+
107115
if (validityChanged) {
108-
dispatch(actions.setFieldsErrors(model, merge(
109-
invertValidity(fieldsValidity),
110-
fieldsErrorsValidity
111-
)));
116+
dispatch(actions.setFieldsErrors(model, fieldsErrors));
112117
}
113118
}
114119

@@ -120,7 +125,7 @@ class Form extends Component {
120125
onSubmit = identity,
121126
} = this.props;
122127

123-
dispatch(actions.setSubmitted(model));
128+
dispatch(actions.setPending(model));
124129

125130
return onSubmit(modelValue);
126131
}

test/form-component-spec.js

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,8 +696,6 @@ describe('<Form> component', () => {
696696

697697
TestUtils.Simulate.submit(formElement);
698698

699-
assert.isTrue(store.getState().testForm.submitted);
700-
701699
assert.deepEqual(
702700
submitValue,
703701
{
@@ -1011,6 +1009,53 @@ describe('<Form> component', () => {
10111009
});
10121010
});
10131011

1012+
describe('invalidating async validity on form change with form validators', () => {
1013+
const store = createTestStore(applyMiddleware(thunk)(createStore)(combineReducers({
1014+
test: modelReducer('test', { foo: 'invalid' }),
1015+
testForm: formReducer('test', { foo: 'invalid' }),
1016+
})));
1017+
1018+
function handleSubmit() {
1019+
store.dispatch(actions.batch('test', [
1020+
actions.setSubmitFailed('test'),
1021+
actions.setErrors('test', 'Form is invalid', { errors: true }),
1022+
]));
1023+
}
1024+
1025+
const form = TestUtils.renderIntoDocument(
1026+
<Provider store={store}>
1027+
<Form model="test"
1028+
validators={{
1029+
foo: (val) => val && val.length,
1030+
}}
1031+
onSubmit={handleSubmit}
1032+
>
1033+
<Field model="test.foo">
1034+
<input type="text" />
1035+
</Field>
1036+
</Form>
1037+
</Provider>
1038+
);
1039+
1040+
const formElement = TestUtils.findRenderedDOMComponentWithTag(form, 'form');
1041+
const inputElement = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
1042+
1043+
it('should set errors from rejected submit handler on valid submit', () => {
1044+
TestUtils.Simulate.submit(formElement);
1045+
1046+
assert.containSubset(
1047+
store.getState().testForm,
1048+
{ errors: 'Form is invalid' });
1049+
});
1050+
1051+
it('should set validity on form changes after submit failed', () => {
1052+
inputElement.value = 'valid';
1053+
TestUtils.Simulate.change(inputElement);
1054+
1055+
assert.isTrue(store.getState().testForm.valid);
1056+
});
1057+
});
1058+
10141059
describe('submit after invalid', () => {
10151060
const handleSubmit = sinon.spy((val) => val);
10161061

@@ -1078,16 +1123,18 @@ describe('<Form> component', () => {
10781123

10791124
TestUtils.Simulate.change(pass2);
10801125

1126+
10811127
TestUtils.Simulate.submit(formElement);
10821128

1129+
assert.isTrue(store.getState().testForm.valid);
1130+
10831131
assert.isTrue(handleSubmit.calledOnce);
10841132

10851133
assert.containSubset(
10861134
store.getState().testForm,
10871135
{
10881136
valid: true,
10891137
submitFailed: false,
1090-
submitted: true,
10911138
});
10921139
});
10931140
});

0 commit comments

Comments
 (0)