[Ivan Diaz] - FrontEnd - Add form validation logic [skip ci]

This commit is contained in:
Ivan Diaz 2016-06-05 14:27:28 -03:00
parent f06b45948a
commit 7b8012401e
4 changed files with 100 additions and 24 deletions

View File

@ -33,8 +33,8 @@ let MainHomePageLoginWidget = React.createClass({
<Widget className="main-home-page--widget" title="Login">
<Form className="login-widget--form" onSubmit={this.handleLoginFormSubmit}>
<div className="login-widget--inputs">
<Input placeholder="email" name="email" className="login-widget--input" validation="EMAIL"/>
<Input placeholder="password" name="password" className="login-widget--input" password/>
<Input placeholder="email" name="email" className="login-widget--input" validation="EMAIL" required/>
<Input placeholder="password" name="password" className="login-widget--input" password required/>
<Checkbox name="remember" label="Remember Me" className="login-widget--input"/>
</div>
<div className="login-widget--submit-button">

View File

@ -0,0 +1,39 @@
const Input = require('core-components/input');
describe('Input component', function () {
let nativeInput, input;
function renderInput(props) {
input = TestUtils.renderIntoDocument(
<Input {...props} />
);
nativeInput = TestUtils.findRenderedDOMComponentWithTag(input, 'input');
}
describe('when passing props that affects the native input', function () {
it('should render type text if it has not specified type', function () {
renderInput();
expect(nativeInput.getAttribute('type')).to.equal('text');
});
it('should render type password if password pass is passed', function () {
renderInput({
password: true
});
expect(nativeInput.getAttribute('type')).to.equal('password');
});
it('should render aria-required instead of required', function () {
renderInput({
required: true
});
expect(nativeInput.getAttribute('required')).to.not.equal('null');
expect(nativeInput.getAttribute('aria-required')).to.equal('true');
});
});
});

View File

@ -1,4 +1,5 @@
const React = require('react');
const ReactDOM = require('react-dom');
const _ = require('lodash');
const {reactDFS, renderChildrenWithProps} = require('lib-core/react-dfs');
@ -14,23 +15,28 @@ const Form = React.createClass({
form: {},
validations: {},
errors: {}
}
};
},
componentDidMount() {
let formState = {};
let validations = {};
reactDFS(this.props.children, function (child) {
if (child.type === Input) {
formState[child.props.name] = child.props.value || '';
validations[child.props.name] = ValidationFactory.getValidator(child.props.validation || 'DEFAULT');
reactDFS(this.props.children, (child) => {
if (this.isValidInputType(child)) {
if (child.type === Input) {
formState[child.props.name] = child.props.value || '';
}
else if (child.type === Checkbox) {
formState[child.props.name] = child.props.checked || false;
}
if (child.props.required) {
validations[child.props.name] = ValidationFactory.getValidator(child.props.validation || 'DEFAULT');
}
}
else if (child.type === Checkbox) {
formState[child.props.name] = child.props.checked || false;
validations[child.props.name] = ValidationFactory.getValidator(child.props.validation || 'DEFAULT');
}
}.bind(this));
});
this.setState({
form: formState,
@ -75,7 +81,9 @@ const Form = React.createClass({
event.preventDefault();
if (this.hasFormErrors()) {
this.focusFirstErrorField();
this.setState({
errors: this.validateAllFields()
}, this.focusFirstErrorField);
} else if (this.props.onSubmit) {
this.props.onSubmit(this.state.form);
}
@ -83,18 +91,15 @@ const Form = React.createClass({
handleInputChange(inputName, type, event) {
let form = _.clone(this.state.form);
let errors = _.clone(this.state.errors);
let inputValue = event.target.value;
let errors;
form[inputName] = inputValue;
errors[inputName] = this.state.validations[inputName].validate(inputValue, form);
form[inputName] = event.target.value;
if (type === Checkbox) {
form[inputName] = event.target.checked || false;
}
console.log(errors);
errors = this.validateField(inputName, form);
this.setState({
form: form,
errors: errors
@ -109,16 +114,45 @@ const Form = React.createClass({
let firstErrorField = this.getFirstErrorField();
if (firstErrorField) {
this.refs[firstErrorField].focus();
firstErrorField.focus();
}
},
getFirstErrorField() {
let fieldName = _.findKey(this.state.errors);
let fieldNode;
if (fieldName) {
fieldNode = ReactDOM.findDOMNode(this.refs[fieldName]);
}
return fieldNode;
},
validateAllFields: function () {
isValidInputType(child) {
return child.type === Input || child.type === Checkbox;
},
validateAllFields() {
let form = this.state.form;
let inputList = Object.keys(this.state.form);
let errors = {};
_.each(inputList, (inputName) => {
errors = this.validateField(inputName, form, errors);
});
return errors;
},
validateField(inputName, form = this.state.form, errors = this.state.errors) {
let newErrors = _.clone(errors);
if (this.state.validations[inputName]) {
newErrors[inputName] = this.state.validations[inputName].validate(form[inputName], form);
}
return newErrors;
}
});

View File

@ -9,7 +9,8 @@ const Input = React.createClass({
validation: React.PropTypes.string,
onChange: React.PropTypes.func,
inputType: React.PropTypes.string,
password: React.PropTypes.bool
password: React.PropTypes.bool,
required: React.PropTypes.bool
},
getDefaultProps() {
@ -22,14 +23,16 @@ const Input = React.createClass({
return (
<label className={this.getClass()}>
<span className="input--label">{this.props.label}</span>
<input {...this.getProps()} className="input--text" />
<input {...this.getInputProps()} className="input--text" />
</label>
);
},
getProps() {
getInputProps() {
let props = _.clone(this.props);
props.required = null;
props['aria-required'] = this.props.required;
props.type = (this.props.password) ? 'password' : 'text';
return props;