UNPKG

react-state-form

Version:
188 lines (158 loc) 4.6 kB
import React, { Component } from 'react' import PropTypes from 'prop-types' // eslint-disable-line import/no-extraneous-dependencies import validations from './utils/validationRules' /** * Main Component, a HOC, will store all fields' state. */ export default class FormContainer extends Component { constructor(props) { super(props) const { isDisabled = false, shouldValidateForm, } = this.props const defaultState = { isDisabled : false, shouldValidateForm : true, errors : {} } this.state = { ...defaultState, shouldValidateForm, isDisabled } } getChildContext() { return { setFieldValue : ({ event, field, value, isMultipleValues, id = 'value' }) => { const fieldName = field.id const setState = (name, fieldValue) => { this.setState((prevState) => ({ ...prevState, fields : { ...prevState.fields, [fieldName] : { ...prevState.fields[name], shouldValidateField : true, [id] : fieldValue } } })) } if (!value) { setState(fieldName, event.currentTarget.value) } else if (isMultipleValues) { const stateCopy = { ...this.state } for (const item in value) { stateCopy.fields[item].shouldValidateField = true stateCopy.fields[item][id] = value[item] } this.setState((prevState) => ({ ...prevState, ...stateCopy })) } else { setState(fieldName, value) } return this.state }, addField : (data) => { this.setState((prevState) => ({ ...prevState, fields : { ...prevState.fields, [data.id] : { ...data, shouldValidateField : false } } })) }, validateForm : (fieldName) => { const { shouldValidateForm, fields } = this.state const field = fields[fieldName] if (shouldValidateForm) { if (field && field.shouldValidateField) { this.validateField(field) return } for (const field in fields) { const fieldData = fields[field] if (fieldData) { this.validateField(fieldData) } } } return }, formData : this.state } } /** * React Lifecycle Method: Renders the data * * @return {DOM} Main container DOM. */ render() { return ( <form action=''> {this.props.children} </form> ) } validateField = (fieldData) => { const { id, label, value, validate, displayName, customRules = {} } = fieldData const rules = validate.split('|') if (rules.length) { for (const rule in rules) { const ruleName = rules[rule] const ruleDetails = ruleName.split('-') const [ ruleValue, ...ruleArgs ] = ruleDetails const validation = validations[ruleValue] || customRules[ruleValue] if (validation) { const result = validation.rule.apply(null, ruleArgs).test(value) let error = '' if (!result) { error = validation.formatter.apply(null, [ displayName || id, ...ruleArgs]) } this.setState((prevState) => ({ ...prevState, errors : { ...prevState.errors, [id] : error } })) if (error) { break } } else { throw `invalid validation rule: ${ruleValue}, please use an existing validation rule name or pass a custom function with same name through 'customRules' prop in Input: ${fieldData.id}. Rule value should be an object with keys: 'rule' as an Regex and 'formatter' as a function, that formats the value.` } } } return '' } static defaultProps = { children : <div />, isDisabled : false, shouldValidateForm : true } static propTypes = { children : PropTypes.node.isRequired, isDisabled : PropTypes.bool, shouldValidateForm : PropTypes.bool } static childContextTypes = { addField : PropTypes.func, setFieldValue : PropTypes.func, validateForm : PropTypes.func, formData : PropTypes.object } }