-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed half of tests, split out component to props based and HoC for s…
…tate
- Loading branch information
Showing
9 changed files
with
272 additions
and
182 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React from 'react'; | ||
import Input from './input'; | ||
import Submit from './submit'; | ||
import Validator from 'validatorjs'; | ||
import GetChildren from './get-children'; | ||
|
||
export default class FormBase extends React.Component { | ||
constructor() { | ||
super(); | ||
this.onChange = this.onChange.bind(this); | ||
this.validate = this.validate.bind(this); | ||
this.validateOnBlurOrChange = this.validateOnBlurOrChange.bind(this); | ||
} | ||
|
||
validate(onClick) { | ||
let { | ||
rules, | ||
errorMessages = {}, | ||
attributeNames = {}, | ||
onErrors, | ||
values, | ||
} = this.props; | ||
if (!rules) return onClick(values); | ||
|
||
const runner = new Validator(values, rules, errorMessages); | ||
runner.setAttributeNames(attributeNames); | ||
|
||
if (runner.fails()) { | ||
return onErrors(runner.errors.errors); | ||
} else onErrors(undefined); | ||
|
||
return onClick(values); | ||
} | ||
|
||
validateOnBlurOrChange(name, value, onChange) { | ||
if (onChange) onChange(); | ||
let { | ||
rules, | ||
errorMessages = {}, | ||
attributeNames = {}, | ||
errors = {}, | ||
onErrors, | ||
} = this.props; | ||
|
||
if (!rules || !rules[name]) return; | ||
|
||
const runner = new Validator( | ||
{ [name]: value }, | ||
{ [name]: rules[name] }, | ||
errorMessages | ||
); | ||
runner.setAttributeNames(attributeNames); | ||
|
||
if (runner.fails() && value && !onChange) { | ||
return onErrors({ ...errors, ...runner.errors.errors }); | ||
} | ||
if (errors[name]) { | ||
return onErrors({ ...errors, [name]: null }); | ||
} | ||
} | ||
|
||
onChange({ target }) { | ||
let { onValues, values } = this.props; | ||
|
||
values[target.name] = | ||
target.type === 'checkbox' || target.type === 'radio' | ||
? target.checked | ||
: target.value; | ||
|
||
onValues({ ...values }); | ||
} | ||
|
||
renderChildren(children) { | ||
return React.Children.map(children, child => { | ||
if (!child || !child.props) return child; | ||
|
||
let children = GetChildren(child, this); | ||
|
||
let { values = {}, errors } = this.props; | ||
if (child.props.name) return Input(child, values, children, errors, this); | ||
if (child.props.submit) return Submit(child, children, this); | ||
|
||
return React.cloneElement(child, { children }); | ||
}); | ||
} | ||
|
||
render() { | ||
let { | ||
children, | ||
rules, | ||
errorMessages, | ||
attributeNames, | ||
values, | ||
onValues, | ||
errors, | ||
onErrors, | ||
...props | ||
} = this.props; | ||
return <div {...props}>{this.renderChildren(children)}</div>; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,31 @@ | ||
import React from 'react'; | ||
import Input from './input'; | ||
import Submit from './submit'; | ||
import Validator from 'validatorjs'; | ||
import GetChildren from './get-children'; | ||
import BaseForm from './base'; | ||
|
||
export default class Form extends React.Component { | ||
constructor({ values = {}, onValues }) { | ||
constructor({ values = {}, errors = {} }) { | ||
super(); | ||
this.state = { values: onValues ? {} : values, errors: {} }; | ||
this.onChange = this.onChange.bind(this); | ||
this.validate = this.validate.bind(this); | ||
this.validateOnBlurOrChange = this.validateOnBlurOrChange.bind(this); | ||
} | ||
|
||
validate(onClick) { | ||
let { rules, errorMessages = {}, attributeNames = {} } = this.props; | ||
let values = { ...this.props.values, ...this.state.values }; | ||
if (!rules) return onClick(values); | ||
|
||
const runner = new Validator(values, rules, errorMessages); | ||
runner.setAttributeNames(attributeNames); | ||
|
||
if (runner.fails()) { | ||
return this.setState({ errors: runner.errors.errors }); | ||
} else this.setState({ errors: {} }); | ||
|
||
return onClick(values); | ||
} | ||
|
||
validateOnBlurOrChange(name, onChange) { | ||
if (onChange) onChange(); | ||
|
||
let { rules, errorMessages = {}, attributeNames = {} } = this.props; | ||
let { errors, values } = this.state; | ||
if (!rules || !rules[name]) return; | ||
|
||
const runner = new Validator( | ||
{ [name]: values[name] }, | ||
{ [name]: rules[name] }, | ||
errorMessages | ||
); | ||
runner.setAttributeNames(attributeNames); | ||
|
||
if (runner.fails() && values[name] && !onChange) { | ||
return this.setState({ errors: { ...errors, ...runner.errors.errors } }); | ||
} | ||
if (errors[name]) { | ||
return this.setState({ errors: { ...errors, [name]: null } }); | ||
} | ||
} | ||
|
||
onChange({ target }) { | ||
let { onValues } = this.props; | ||
let values = { ...this.props.values, ...this.state.values }; | ||
|
||
values[target.name] = | ||
target.type === 'checkbox' || target.type === 'radio' | ||
? target.checked | ||
: target.value; | ||
|
||
if (onValues) return onValues({ ...values }); | ||
|
||
this.setState({ values }); | ||
} | ||
|
||
renderChildren(children) { | ||
return React.Children.map(children, child => { | ||
if (!child || !child.props) return child; | ||
|
||
let children = GetChildren(child, this); | ||
|
||
let { values = {} } = this.props; | ||
let { errors } = this.state; | ||
|
||
if (child.props.name) return Input(child, values, children, errors, this); | ||
if (child.props.submit) return Submit(child, children, this); | ||
|
||
return React.cloneElement(child, { children }); | ||
}); | ||
this.state = { values, errors }; | ||
} | ||
|
||
render() { | ||
let { | ||
children, | ||
rules, | ||
errorMessages, | ||
attributeNames, | ||
values, | ||
onValues, | ||
errors, | ||
...props | ||
} = this.props; | ||
return <div {...props}>{this.renderChildren(children)}</div>; | ||
let { values, errors } = this.state; | ||
let { children, ...props } = this.props; | ||
return ( | ||
<BaseForm | ||
{...props} | ||
values={values} | ||
errors={errors} | ||
onValues={values => { | ||
//console.log(values, 'values'); | ||
this.setState({ values }); | ||
}} | ||
onErrors={errors => { | ||
//console.log(errors, 'wtf'); | ||
this.setState({ errors }); | ||
}} | ||
> | ||
{children} | ||
</BaseForm> | ||
); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,5 @@ | ||
// errors are returned a little weird from the validator so we split it out | ||
export default (errors, propErrors, name) => { | ||
if (propErrors) errors = { ...errors, ...propErrors }; | ||
|
||
return errors[name] && typeof errors[name] !== 'string' | ||
export default (errors = {}, name) => | ||
errors[name] && typeof errors[name] !== 'string' | ||
? errors[name][0] | ||
: errors[name] || ''; | ||
}; |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,31 @@ | ||
//Test that components work with fields that pass target.checked instead of target.value | ||
import React from 'react'; | ||
import Form from '../src/form'; | ||
import { shallow } from 'enzyme'; | ||
import { mount } from 'enzyme'; | ||
|
||
const Input = ({ error, ...props }) => | ||
error ? <p className="error">{error}</p> : <input {...props} />; | ||
const Input = ({ error, ...props }) => ( | ||
<div> | ||
{error ? <p className="error">{error}</p> : null} | ||
<input {...props} /> | ||
</div> | ||
); | ||
|
||
test('Input works with checkbox', () => { | ||
const wrapper = shallow( | ||
const wrapper = mount( | ||
<Form> | ||
<Input name="Awesome" type="checkbox" /> | ||
</Form> | ||
); | ||
|
||
wrapper | ||
.find(Input) | ||
.simulate('change', { | ||
target: { name: 'Awesome', checked: true, type: 'checkbox' }, | ||
}); | ||
wrapper.find('input').simulate('change', { | ||
target: { name: 'Awesome', checked: true, type: 'checkbox' }, | ||
}); | ||
|
||
expect(wrapper.find(Input).props().value).toEqual(true); | ||
|
||
wrapper | ||
.find(Input) | ||
.simulate('change', { | ||
target: { name: 'Awesome', checked: false, type: 'checkbox' }, | ||
}); | ||
wrapper.find('input').simulate('change', { | ||
target: { name: 'Awesome', checked: false, type: 'checkbox' }, | ||
}); | ||
|
||
expect(wrapper.find(Input).props().value).toEqual(false); | ||
}); |
This file contains 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
Oops, something went wrong.