UNPKG

simple-redux-form

Version:
142 lines (139 loc) 4.85 kB
import React, { PropTypes, Component } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import deepEqual from 'deep-equal'; import { setField, initialize, touchAll } from './actions'; import { simplifiedVlaues, createField, hasSyncErrors } from './helpers'; // Higher order component for huge fast dynamic deeply nested universal forms. export default function simpleReduxForm(Wrapped, options) { const { form = '', fields: initFields = [], getInitialState, validate = () => {} } = options; class SimpleReduxForm extends Component { constructor(props) { super(props); this.state = { model: null }; this.onFieldChange = this.onFieldChange.bind(this); this.validate = this.validate.bind(this); } componentWillMount() { this.createFields(this.props.fields); // Create all the fields this.setModel(); // set Current state of HOC } componentDidMount() { /* initialize the form on client side, as we can access storage easily and can avoid the Dom difference. */ let initialState = getInitialState && getInitialState(this.props); if (!initialState) { initialState = {}; } const state = this.props.currentForm; const initialized = state && state.initialized ? state.initialized : false; // Make initialized only if object is not empty if (!initialized && Object.keys(initialState).length > 0) { this.props.actions.initialize(initialState, form, this.props.fields); this.setModel(); } } componentWillReceiveProps(nextProps) { // console.log('NextProps.currentForm', nextProps.currentForm); if (!deepEqual(this.props.currentForm, nextProps.currentForm)) { const currentFields = Object.keys(this.fields); if (!deepEqual(currentFields, nextProps.fields)) { this.createFields(nextProps.fields); // Create all the fields } this.setModel(nextProps.currentForm); // set Current state of HOC } // Need to compare and then do this thing const state = this.props.currentForm; const initialized = state && state.initialized ? state.initialized : false; if (!initialized) { const initialState = getInitialState && getInitialState(nextProps); if (initialState) { this.props.actions.initialize(initialState, form, this.props.fields); } } } componentWillUnmount() { this.fields = null; } onFieldChange(field, value) { this.props.actions.setField(field, value, form); } setModel(newState) { const fieldsKeys = Object.keys(this.fields); this.values = simplifiedVlaues(newState, fieldsKeys); // We are passing two arguments to validate function // Second can be used for dynamic validation usecase const errors = validate(this.values, this.props); fieldsKeys.forEach(field => { const { fields, values } = this; fields[field].value = values[field]; fields[field].error = errors && errors[field] ? errors[field] : undefined; fields[field].touched = newState && newState[field] ? newState[field].touched : false; }); this.fields = { ...this.fields }; this.allValid = !hasSyncErrors(errors); // this.setState({ model: newState }); } /* TODO::This needs to be triggred before every submit. We can commbine this to handle All submit which will make sure it validates and gives value back with returning promise. */ validate() { this.props.actions.touchAll(form, this.props.fields); return this.allValid; } // Create all Fields with all sugar functions createFields(fieldList) { const formFields = fieldList.reduce((fields, field) => ({ ...fields, [field]: createField(field, this.onFieldChange) }), {}); this.fields = { ...formFields }; } render() { return ( <Wrapped {...this.props} fields={this.fields} allValid={this.allValid} values={this.values} validate={this.validate} />); } } SimpleReduxForm.propTypes = { fields: PropTypes.array, actions: PropTypes.object, currentForm: PropTypes.object, }; SimpleReduxForm.defaultProps = { fields: initFields // Take either from the Decorator or else as props }; function mapStateToProps(state) { return { currentForm: state.forms[form] }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ setField, initialize, touchAll, }, dispatch), dispatch }; } return connect(mapStateToProps, mapDispatchToProps)(SimpleReduxForm); }