2.2.4 • Published 5 years ago

@troglotit/react-redux-form-generator v2.2.4

Weekly downloads
-
License
ISC
Repository
github
Last release
5 years ago

react-redux-form-generator

Forms generator for react/redux apps based on redux-form and JSON-schemas.

Installation

npm install redux-form
npm install react-redux-form-generator

Usage

import _ from "lodash";
import { PureComponent } from "react";

import ReactReduxFormGeneratorWrapper from "./ReactReduxFormGeneratorWrapper";

// We will look closer to the schemas and values below in documentation
import formSchema from "../data/schema.json";
import initialValues from "../data/values.json";

export default class Demo extends PureComponent {
  state = {
    savedValues: initialValues,
    invalidateFields: {}
  };

  componentWillMount() {
    const savedValues = JSON.parse(localStorage.getItem("demo"));
    if (savedValues) this.setState({ savedValues });
  }

  handleChange = values => {
    console.log("Demo -> handleChange", { values });
  };

  handleSubmit = values => {
    localStorage.setItem("demo", JSON.stringify(values));
  };

  handleValidate = invalidateFields => {
    this.setState({ invalidateFields });
  };

  render() {
    const { savedValues, invalidateFields } = this.state;
    return (
      <>
        <h2>ReactReduxFormGenerator</h2>
        <hr />
        <ReactReduxFormGeneratorWrapper
          id="demo"
          form="demo"
          schema={formSchema}
          context={this}
          initialValues={savedValues}
          onChange={this.handleChange}
          onSubmit={this.handleSubmit}
          onValidate={this.handleValidate}
        />
        <button form="demo" type="submit">
          Submit after valid
        </button>
      </>
    );
  }
}

Wrapper

The form generator uses the user-provided React Components for form fields (Input, Select, RadioButton etc.) and validation functions (for example required, onlyDigits). So, firstly, you need to create a wrapper that provides the generator with templates and validators and connects it to the redux-storage of the application.

You can simply copy and paste this file and only change templates and validators to yours:

import _ from "lodash";
import { compose } from "redux";
import { Component } from "react";
import { connect } from "react-redux";
import { reduxForm, Field, getFormValues, getFormSyncErrors } from "redux-form";

// Here you need to import your JSX-templates for the Field wrapper,
// the Fields` Block wrapper and the form controls themselves (Input, Radio etc)
// We`ll look closer to them below in this documentation
import TextField from "./TextField";
import RadioField from "./RadioField";
import SelectField from "./SelectField";
import BlockWrapper from "./BlockWrapper";
import FieldWrapper from "./FieldWrapper";

// Here you need to import your validate functions
// We`ll look closer to them below in this documentation
import * as validators from "../utils/validators";

import ReactReduxFormGenerator from "./ReactReduxFormGenerator";

class ReactReduxFormGeneratorWrapper extends Component {
  componentWillReceiveProps({ data: nextData, errors: nextErrors }) {
    const {
      onChange,
      data: prevData,
      onValidate,
      errors: prevErrors
    } = this.props;

    // ReactReduxFormGenerator not provides any onChange or onValidate events,
    // so if you need this – you need to handle data and errors updates yourself
    if (!_.isEqual(nextData, prevData)) onChange(nextErrors);
    if (!_.isEqual(nextErrors, prevErrors)) onValidate(nextErrors);
  }

  render() {
    const {
      id,
      form,
      schema,
      context,
      children,
      onChange,
      onSubmit,
      initialValues
    } = this.props;

    return (
      <ConnectedReactReduxFormGenerator
        id={id}
        form={form}
        Field={Field}
        schema={schema}
        context={context}
        // Specify your validate functions here
        validators={validators}
        initialValues={initialValues}
        onChange={onChange}
        onSubmit={onSubmit}
        // And here you need to provide your templates
        templates={{
          block: BlockWrapper,
          field: FieldWrapper,
          text: TextField,
          radio: RadioField,
          select: SelectField
        }}
      >
        {children}
      </ConnectedReactReduxFormGenerator>
    );
  }
}

const mapStateToFormGeneratorProps = (state, { form: formName }) => ({
  form: formName,
  data: getFormValues(formName)(state)
});

const ConnectedReactReduxFormGenerator = compose(
  connect(mapStateToFormGeneratorProps),
  reduxForm({ enableReinitialize: true })
)(ReactReduxFormGenerator);

const mapStateToGeneratorWrapperProps = (state, { form }) => ({
  data: getFormValues(form)(state),
  errors: getFormSyncErrors(form)(state)
});

export default connect(mapStateToGeneratorWrapperProps)(
  ReactReduxFormGeneratorWrapper
);

Props specification

Form`s schema example

[{
	"key": "simple-fields",
	"fields": [{
		"label": "Text Field",
		"name": "text_field",
		"type": "text",
		"validations": ["required"]
	}, {
		"label": "Radios Field",
		"name": "radios_field",
		"type": "radios",
		"options": [{
			"label": "First",
			"value": "1"
		}, {
			"label": "Second",
			"value": "2"
		}],
		"validations": ["required"]
	}, {
		"label": "Select Field",
		"name": "select_field",
		"type": "select",
		"options": [{
			"label": "First",
			"value": "1",
			"showIf": "data.radios_field !== '2'"
		}, {
			"label": "Second",
			"value": "2",
			"showIf": "data.radios_field !== '1'"
		}],
		"validations": ["required"]
	}]
}]

Validate functions example

export const required = value => !value ? 'Is required!' : undefined;
export const numeric = value => value && isNaN(value) ? 'Need to be a number' : undefined;