Skip to content

Instantly share code, notes, and snippets.

@granmoe
Last active April 3, 2016 00:59
Show Gist options
  • Select an option

  • Save granmoe/056cdadbbf501827e390 to your computer and use it in GitHub Desktop.

Select an option

Save granmoe/056cdadbbf501827e390 to your computer and use it in GitHub Desktop.
Simple form validation implemented with a higher-order component
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)} />
}
}
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)
@granmoe
Copy link
Copy Markdown
Author

granmoe commented Mar 28, 2016

My first stab at a HoC. Any feedback is welcomed :-)

@granmoe
Copy link
Copy Markdown
Author

granmoe commented Mar 28, 2016

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