redux-form
Advanced tools
Comparing version 0.1.3 to 0.2.0
@@ -396,29 +396,5 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
/** | ||
* @param sliceName The key in the state corresponding to the data in this form | ||
* @param validate [optional] A validation function that takes all the data and returns all the errors | ||
* @param asyncConfig [optional] { | ||
* validate: an asynchronous validation function that takes all the data and returns a promise | ||
* that resolves to async validation errors, or {} if none, | ||
* fields: an array of field names for which handleBlur should trigger an async validation call | ||
* } | ||
*/ | ||
function reduxForm(sliceName) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
var validate = function validate() { | ||
return { valid: true }; | ||
}; | ||
var asyncConfig = undefined; | ||
if (typeof args[0] === 'function') { | ||
validate = args.shift(); | ||
} | ||
if (typeof args[0] === 'object') { | ||
asyncConfig = args[0]; | ||
} | ||
function runValidation(form) { | ||
var syncErrors = validate(form.data); | ||
function createReduxFormDecorator(sliceName, syncValidate, asyncValidate, asyncBlurFields) { | ||
function combineValidationErrors(form) { | ||
var syncErrors = syncValidate(form.data); | ||
var asyncErrors = _extends({ valid: true }, form.asyncErrors); | ||
@@ -447,5 +423,17 @@ var valid = !!(syncErrors.valid && asyncErrors.valid); // !! to convert falsy to boolean | ||
var dispatch = _props.dispatch; | ||
var onSubmit = _props.onSubmit; | ||
var passableProps = _objectWithoutProperties(_props, ['form', 'sliceName', 'dispatch']); | ||
var passableProps = _objectWithoutProperties(_props, ['form', 'sliceName', 'dispatch', 'onSubmit']); | ||
var runAsyncValidation = asyncValidate ? function () { | ||
dispatch(_actions.startAsyncValidation(sliceName)); | ||
var promise = asyncValidate(form.data); | ||
if (!promise || typeof promise.then !== 'function') { | ||
throw new Error('asyncValidate function passed to reduxForm must return a promise!'); | ||
} | ||
return promise.then(function (asyncErrors) { | ||
dispatch(_actions.stopAsyncValidation(sliceName, asyncErrors)); | ||
return !!asyncErrors.valid; | ||
}); | ||
} : undefined; | ||
var handleBlur = function handleBlur(name, value) { | ||
@@ -455,12 +443,9 @@ return function (event) { | ||
dispatch(_actions.blur(sliceName, name, fieldValue)); | ||
if (asyncConfig && asyncConfig.validate && asyncConfig.fields && ~asyncConfig.fields.indexOf(name)) { | ||
if (runAsyncValidation && ~asyncBlurFields.indexOf(name)) { | ||
var _extends2; | ||
var syncError = validate(_extends({}, form.data, (_extends2 = {}, _extends2[name] = fieldValue, _extends2)))[name]; | ||
var syncError = syncValidate(_extends({}, form.data, (_extends2 = {}, _extends2[name] = fieldValue, _extends2)))[name]; | ||
// only dispatch async call if all synchronous client-side validation passes for this field | ||
if (!syncError) { | ||
dispatch(_actions.startAsyncValidation(sliceName)); | ||
asyncConfig.validate(form.data).then(function (asyncErrors) { | ||
return dispatch(_actions.stopAsyncValidation(sliceName, asyncErrors)); | ||
}); | ||
runAsyncValidation(); | ||
} | ||
@@ -470,2 +455,10 @@ } | ||
}; | ||
var pristine = _util.isPristine(form.initial, form.data); | ||
var _combineValidationErrors = combineValidationErrors(form); | ||
var valid = _combineValidationErrors.valid; | ||
var errors = _objectWithoutProperties(_combineValidationErrors, ['valid']); | ||
var handleChange = function handleChange(name, value) { | ||
@@ -476,11 +469,22 @@ return function (event) { | ||
}; | ||
var pristine = _util.isPristine(form.initial, form.data); | ||
var _runValidation = runValidation(form); | ||
var valid = _runValidation.valid; | ||
var errors = _objectWithoutProperties(_runValidation, ['valid']); | ||
var handleSubmit = function handleSubmit(event) { | ||
if (event) { | ||
event.preventDefault(); | ||
} | ||
if (!onSubmit) { | ||
throw new Error('If you are going to use handleSubmit(), you must specify an onSubmit prop'); | ||
} | ||
dispatch(_actions.touchAll(sliceName)); | ||
if (runAsyncValidation) { | ||
runAsyncValidation().then(function (asyncValid) { | ||
if (valid && asyncValid) { | ||
onSubmit(form.data); | ||
} | ||
}); | ||
} else if (valid) { | ||
onSubmit(form.data); | ||
} | ||
}; | ||
return _react2['default'].createElement(DecoratedComponent, _extends({ | ||
asyncValidate: runAsyncValidation, | ||
asyncValidating: form.asyncValidating, | ||
@@ -493,2 +497,3 @@ data: form.data, | ||
handleChange: handleChange, | ||
handleSubmit: handleSubmit, | ||
initializeForm: function (data) { | ||
@@ -503,7 +508,7 @@ return dispatch(_actions.initialize(sliceName, data)); | ||
touch: function () { | ||
for (var _len2 = arguments.length, fields = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
fields[_key2] = arguments[_key2]; | ||
for (var _len = arguments.length, touchFields = Array(_len), _key = 0; _key < _len; _key++) { | ||
touchFields[_key] = arguments[_key]; | ||
} | ||
return dispatch(_actions.touch.apply(undefined, [sliceName].concat(fields))); | ||
return dispatch(_actions.touch.apply(undefined, [sliceName].concat(touchFields))); | ||
}, | ||
@@ -515,7 +520,7 @@ touched: form.touched, | ||
untouch: function () { | ||
for (var _len3 = arguments.length, fields = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
fields[_key3] = arguments[_key3]; | ||
for (var _len2 = arguments.length, untouchFields = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
untouchFields[_key2] = arguments[_key2]; | ||
} | ||
return dispatch(_actions.untouch.apply(undefined, [sliceName].concat(fields))); | ||
return dispatch(_actions.untouch.apply(undefined, [sliceName].concat(untouchFields))); | ||
}, | ||
@@ -542,2 +547,3 @@ untouchAll: function () { | ||
form: _react.PropTypes.object.isRequired, | ||
onSubmit: _react.PropTypes.func, | ||
dispatch: _react.PropTypes.func.isRequired | ||
@@ -559,2 +565,19 @@ }, | ||
function reduxForm(sliceName) { | ||
var syncValidate = arguments.length <= 1 || arguments[1] === undefined ? function () { | ||
return { valid: true }; | ||
} : arguments[1]; | ||
var decorator = createReduxFormDecorator(sliceName, syncValidate); | ||
decorator.async = function (asyncValidate) { | ||
for (var _len3 = arguments.length, fields = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { | ||
fields[_key3 - 1] = arguments[_key3]; | ||
} | ||
var blurFields = Array.isArray(fields[0]) ? fields[0] : fields; | ||
return createReduxFormDecorator(sliceName, syncValidate, asyncValidate, blurFields); | ||
}; | ||
return decorator; | ||
} | ||
module.exports = exports['default']; | ||
@@ -561,0 +584,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports.ReduxForm=e(require("react")):t.ReduxForm=e(t.React)}(this,function(t){return function(t){function e(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}e.__esModule=!0;var a=r(3),u=n(a),o=r(4),i=n(o),c=r(2);e.default=i.default,e.blur=c.blur,e.change=c.change,e.createFormReducer=u.default,e.initialize=c.initialize,e.reset=c.reset,e.startAsyncValidation=c.startAsyncValidation,e.stopAsyncValidation=c.stopAsyncValidation,e.touch=c.touch,e.touchAll=c.touchAll,e.untouch=c.untouch,e.untouchAll=c.untouchAll},function(t,e){"use strict";e.__esModule=!0;var r="redux-form/BLUR";e.BLUR=r;var n="redux-form/CHANGE";e.CHANGE=n;var a="redux-form/INITIALIZE";e.INITIALIZE=a;var u="redux-form/RESET";e.RESET=u;var o="redux-form/START_ASYNC_VALIDATION";e.START_ASYNC_VALIDATION=o;var i="redux-form/STOP_ASYNC_VALIDATION";e.STOP_ASYNC_VALIDATION=i;var c="redux-form/TOUCH";e.TOUCH=c;var s="redux-form/TOUCH_ALL";e.TOUCH_ALL=s;var l="redux-form/UNTOUCH";e.UNTOUCH=l;var f="redux-form/UNTOUCH_ALL";e.UNTOUCH_ALL=f},function(t,e,r){"use strict";function n(t,e,r){return{type:p.BLUR,form:t,field:e,value:r}}function a(t,e,r){return{type:p.CHANGE,form:t,field:e,value:r}}function u(t,e){return{type:p.INITIALIZE,form:t,data:e}}function o(t){return{type:p.RESET,form:t}}function i(t){return{type:p.START_ASYNC_VALIDATION,form:t}}function c(t,e){return{type:p.STOP_ASYNC_VALIDATION,form:t,errors:e}}function s(t){for(var e=arguments.length,r=Array(e>1?e-1:0),n=1;e>n;n++)r[n-1]=arguments[n];return{type:p.TOUCH,form:t,fields:r}}function l(t){return{type:p.TOUCH_ALL,form:t}}function f(t){for(var e=arguments.length,r=Array(e>1?e-1:0),n=1;e>n;n++)r[n-1]=arguments[n];return{type:p.UNTOUCH,form:t,fields:r}}function d(t){return{type:p.UNTOUCH_ALL,form:t}}e.__esModule=!0,e.blur=n,e.change=a,e.initialize=u,e.reset=o,e.startAsyncValidation=i,e.stopAsyncValidation=c,e.touch=s,e.touchAll=l,e.untouch=f,e.untouchAll=d;var p=r(1)},function(t,e,r){"use strict";function n(t,e){var r=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=r.touchOnBlur,o=void 0===n?!0:n,i=r.touchOnChange,c=void 0===i?!1:i;return function(){var r,n,i=arguments.length<=0||void 0===arguments[0]?{initial:{},data:{},touched:{},asyncValidating:!1,asyncErrors:{}}:arguments[0],s=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if(s.form!==t)return i;switch(s.type){case u.BLUR:var l={data:a({},i.data,(r={},r[s.field]=s.value,r))};if(o){var f;l.touched=a({},i.touched,(f={},f[s.field]=!0,f))}return a({},i,l);case u.CHANGE:var d={data:a({},i.data,(n={},n[s.field]=s.value,n))};if(c){var p;d.touched=a({},i.touched,(p={},p[s.field]=!0,p))}return a({},i,d);case u.INITIALIZE:return{initial:s.data,data:s.data,asyncValidating:!1,asyncErrors:{},touched:{}};case u.RESET:return{initial:i.initial,data:i.initial,touched:{},asyncValidating:!1,asyncErrors:{}};case u.START_ASYNC_VALIDATION:return a({},i,{asyncValidating:!0});case u.STOP_ASYNC_VALIDATION:return a({},i,{asyncValidating:!1,asyncErrors:s.errors});case u.TOUCH:var h={};return s.fields.forEach(function(t){if("string"!=typeof t)throw new Error("fields passed to touch() must be strings");h[t]=!0}),a({},i,{touched:a({},i.touched,h)});case u.TOUCH_ALL:var m={};return e.forEach(function(t){return m[t]=!0}),a({},i,{touched:m});case u.UNTOUCH:var v={};return s.fields.forEach(function(t){if("string"!=typeof t)throw new Error("fields passed to untouch() must be strings");v[t]=!1}),a({},i,{touched:a({},i.touched,v)});case u.UNTOUCH_ALL:return a({},i,{touched:{}});default:return i}}}e.__esModule=!0;var a=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};e.default=n;var u=r(1);t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function a(t,e){var r={};for(var n in t)e.indexOf(n)>=0||Object.prototype.hasOwnProperty.call(t,n)&&(r[n]=t[n]);return r}function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t){function e(t){var e=h(t.data),r=s({valid:!0},t.asyncErrors),n=!(!e.valid||!r.valid);return s({},e,r,{valid:n})}for(var r=arguments.length,n=Array(r>1?r-1:0),i=1;r>i;i++)n[i-1]=arguments[i];var h=function(){return{valid:!0}},m=void 0;return"function"==typeof n[0]&&(h=n.shift()),"object"==typeof n[0]&&(m=n[0]),function(r){return function(n){function i(){u(this,i),n.apply(this,arguments)}return o(i,n),i.prototype.render=function(){var t=this.props,n=t.form,u=t.sliceName,o=t.dispatch,i=a(t,["form","sliceName","dispatch"]),c=function(t,e){return function(r){var a=e||r.target.value;if(o(d.blur(u,t,a)),m&&m.validate&&m.fields&&~m.fields.indexOf(t)){var i,c=h(s({},n.data,(i={},i[t]=a,i)))[t];c||(o(d.startAsyncValidation(u)),m.validate(n.data).then(function(t){return o(d.stopAsyncValidation(u,t))}))}}},l=function(t,e){return function(r){return o(d.change(u,t,e||r.target.value))}},v=p.isPristine(n.initial,n.data),y=e(n),A=y.valid,g=a(y,["valid"]);return f.default.createElement(r,s({asyncValidating:n.asyncValidating,data:n.data,dirty:!v,dispatch:o,errors:g,handleBlur:c,handleChange:l,initializeForm:function(t){return o(d.initialize(u,t))},invalid:!A,pristine:v,resetForm:function(){return o(d.reset(u))},touch:function(){for(var t=arguments.length,e=Array(t),r=0;t>r;r++)e[r]=arguments[r];return o(d.touch.apply(void 0,[u].concat(e)))},touched:n.touched,touchAll:function(){return o(d.touchAll(u))},untouch:function(){for(var t=arguments.length,e=Array(t),r=0;t>r;r++)e[r]=arguments[r];return o(d.untouch.apply(void 0,[u].concat(e)))},untouchAll:function(){return o(d.untouchAll(u))},valid:A},i))},c(i,null,[{key:"displayName",value:"ReduxForm("+p.getDisplayName(r)+")",enumerable:!0},{key:"DecoratedComponent",value:r,enumerable:!0},{key:"propTypes",value:{sliceName:l.PropTypes.string,form:l.PropTypes.object.isRequired,dispatch:l.PropTypes.func.isRequired},enumerable:!0},{key:"defaultProps",value:{sliceName:t},enumerable:!0}]),i}(l.Component)}}e.__esModule=!0;var c=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),s=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};e.default=i;var l=r(6),f=n(l),d=r(2),p=r(5);t.exports=e.default},function(t,e){"use strict";function r(t){return t.displayName||t.name||"Component"}function n(t,e){if(t===e)return!0;for(var r=Object.keys(e),n=0;n<r.length;n++){var a=r[n],u=e[a],o=t[a];if((u||o)&&u!==o)return!1}return!0}e.__esModule=!0,e.getDisplayName=r,e.isPristine=n},function(e,r){e.exports=t}])}); | ||
!function(t,r){"object"==typeof exports&&"object"==typeof module?module.exports=r(require("react")):"function"==typeof define&&define.amd?define(["react"],r):"object"==typeof exports?exports.ReduxForm=r(require("react")):t.ReduxForm=r(t.React)}(this,function(t){return function(t){function r(n){if(e[n])return e[n].exports;var a=e[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,r),a.loaded=!0,a.exports}var e={};return r.m=t,r.c=e,r.p="",r(0)}([function(t,r,e){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}r.__esModule=!0;var a=e(3),u=n(a),o=e(4),i=n(o),c=e(2);r.default=i.default,r.blur=c.blur,r.change=c.change,r.createFormReducer=u.default,r.initialize=c.initialize,r.reset=c.reset,r.startAsyncValidation=c.startAsyncValidation,r.stopAsyncValidation=c.stopAsyncValidation,r.touch=c.touch,r.touchAll=c.touchAll,r.untouch=c.untouch,r.untouchAll=c.untouchAll},function(t,r){"use strict";r.__esModule=!0;var e="redux-form/BLUR";r.BLUR=e;var n="redux-form/CHANGE";r.CHANGE=n;var a="redux-form/INITIALIZE";r.INITIALIZE=a;var u="redux-form/RESET";r.RESET=u;var o="redux-form/START_ASYNC_VALIDATION";r.START_ASYNC_VALIDATION=o;var i="redux-form/STOP_ASYNC_VALIDATION";r.STOP_ASYNC_VALIDATION=i;var c="redux-form/TOUCH";r.TOUCH=c;var s="redux-form/TOUCH_ALL";r.TOUCH_ALL=s;var l="redux-form/UNTOUCH";r.UNTOUCH=l;var f="redux-form/UNTOUCH_ALL";r.UNTOUCH_ALL=f},function(t,r,e){"use strict";function n(t,r,e){return{type:p.BLUR,form:t,field:r,value:e}}function a(t,r,e){return{type:p.CHANGE,form:t,field:r,value:e}}function u(t,r){return{type:p.INITIALIZE,form:t,data:r}}function o(t){return{type:p.RESET,form:t}}function i(t){return{type:p.START_ASYNC_VALIDATION,form:t}}function c(t,r){return{type:p.STOP_ASYNC_VALIDATION,form:t,errors:r}}function s(t){for(var r=arguments.length,e=Array(r>1?r-1:0),n=1;r>n;n++)e[n-1]=arguments[n];return{type:p.TOUCH,form:t,fields:e}}function l(t){return{type:p.TOUCH_ALL,form:t}}function f(t){for(var r=arguments.length,e=Array(r>1?r-1:0),n=1;r>n;n++)e[n-1]=arguments[n];return{type:p.UNTOUCH,form:t,fields:e}}function d(t){return{type:p.UNTOUCH_ALL,form:t}}r.__esModule=!0,r.blur=n,r.change=a,r.initialize=u,r.reset=o,r.startAsyncValidation=i,r.stopAsyncValidation=c,r.touch=s,r.touchAll=l,r.untouch=f,r.untouchAll=d;var p=e(1)},function(t,r,e){"use strict";function n(t,r){var e=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=e.touchOnBlur,o=void 0===n?!0:n,i=e.touchOnChange,c=void 0===i?!1:i;return function(){var e,n,i=arguments.length<=0||void 0===arguments[0]?{initial:{},data:{},touched:{},asyncValidating:!1,asyncErrors:{}}:arguments[0],s=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if(s.form!==t)return i;switch(s.type){case u.BLUR:var l={data:a({},i.data,(e={},e[s.field]=s.value,e))};if(o){var f;l.touched=a({},i.touched,(f={},f[s.field]=!0,f))}return a({},i,l);case u.CHANGE:var d={data:a({},i.data,(n={},n[s.field]=s.value,n))};if(c){var p;d.touched=a({},i.touched,(p={},p[s.field]=!0,p))}return a({},i,d);case u.INITIALIZE:return{initial:s.data,data:s.data,asyncValidating:!1,asyncErrors:{},touched:{}};case u.RESET:return{initial:i.initial,data:i.initial,touched:{},asyncValidating:!1,asyncErrors:{}};case u.START_ASYNC_VALIDATION:return a({},i,{asyncValidating:!0});case u.STOP_ASYNC_VALIDATION:return a({},i,{asyncValidating:!1,asyncErrors:s.errors});case u.TOUCH:var m={};return s.fields.forEach(function(t){if("string"!=typeof t)throw new Error("fields passed to touch() must be strings");m[t]=!0}),a({},i,{touched:a({},i.touched,m)});case u.TOUCH_ALL:var h={};return r.forEach(function(t){return h[t]=!0}),a({},i,{touched:h});case u.UNTOUCH:var y={};return s.fields.forEach(function(t){if("string"!=typeof t)throw new Error("fields passed to untouch() must be strings");y[t]=!1}),a({},i,{touched:a({},i.touched,y)});case u.UNTOUCH_ALL:return a({},i,{touched:{}});default:return i}}}r.__esModule=!0;var a=Object.assign||function(t){for(var r=1;r<arguments.length;r++){var e=arguments[r];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}return t};r.default=n;var u=e(1);t.exports=r.default},function(t,r,e){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function a(t,r){var e={};for(var n in t)r.indexOf(n)>=0||Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e}function u(t,r){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}function o(t,r){if("function"!=typeof r&&null!==r)throw new TypeError("Super expression must either be null or a function, not "+typeof r);t.prototype=Object.create(r&&r.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),r&&(Object.setPrototypeOf?Object.setPrototypeOf(t,r):t.__proto__=r)}function i(t,r,e,n){function i(t){var e=r(t.data),n=l({valid:!0},t.asyncErrors),a=!(!e.valid||!n.valid);return l({},e,n,{valid:a})}return function(c){return function(h){function y(){u(this,y),h.apply(this,arguments)}return o(y,h),y.prototype.render=function(){var t=this.props,u=t.form,o=t.sliceName,s=t.dispatch,f=t.onSubmit,h=a(t,["form","sliceName","dispatch","onSubmit"]),y=e?function(){s(p.startAsyncValidation(o));var t=e(u.data);if(!t||"function"!=typeof t.then)throw new Error("asyncValidate function passed to reduxForm must return a promise!");return t.then(function(t){return s(p.stopAsyncValidation(o,t)),!!t.valid})}:void 0,v=function(t,e){return function(a){var i=e||a.target.value;if(s(p.blur(o,t,i)),y&&~n.indexOf(t)){var c,f=r(l({},u.data,(c={},c[t]=i,c)))[t];f||y()}}},A=m.isPristine(u.initial,u.data),g=i(u),T=g.valid,O=a(g,["valid"]),_=function(t,r){return function(e){return s(p.change(o,t,r||e.target.value))}},N=function(t){if(t&&t.preventDefault(),!f)throw new Error("If you are going to use handleSubmit(), you must specify an onSubmit prop");s(p.touchAll(o)),y?y().then(function(t){T&&t&&f(u.data)}):T&&f(u.data)};return d.default.createElement(c,l({asyncValidate:y,asyncValidating:u.asyncValidating,data:u.data,dirty:!A,dispatch:s,errors:O,handleBlur:v,handleChange:_,handleSubmit:N,initializeForm:function(t){return s(p.initialize(o,t))},invalid:!T,pristine:A,resetForm:function(){return s(p.reset(o))},touch:function(){for(var t=arguments.length,r=Array(t),e=0;t>e;e++)r[e]=arguments[e];return s(p.touch.apply(void 0,[o].concat(r)))},touched:u.touched,touchAll:function(){return s(p.touchAll(o))},untouch:function(){for(var t=arguments.length,r=Array(t),e=0;t>e;e++)r[e]=arguments[e];return s(p.untouch.apply(void 0,[o].concat(r)))},untouchAll:function(){return s(p.untouchAll(o))},valid:T},h))},s(y,null,[{key:"displayName",value:"ReduxForm("+m.getDisplayName(c)+")",enumerable:!0},{key:"DecoratedComponent",value:c,enumerable:!0},{key:"propTypes",value:{sliceName:f.PropTypes.string,form:f.PropTypes.object.isRequired,onSubmit:f.PropTypes.func,dispatch:f.PropTypes.func.isRequired},enumerable:!0},{key:"defaultProps",value:{sliceName:t},enumerable:!0}]),y}(f.Component)}}function c(t){var r=arguments.length<=1||void 0===arguments[1]?function(){return{valid:!0}}:arguments[1],e=i(t,r);return e.async=function(e){for(var n=arguments.length,a=Array(n>1?n-1:0),u=1;n>u;u++)a[u-1]=arguments[u];var o=Array.isArray(a[0])?a[0]:a;return i(t,r,e,o)},e}r.__esModule=!0;var s=function(){function t(t,r){for(var e=0;e<r.length;e++){var n=r[e];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(r,e,n){return e&&t(r.prototype,e),n&&t(r,n),r}}(),l=Object.assign||function(t){for(var r=1;r<arguments.length;r++){var e=arguments[r];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}return t};r.default=c;var f=e(6),d=n(f),p=e(2),m=e(5);t.exports=r.default},function(t,r){"use strict";function e(t){return t.displayName||t.name||"Component"}function n(t,r){if(t===r)return!0;for(var e=Object.keys(r),n=0;n<e.length;n++){var a=e[n],u=r[a],o=t[a];if((u||o)&&u!==o)return!1}return!0}r.__esModule=!0,r.getDisplayName=e,r.isPristine=n},function(r,e){r.exports=t}])}); |
@@ -27,29 +27,5 @@ 'use strict'; | ||
/** | ||
* @param sliceName The key in the state corresponding to the data in this form | ||
* @param validate [optional] A validation function that takes all the data and returns all the errors | ||
* @param asyncConfig [optional] { | ||
* validate: an asynchronous validation function that takes all the data and returns a promise | ||
* that resolves to async validation errors, or {} if none, | ||
* fields: an array of field names for which handleBlur should trigger an async validation call | ||
* } | ||
*/ | ||
function reduxForm(sliceName) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
var validate = function validate() { | ||
return { valid: true }; | ||
}; | ||
var asyncConfig = undefined; | ||
if (typeof args[0] === 'function') { | ||
validate = args.shift(); | ||
} | ||
if (typeof args[0] === 'object') { | ||
asyncConfig = args[0]; | ||
} | ||
function runValidation(form) { | ||
var syncErrors = validate(form.data); | ||
function createReduxFormDecorator(sliceName, syncValidate, asyncValidate, asyncBlurFields) { | ||
function combineValidationErrors(form) { | ||
var syncErrors = syncValidate(form.data); | ||
var asyncErrors = _extends({ valid: true }, form.asyncErrors); | ||
@@ -78,5 +54,17 @@ var valid = !!(syncErrors.valid && asyncErrors.valid); // !! to convert falsy to boolean | ||
var dispatch = _props.dispatch; | ||
var onSubmit = _props.onSubmit; | ||
var passableProps = _objectWithoutProperties(_props, ['form', 'sliceName', 'dispatch']); | ||
var passableProps = _objectWithoutProperties(_props, ['form', 'sliceName', 'dispatch', 'onSubmit']); | ||
var runAsyncValidation = asyncValidate ? function () { | ||
dispatch(_actions.startAsyncValidation(sliceName)); | ||
var promise = asyncValidate(form.data); | ||
if (!promise || typeof promise.then !== 'function') { | ||
throw new Error('asyncValidate function passed to reduxForm must return a promise!'); | ||
} | ||
return promise.then(function (asyncErrors) { | ||
dispatch(_actions.stopAsyncValidation(sliceName, asyncErrors)); | ||
return !!asyncErrors.valid; | ||
}); | ||
} : undefined; | ||
var handleBlur = function handleBlur(name, value) { | ||
@@ -86,12 +74,9 @@ return function (event) { | ||
dispatch(_actions.blur(sliceName, name, fieldValue)); | ||
if (asyncConfig && asyncConfig.validate && asyncConfig.fields && ~asyncConfig.fields.indexOf(name)) { | ||
if (runAsyncValidation && ~asyncBlurFields.indexOf(name)) { | ||
var _extends2; | ||
var syncError = validate(_extends({}, form.data, (_extends2 = {}, _extends2[name] = fieldValue, _extends2)))[name]; | ||
var syncError = syncValidate(_extends({}, form.data, (_extends2 = {}, _extends2[name] = fieldValue, _extends2)))[name]; | ||
// only dispatch async call if all synchronous client-side validation passes for this field | ||
if (!syncError) { | ||
dispatch(_actions.startAsyncValidation(sliceName)); | ||
asyncConfig.validate(form.data).then(function (asyncErrors) { | ||
return dispatch(_actions.stopAsyncValidation(sliceName, asyncErrors)); | ||
}); | ||
runAsyncValidation(); | ||
} | ||
@@ -101,2 +86,10 @@ } | ||
}; | ||
var pristine = _util.isPristine(form.initial, form.data); | ||
var _combineValidationErrors = combineValidationErrors(form); | ||
var valid = _combineValidationErrors.valid; | ||
var errors = _objectWithoutProperties(_combineValidationErrors, ['valid']); | ||
var handleChange = function handleChange(name, value) { | ||
@@ -107,11 +100,22 @@ return function (event) { | ||
}; | ||
var pristine = _util.isPristine(form.initial, form.data); | ||
var _runValidation = runValidation(form); | ||
var valid = _runValidation.valid; | ||
var errors = _objectWithoutProperties(_runValidation, ['valid']); | ||
var handleSubmit = function handleSubmit(event) { | ||
if (event) { | ||
event.preventDefault(); | ||
} | ||
if (!onSubmit) { | ||
throw new Error('If you are going to use handleSubmit(), you must specify an onSubmit prop'); | ||
} | ||
dispatch(_actions.touchAll(sliceName)); | ||
if (runAsyncValidation) { | ||
runAsyncValidation().then(function (asyncValid) { | ||
if (valid && asyncValid) { | ||
onSubmit(form.data); | ||
} | ||
}); | ||
} else if (valid) { | ||
onSubmit(form.data); | ||
} | ||
}; | ||
return _react2['default'].createElement(DecoratedComponent, _extends({ | ||
asyncValidate: runAsyncValidation, | ||
asyncValidating: form.asyncValidating, | ||
@@ -124,2 +128,3 @@ data: form.data, | ||
handleChange: handleChange, | ||
handleSubmit: handleSubmit, | ||
initializeForm: function (data) { | ||
@@ -134,7 +139,7 @@ return dispatch(_actions.initialize(sliceName, data)); | ||
touch: function () { | ||
for (var _len2 = arguments.length, fields = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
fields[_key2] = arguments[_key2]; | ||
for (var _len = arguments.length, touchFields = Array(_len), _key = 0; _key < _len; _key++) { | ||
touchFields[_key] = arguments[_key]; | ||
} | ||
return dispatch(_actions.touch.apply(undefined, [sliceName].concat(fields))); | ||
return dispatch(_actions.touch.apply(undefined, [sliceName].concat(touchFields))); | ||
}, | ||
@@ -146,7 +151,7 @@ touched: form.touched, | ||
untouch: function () { | ||
for (var _len3 = arguments.length, fields = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
fields[_key3] = arguments[_key3]; | ||
for (var _len2 = arguments.length, untouchFields = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
untouchFields[_key2] = arguments[_key2]; | ||
} | ||
return dispatch(_actions.untouch.apply(undefined, [sliceName].concat(fields))); | ||
return dispatch(_actions.untouch.apply(undefined, [sliceName].concat(untouchFields))); | ||
}, | ||
@@ -173,2 +178,3 @@ untouchAll: function () { | ||
form: _react.PropTypes.object.isRequired, | ||
onSubmit: _react.PropTypes.func, | ||
dispatch: _react.PropTypes.func.isRequired | ||
@@ -190,2 +196,19 @@ }, | ||
function reduxForm(sliceName) { | ||
var syncValidate = arguments.length <= 1 || arguments[1] === undefined ? function () { | ||
return { valid: true }; | ||
} : arguments[1]; | ||
var decorator = createReduxFormDecorator(sliceName, syncValidate); | ||
decorator.async = function (asyncValidate) { | ||
for (var _len3 = arguments.length, fields = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { | ||
fields[_key3 - 1] = arguments[_key3]; | ||
} | ||
var blurFields = Array.isArray(fields[0]) ? fields[0] : fields; | ||
return createReduxFormDecorator(sliceName, syncValidate, asyncValidate, blurFields); | ||
}; | ||
return decorator; | ||
} | ||
module.exports = exports['default']; |
{ | ||
"name": "redux-form", | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"description": "A higher order component generator for forms using Redux and React", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
150
README.md
@@ -41,3 +41,3 @@ #redux-form | ||
// ... your other reducers here ... | ||
createFormReducer('contacts', ['name', 'address', 'phone']) | ||
createFormReducer('contactForm', ['name', 'address', 'phone']) | ||
} | ||
@@ -52,3 +52,3 @@ const reducer = combineReducers(reducers); | ||
Then, on your form component, add the `@reduxForm('contacts')` decorator. | ||
Then, on your form component, add the `@reduxForm('contactForm')` decorator. | ||
@@ -87,17 +87,30 @@ ```javascript | ||
touched: {name: nameTouched, address: addressTouched, phone: phoneTouched}, | ||
handleChange | ||
handleBlur, | ||
handleChange, | ||
handleSubmit | ||
} = this.props; | ||
return ( | ||
<form> | ||
<form onSubmit={handleSubmit}> | ||
<label>Name</label> | ||
<input type="text" value={name} onChange={handleChange('name')}/> | ||
<input type="text" | ||
value={name} | ||
onChange={handleChange('name')} | ||
onBlur={handleBlur('name')}/> | ||
{nameError && nameTouched ? <div>{nameError}</div>} | ||
<label>Address</label> | ||
<input type="text" value={address} onChange={handleChange('address')}/> | ||
<input type="text" | ||
value={address} | ||
onChange={handleChange('address')} | ||
onBlur={handleBlur('address')}/> | ||
{addressError && addressTouched ? <div>{addressError}</div>} | ||
<label>Phone</label> | ||
<input type="text" value={phone} onChange={handleChange('phone')}/> | ||
<input type="text" | ||
value={phone} | ||
onChange={handleChange('phone')} | ||
onBlur={handleBlur('phone')}/> | ||
{phoneError && phoneTouched ? <div>{phoneError}</div>} | ||
<button onClick={handleSubmit}>Submit</button> | ||
</form> | ||
@@ -108,8 +121,8 @@ ); | ||
// apply reduxForm() to teach it validation | ||
ContactForm = reduxForm('contacts', contactValidation)(ContactForm); | ||
// apply reduxForm() and include synchronous validation | ||
ContactForm = reduxForm('contactForm', contactValidation)(ContactForm); | ||
// ------- HERE'S THE IMPORTANT BIT ------- | ||
function mapStateToProps(state) { | ||
return { form: state.contacts }; | ||
return { form: state.contactForm }; | ||
} | ||
@@ -160,7 +173,8 @@ // apply connect() to bind it to Redux state | ||
Using [ES7 decorator proposal](https://github.com/wycats/javascript-decorators), the example above could be written as: | ||
Using [ES7 decorator proposal](https://github.com/wycats/javascript-decorators), the example above | ||
could be written as: | ||
```javascript | ||
@connect(state => ({ form: state.contacts })) | ||
@reduxForm('contacts', contactValidation) | ||
@connect(state => ({ form: state.contactForm })) | ||
@reduxForm('contactForm', contactValidation) | ||
export default class ContactForm extends Component { | ||
@@ -174,5 +188,6 @@ ``` | ||
## Validation | ||
## Synchronous Validation | ||
You may optionally supply a validation function, which is in the form `({}) => {}` and takes in all your data and spits out error messages as well as a `valid` flag. For example: | ||
You may optionally supply a validation function, which is in the form `({}) => {}` and takes in all | ||
your data and spits out error messages as well as a `valid` flag. For example: | ||
@@ -206,4 +221,42 @@ ```javascript | ||
Async validation can be achieved by passing an `asyncConfig` parameter to `reduxForm()` containing a function that takes all the form data and returns a promise that will resolve to validation errors. | ||
Async validation can be achieved by calling an additional function on the function returned by | ||
`reduxForm()` and passing it an asynchronous function that returns a promise that will resolve | ||
to validation errors of the format that the synchronous [validation function](#synchronous-validation) | ||
generates. So this... | ||
```javascript | ||
// apply reduxForm() and include synchronous validation | ||
ContactForm = reduxForm('contactForm', contactValidation)(ContactForm); | ||
``` | ||
...changes to this: | ||
```javascript | ||
function asyncValidation(data) { | ||
return new Promise((resolve, reject) => { | ||
const errors = {valid: true}; | ||
// do async validation | ||
resolve(errors); | ||
}); | ||
} | ||
// apply reduxForm() and include synchronous AND asynchronous validation | ||
ContactForm = reduxForm('contactForm', contactValidation) | ||
.async(asyncValidation)(ContactForm); | ||
``` | ||
Optionally, if you want asynchronous validation to be triggered when one or more of your form | ||
fields is blurred, you may pass those fields to the `async()` function along with the asynchronous | ||
validation function. Like so: | ||
```javascript | ||
ContactForm = reduxForm('contactForm', contactValidation) | ||
.async(asyncValidation, 'name', 'phone')(ContactForm); | ||
``` | ||
With that call, the asynchronous validation will be called when either `name` or `phone` is blurred. | ||
*Assuming that they have their `onBlur={handleBlur('name')}` properties properly set up.* | ||
**NOTE!** If you _only_ want asynchronous validation, you may leave out the synchronous validation function. | ||
And if you only want it to be run on submit, you may leave out the fields, as well. | ||
```javascript | ||
ContactForm = reduxForm('contactForm').async(asyncValidation)(ContactForm); | ||
``` | ||
## API | ||
@@ -213,3 +266,3 @@ | ||
### `createFormReducer(sliceName:string, fields:Array<string>, config:Object)` | ||
### `createFormReducer(sliceName:string, fields:Array<string>, config:Object?)` | ||
@@ -236,3 +289,3 @@ ##### -`sliceName` : string | ||
### `reduxForm(sliceName:string, validate:Function?, asyncConfig:Object?)` | ||
### `reduxForm(sliceName:string, validate:Function?)` | ||
@@ -245,16 +298,17 @@ ##### -`sliceName : string` | ||
> your [validation function](#validation) | ||
> your [synchronous validation function](#synchronous-validation). Defaults to `() => ({valid: true})` | ||
##### -`asyncConfig : Object` [optional] | ||
### `reduxForm().async(asyncValidate:Function, ...fields:String?)` | ||
> an object containing the following two values: | ||
##### -`asyncValidate : Function` | ||
###### -`validate : Function` | ||
> a function that takes all the form data and returns a Promise that will resolve to an object | ||
of validation errors in the form `{ field1: <string>, field2: <string>, valid: <boolean> }` just like the | ||
[synchronous validation function](#synchronous-validation). See | ||
[Aynchronous Validation](#asynchronous-validation) for more details. | ||
> a function that takes all the form data and returns a Promise that will resolve to an object of validation errors in the form `{ field1: <string>, field2: <string> }` just like the synchronous [validation function](#validation). | ||
###### -`...fields : String` [optional] | ||
###### -`fields : Array<string>` | ||
> field names for which `handleBlur` should trigger a call to the `asyncValidate` function | ||
> an array of field names for which `handleBlur` should trigger a call to the asynchronous validation function | ||
### props | ||
@@ -264,2 +318,6 @@ | ||
##### -`asyncValidate : Function` | ||
> a function that may be called to initiate asynchronous validation if asynchronous validation is enabled | ||
##### -`asyncValidating : boolean` | ||
@@ -289,2 +347,8 @@ | ||
##### -`handleSubmit : Function` | ||
> a function meant to be passed to `<form onSubmit={handleSubmit}>` or to `<button onClick={handleSubmit}>`. | ||
It will run validation, both sync and async, and, if the form is valid, it will call `this.props.onSubmit(data)` | ||
with the contents of the form data. | ||
##### -`initializeForm(data:Object) : Function` | ||
@@ -330,2 +394,36 @@ | ||
## Submitting your form | ||
The recommended way to submit your form is to create your form component as [shown above](#how-it-works), | ||
using the `handleSubmit` prop, and then pass an `onSubmit` prop to your form component. | ||
```javascript | ||
import React, {Component, PropTypes} from 'redux-form'; | ||
import {connect} from 'redux'; | ||
import {initialize} from 'redux-form'; | ||
class ContactPage extends Component { | ||
static propTypes = { | ||
dispatch: PropTypes.func.isRequired | ||
} | ||
handleSubmit(data) { | ||
console.log('Submission received!', data); | ||
this.props.dispatch(initialize('contactForm', {})); // clear form | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<h1>Contact Information</h1> | ||
<ContactForm onSubmit={::this.handleSubmit}/> | ||
</div> | ||
); | ||
} | ||
} | ||
export default connect()(ContactPage); // adds dispatch prop | ||
``` | ||
## Responding to other actions | ||
@@ -332,0 +430,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
128312
1484
448