react-simpler-forms
Version:
React Higher Order component that manages all of your forms state along with other components that make it easy to create, validate, perform search queries, and submit single or multi-step forms.
445 lines (305 loc) • 10.3 kB
JavaScript
import React, { Component } from 'react'
import { validator, isEmpty } from '../helpers/validators'
class Input extends Component {
constructor () {
super()
this.state = {
checkbox: {},
radio: {}
}
this.onChangeInput = this.onChangeInput.bind(this)
this.onChangeSelection = this.onChangeSelection.bind(this)
this.onFocus = this.onFocus.bind(this)
this.onBlur = this.onBlur.bind(this)
}
componentDidUpdate(prevProps) {
if (this.props.value === this.state.checkbox.value && this.props.value !== undefined && this.state.checkbox.value !== undefined) {
if (prevProps.form.data[this.props.name]) {
let array = prevProps.form.data[this.props.name].values
let currentItemArray = array.filter(item => item.value === this.state.checkbox.value)
if (currentItemArray.length === 0) {
let newArray = [...array]
newArray.push(this.state.checkbox)
let payload = {
property: this.props.name,
values: newArray
}
this.props.updateform('updateData', payload)
}
}
}
if (this.props.name === this.state.radio.property && this.props.name !== undefined && this.state.radio.property !== undefined) {
if (prevProps.form.data[this.props.name]) {
if (prevProps.form.data[this.props.name].checked !== this.state.radio.checked) {
let payload = {
property: this.props.name,
checked: true,
value: this.state.radio.value
}
this.props.updateform('updateData', payload)
}
}
}
}
componentDidMount() {
if (typeof this.props.name !== 'string') {
console.error(
"Input prop 'name' is required and must be a string.\n",
"Example: name='first_name'"
);
}
if (!Array.isArray(this.props.validators) && this.props.type !== 'select' && this.props.type !== 'radio' && this.props.type !== 'textarea' && this.props.type !== 'checkbox') {
console.error(
"Input prop 'validators' is required and must be an array.\n",
"Example: \n",
"validators={[method: 'notEmpty', error: 'Input cannot be empty.']}"
);
}
if (!Array.isArray(this.props.options) && this.props.type === 'select') {
console.error(
"Input prop 'options' is required and must be an array.\n",
"Example: \n",
"options={[value: 'MA', text: 'Massachusetts']}"
);
}
if (this.props.type === 'radio' && typeof this.props.value !== 'string') {
console.error(
"Input prop 'value' is required and must be a string.\n",
"Example: value='red'"
);
}
if (!this.props.form.data[this.props.name]) {
let payload = {
step: this.props.form.step,
error: null,
property: this.props.name,
focused: false,
value: null,
validators: this.props.validators
}
if (this.props.type === 'checkbox') {
delete payload.value
delete payload.validators
let checkbox = {
value: this.props.value
}
if (this.props.required) {
checkbox.required = true
}
if (this.props.checked) {
checkbox.checked = true
} else {
checkbox.checked = false
}
payload.values = []
payload.error = false
this.setState({
checkbox: checkbox
}, () => {
this.forceUpdate()
})
}
if (this.props.type === 'radio') {
delete payload.validators
if (this.props.required) {
payload.required = true
}
if (this.props.checked) {
this.setState({
radio: {
value: this.props.value,
property: this.props.name,
checked: true
}
}, () => {
this.forceUpdate()
})
}
payload.checked = false
payload.error = false
}
if (this.props.type === 'select') {
delete payload.validators
if (this.props.required) {
payload.required = true
}
payload.error = false
}
if (this.props.type === 'textarea') {
if (!this.props.validators) {
delete payload.validators
}
}
if (this.props.delayError) {
payload.typingDelay = null
payload.typing = false
}
if (this.props.query) {
payload.typing = false
payload.query = true
payload.queryVerified = false
payload.queryResponse = null
payload.queryDelay = null
}
if (this.props.match) {
payload.match = this.props.match
}
this.props.updateform('updateData', payload)
}
}
onChangeInput (e) {
let payload = {
value: e.target.value,
property: this.props.name
}
if (this.props.form.data[this.props.name].queryDelay) {
clearTimeout(this.props.form.data[this.props.name].queryDelay)
payload.queryDelay = null
}
if (this.props.form.data[this.props.name].typingDelay) {
clearTimeout(this.props.form.data[this.props.name].typingDelay)
payload.typing = false
payload.typingDelay = null
}
if (this.props.validators) {
payload.error = validator(this.props.validators, e.target.value)
}
if (this.props.delayError && payload.error) {
payload.typing = true
payload.typingDelay = setTimeout(() => {
this.props.updateform('updateData', {property: this.props.name, typing: false})
}, this.props.delayError)
}
if (this.props.query) {
payload.queryVerified = false
payload.queryResponse = null
if (!payload.error) {
payload.typing = false
payload.queryDelay = setTimeout(() => {
let value = this.props.form.data[this.props.name].value
let payload = {
data: { [this.props.name]: value },
url: this.props.query,
cancelable: true,
property: this.props.name
}
this.props.updateform('queryData', payload)
}, 350)
}
}
this.props.updateform('updateData', payload)
}
onChangeSelection (e) {
let formInput = this.props.form.data[this.props.name]
let payload = {
property: this.props.name,
value: this.props.value || e.target.value,
error: false
}
if (this.props.type === 'radio') {
payload.checked = true
}
if (this.props.type === 'select' && payload.value === '') {
payload.error = true
}
if (this.props.type === 'checkbox') {
delete payload.value
let currentArray = [...formInput.values]
let currentItem = currentArray.filter(item => item.value === this.props.value)
let indexOf = currentArray.indexOf(currentItem[0])
currentArray[indexOf].checked = !currentArray[indexOf].checked
let allrequiredTrue = currentArray.filter(item => item.required).every(item => item.checked === true)
if (!allrequiredTrue) {
payload.error = true
}
payload.values = currentArray
}
this.props.updateform('updateData', payload)
}
onFocus () {
let payload = {
property: this.props.name,
focused: true
}
this.props.updateform('updateData', payload)
}
onBlur() {
if (this.props.scrollUp) {
window.scroll(0,0)
}
let payload = {
property: this.props.name,
focused: false
}
this.props.updateform('updateData', payload)
}
render () {
let { name, delayError, match, validators, query, focusedClassName, errorClassName, form, className, scrollUp, updateform, ...rest} = this.props
let input = this.props.form.data[this.props.name]
let error, typing, value, inputType, classNames, checked, focused
if (input) {
if (this.props.type === 'checkbox') {
let currentInput = input.values.filter(item => item.value === this.props.value)
if (currentInput.length > 0) {
value = currentInput[0].value
checked = currentInput[0].checked
}
} else {
value = input.value
checked = input.checked
}
focused = input.focused
error = input.error
typing = input.typing
}
if (focused && (!error || typing)) {
classNames = [className, focusedClassName]
} else if (error && !typing) {
classNames = [className, errorClassName]
} else {
classNames = [className]
}
if (this.props.type === 'textarea') {
inputType = (
<textarea
{...rest}
className={classNames.join(' ')}
onChange={this.onChangeInput}
onBlur={this.onBlur}
onFocus={this.onFocus}
value={value ? value : ''}
/>
)
} else if (this.props.type === 'select') {
inputType = (
<select className={classNames.join(' ')} onBlur={this.onBlur} onFocus={this.onFocus} onChange={this.onChangeSelection} value={value ? value : ''}>
{Array.isArray(this.props.options) && this.props.options.map((item, i) => {
return <option
key={item.value}
value={item.value}
selected={item.selected}
className={i & 1 ? this.props.oddOptionClass : this.props.evenOptionClass}
>
{item.text}
</option>
})}
</select>
)
} else {
inputType = (
<input
{...rest}
name={name}
className={classNames.join(' ')}
onChange={(this.props.type !== 'radio' && this.props.type !== 'checkbox') ? this.onChangeInput : this.onChangeSelection}
checked={(this.props.type === 'radio' || this.props.type === 'checkbox') && value === this.props.value && checked ? checked : false}
value={value ? value : ''}
onBlur={this.onBlur}
onFocus={this.onFocus}
/>
)
}
return (inputType)
}
}
export default Input