Last active
April 3, 2016 00:59
-
-
Save granmoe/056cdadbbf501827e390 to your computer and use it in GitHub Desktop.
Simple form validation implemented with a higher-order component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
export default (options, WrappedComponent) => class extends React.Component { | |
constructor () { | |
super() | |
this.validate = options.validate | |
this.state = options.fields.reduce((result, field) => { | |
result.fields.push(field) | |
result.errors[field] = '' | |
result.values[field] = '' | |
result.touched[field] = false | |
return result | |
}, { fields: [], errors: {}, values: {}, touched: {} }) | |
this.mapStateToProps.bind(this) | |
this.runValidate.bind(this) | |
} | |
onBlur (field, e) { | |
var touched = this.state.touched | |
touched[field] = true | |
this.setState({ touched: touched }) | |
this.runValidate(field, e.target.value) | |
} | |
onChange (field, e) { | |
this.runValidate(field, e.target.value) | |
} | |
runValidate (field, value) { | |
var values = this.state.values | |
values[field] = value | |
this.setState(this.validate(values)) | |
} | |
mapStateToProps (state) { | |
return state.fields.reduce((result, field) => { | |
result[field] = { | |
value: state.values[field], | |
error: state.errors[field], | |
touched: state.touched[field], | |
onChange: this.onChange.bind(this, field), | |
onBlur: this.onBlur.bind(this, field) | |
} | |
return result | |
}, {}) | |
} | |
render () { | |
return <WrappedComponent {...this.props} {...this.mapStateToProps(this.state)} /> | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import formValidation from './form-validation.jsx' | |
class LoginForm extends React.Component { | |
render () { | |
const { username, password } = this.props | |
return ( | |
<div> | |
<input type='text' placeholder='Username' {...username} /> | |
{username.touched && username.error && <div>{username.error}</div>} | |
<input type='password' placeholder='Password' {...password} /> | |
{password.touched && password.error && <div>{password.error}</div>} | |
</div> | |
) | |
} | |
} | |
const validate = values => { | |
let errors = {} | |
if (!values.username) { | |
errors.username = 'Required' | |
} else if (values.username.length > 15) { | |
errors.username = 'Must be 15 characters or less' | |
} | |
if (!values.password) { | |
errors.password = 'Required' | |
} | |
return { errors: errors, values: values } | |
} | |
const validationOptions = { | |
fields: ['username', 'password'], | |
validate: validate | |
} | |
export default formValidation(validationOptions, LoginForm) |
One could also do filtering within the validate function. Although, it would probably be better to expand the HoC to accept a separate filter method.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My first stab at a HoC. Any feedback is welcomed :-)