1.0.7 • Published 7 years ago

reusable-formsy-components v1.0.7

Weekly downloads
3
License
ISC
Repository
github
Last release
7 years ago

React-reusable-formsy-components

Introduction

A simple library for form elements which can be used with react-formsy library.

Currently contains: 1. Input text ( Native HTML ) 2. Select box ( Native HTML ) 3. Check box ( Native HTML ) 4. Radio button ( Native HTML ) 5. single and multiple select using react-select library 6. Date range picker

Motivation

A simple reusable component which can be used for following cases (Components in this library are called Lib Components).

  1. A basic Lib Component which will bind with Formsy Form.
  2. A component which efficiently renders the content.
  3. Controlling the (value set on the element and its display) through (props from parent or user input).
  4. Lib Component itself has its own state which interacts with parent component ( User defined component in which the form will be rendered) and formsy HOC and keeps its value updated, ie. the component state will update based on the value props. Also it can respond to user interactions.
  5. Supports all synthetic events as callback (through props) which can be passed to the native HTML element. Just pass to the events to Lib component through props.
  6. Show Error message for validations either inline or block.

Default Structure of the component

Every input element is wrapped in a div. Any error message for the formsy component can be positioned inline or block.

<div
  className={this.props.wrapperClass}
  style={this.props.wrapperStyle}
>
  {Content}
  <div className={this.props.errorClass} style={errorMessageStyle}>
    { this.props.getErrorMessage() }
  </div>
</div>

Code Example

// Import the necessary Lib Components
import { InputText, InputSelect, InputCheck, InputRadioButtonGroup } from reusable-formsy-components;

// Pass this as props to selectbox. It will render based on the name and value.
this.selectBoxOptions = [
      { name: "option1", value: "1" },
      { name: "option2", value: "2" }
    ];

// Pass this as props to radio buttons.
this.radioButtonGroupOptions = [
      { name: "option1", value: "1", displayName: "1" },
      { name: "option2", value: "2", displayName: "2" }
];

// in the render function of the your component declare a form

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      canSubmit: true,
      selectValue: '',
      isSettingPristineValue: {},
    };

    // Hold the form names. Used to construct a state object with true.
    this.formName = [1, 2, 3, 4, 5, 6];
    // On changing input. used as callback for altering {this.state.isSettingPristineValue}
    this.onChangeInput = this.onChangeInput.bind(this);
    // Custom reset function. Resets the pristine values
    this.onReset = this.onReset.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
    // Static options
    this.selectBoxOptions = [
      { name: "option1", value: "1" },
      { name: "option2", value: "2" }
    ];
    this.radioButtonGroupOptions = [
      { name: "option1", value: "1", displayName: "1" },
      { name: "option2", value: "2", displayName: "2" }
    ];
    this.customSelect = [
      { value: 'one', label: 'one', className: 'select-options-custom' },
      { value: 'two', label: 'two', className: 'select-options-custom' },
      { value: 'three', label: 'three', className: 'select-options-custom' },
      { value: 'four', label: 'four', className: 'select-options-custom' },
      { value: 'five', label: 'five', className: 'select-options-custom' },
      { value: 'six', label: 'six', className: 'select-options-custom' }
    ];
  }

  componentDidMount() {
    // Set all key value pair to have true for all form fields with name.
    let isSettingPristineValue = {};
    _.each((this.formName), (name) => {
      isSettingPristineValue[name] = true;
    });
    // This will store every input as untouched
    this.setState({
      isSettingPristineValue
    });
  }

  onChangeInput(name, value) {
    // If any of the form input change and if it is not the original value
    if(!_.isEqual(this.refs.hello.getPristineValues()[name], value)) {
      let isSettingPristineValue = JSON.parse(JSON.stringify(this.state.isSettingPristineValue));
      isSettingPristineValue[name] = false;
      this.setState({
        isSettingPristineValue,
      });
    }
  }

  onReset() {
    // on clicking reset just update the pristine value of form elements to true so that it will render from the value prop
    let isSettingPristineValue = {};
    _.each((this.formName), (name) => {
      isSettingPristineValue[name] = true;
    });
    this.setState({
      isSettingPristineValue,
    });
  }

  onSubmit() {
    console.log('submitting ', this.refs.hello.getModel());
  }

  render() {
    const dateTime = {
      startDate: moment('25/12/2017 12:00:00 am', 'DD/MM/YYYY hh:mm:ss a'),
      endDate: moment('25/12/2018 12:00:01 am', 'DD/MM/YYYY hh:mm:ss a'),
    };

    return (
      <div>
        <Formsy.Form
          ref="hello"
          onChange={this.onChangeForm}
          noValidate
        >
          <InputText
            name="1"
            label="Textbox:"
            onChangeInput={this.onChangeInput}
            wrapperClass="divs"
            value='abcdef'
            isValuePristine={this.state.isSettingPristineValue[1]}
          />
          <InputSelect
            name="2"
            label="SelectBox:"
            options={this.selectBoxOptions}
            value="2"
            onChangeInput={this.onChangeInput}
            isValuePristine={this.state.isSettingPristineValue[2]}
            value={'2'}
            wrapperClass="divs"
          />
          <InputCheck
            name="3"
            label="Checkbox:"
            displayName="input check"
            onChangeInput={this.onChangeInput}
            isValuePristine={this.state.isSettingPristineValue[3]}
            value={true}
            wrapperClass="divs"
          />
          <InputRadioButtonGroup
            name="4"
            label="Radio button:"
            options={this.radioButtonGroupOptions}
            onChangeInput={this.onChangeInput}
            wrapperClass="divs"
            isValuePristine={this.state.isSettingPristineValue[4]}
            value={'2'}
          />

          <InputSelectCustom
            name="5"
            options = { this.customSelect }
            onChangeInput = { this.onChangeInput }
            className = 'react-select'
            autofocus = {false}
            multi={true}
            isValuePristine={this.state.isSettingPristineValue[5]}
            value={['two', 'three']}
            wrapperClass="select-custom"
            label="React-select"
            labelClass="select-label"
            selectClass="select-class"
          />
          <InputDateTime
            name="6"
            timePicker={true}
            wrapperClass="date-time"
            onChangeInput = { this.onChangeInput }
            isValuePristine={this.state.isSettingPristineValue[6]}
            value={dateTime}
          >
            Select a date
          </InputDateTime>
          <input
            type="button"
            value="Reset to pristine value"
            onClick={this.onReset}
          />
          <button
            type="submit"
            disabled={!this.state.canSubmit}
            onClick={this.onSubmit}
          >
            Submit
          </button>
        </Formsy.Form>
      </div>
    );
  }
}
/*
 * Renders the app with the target container
 */
render(
  <App />,
  document.getElementById('app'));


Any synthetic react events can be passed to the Lib Component as props.

Efficient re rendering.

Every component re renders only when the value of its iternal state changes. It avoids unnecessary re rendering due to props change of the Formsy library.

Installation

npm i reusable-formsy-components

API Reference

1. InputText

PropNameTypeRequirementDescription
namestringisRequiredname of the form element,
valueanyoptionalPass this as props to set the value
wrapperClassstringoptionalcss class for the wrapper div,
fieldClassstringoptionalcss class for the input element,
onChangeInputfuncoptionalcallback to the parent component based on user interaction,
requiredbooloptionalspecifies whether form requires this to be valid,
wrapperStyleobjectoptionalSet inline style for wrapper div,
fieldStyleobjectoptionalSet inline style for input element,
inlinebooloptionalDisplay error message inline or block,
refstringoptionalPassing refs for accessing,

2. InputCheck

PropNameTypeRequirementDescription
namestringRequiredname of the form element,
displayNamestringRequireddisplay name of the checkbox
valueanyoptionalPass this as props to set the value
wrapperClassstringoptionalcss class for the wrapper div,
selectClassstringoptionalcss class for the select element,
optionClassstringoptionalcss class for the option element,
onChangeInputfuncoptionalcallback to the parent component based on user interaction,
requiredbooloptionalspecifies whether form requires this to be valid,
inlinebooloptionalDisplay error message inline or block,
refstringoptionalPassing refs for accessing,

3. InputSelect

PropNameTypeRequirementDescription
namestringRequiredname of the form element,
optionsarrayRequiredArray of objects { name (display), value (actual value holded) }
valueanyoptionalPass this as props to set the value
wrapperClassstringoptionalcss class for the wrapper div,
selectClassstringoptionalcss class for the select element,
optionClassstringoptionalcss class for the option element,
onChangeInputfuncoptionalcallback to the parent component based on user interaction,
requiredbooloptionalspecifies whether form requires this to be valid,
inlinebooloptionalDisplay error message inline or block,
refstringoptionalPassing refs for accessing,

4. InputRadioButton

PropNameTypeRequirementDescription
namestringRequiredname of the form element,
optionsarrayRequiredArray of objects { name (form value will be on this name), value (actual value holded), displayName (display) }
valueanyoptionalPass this as props to set the value
wrapperClassstringoptionalcss class for the wrapper div,
selectClassstringoptionalcss class for the select element,
optionClassstringoptionalcss class for the option element,
onChangeInputfuncoptionalcallback to the parent component based on user interaction,
requiredbooloptionalspecifies whether form requires this to be valid,
inlinebooloptionalDisplay error message inline or block,
refstringoptionalPassing refs for accessing,

Tests

Download the repository. run npm test.

Contributors

The whole aim is to keep it simple and more generic. Feel free to suggest improvements.

License

MIT License