v1.2.0 Redux flow and validation refacotring
·
117 commits
to master
since this release
This new release brings some major lib flow refactoring aiming future Redux integration and some improvements to increase the code testability and coverage.
Library changelog
Breaking changes
- #30 Major validation refactoring to improve code testability:
Before: to attach custom validations, you are required to provide an array of objects of a specific shape to the FormProvider component:
function App() {
const customValidators = [{
name: 'noadmin',
validate: (value) => {
if(value) return !(/^admin$/i.test(value))
return true
}
}]
return (
<FormProvider customValidators={customValidators}>
[...]
</FormProvider>
)
}
After: now you just need to extend the CustomValidator class, and provide it into an array to the FormProvider component.
import {CustomValidator} from 'react-formctrl'
class NoAdminValidator extends CustomValidator {
constructor() {
super('noadmin') // This constructor parameter defines the error message key
}
validate(formCtrl, props, value, files) {
return !/^admin$/i.test(value)
}
}
function App() {
const customValidators = [
new NoAdminValidator()
]
return (
<FormProvider customValidators={customValidators}>
[...]
</FormProvider>
)
}
Fixes
- #34 Field "validate" property PropType
Enhancements
- #26 Increased code test coverage to 97%!
Postponed changes
- #21 The last missing major feature of the library, the dynamic fields, was postponed due some difficulties with the flow, refactor, testability and coverage. This feature may be available in 1.3.0 version. Until then, use this approach:
function App() {
const handleSubmit = person => yourApi.save(person)
return (
<div>
<FormProvider>
<FormControl name="personForm">
<PersonForm onSubmit={handleSubmit} />
</FormControl>
</FormProvider>
</div>
)
}
class PersonForm extends React.Component {
constructor(props) {
super(props)
this.state = {
relationships: []
}
this.handleAddRelationship = this.handleAddRelationship.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleAddRelationship(relationship) {
this.setState(state => ({
relationships: state.relationships.push(relationship)
}))
}
handleSubmit(person) {
person.relationships = this.state.relationships
this.props.onSubmit(person)
}
render() {
const { formCtrl: { formName, invalid }, onSubmit } = this.props
const { relationships } = this.state
return (
<Form name={formName} onSubmit={onSubmit}>
<div>
<div className="col-6">
<h3>Person data</h3>
<InputField form={formName} name="name" required />
<InputField form={formName} name="age" type="number" />
</div>
<div className="col-6">
<h3>Person's relationships</h3>
<RelationshipTable relationships={relationships} />
<hr />
<FormControl formName="personRelationshipForm">
<RelationshipForm onSubmit={this.handleAddRelationship} />
</FormControl>
</div>
<hr />
<button disabled={invalid || !relationships.length} type="submit">Save person</button>
</div>
</Form>
)
}
}
function RelationshipForm({ formCtrl: { formName, invalid }, onSubmit }) {
return (
<Form name={formName} onSubmit={onSubmit}>
<InputField form={formName} name="relation" required />
<InputField form={formName} name="name" required />
<InputField form={formName} name="age" type="number" />
<button disabled={invalid} type="submit">Add relationship</button>
</Form>
)
}
function RelationshipTable({ relationships }) {
return (
<table>
<thead>
<tr>
<th>Relation</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{relationships.map((relationship, index) => (
<tr key={index}>
<td>{relationship.relation}</td>
<td>{relationship.name}</td>
<td>{relationship.age || ''}</td>
</tr>
))}
</tbody>
</table>
)
}
Live demo changelog
Fixes
- #27 User form example responsivity
Enhancements
- #31 Bundle size tracker badge on README page.