Skip to content

Kujbor/react-redux-form-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

id Passes string for DOM attribute id for <form> tag from parent components.
data For pass state of form from redux store (ReactReduxFormGenerator not importing redux internally, so you need to provide it yourself).
Field Field wrapper from redux-form (ReactReduxFormGenerator not importing redux-form internally, so you need to provide it yourself). You can find out about Field on their website or just copy and paste this code shown above.
schema Form`s schema passed from parent component
children Children, passed from parent component for rendering at the bottom of the form (for exemple: very beautiful submit button)
context You can provide any additional data here so that you can use it later inside the schema.
{
  ...
  isNew: true,
  status: 'created',
  ...
}
onSubmit Callback function to provide it for handleSubmit(onSubmit) from redux-form. You can find out about handleSubmit(onSubmit) on their website or just copy and paste this code shown above.
values => doSomething()
templates Object of JSX-components that includes required templates (BlockWrapper and FieldWrapper) and the form controls themselves (Input, Radio etc).
{
  BlockWrapper: ({ title, caption, children }) => ([
    <h3>{title}</h3>
    <p>{caption}</p>
    {children}
  ]),
  FieldWrapper: ({ children }) => ([
    <>{children}</>
  ]),
  TextField: ({ type, meta, input, label }) => ([
    <label>{label}</label>
    <input type={type} {...input} />
    <p>{meta.error}</p>
  ]),
  ...
}
validators The object of validation functions. Functions take the value of the field being checked and the values ​​of other fields of the form and should return an error that you can render later, or nothing if the value is valid.
{
  ...
  validationName: (value, otherValues) => {
    if (theValidationFailed()) return 'Detected some error'
  }
}
In addition, you can pass some additional parameters to validation scope from the schema using functions that return a validation function.
{
  ...
  anotherValidationName: extraParams => (value, otherValues) => {
    if (theValidationFailed()) return 'Detected yet another error'
  }
}
initialValues An object with an initial state of form values in the same format as the form data in a reduct state.
{
  ...
  firstName: 'First Name',
  lastName: 'Last Name',
  ...
}

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;

About

Forms generator by JSON-schemas for react/redux

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published