0.1.2 • Published 5 years ago

react-form-data-structure v0.1.2

Weekly downloads
2
License
MIT
Repository
github
Last release
5 years ago

React form builder

react-form-data-structure was created to manage complex data structures. A single configuration is used to describe both the data structure and the form. The configuration is designed have a minimal feel/code footprint, with the ability to tune or change almost anything. The idea is to be able to create an manage an infinitly scaling form/data structure that is only limited by browser resources.

Install

yarn add react-form-data-structure

Basic use case

import { Form } from 'react-form-data-structure';
import 'react-form-data-structure/react-form.css';  // to load the css

render( <Form  label="I am a form!" 
  display={{ 
    type: 'hash', 
    display: [ 
      {type: 'text', label: 'Email Address', name: "email", required: true}, 
      {type: 'password', label: "password", name: "password", required: true} ] }}/>, 
      document.getElementById( 'app' ) 
); 

Mindset

Objects are typically displayed in containers; Containers represent data structures. Example: if you want the form to manage a list ( Array Object ) the first container would be a type: list, and the display contents would then represent list elements.

Terms

  • path Path(s) are a list that represent where in the object structure this thing exists.
  • dataPath An Array Object path that refers to an object that exists in Form this.state.data
  • displayPath An Array Object path that refers to an object that exists in Form this.state.display
  • scalar primitive data value

Form Options

  • Arguments
optiondescription
datadata structure to be displayed
displayform/data structure configuration
showSubmitdefault: true, show or hide the submit button
showResetdefault: true, show or hide the reset button
submitTextdefault "Submit", submit button text
resetTextdefault "Rest", submit button reset
formErrordefault: false, State for the form ( error: true|false )
namedefault "form", used for internal key geneation ( recommended this be set to something unique )
labeldefault "", header text of the form
errorTextdefault "Some fields are not filled out properly"

Getting Data out

Form provides a collection of callback handlers that return a semi deep copy of the the internal data.

  • Event Handlers
nameWhen its calledArguments
onChangewhen a field changes(data,dataPath,displayPath)
onSubmitwhen the submit button is pressed(data,display)
onResetwhen the reset button is pressed()
preSubmitwhen onSubmit would be called this function is called, if it returns onSubmit will be called(data,display)
  • ** Getting the default state

The Form object allows for generation of the default state based on the following:

const state=Form.buildStateFromProps(props);

Given: props state will contain state.data and state.display

  • Css Options

Form uses the following CSS Classes, and each class can be passed in as an argument.

optiondefault value
classNameFormContainerrf-form-container
classNameFormHeaderrf-form-header
classNameHeaderLine""
classNameSubmitRowrf-form-submit-row
classNameFormDiv""
classNameButtonrfFormSubmit
classNameFormErrorrf-form-error

Default Plugins

Each plugin has its on css, and each css class can be passed in as an argument.

PluginType
textinput
quillEbmbeded html editor, ( wrapper for quill )
datepickerDate Time picker
colorColor picker
text-autocompleteinput, with autocomplete
passwordpassword
textareatextarea
selectselect
multiselectselect multiple
radioradio
checkboxcheckbox
addsubform add
hashcontainer for hashes
listcontainer for lists
watchchooses a configuration based on an item being watched

Input Examples

input text box ( text plugin )

  • Example

This example shows how to manage a scalar value with a text input.

<Form display={
  { 
    type: 'text', 
    input: "", 
    required: true, 
    label: "input test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
  • CSS Options
optiondefault value
classNameInputTextrfFormDefaultsInputText
classNameInputTextCheckFailedrfFormDefaultsInputTextfailed
classNameInputLabelrfFormLabel
classNameInputContainerrf-form-input-container
classNameInputTextDefaultrfFormDefaultsInputText

Html Editor ( quill plugin )

  • Example

This plugin is really a wrapper for: https://www.npmjs.com/package/react-quill .This example shows how to manage editable html input.

import 'react-quill/dist/quill.snow.css';
<Form display={
  { 
    type: 'quill', 
    input: "", 
    required: true, 
    label: "input test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
toolbarOptionsdefault: [ [{'background': []}, 'bold', { font: []}, {color: []}, 'code', 'italic', 'link', 'strike', 'underline'], ['blockquote', { 'header': 1, 2, 3, 4, 5, 6, false }, { 'indent': '-1' }, { 'indent': '+1' }, { 'list': 'ordered' }, { 'list': 'bullet' }, { 'align': [] }, { 'direction': 'rtl' }, 'code-block'], 'formula', 'image', 'video' ]
  • CSS Options
optiondefault value
classNameInputTextrfFormDefaultsInputText
classNameInputTextCheckFailedrfFormDefaultsInputTextfailed
classNameInputLabelrfFormLabel
classNameInputContainerrf-form-input-container
classNameInputTextDefaultrfFormDefaultsInputText

Date Picker ( datepicker plugin )

  • Example

This plugin is wrapper for: https://chmln.github.io/flatpickr/ This example shows how to manage a scalar value with a text input.

import 'flatpickr/dist/themes/material_blue.css';
<Form display={
  { 
    type: 'datepicker', 
    input: "", 
    required: true, 
    label: "input test", 
    options: { enableTime: true, enableSeconds: true, dateFormat: "Y-m-d H:i:S" }
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
optionsdefault: { enableTime: true, enableSeconds: true, dateFormat: "Y-m-d H:i:s" } see: https://chmln.github.io/flatpickr/options/
  • CSS Options
optiondefault value
classNameInputTextrfFormDefaultsInputText
classNameInputTextCheckFailedrfFormDefaultsInputTextfailed
classNameInputLabelrfFormLabel
classNameInputContainerrf-form-input-container
classNameInputTextDefaultrfFormDefaultsInputText

input text box ( text-autocomplete plugin )

  • Example

This example shows how to manage a scalar value with a text input.

<Form display={
  { 
    type: 'text-autocomplete ', 
    input: "", 
    required: true, 
    label: "input test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
dataArray, each value represents an auto complete option
  • CSS Options
optiondefault value
classNameInputTextrfFormDefaultsInputText
classNameInputTextCheckFailedrfFormDefaultsInputTextfailed
classNameInputLabelrfFormLabel
classNameInputContainerrf-form-input-container
classNameInputTextDefaultrfFormDefaultsInputText
classNameInputAutoComplete"rf-auto-complete"

Password ( password plugin )

  • Example

This example shows how to manage a scalar value with a text input.

<Form display={
  { 
    type: 'password', 
    input: "", 
    required: true, 
    label: "password test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
  • CSS Options
optiondefault value
classNameInputTextrfFormDefaultsInputText
classNameInputTextCheckFailedrfFormDefaultsInputTextfailed
classNameInputLabelrfFormLabel
classNameInputContainerrf-form-input-container
classNameInputTextDefaultrfFormDefaultsInputText

Textarea ( textarea plugin )

  • Example

This example shows how to manage a scalar value with a textarea.

<Form display={
  { 
    type: 'textarea', 
    input: "", 
    required: true, 
    label: "password test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
  • CSS Options
optiondefault value
classNameInputTextrf-form-textarea
classNameInputTextCheckFailedrf-form-textarea-error
classNameInputLabelrf-form-label
classNameInputContainerrf-form-textarea-container
classNameInputTextDefaultrf-form-textarea-container

Color picker ( color plugin )

  • Example

This example shows how to manage a scalar value with a color picker.

<Form display={
  { 
    type: 'color', 
    input: "", 
    required: true, 
    label: "password test", 
  }
}/>
  • Options
optiondescription
inputdefault value
requiredtrue|false determines if this field is required
validatefunction(currentValue), must return true if the value is valid false if it is not
disabledtrue|false determines if the field is disabled
  • CSS Options
optiondefault value
classNameInputTextrf-form-textarea
classNameInputTextCheckFailedrf-form-textarea-error
classNameInputLabelrf-form-label
classNameInputContainerrf-form-textarea-container
classNameInputTextDefaultrf-form-textarea-container

Select box ( select plugin )

  • Example

This example shows how to manage a scalar value with a select box.

<Form display={
  { 
    type: 'select', 
    input: "", 
    required: true, 
    label: "Select Test", 
    data: [
      { value: "one", label: "Option one" }, 
      { value: 'two', label: "Option two" }
    ] 
  }
}/>
  • Options
optiondescription
dataArray of Objects: { value: "value", label: "display text }
inputThe default selected value "" if you don't want anything selected
requiredtrue|false, denotes if the field is required for the onSubmit action to be called
labeldisplay text
disabledtrue|false, denotes if this field is disabled
  • CSS Options

The select plugin has the following css options

optiondefault value
classNameSelectRowrfFormSelectRow
classNameSelectHeaderrfFormSelectHeader
classNameSelectCellrf-form-select-cell
classNameSelectCellDefaultrf-form-select-cell
classNameSelectCellErrorrf-form-select-cell-error
classNameSelectrfFormSelect
classNameSelectDefaultrfFormSelect
classNameSelectErrorrfFormSelectError
classNameSelectOptionrf-form-select-option
classNameSelectOptionDefaultrf-form-select-option
classNameSelectOptionErrorrf-form-select-option-error

Radio Set ( radio plugin )

  • Example

This example shows how to manage a scalar value with a radio set.

<Form display={
  { 
    type: 'radio', 
    input: "", 
    required: true, 
    label: "Raidio Test", 
    data: [
      { value: "one", label: "Option one" }, 
      { value: 'two', label: "Option two" }
    ] 
  }
}/>
  • Options
optiondescription
dataArray of Objects: { value: "value", label: "display text }
inputThe default selected value "" if you don't want anything selected
requiredtrue|false, denotes if the field is required for the onSubmit action to be called
labeldisplay text
disabledtrue|false, denotes if this field is disabled
  • CSS Options
optiondefault value
classNameInputRaidiorfFormDefaultsInputRaidio
classNameRadioCellIndentrf-form-radio-indent
classNameRadioHeaderrfFormRadioHeader
classNameRaidoRowrf-form-raidio-row
classNameRaidioRowContainerrf-form-raidio-row-container
classNameRadioButtonCellrf-form-radio-button-cell
classNameRadioButtonCellDefaultrf-form-radio-button-cell
classNameRadioButtonCellFailedrf-form-radio-button-cell-failed

Multiple Select ( multiselect plugin )

  • Example

This example shows how to manage a scalar value with a multiple select.

<Form display={
  { 
    type: 'multiselect', 
    input: [], 
    required: true, 
    label: "Milti Select Test", 
    data: [
      { value: "one", label: "Option one" }, 
      { value: 'two', label: "Option two" }
    ] 
  }
}/>
  • Options
optiondescription
dataArray of Objects: { value: "value", label: "display text }
inputArray of selected values, [] if you don't want anything selected
requiredtrue|false, denotes if the field is required for the onSubmit action to be called
labeldisplay text
disabledtrue|false, denotes if this field is disabled
sizedefault: 5, sets how many records will be shown
  • CSS Options
optiondefault value
classNameSelectRowrfFormSelectRow
classNameSelectHeaderrfFormSelectHeader
classNameSelectCellrf-form-select-cell
classNameSelectCellDefaultrf-form-select-cell
classNameSelectCellErrorrf-form-select-cell-error
classNameSelectrf-form-select-multi
classNameSelectOptionrf-form-select-option
classNameSelectOptionDefaultrf-form-select-option
classNameSelectOptionErrorrf-form-select-option-error

CheckBox ( checbox plugin )

  • Example

This example shows how to manage a scalar value with a multiple select.

<Form display={
  { 
    type: 'checkbox', 
    label: "Label Example", 
  }
}/>
  • Options
optiondescription
inputtrue|false, if not set defaults to false
requiredtrue|false, denotes if the field is required for the onSubmit action to be called
labeldisplay text
disabledtrue|false, denotes if this field is disabled
  • CSS Options
optiondefault value
classNameFormCheckboxLeftrf-form-label-right
classNameFormCheckboxRightrf-form-element-left
classNameFormCheckboxContainerrf-form-input-container
classNameFormCheckBoxrf-form-input-checkbox
classNameFormCheckBoxDefaultrf-form-input-checkbox
classNameFormCheckBoxErrorrf-form-input-checkbox-error
classNameFormCheckboxRightErrorrf-form-label-right-error
classNameFormCheckBoxRightDefaultrf-form-label-right

Container Examples

Containers represent Data structures of type Array or Object. Containers make it possible to move beyond a scalar value.

list ( list plugin )

  • Example

This example shows how to manage a list of text inputs.

<Form display={{
  "type": "list",
  "label": "Test Set 1",
  "canMove": true,
  "canDelete": true,
  "display": [
    {
      "type": "text",
      "label": "test One",
      "required": true
    },
    {
      "type": "text",
      "label": "Test Two",
      "required": true
    }]
    }}
/>
  • Options
optiondescription
deleteTextdefault "Delete", text of the delete button
moveUpTextdefault value "^", text of the move up button
moveDownTextdefault value "v", text of the move down button
canMovefalse, enables or disables the move option
canDeletefalse, enables or disables the delete option
headerTextdefault "I am a list", sets the header text for the list block
displayArray that contains the plugins options to display
  • CSS Options
optiondefault value
classNameListContainerrf-form-container
classNameListRowrf-form-container-list-row
classNameListButtonrfFormSubmit
classNameListCellrf-form-container-list-cell
classNameListButtonContainerrf-form-container-list-cell-buttons
classNameHiddenrfFormHidden
classNameSmallerWidthrf-form-container-smaller-row
classNameListHeaderrf-form-container-list-header

hash

  • Example

This example shows how to manage a hash of text and password inputs.

Note Note Note All objects in a hash container require an additional argument name, the name represents the key in the data structure.

<Form display={{
        label: "Simple Hash example",
        display: {
            type: 'hash',
            display: [
                { type: 'text', label: 'Email Address', name: "email", required: true },
                { type: 'password', label: "password", name: "password", required: true }
            ]
        }
    }}
/>
  • Options
optiondescription
displayArray that contains the plugins options to display
  • CSS Options
optiondefault value
classNameListContainerrf-form-container
classNameHashRowrf-form-container-hash-row
classNameHashCellrf-form-container-hash-cell
classNameListHeaderrf-form-container-list-header

Add Elements ( add plugin )

  • Basic Example
<Form display={{
        label: "Add to list",
        display: {
            type: 'add',
            add: {
            type: 'hash',
            display: [
              { name: 'label', type: 'text', label: "label", required: true },
              { name: 'value', type: 'text', label: "value", required: true }
            ]
          },
          form: {
                display: {
                    type: 'hash', display: [
                      { name: 'label', type: 'text', label: "label", required: true },
                      { name: 'value', type: 'text', label: "value", required: true }
                    ]
                }
        },
        list: {
            canMove: true,
            canDelete: true,
            label: 'sets added', 
            display: [],
        }
    }}
/>
  • Comlpex Example

The following is an example of how to use the add plugin.

<Form display={{
        label: "Add to list",
        display: {
            type: 'add',
            add: ['forms'],
            form: {
                display: {
                    type: 'hash', display: [
                        { name: 'label', type: 'text', label: "label", required: true },
                        { name: 'value', type: 'text', label: "value", required: true }
                        {
                            name: 'forms', 
                            type: 'select', 
                            label: "Choose the subform", 
                            data: [
                              { value: 'Informal', label: 'informal' }, 
                              { value: 'Formal', label: 'formal' }
                            ]
                        }
                    ]
                }
        },
        list: {
            canMove: true,
            canDelete: true,
            label: 'sets added', 
            display: [],
        },
        chooser: {
            Informal: {
                label: 'Form One',
                type: 'hash',
                display: [
                    { name: 'label', type: 'text', label: "label", required: true },
                    { name: 'value', type: 'text', label: "value", required: true }
                ]
            },
            Formal: {
              label: 'Form Two',
              type: 'hash',
              display: [
                  { name: 'label', type: 'text', label: "Nomenclature", required: true },
                  { name: 'value', type: 'text', label: "Assignment", required: true },
                  { name: 'select', type: 'select', label: 'Choose One', required: true, 
                    data: [{ label: 'one', value: 'one' }, { label: 'two', value: 'two' }] }
                    ]
              }
            },

        }
    }}
/>
  • Options
optiondescription
displayArray that contains the plugins options to display
addArray, path representing the current most display container element to watch
addObject, display object to add
listignored if add.constructor==Object, all objects added exist in a "list" plugin object, this is where those options are set
chooserObject, of display Objects, when a user clicks the add button, the option matching the chooser will be used
submitTextdefault "Add", the submit button text
errorTextdefault "Some fields are not filled out properly", error show when validation fails
  • CSS Options
optiondefault value
classNameFormContainerrf-form-container
classNameListContainerrf-form-container

Watch example(s)

  • Example

THe following example shows how to use watch in a hash container.

Note Note Note! Unlike other plugins, watch does not contain what it is watching.

<Form display={{
  "type": "hash",
  "display": [
    {
      "type": "select",
      "label": "choose a subform",
      "input": "one",
      "name": "choose",
      "data": [
        {
          "value": "one",
          "label": "Form One"
        },
        {
          "value": "two",
          "label": "Form Two"
        }
      ]
    },
    {
      "type": "watch",
      "name": "subform",
      "watch": [
        "choose"
      ],
      "setDisplay": "one",
      "displays": {
        "one": {
          "type": "text",
          "label": "test"
        },
        "two": {
          "type": "checkbox",
          "label": "subform checkbox"
        }
      }
    }
  ]
}} 
/>
  • Options
optiondescription
watchpath to the parent container value to watch
setDisplaywhich display to use from "displays"
displaysObject of Objects, each key should map to the watch path value.

Creating plugins

The plugin API is very flexible and powerful, it was designed to allow the encapsulation of any plugin within any plugin. This means a list can contain a list, hash, add and and any other assortment of plugins. Any plugin created must follow this mind set.

When creating a plugin the static buildData(props) method must be implemented. The buildData(props) provides the default data structure for a given dataPath.

  • Example from the text plugin
    static buildData( props ) {

        const input = props.hasOwnProperty( 'input' ) ? 
          props.input 
            : 
          FormTextInput.defaultProps.input;
        return input == null ? "" : input;
    }
  • Plugin intantiation arguments

Plugins are rendered with the following arguments

  <Plugin
    key={key} {...displayArguments}
    root={root}
    displayPath={displayPath}
    dataPath={dataPath}
    {...root.defaultHandlers() }
    input={root.getPathValue( this.state, dataPath )}
  />
    
  • Plugin Options
optiondescription
keyrequired by the react api
rootthe top level Form object instance
displayArgumentsa copy of the prop arguments for this plugin
displayPatha path array representing the display configuration in the root.state data structure
dataPatha path array representing the stored in root.state
root.defaultHandlers()object event handlers
inputthe default data structure for this object

** root.defaultHandelers()

namedescriptionarguments
onChangethe function used to push state into the root(dataPath,displayPath,newProps)
onSubmitallows the plugin to call the submit method of root()
onMovecalled by a plugin to move itself within a list plugin( dataPath, displayPath, +1|-1 )
onDeletecalled by a plugin to delete a plugin from a list plugin( list_id, dataPath, displayPath )
onValidateused to call validation for a given plugin( dataPath, displayPath, props, state )

** Registering a plugin for events

The root object offers the following event handler registration methods, and clean up methods.

namedescriptionwhere to initializearguments
registerSubmitCheckregisters a pre-submit checkcomponentDidMount,componentWillReceiveProps(dataPath,function)
registerWatchregisters the monitoring of a valuecomponentDidMount,componentWillReceiveProps(dataPath,function)
deleteWatchdeletes a callback for dataPathcomponentWillReceiveProps,componentWillUnmount(dataPath)
deleteSubmitCheckdeletes a submit checkcomponentWillUnmount,componentWillReceiveProps(dataPath)
  • Registering your plugin

Import the module registry.

import { FormElements } from 'react-form-data-structure/build/form-elements.jsx';

Register your module

FormElements['your-plugin']=YourPluginClass;

Built in demo

The project contains a very basic demo which can be accessed by by issuing the following command, in the project folder.

npm run demo

From there the demo/index.html can be viewed locally.