Skip to content

Wavelop/dynamic-form

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NPM Contributors Forks Stargazers Issues MIT License LinkedIn


Logo

Dynamic Form

Build forms πŸ“„ with React πŸš€
Explore the docs Β»

View Demo Β· Open an Issue Β· Request Feature

πŸ“‘ Table of Contents

πŸ” About The Project

This project implements a form generator with React Hooks.

πŸ”§ Built With

πŸ”« Getting Started

To start to use the library, follow these simple steps.

πŸ‘Ά Prerequisites

This is an example of how to list things you need to use the software and how to install them.

npm install react react-dom

πŸ’» Installation

npm install @wavelop/dynamic-form @wavelop/dynamic-form-base-components

🚲 Usage

Create a configuration file:

// config.js

import { Input } from "@wavelop/dynamic-form-base-components";
import { validations } from "@wavelop/dynamic-form";

const { required, pattern } = validations;

export default [
  {
    name: "email",
    label: "Email",
    helperText: "Write your email",
    tag: Input,
    type: "email",
    defaultValue: "[email protected]",
    validations: [
      {
        kind: required,
        message: "Email is required"
      },
      {
        kind: pattern,
        reg: /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/,
        negate: true,
        message: "You must type an email i.e. [email protected]"
      }
    ]
  }
];
import React, { useRef } from "react";
import PropTypes from "prop-types";

import {
  DynamicForm,
  useDynamicForm,
  withDynamicForm
} from "@wavelop/dynamic-form";

import { form as formConfig } from "./config.js";

function Example(props) {

  const dynamicForm = useDynamicForm();

  const onSubmit = event => {

    event.preventDefault();

    try {
      const { state, stateCrypted } = dynamicForm.submit();
      // Do something with you valid state...
      console.log(state, stateCrypted);

    } catch ({numberOfErrors, errors}) {
      // Do something in case of error...
      console.log(numberOfErrors, errors);
    }
  };

  // Render
  return (
    <form onSubmit={onSubmit}>
      <DynamicForm
        config={formConfig}
        updateErrorAtBlur={true}
        debug={true}
      />

      <button
        type="submit"
        onClick={onSubmit}
      >
        Confirm
      </button>
    </form>
  );
}

Example.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withDynamicForm()(Example);

For more examples, please refer to the Example folder.

πŸ“š Documentation

Check out our documentation website.

πŸ₯‡ Add your values

Use the deafultValue option to add an initial value to a field.

// config.js
...
fields: [
  {
    name: "field1_row2",
    label: "field1_row2",
    helperText: "field1_row2",
    tag: "notRow",
    defaultValue: "hello",
  }
]
...

🏘 Using existing components

Core functionalities can be used with exinsing components, as with the one of the package @wavelop/dynamic-form-base-components or you can create your custom components to inject inside the configuration.

🧱 Build your custom components

WIP.

πŸ’« Repeater components

There are more way to create repeater components:

  1. Update your configuration dinamically adding new piece of configuration. To group state results you should use rowOptions, both on row container and field.
Example point 1

In the configuration create the initial configuration:

// config.js

// import and other stuff..

export default [ 
  {
    name: "row1",
    tag: "row",
    fields: [
      {
        name: "field1_row1",
        label: "field1_row1",
        helperText: "field1_row1",
        tag: "notRow"
      }
    ]
  },
  {
    name: "row2",
    tag: "row",
    rowOptions: { // <--- Add rowOptions to the row container and use the property groupIn
      groupIn: "rowsToGroupAsArray"
    },
    fields: [
      {
        name: "field1_row2",
        label: "field1_row2",
        helperText: "field1_row2",
        tag: "notRow",
        rowOptions: { // <--- Add rowOptions to the child and use the property alternativeName
          alternativeName: "field1",
        }
      }
    ]
  },
  {
    name: "row3",
    tag: "row",
    rowOptions: { // <--- Add rowOptions to the row container and use the property groupIn
      groupIn: "rowsToGroupAsArray"
    },
    fields: [
      {
        name: "field1_row3",
        label: "field1_row3",
        helperText: "field1_row3",
        tag: Input,
        rowOptions: { // <--- Add rowOptions to the child and use the property alternativeName
          alternativeName: "field1",
        }
      }
    ]
  },
  {
    name: "row4",
    tag: "row",
    rowOptions: { // <--- Add rowOptions to the row container and use the property groupIn
      groupIn: "rowsToGroupAsArray2"
    },
    fields: [
      {
        name: "field2_row4",
        label: "field2_row4",
        helperText: "field2_row4",
        tag: "notRow",
        rowOptions: { // <--- Add rowOptions to the child and use the property alternativeName
          alternativeName: "field2",
        }
      },
    ]
  },
  {
    name: "row5",
    tag: "row",
    rowOptions: { // <--- Add rowOptions to the row container and use the property groupIn
      groupIn: "rowsToGroupAsArray2"
    },
    fields: [
      {
        name: "field2_row5",
        label: "field2_row5",
        helperText: "field2_row5",
        tag: "notRow",
        rowOptions: { // <--- Add rowOptions to the child and use the property alternativeName
          alternativeName: "field2",
        }
      },
    ]
  }
];

Where you use DynamicForm and execute submit having this current state:

{
  "field1_row1": "1a",
  "field1_row2": "2a",
  "field1_row3": "3a",
  "field2_row4": "4b",
  "field2_row5": "5b",
}
// Other stuff...

const { state, stateGroupedByRows, stateGroupedByRowsGroupIn } = dynamicForm.submit();

console.log(state);
/**
{
  "field1_row1": "1a",
  "field1_row2": "2a",
  "field1_row3": "3a",
  "field2_row4": "4b",
  "field2_row5": "5b",
}
**/ 

console.log(groupByRows);
/**
{
  "row1": {
    "field1_row1": "1a",
  },
  "row2": {
    "field1_row2": "2a",
  },
  "row3": {
    "field1_row3": "3a",
  },
  "row4": {
    "field2_row4": "4b",
  },
  "row5": {
    "field2_row5": "5b"
  }
}
**/ 

console.log(groupByRowsGroupIn);
/**
{
  "row1": {
    "field1_row1": "1a",
    "field2_row1": "1b"
  },
  "rowsToGroupAsArray": [
    {
      "field1": "2a",
    },
    {
      "field1": "3a",
    }
  ],
  "rowsToGroupAsArray2": [
    {
      "field2": "4b"
    },
    {
      "field2": "5b"
    }
  ]
}
**/ 

Think now to add to the above configuration a new row:

configuration.push({
  name: "row6",
  tag: "row",
  rowOptions: { // <--- Add rowOptions to the row container and use the property groupIn
    groupIn: "rowsToGroupAsArray"
  },
  fields: [
    {
      name: "field1_row6",
      label: "field1_row6",
      helperText: "field1_row6",
      tag: "notRow",
      rowOptions: { // <--- Add rowOptions to the child and use the property alternativeName
        alternativeName: "field1",
      }
    },
  ]
});

At the submit we will have (considering to have written 6a inside the new input):

// Other stuff...

const { state, stateGroupedByRows, stateGroupedByRowsGroupIn } = dynamicForm.submit();

console.log(state);
/**
{
  "field1_row1": "1a",
  "field1_row2": "2a",
  "field1_row3": "3a",
  "field2_row4": "4b",
  "field2_row5": "5b",
  "field1_row6": "6a",
}
**/ 

console.log(groupByRows);
/**
{
  "row1": {
    "field1_row1": "1a",
  },
  "row2": {
    "field1_row2": "2a",
  },
  "row3": {
    "field1_row3": "3a",
  },
  "row4": {
    "field2_row4": "4b",
  },
  "row5": {
    "field2_row5": "5b"
  },
  "row6": {
    "field1_row6": "6a"
  }
}
**/ 

console.log(groupByRowsGroupIn);
/**
{
  "row1": {
    "field1_row1": "1a",
    "field2_row1": "1b"
  },
  "rowsToGroupAsArray": [
    {
      "field1": "2a",
    },
    {
      "field1": "3a",
    },
    {
      "field1": "6a",
    }
  ],
  "rowsToGroupAsArray2": [
    {
      "field2": "4b"
    },
    {
      "field2": "5b"
    }
  ]
}
**/

1. (WIP) Create a custom component that implement the repeater logic and it update the form values.

✈️ Roadmap

See the open issues for a list of proposed features (and known issues).

πŸš‘ Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

Read our contributing guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes.

πŸ’° License

Distributed under the MIT License. See LICENSE for more information.

πŸ“ž Contact

Matteo Granzotto - @wavelop - [email protected]

Wavelop - [email protected]

Project Link: https://github.com/Wavelop/dynamic-form