[Ivan Diaz] - FrontEnd - Add form validation logic [skip ci]
This commit is contained in:
parent
f06b45948a
commit
7b8012401e
|
@ -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">
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue