Skip to content

Commit

Permalink
Fixed validation errors using callback
Browse files Browse the repository at this point in the history
  • Loading branch information
christianalfoni committed Apr 17, 2015
1 parent 7e909fb commit 4267c40
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 19 deletions.
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsy-react",
"version": "0.12.4",
"version": "0.12.5",
"main": "src/main.js",
"dependencies": {
"react": "^0.13.1"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsy-react",
"version": "0.12.4",
"version": "0.12.5",
"description": "A form input builder and validator for React JS",
"repository": {
"type": "git",
Expand Down
23 changes: 15 additions & 8 deletions release/formsy-react.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ Formsy.Form = React.createClass({displayName: "Form",

// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();

event && event.preventDefault();

// Trigger form as not pristine.
// If any inputs have not been touched yet this will make them dirty
Expand Down Expand Up @@ -117,7 +118,7 @@ Formsy.Form = React.createClass({displayName: "Form",
var component = this.inputs[name];
var args = [{
_isValid: !(name in errors),
_serverError: errors[name]
_validationError: errors[name]
}];
component.setState.apply(component, args);
}.bind(this));
Expand All @@ -136,7 +137,7 @@ Formsy.Form = React.createClass({displayName: "Form",

var args = [{
_isValid: false,
_validationError: errors[name]
_externalError: errors[name]
}];
component.setState.apply(component, args);
}.bind(this));
Expand Down Expand Up @@ -217,15 +218,15 @@ Formsy.Form = React.createClass({displayName: "Form",
component.setState({
_isValid: validation.isValid,
_isRequired: validation.isRequired,
_validationError: validation.error
_validationError: validation.error,
_externalError: null
}, this.validateForm);

},

// Checks validation on current value or a passed value
runValidation: function (component, value) {


var currentValues = this.getCurrentValues();
var validationErrors = component.props.validationErrors;
var validationError = component.props.validationError;
Expand All @@ -241,6 +242,7 @@ Formsy.Form = React.createClass({displayName: "Form",

var isRequired = Object.keys(component._requiredValidations).length ? !!requiredResults.success.length : false;
var isValid = !validationResults.failed.length && !(this.props.validationErrors && this.props.validationErrors[component.props.name]);

return {
isRequired: isRequired,
isValid: isRequired ? false : isValid,
Expand Down Expand Up @@ -360,10 +362,14 @@ Formsy.Form = React.createClass({displayName: "Form",
inputKeys.forEach(function (name, index) {
var component = inputs[name];
var validation = this.runValidation(component);
if (validation.isValid && component.state._externalError) {
validation.isValid = false;
}
component.setState({
_isValid: validation.isValid,
_isRequired: validation.isRequired,
_validationError: validation.error
_validationError: validation.error,
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));

Expand Down Expand Up @@ -447,7 +453,8 @@ module.exports = {
_isValid: true,
_isPristine: true,
_pristineValue: this.props.value,
_validationError: ''
_validationError: '',
_externalError: null
};
},
getDefaultProps: function () {
Expand Down Expand Up @@ -538,7 +545,7 @@ module.exports = {
return this.state._value !== '';
},
getErrorMessage: function () {
return !this.isValid() || this.showRequired() ? this.state._validationError : null;
return !this.isValid() || this.showRequired() ? (this.state._externalError || this.state._validationError) : null;
},
isFormDisabled: function () {
return this.props._isFormDisabled();
Expand Down
2 changes: 1 addition & 1 deletion release/formsy-react.min.js

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions specs/Validation-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,79 @@ var Formsy = require('./../src/main.js');

describe('Validation', function() {

it('should reset only changed form element when external error is passed', function (done) {

var onSubmit = function (model, reset, invalidate) {
invalidate({
foo: 'bar',
bar: 'foo'
});
}
var TestInput = React.createClass({
mixins: [Formsy.Mixin],
updateValue: function (event) {
this.setValue(event.target.value);
},
render: function () {
return <input value={this.getValue()} onChange={this.updateValue}/>
}
});
var form = TestUtils.renderIntoDocument(
<Formsy.Form onSubmit={onSubmit}>
<TestInput name="foo"/>
<TestInput name="bar"/>
</Formsy.Form>
);

var input = TestUtils.scryRenderedDOMComponentsWithTag(form, 'INPUT')[0];
var inputComponents = TestUtils.scryRenderedComponentsWithType(form, TestInput);

form.submit();
expect(inputComponents[0].isValid()).toBe(false);
expect(inputComponents[1].isValid()).toBe(false);
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
setTimeout(function () {
expect(inputComponents[0].isValid()).toBe(true);
expect(inputComponents[1].isValid()).toBe(false);
done();
}, 0);
});

it('should let normal validation take over when component with external error is changed', function (done) {

var onSubmit = function (model, reset, invalidate) {
invalidate({
foo: 'bar'
});
}
var TestInput = React.createClass({
mixins: [Formsy.Mixin],
updateValue: function (event) {
this.setValue(event.target.value);
},
render: function () {
return <input value={this.getValue()} onChange={this.updateValue}/>
}
});
var form = TestUtils.renderIntoDocument(
<Formsy.Form onSubmit={onSubmit}>
<TestInput name="foo" validations="isEmail"/>
</Formsy.Form>
);

var input = TestUtils.findRenderedDOMComponentWithTag(form, 'INPUT');
var inputComponent = TestUtils.findRenderedComponentWithType(form, TestInput);

form.submit();
expect(inputComponent.isValid()).toBe(false);
TestUtils.Simulate.change(input, {target: {value: 'bar'}});
setTimeout(function () {
expect(inputComponent.getValue()).toBe('bar');
expect(inputComponent.isValid()).toBe(false);
done();
}, 0);
});

it('should trigger an onValid handler, if passed, when form is valid', function () {

var onValid = jasmine.createSpy('valid');
Expand Down
5 changes: 3 additions & 2 deletions src/Mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = {
_isValid: true,
_isPristine: true,
_pristineValue: this.props.value,
_validationError: ''
_validationError: '',
_externalError: null
};
},
getDefaultProps: function () {
Expand Down Expand Up @@ -124,7 +125,7 @@ module.exports = {
return this.state._value !== '';
},
getErrorMessage: function () {
return !this.isValid() || this.showRequired() ? this.state._validationError : null;
return !this.isValid() || this.showRequired() ? (this.state._externalError || this.state._validationError) : null;
},
isFormDisabled: function () {
return this.props._isFormDisabled();
Expand Down
18 changes: 12 additions & 6 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ Formsy.Form = React.createClass({

// Update model, submit to url prop and send the model
submit: function (event) {
event.preventDefault();

event && event.preventDefault();

// Trigger form as not pristine.
// If any inputs have not been touched yet this will make them dirty
Expand Down Expand Up @@ -115,7 +116,7 @@ Formsy.Form = React.createClass({
var component = this.inputs[name];
var args = [{
_isValid: !(name in errors),
_serverError: errors[name]
_validationError: errors[name]
}];
component.setState.apply(component, args);
}.bind(this));
Expand All @@ -134,7 +135,7 @@ Formsy.Form = React.createClass({

var args = [{
_isValid: false,
_validationError: errors[name]
_externalError: errors[name]
}];
component.setState.apply(component, args);
}.bind(this));
Expand Down Expand Up @@ -215,15 +216,15 @@ Formsy.Form = React.createClass({
component.setState({
_isValid: validation.isValid,
_isRequired: validation.isRequired,
_validationError: validation.error
_validationError: validation.error,
_externalError: null
}, this.validateForm);

},

// Checks validation on current value or a passed value
runValidation: function (component, value) {


var currentValues = this.getCurrentValues();
var validationErrors = component.props.validationErrors;
var validationError = component.props.validationError;
Expand All @@ -239,6 +240,7 @@ Formsy.Form = React.createClass({

var isRequired = Object.keys(component._requiredValidations).length ? !!requiredResults.success.length : false;
var isValid = !validationResults.failed.length && !(this.props.validationErrors && this.props.validationErrors[component.props.name]);

return {
isRequired: isRequired,
isValid: isRequired ? false : isValid,
Expand Down Expand Up @@ -358,10 +360,14 @@ Formsy.Form = React.createClass({
inputKeys.forEach(function (name, index) {
var component = inputs[name];
var validation = this.runValidation(component);
if (validation.isValid && component.state._externalError) {
validation.isValid = false;
}
component.setState({
_isValid: validation.isValid,
_isRequired: validation.isRequired,
_validationError: validation.error
_validationError: validation.error,
_externalError: !validation.isValid && component.state._externalError ? component.state._externalError : null
}, index === inputKeys.length - 1 ? onValidationComplete : null);
}.bind(this));

Expand Down

0 comments on commit 4267c40

Please sign in to comment.