diff --git a/INTRODUCTION.md b/INTRODUCTION.md
index 9ae6f325f..35509c5df 100644
--- a/INTRODUCTION.md
+++ b/INTRODUCTION.md
@@ -884,6 +884,7 @@ MyComponentUsingUniformsContext.contextTypes = {
state: PropTypes.shape({
changed: PropTypes.bool.isRequired,
changedMap: PropTypes.object.isRequired,
+ submitting: PropTypes.bool.isRequired,
label: PropTypes.bool.isRequired,
disabled: PropTypes.bool.isRequired,
@@ -948,8 +949,8 @@ import filterDOMProps from 'uniforms/filterDOMProps';
// This field works as follows: render standard submit field and disable it, when
// the form is invalid. It's a simplified version of a default SubmitField from
// uniforms-unstyled.
-const SubmitField = (props, {uniforms: {error, state: {disabled}}}) =>
-
+const SubmitField = (props, {uniforms: {error, state: {disabled, submitting, validating}}}) =>
+
;
SubmitField.contextTypes = BaseField.contextTypes;
diff --git a/demo/imports/components/ApplicationPreviewField.js b/demo/imports/components/ApplicationPreviewField.js
index dd8324a9d..3ae1d2812 100644
--- a/demo/imports/components/ApplicationPreviewField.js
+++ b/demo/imports/components/ApplicationPreviewField.js
@@ -32,8 +32,14 @@ class ApplicationPreview extends Component {
const Form = themes[this.props.theme].AutoForm;
const link = styles[this.props.theme];
- const props = {...this.props.value};
+ const {asyncOnSubmit, asyncOnValidate, ...props} = {...this.props.value};
props.schema = this._schema;
+ if (asyncOnSubmit) {
+ props.onSubmit = () => new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ if (asyncOnValidate) {
+ props.onValidate = (model, error, next) => setTimeout(() => next(), 1000);
+ }
return (
@@ -42,7 +48,7 @@ class ApplicationPreview extends Component {
{this.props.errorMessage ? (
) : (
-
+
)}
{this.state.model !== undefined &&
}
diff --git a/demo/imports/components/ApplicationPropsField.js b/demo/imports/components/ApplicationPropsField.js
index 2d1e3b4b6..36ffbeefe 100644
--- a/demo/imports/components/ApplicationPropsField.js
+++ b/demo/imports/components/ApplicationPropsField.js
@@ -31,6 +31,8 @@ const ApplicationProps = ({onChange, schema, theme, value}) => {
+
+
diff --git a/demo/imports/lib/schema.js b/demo/imports/lib/schema.js
index 39ba96284..633d9cc9e 100644
--- a/demo/imports/lib/schema.js
+++ b/demo/imports/lib/schema.js
@@ -49,7 +49,9 @@ const schema = new SimpleSchema2({
label: true,
placeholder: false,
schema: presets[Object.keys(presets)[0]],
- showInlineError: false
+ showInlineError: false,
+ asyncOnSubmit: false,
+ asyncOnValidate: false
},
uniforms: {
schema: new SimpleSchema2({
@@ -59,6 +61,8 @@ const schema = new SimpleSchema2({
label: {optional: true, type: Boolean},
placeholder: {optional: true, type: Boolean},
showInlineError: {optional: true, type: Boolean},
+ asyncOnSubmit: {optional: true, type: Boolean, label: 'Async onSubmit (1 sec)'},
+ asyncOnValidate: {optional: true, type: Boolean, label: 'Async onValidate (1 sec)'},
schema: {
optional: true,
diff --git a/packages/uniforms-antd/__tests__/_createContext.js b/packages/uniforms-antd/__tests__/_createContext.js
index b6c4a5f5e..7c44b7d8e 100644
--- a/packages/uniforms-antd/__tests__/_createContext.js
+++ b/packages/uniforms-antd/__tests__/_createContext.js
@@ -20,6 +20,7 @@ const createContext = (schema, context) => ({
changedMap: {},
changed: false,
+ submitting: false,
disabled: false,
label: false,
placeholder: false,
diff --git a/packages/uniforms-bootstrap3/__tests__/_createContext.js b/packages/uniforms-bootstrap3/__tests__/_createContext.js
index b6c4a5f5e..7c44b7d8e 100644
--- a/packages/uniforms-bootstrap3/__tests__/_createContext.js
+++ b/packages/uniforms-bootstrap3/__tests__/_createContext.js
@@ -20,6 +20,7 @@ const createContext = (schema, context) => ({
changedMap: {},
changed: false,
+ submitting: false,
disabled: false,
label: false,
placeholder: false,
diff --git a/packages/uniforms-bootstrap4/__tests__/_createContext.js b/packages/uniforms-bootstrap4/__tests__/_createContext.js
index b6c4a5f5e..7c44b7d8e 100644
--- a/packages/uniforms-bootstrap4/__tests__/_createContext.js
+++ b/packages/uniforms-bootstrap4/__tests__/_createContext.js
@@ -20,6 +20,7 @@ const createContext = (schema, context) => ({
changedMap: {},
changed: false,
+ submitting: false,
disabled: false,
label: false,
placeholder: false,
diff --git a/packages/uniforms-material/__tests__/_createContext.js b/packages/uniforms-material/__tests__/_createContext.js
index d0eec02e5..3b6726839 100644
--- a/packages/uniforms-material/__tests__/_createContext.js
+++ b/packages/uniforms-material/__tests__/_createContext.js
@@ -23,6 +23,7 @@ const createContext = (schema, context) => ({
changed: false,
disabled: false,
+ submitting: false,
label: false,
placeholder: false,
showInlineError: false,
diff --git a/packages/uniforms-semantic/__tests__/_createContext.js b/packages/uniforms-semantic/__tests__/_createContext.js
index b6c4a5f5e..7c44b7d8e 100644
--- a/packages/uniforms-semantic/__tests__/_createContext.js
+++ b/packages/uniforms-semantic/__tests__/_createContext.js
@@ -20,6 +20,7 @@ const createContext = (schema, context) => ({
changedMap: {},
changed: false,
+ submitting: false,
disabled: false,
label: false,
placeholder: false,
diff --git a/packages/uniforms-unstyled/__tests__/_createContext.js b/packages/uniforms-unstyled/__tests__/_createContext.js
index b6c4a5f5e..7c44b7d8e 100644
--- a/packages/uniforms-unstyled/__tests__/_createContext.js
+++ b/packages/uniforms-unstyled/__tests__/_createContext.js
@@ -20,6 +20,7 @@ const createContext = (schema, context) => ({
changedMap: {},
changed: false,
+ submitting: false,
disabled: false,
label: false,
placeholder: false,
diff --git a/packages/uniforms/__tests__/BaseField.js b/packages/uniforms/__tests__/BaseField.js
index aa7b5ed42..d0e24444d 100644
--- a/packages/uniforms/__tests__/BaseField.js
+++ b/packages/uniforms/__tests__/BaseField.js
@@ -30,7 +30,15 @@ describe('BaseField', () => {
const model = {a: {b: {c: 'example'}}};
const onChange = jest.fn();
const randomId = randomIds();
- const state = {changed: !1, changedMap: {}, label: !0, disabled: !1, placeholder: !0, showInlineError: !0};
+ const state = {
+ changed: false,
+ changedMap: {},
+ submitting: false,
+ label: true,
+ disabled: false,
+ placeholder: true,
+ showInlineError: true
+ };
const schema = createSchemaBridge({
getDefinition (name) {
// Simulate SimpleSchema.
diff --git a/packages/uniforms/__tests__/BaseForm.js b/packages/uniforms/__tests__/BaseForm.js
index 414037f71..94174e9a2 100644
--- a/packages/uniforms/__tests__/BaseForm.js
+++ b/packages/uniforms/__tests__/BaseForm.js
@@ -30,6 +30,8 @@ describe('BaseForm', () => {
afterEach(() => {
onChange.mockReset();
onSubmit.mockReset();
+ onSubmitSuccess.mockReset();
+ onSubmitFailure.mockReset();
});
describe('child context', () => {
@@ -64,6 +66,7 @@ describe('BaseForm', () => {
expect(context.uniforms).toHaveProperty('state', expect.any(Object));
expect(context.uniforms.state).toHaveProperty('changed', false);
expect(context.uniforms.state).toHaveProperty('changedMap', {});
+ expect(context.uniforms.state).toHaveProperty('submitting', false);
expect(context.uniforms.state).toHaveProperty('label', true);
expect(context.uniforms.state).toHaveProperty('disabled', false);
expect(context.uniforms.state).toHaveProperty('placeholder', false);
@@ -254,7 +257,7 @@ describe('BaseForm', () => {
expect(onSubmit).toHaveBeenLastCalledWith(model);
});
- it('calls `onSubmit` with correct model (`modelTransform`)', () => {
+ it('calls `onSubmit` with the correctly `modelTransform`ed model', () => {
wrapper.setProps({
modelTransform (mode, model) {
if (mode === 'submit') {
@@ -272,15 +275,39 @@ describe('BaseForm', () => {
wrapper.setProps({modelTransform: undefined});
});
- it('does nothing without `onSubmit`', () => {
- wrapper.setProps({onSubmit: undefined});
+ it('without `onSubmit` calls only `onSubmitSuccess`', async () => {
+ wrapper.setProps({onSubmit: undefined, onSubmitSuccess, onSubmitFailure});
wrapper.find('form').simulate('submit');
+ await new Promise(resolve => process.nextTick(resolve));
expect(onSubmit).not.toBeCalled();
+ expect(onSubmitSuccess).toBeCalledTimes(1);
+ expect(onSubmitFailure).not.toBeCalled();
+ });
+
+ it('sets `submitting` state while submitting', async () => {
+ let resolveSubmit = null;
+ wrapper.setProps({onSubmit: () => new Promise(resolve => resolveSubmit = resolve)});
+
+ const context1 = wrapper.instance().getChildContext().uniforms.state;
+ expect(context1).toHaveProperty('submitting', false);
+
+ wrapper.find('form').simulate('submit');
+ await new Promise(resolve => process.nextTick(resolve));
+
+ const context2 = wrapper.instance().getChildContext().uniforms.state;
+ expect(context2).toHaveProperty('submitting', true);
+
+ resolveSubmit();
+ await new Promise(resolve => process.nextTick(resolve));
+
+ const context3 = wrapper.instance().getChildContext().uniforms.state;
+ expect(context3).toHaveProperty('submitting', false);
});
- it('calls `onSubmitSuccess` when `onSubmit` resolves', async () => {
- onSubmit.mockReturnValueOnce(Promise.resolve());
+ it('calls `onSubmitSuccess` with the returned value when `onSubmit` resolves', async () => {
+ const onSubmitValue = 'value';
+ onSubmit.mockReturnValueOnce(Promise.resolve(onSubmitValue));
const wrapper = mount(
@@ -291,10 +318,12 @@ describe('BaseForm', () => {
await new Promise(resolve => process.nextTick(resolve));
expect(onSubmitSuccess).toHaveBeenCalledTimes(1);
+ expect(onSubmitSuccess).toHaveBeenLastCalledWith(onSubmitValue);
});
- it('calls `onSubmitFailure` when `onSubmit` rejects', async () => {
- onSubmit.mockReturnValueOnce(Promise.reject());
+ it('calls `onSubmitFailure` with the thrown error when `onSubmit` rejects', async () => {
+ const onSubmitError = 'error';
+ onSubmit.mockReturnValueOnce(Promise.reject(onSubmitError));
const wrapper = mount(
@@ -305,6 +334,7 @@ describe('BaseForm', () => {
await new Promise(resolve => process.nextTick(resolve));
expect(onSubmitFailure).toHaveBeenCalledTimes(1);
+ expect(onSubmitFailure).toHaveBeenLastCalledWith(onSubmitError);
});
});
});
diff --git a/packages/uniforms/__tests__/ValidatedForm.js b/packages/uniforms/__tests__/ValidatedForm.js
index c788ae129..f0878da7e 100644
--- a/packages/uniforms/__tests__/ValidatedForm.js
+++ b/packages/uniforms/__tests__/ValidatedForm.js
@@ -100,6 +100,20 @@ describe('ValidatedForm', () => {
expect(wrapper.instance().getChildContext()).not.toHaveProperty('uniforms.error', error);
});
+ it('has `validating` context variable, default `false`', () => {
+ expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.state.validating', false);
+ });
+
+ it('sets `validating` `true` while validating', async () => {
+ onValidate.mockImplementationOnce(() => {});
+ form.validate();
+ expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.state.validating', true);
+
+ // Resolve the async validation by calling the third argument of the first call to onValidate.
+ expect(onValidate).toHaveBeenCalledTimes(1);
+ onValidate.mock.calls[0][2]();
+ expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.state.validating', false);
+ });
it('uses `modelTransform`s `validate` mode', () => {
const transformedModel = {b: 1};
@@ -114,7 +128,9 @@ describe('ValidatedForm', () => {
describe('when submitted', () => {
let wrapper;
beforeEach(() => {
- wrapper = mount();
+ wrapper = mount(
+
+ );
});
it('calls `onSubmit` when validation succeeds', async () => {
@@ -142,6 +158,27 @@ describe('ValidatedForm', () => {
expect(onSubmit).toHaveBeenCalled();
expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.error', error);
});
+
+ it('sets `submitting` `true` while validating, before `BaseForm#onSubmit`', async () => {
+ onValidate.mockImplementationOnce(() => {});
+ wrapper.find('form').simulate('submit');
+ await new Promise(resolve => process.nextTick(resolve));
+ expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.state.submitting', true);
+ });
+
+ it('sets `submitting` back to `false` after sync `onSubmit`', async () => {
+ onValidate.mockImplementationOnce(() => {});
+ onSubmit.mockImplementationOnce(() => {});
+ wrapper.find('form').simulate('submit');
+ await new Promise(resolve => process.nextTick(resolve));
+
+ expect(onValidate).toHaveBeenCalledTimes(1);
+ // Resolve the async validation by calling the third argument of the first call to onValidate.
+ onValidate.mock.calls[0][2]();
+
+ await new Promise(resolve => process.nextTick(resolve));
+ expect(wrapper.instance().getChildContext()).toHaveProperty('uniforms.state.submitting', false);
+ });
});
describe('on change', () => {
diff --git a/packages/uniforms/__tests__/connectField.js b/packages/uniforms/__tests__/connectField.js
index 2deea6232..05f392af8 100644
--- a/packages/uniforms/__tests__/connectField.js
+++ b/packages/uniforms/__tests__/connectField.js
@@ -13,7 +13,15 @@ describe('connectField', () => {
const error = new Error();
const onChange = jest.fn();
const randomId = randomIds();
- const state = {changed: !1, changedMap: {}, label: !0, disabled: !1, placeholder: !1, showInlineError: !0};
+ const state = {
+ changed: false,
+ changedMap: {},
+ submitting: false,
+ label: true,
+ disabled: false,
+ placeholder: false,
+ showInlineError: true
+ };
const schema = createSchemaBridge({
getDefinition (name) {
return {
diff --git a/packages/uniforms/__tests__/injectName.js b/packages/uniforms/__tests__/injectName.js
index b9c50a5c3..9fb9c3cff 100644
--- a/packages/uniforms/__tests__/injectName.js
+++ b/packages/uniforms/__tests__/injectName.js
@@ -14,7 +14,15 @@ describe('injectName', () => {
const error = new Error();
const onChange = () => {};
const randomId = randomIds();
- const state = {changed: !1, changedMap: {}, label: !0, disabled: !1, placeholder: !1, showInlineError: !0};
+ const state = {
+ changed: false,
+ changedMap: {},
+ submitting: false,
+ label: true,
+ disabled: false,
+ placeholder: false,
+ showInlineError: true
+ };
const schema = createSchemaBridge({
getDefinition (name) {
return {
diff --git a/packages/uniforms/src/BaseForm.js b/packages/uniforms/src/BaseForm.js
index e6b50fdce..11f0b7153 100644
--- a/packages/uniforms/src/BaseForm.js
+++ b/packages/uniforms/src/BaseForm.js
@@ -1,14 +1,55 @@
import PropTypes from 'prop-types';
import React from 'react';
import cloneDeep from 'lodash/cloneDeep';
+import mapValues from 'lodash/mapValues';
import get from 'lodash/get';
import set from 'lodash/set';
+import isFunction from 'lodash/isFunction';
+import isPlainObject from 'lodash/isPlainObject';
import {Component} from 'react';
import changedKeys from './changedKeys';
import createSchemaBridge from './createSchemaBridge';
import randomIds from './randomIds';
+export const __childContextTypes = {
+ name: PropTypes.arrayOf(PropTypes.string).isRequired,
+
+ error: PropTypes.object,
+ model: PropTypes.object.isRequired,
+
+ schema: {
+ getError: PropTypes.func.isRequired,
+ getErrorMessage: PropTypes.func.isRequired,
+ getErrorMessages: PropTypes.func.isRequired,
+ getField: PropTypes.func.isRequired,
+ getInitialValue: PropTypes.func.isRequired,
+ getProps: PropTypes.func.isRequired,
+ getSubfields: PropTypes.func.isRequired,
+ getType: PropTypes.func.isRequired,
+ getValidator: PropTypes.func.isRequired
+ },
+
+ state: {
+ changed: PropTypes.bool.isRequired,
+ changedMap: PropTypes.object.isRequired,
+ submitting: PropTypes.bool.isRequired,
+
+ label: PropTypes.bool.isRequired,
+ disabled: PropTypes.bool.isRequired,
+ placeholder: PropTypes.bool.isRequired,
+ showInlineError: PropTypes.bool.isRequired
+ },
+
+ onChange: PropTypes.func.isRequired,
+ randomId: PropTypes.func.isRequired
+};
+
+export const __childContextTypesBuild = type =>
+ isPlainObject(type)
+ ? PropTypes.shape(mapValues(type, __childContextTypesBuild)).isRequired
+ : type;
+
export default class BaseForm extends Component {
static displayName = 'Form';
@@ -44,43 +85,19 @@ export default class BaseForm extends Component {
};
static childContextTypes = {
- uniforms: PropTypes.shape({
- name: PropTypes.arrayOf(PropTypes.string).isRequired,
-
- error: PropTypes.object,
- model: PropTypes.object.isRequired,
-
- schema: PropTypes.shape({
- getError: PropTypes.func.isRequired,
- getErrorMessage: PropTypes.func.isRequired,
- getErrorMessages: PropTypes.func.isRequired,
- getField: PropTypes.func.isRequired,
- getInitialValue: PropTypes.func.isRequired,
- getProps: PropTypes.func.isRequired,
- getSubfields: PropTypes.func.isRequired,
- getType: PropTypes.func.isRequired,
- getValidator: PropTypes.func.isRequired
- }).isRequired,
-
- state: PropTypes.shape({
- changed: PropTypes.bool.isRequired,
- changedMap: PropTypes.object.isRequired,
-
- label: PropTypes.bool.isRequired,
- disabled: PropTypes.bool.isRequired,
- placeholder: PropTypes.bool.isRequired,
- showInlineError: PropTypes.bool.isRequired
- }).isRequired,
-
- onChange: PropTypes.func.isRequired,
- randomId: PropTypes.func.isRequired
- }).isRequired
+ uniforms: __childContextTypesBuild(__childContextTypes)
};
constructor () {
super(...arguments);
- this.state = {bridge: createSchemaBridge(this.props.schema), changed: null, changedMap: {}, resetCount: 0};
+ this.state = {
+ bridge: createSchemaBridge(this.props.schema),
+ changed: null,
+ changedMap: {},
+ resetCount: 0,
+ submitting: false
+ };
this.delayId = false;
this.randomId = randomIds(this.props.id);
@@ -128,6 +145,7 @@ export default class BaseForm extends Component {
return {
changed: !!this.state.changed,
changedMap: this.state.changedMap,
+ submitting: this.state.submitting,
label: !!this.props.label,
disabled: !!this.props.disabled,
@@ -225,7 +243,7 @@ export default class BaseForm extends Component {
}
__reset (state) {
- return {changed: false, changedMap: {}, resetCount: state.resetCount + 1};
+ return {changed: false, changedMap: {}, submitting: false, resetCount: state.resetCount + 1};
}
onReset () {
@@ -238,10 +256,18 @@ export default class BaseForm extends Component {
event.stopPropagation();
}
- return Promise.resolve(
- this.props.onSubmit &&
- this.props.onSubmit(this.getModel('submit'))
- ).then(
+ const result = this.props.onSubmit && this.props.onSubmit(this.getModel('submit'));
+
+ // Set the `submitting` state only if onSubmit is async so we don't cause an unnecessary re-render
+ let submitting;
+ if (result && isFunction(result.then)) {
+ this.setState({submitting: true});
+ submitting = result.finally(() => this.setState({submitting: false}));
+ } else {
+ submitting = Promise.resolve(result);
+ }
+
+ return submitting.then(
this.props.onSubmitSuccess,
this.props.onSubmitFailure
);
diff --git a/packages/uniforms/src/ValidatedForm.js b/packages/uniforms/src/ValidatedForm.js
index 21f2db79b..764de9169 100644
--- a/packages/uniforms/src/ValidatedForm.js
+++ b/packages/uniforms/src/ValidatedForm.js
@@ -1,9 +1,17 @@
import PropTypes from 'prop-types';
import cloneDeep from 'lodash/cloneDeep';
+import merge from 'lodash/merge';
import isEqual from 'lodash/isEqual';
import set from 'lodash/set';
-import BaseForm from './BaseForm';
+import BaseForm from './BaseForm';
+import {__childContextTypesBuild} from './BaseForm';
+import {__childContextTypes} from './BaseForm';
+
+const childContextTypes = __childContextTypesBuild(merge(
+ {state: {validating: PropTypes.bool.isRequired}},
+ __childContextTypes
+));
const Validated = parent => class extends parent {
static Validated = Validated;
@@ -33,6 +41,11 @@ const Validated = parent => class extends parent {
]).isRequired
};
+ static childContextTypes = {
+ ...parent.childContextTypes || {},
+ uniforms: childContextTypes
+ };
+
constructor () {
super(...arguments);
@@ -41,6 +54,7 @@ const Validated = parent => class extends parent {
error: null,
validate: false,
+ validating: false,
validator: this
.getChildContextSchema()
.getValidator(this.props.validator)
@@ -54,6 +68,14 @@ const Validated = parent => class extends parent {
return super.getChildContextError() || this.state.error;
}
+ getChildContextState () {
+ return {
+ ...super.getChildContextState(),
+
+ validating: this.state.validating
+ };
+ }
+
getNativeFormProps () {
const {
onValidate, // eslint-disable-line no-unused-vars
@@ -74,12 +96,12 @@ const Validated = parent => class extends parent {
validator: bridge.getValidator(validator)
}), () => {
if (validate === 'onChange' || validate === 'onChangeAfterSubmit' && this.state.validate) {
- this.onValidate();
+ this.onValidate().catch(() => {});
}
});
} else if (!isEqual(this.props.model, model)) {
if (validate === 'onChange' || validate === 'onChangeAfterSubmit' && this.state.validate) {
- this.onValidateModel(model);
+ this.onValidateModel(model).catch(() => {});
}
}
}
@@ -99,7 +121,7 @@ const Validated = parent => class extends parent {
}
__reset (state) {
- return {...super.__reset(state), error: null, validate: false};
+ return {...super.__reset(state), error: null, validate: false, validating: false};
}
onSubmit (event) {
@@ -109,7 +131,7 @@ const Validated = parent => class extends parent {
}
const promise = new Promise((resolve, reject) => {
- this.setState(() => ({validate: true}), () => {
+ this.setState(() => ({submitting: true, validate: true}), () => {
this.onValidate().then(
() => {
super.onSubmit().then(
@@ -125,8 +147,14 @@ const Validated = parent => class extends parent {
});
});
- // NOTE: It's okay for this Promise to reject.
- promise.catch(() => {});
+ promise
+ .catch(() => {
+ // `onSubmit` should never reject, so we ignore this rejection.
+ })
+ .then(() => {
+ // If validation fails, or `super.onSubmit` doesn't touch `submitting`, we need to reset it.
+ this.setState(state => state.submitting ? {submitting: false} : null);
+ });
return promise;
}
@@ -150,10 +178,11 @@ const Validated = parent => class extends parent {
catched = error;
}
+ this.setState({validating: true});
return new Promise((resolve, reject) => {
this.props.onValidate(model, catched, (error = catched) => {
// Do not copy error from props to state.
- this.setState(() => ({error: error === this.props.error ? null : error}), () => {
+ this.setState(() => ({error: error === this.props.error ? null : error, validating: false}), () => {
if (error) {
reject(error);
} else {
diff --git a/packages/uniforms/src/filterDOMProps.js b/packages/uniforms/src/filterDOMProps.js
index 255387ab0..96e8f96ba 100644
--- a/packages/uniforms/src/filterDOMProps.js
+++ b/packages/uniforms/src/filterDOMProps.js
@@ -20,7 +20,9 @@ const unwantedProps = [
'parent',
'placeholder',
'showInlineError',
+ 'submitting',
'transform',
+ 'validating',
'value',
// These are used by AutoField