Last active
January 4, 2018 12:20
-
-
Save Hamzali/7b7dfec186ef9ade26b1d62d695be96c to your computer and use it in GitHub Desktop.
React JSON Form
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
import React, { Component } from "react"; | |
import PropTypes from "prop-types"; | |
import styled from "styled-components"; | |
import { INPUT_TYPES } from "../../constants"; | |
import { isEmpty } from "../../utils"; | |
import Input from "./input"; | |
import Button from "./button"; | |
import Textarea from "./textarea"; | |
import Checkbox from "./checkbox"; | |
import Selector from "./selector"; | |
import { DatePicker } from "../date-picker"; | |
import Label from "./label"; | |
import Error from "./error"; | |
const { BOOL, TEXT, NUMBER, DATE, SELECTOR, LONG_TEXT } = INPUT_TYPES; | |
const FieldWrapper = styled.div` | |
margin: 0.5em 0; | |
`; | |
const FieldComponent = ({ children, label, error, noBreak }) => ( | |
<FieldWrapper> | |
{label && <Label text={label} />} | |
{!noBreak && <br />} | |
{children} | |
<br /> | |
{error && <Error text={error} />} | |
</FieldWrapper> | |
); | |
class Form extends Component { | |
constructor(props) { | |
super(props); | |
const { inputFields } = props; | |
const stateObj = inputFields.reduce((acc, elem) => { | |
acc[elem.key] = ""; | |
return acc; | |
}, {}); | |
this.state = { | |
err: "", | |
data: { ...stateObj } | |
}; | |
} | |
handleChange(key) { | |
return val => { | |
const obj = { data: { ...this.state.data } }; | |
obj.data[key] = val; | |
this.setState(obj); | |
}; | |
} | |
handleSubmit(e) { | |
e.preventDefault(); | |
this.props.onSubmit(this.state.data); | |
} | |
renderFormElements() { | |
const { inputFields } = this.props; | |
return inputFields.map((field, _key) => { | |
const { type, label, key, validator, defaultValue, props } = field; | |
const value = this.state.data[key]; | |
const error = validator && validator(value); | |
let input = null; | |
let noBreak = false; | |
switch (type) { | |
case TEXT: | |
input = ( | |
<Input | |
key={_key} | |
value={value || defaultValue} | |
onChange={this.handleChange(key)} | |
/> | |
); | |
break; | |
case LONG_TEXT: | |
input = ( | |
<Textarea | |
key={_key} | |
value={value || defaultValue} | |
onChange={this.handleChange(key)} | |
/> | |
); | |
break; | |
case SELECTOR: | |
input = ( | |
<Selector | |
sections={props.sections} | |
key={_key} | |
value={value || defaultValue} | |
onSelect={this.handleChange(key)} | |
/> | |
); | |
break; | |
case BOOL: | |
noBreak = true; | |
input = ( | |
<Checkbox | |
key={_key} | |
value={value || defaultValue} | |
onChange={this.handleChange(key)} | |
/> | |
); | |
break; | |
case DATE: | |
input = ( | |
<DatePicker | |
key={_key} | |
value={value || defaultValue} | |
onChange={this.handleChange(key)} | |
/> | |
); | |
break; | |
case NUMBER: | |
input = ( | |
<Input | |
type="number" | |
key={_key} | |
value={value || defaultValue} | |
onChange={this.handleChange(key)} | |
/> | |
); | |
break; | |
default: | |
break; | |
// add other type of inputs. | |
} | |
return ( | |
<FieldComponent | |
key={_key} | |
label={label} | |
error={error} | |
noBreak={noBreak} | |
> | |
{input} | |
</FieldComponent> | |
); | |
}); | |
} | |
render() { | |
return ( | |
<form> | |
{this.renderFormElements()} | |
<Button green text="Submit" onClick={e => this.handleSubmit(e)} /> | |
</form> | |
); | |
} | |
} | |
Form.propTypes = { | |
// formTitle: PropTypes.string, | |
inputFields: PropTypes.arrayOf( | |
PropTypes.shape({ | |
label: PropTypes.string, | |
defaultValue: PropTypes.any, | |
key: PropTypes.string.isRequired, | |
type: PropTypes.oneOf([BOOL, TEXT, NUMBER, DATE, SELECTOR, LONG_TEXT]) | |
.isRequired, | |
validator: PropTypes.func, | |
props: PropTypes.object | |
}) | |
).isRequired, | |
onSubmit: PropTypes.func, | |
validateOnSubmit: PropTypes.func | |
}; | |
Form.defaultProps = { | |
// formTitle: 'Form Title', | |
inputFields: [ | |
{ | |
label: "Name", | |
key: "name", | |
type: TEXT, | |
validator: val => { | |
if (isEmpty(val)) { | |
return null; | |
} | |
if (val.length < 5) { | |
return "Name cannot be shorter than 5!"; | |
} | |
return null; | |
} | |
} | |
], | |
validateOnSubmit: data => { | |
if (data.name) { | |
return "Name field should not be empty!"; | |
} | |
}, | |
onSubmit: data => console.log(data) | |
}; | |
export default Form; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment