Coder Social home page Coder Social logo

voletiswaroop / react-material-ui-form Goto Github PK

View Code? Open in Web Editor NEW
16.0 1.0 6.0 3.32 MB

react-material-ui-form is a React wrapper for Material-UI form components. Simply replace the <form> element with <MaterialUIForm> to get out-of-the-box state and validation support as-is. There's no need to use any other components, alter your form's nesting structure, or write onChange handlers.

Home Page: https://www.npmjs.com/package/react-material-ui-form

License: MIT License

JavaScript 100.00%
reactjs material-ui react-forms react-form-validation react-form-component react-form-validator react-form-builder textfield checkbox select dropdown radio radio-buttons inputfield date numberfield react-material-ui-form react-material-ui react-form

react-material-ui-form's Introduction

react-material-ui-form

MIT npm BuildStatus Downloads SourceRank

  1. About
  2. Setup
  3. Props
  4. Examples
  5. Contributing
  6. License

About

react-material-ui-form is a React wrapper for Material-UI form components. Simply replace the <form> element with <MaterialUIForm> to get out-of-the-box state and validation support as-is. There's no need to use any other components, alter your form's nesting structure, or write onChange handlers.

Validation is done with validator.js but you can extend/customize validation messages, validators, and use your own validation logic too. Steppers, dynamic array fields and custom components are also supported.

use and requirements

  • requires React 16.3.0 or newer
  • supports official and unofficial Material-UI fields (other input elements are rendered without state/validation support)
  • every input field must have value and name props
  • every input field should NOT have onChange and onBlur props (unless you need custom field-specific logic)
  • add a data-validators prop to any input field (or FormControl / FormControlLabel) to specify validation rules

extra validators

react-material-ui-form extends validator.js validators with the following validators:

  • isAlias /^[a-zA-Z0-9-_\.]*$/i
  • isDate
  • isNumber /^([,.\d]+)$/
  • isRequired value.length !== 0
  • isSerial /^([-\s\da-zA-Z]+)$/
  • isSize value >= min && value <= max
  • isTime
  • isLength(min,max) [{ isLength: { min: 2, max: 50 } }]

Supported field components

  • TextField
  • TextField { select }
  • TextField { multiline, textarea }
  • Checkbox
  • RadioGroup
  • Radio
  • FormControlLabel (control prop)
  • FormLabel
  • InputLabel

Note

Currently this package will support only till Material-UI v3

Setup

install

npm install --save react-material-ui-form

demo

  1. $ git clone https://github.com/voletiswaroop/react-material-ui-form.git
  2. $ cd react-material-ui-form
  3. $ npm install && npm run dev

Props

Form props (optional):

Prop Description Default
[class] [string] Sets className attribute to the form
[id] [string] Sets id attribute to the form
[name] [string] Sets name attribute to the form
[action] [string] Sets action attribute to the form
activeStep [number] Use together with onFieldValidation for better Stepper support
autoComplete [string] Sets form autoComplete prop. Accepts one of ["on", "off"] "off"
disableSubmitButtonOnError [boolean] Disables submit button if any errors exist true
onFieldValidation [func] Returns @field and @errorSteps (if activeStep prop is provided) on field validation
onSubmit [func] Returns @values and @pristineValues on form submission
onValuesChange [func] Returns @values and @pristineValues on field value change
validation [object] Object specifing validation config options (prefixed below with ↳)
messageMap [object] A key-value list where the key is the validator name and the value is the error message. Is exposed as a react-material-ui-form export parameter object
messageKeyPrefix [string] Optional prefix to apply to all messageMap keys. If specified, field validator names will automatically be appended the prefix ""
requiredValidatorName [boolean, string] Specifies the validator name and matching messegeMap key for required fields. To disable and rely on the native required field prop, set to false "isRequired"
validate [func] Overrides the internal validate method. Receives the following parameters: @fieldValue, @fieldValidators, and @...rest (where @...rest is the validation prop object) func
validators [object] Defaults to an extended validator.js object. Is exposed as a react-material-ui-form export parameter object
validateInputOnBlur [boolean] Makes text input validations happen on blur instead of on change false
validations [object] Validations to pass to the form (i.e. from the server). Should be an object with keys representing field name props and values as arrays of field error messages. The first error message will be displayed per field

Field props:

Prop Description Required
value [any] The value of the field. If empty set an empty string Yes
name [string] The name of the field Yes
data-validators [string, array[object]] Validators to apply to the field. Multiple validator names can be specified with a comma-delimited string
onBlur [func] A custom handler that will be called after the field's onBlur event. Provides @value/checked, @field and @event parameters
onChange [func] A custom handler that will be called after the field's onChange event. Provides @value/checked, @field and @event parameters

Other props:

Prop Value Description
deletefieldrow [string] Field name prop up to and including the row index (i.e. rooms[2]) Add to button components that use onClick to remove any array field rows

Material-UI form production build classnames conflict issues

To avoid default material-ui production build classnames conflict issues include your entire form inside Example: Nested fields

Examples

Nested fields:

import MaterialUIForm from 'react-material-ui-form'
import JssProvider from 'react-jss/lib/JssProvider';

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  customInputHandler = (value, { name }, event) => {
    // the form will update the field as usual, and then call this handler
    // if you want to have complete control of the field, change the "value" prop to "defaultValue"
  }

  customToggleHandler = (checked, { name, value }, event) => {
    // the form will update the field as usual, and then call this handler
    // if you want to have complete control of the field, change the "value" prop to "defaultValue"
  }

  render() {
    return (
      <JssProvider>
        <MaterialUIForm onSubmit={this.submit}>
          <TextField label="Name" type="text" name="name" value="" data-validators="isRequired,isAlpha" onChange={this.customInputHandler} />
          <fieldset>
            <FormControl>
                {/* form label is required here to perform default validations */}
                <FormLabel component="legend">I love React material UI form</FormLabel>
                <FormGroup value=''>
                  <FormControlLabel control={<Checkbox value='yes' />}
                    label='I love React material UI form'/>
                </FormGroup>
              </FormControl>

            <FormControl required>
              <InputLabel>Age</InputLabel>
              <Select value="" name="age">
                <MenuItem value=""><em>Please select your age ...</em></MenuItem>
                <MenuItem value={10}>Teens</MenuItem>
                <MenuItem value={20}>Twenties</MenuItem>
                <MenuItem value={30}>Thirties</MenuItem>
                <MenuItem value="40+">Fourties +</MenuItem>
              </Select>
              <FormHelperText>Some important helper text</FormHelperText>
            </FormControl> 
          </fieldset>
          
          <FormControl>
            <FormLabel component="legend">Gender</FormLabel>
            <RadioGroup aria-label="Gender" name="gender"  value="male">
              <FormControlLabel value="female" control={<Radio />} label="Female" />
              <FormControlLabel value="male" control={<Radio />} label="Male" /> 
            </RadioGroup>
          </FormControl>
          
          <Button variant="raised" type="reset">Reset</Button>
          <Button variant="raised" type="submit">Submit</Button>
        </MaterialUIForm>
      </JssProvider>
    )
  }
}

Custom validators:

import Form, { messageMap, validators } from 'react-material-ui-form/dist/validation/index';
 

validators.isBorat = value => value === 'borat'
const customMessageMap = Object.assign(messageMap, {
  isBorat: 'NAAAAAT! You can only write "borat" lol',
})

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validation={{ messageMap: customMessageMap, validators, }}>
        <TextField label="Write anything..." type="text" name="trickster" value="" helperText="this is not a trick" data-validators="isBorat" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Custom validation messages:

const customFormMsg = Object.assign(messageMap, { 
  isEmail: 'Please enter a valid email address',  
  isLength:'Must be 2-50 characters', 
})
class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }
render() {
  return (
    <MaterialUIForm onSubmit={this.submit} validation={{ messageMap: customFormMsg}}>
      <TextField label="Name" type="text" name="FirstName" value="Name" data-validators="isLength" />
      <TextField label="Email" type="text" name="Email" value="[email protected]" data-validators="isRequired,isEmail" />
      <Button variant="raised" type="submit">Submit</Button>
    </MaterialUIForm>
    )
  }
}

Custom validation logic:

import MaterialUIForm from 'react-material-ui-form'
 

function validate(value, fieldValidators, options) {
  const fieldValidations = []
  fieldValidators.forEach((validator) => {
    const validation = {
      code: String(validator),
      message: 'its invalid so maybe try harder...',
    }
    if (_.has(options, 'genericMessage')) {
      validation.message = options.genericMessage
    }
    fieldValidations.push(validation)
  })
  return fieldValidations
}

const validationOptions = {
  genericMessage: 'yeah... *tisk*',
}

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validation={{ requiredValidatorName: false, validate, ...validationOptions, }}>
        <TextField label="Whatever you write isn't gonna be good enough" type="text" name="test" value="" data-validators="whatever - our custom validator will ignore this" required />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Server validations:

import MaterialUIForm from 'react-material-ui-form'
 

const mockServerValidations = {
  name: [{ code: 'isInvalid', message: 'such invalid...' }],
}

class MyForm extends React.Component {
  state = {
    mockServerValidations,
  }

  componentDidMount() {
    let validations = {
      name: [{ message: 'such WOOOOOOOOOW...' }],
    }

    setTimeout(() => {
      this.setState({ mockServerValidations: validations })
    }, 1500)

    setTimeout(() => {
      validations = {
        name: [{ message: 'so still haven\'t watched Italian Spiderman?' }],
      }
      this.setState({ mockServerValidations: validations })
    }, 3000)
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validations={this.state.mockServerValidations}>
        <TextField label="Name" type="text" name="name" value="doge" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Form autoComplete and "on error" submission:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm autoComplete="on" disableSubmitButtonOnError={false} onSubmit={this.submit}>
        <TextField label="Name" type="text" name="name" value="doge" data-validators="isInt" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Getting form values on field update:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  handleValuesChange = (values, pristineValues) => {
    // get all values and pristineValues when any field updates
  }

  handleFieldValidations = (field) => {
    // get field object when its validation status updates
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} onValuesChange={this.handleValuesChange} onFieldValidation={this.handleFieldValidations}>
        <TextField label="Name" name="name" value="doge" required />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Stepper:

import Stepper, { Step, StepLabel } from 'material-ui/Stepper'
import MaterialUIForm from 'react-material-ui-form'
 

function getSteps() {
  return [
    'Step 1',
    'Step 2',
  ]
}

class MyForm extends React.Component {
  state = {
    activeStep: 0,
    errorSteps: [],
  }

  clickNext = () => {
    this.setState({
      activeStep: this.state.activeStep + 1,
    })
  }

  clickBack = () => {
    this.setState({
      activeStep: this.state.activeStep - 1,
    })
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  updateErrorSteps = (field, errorSteps) => {
    this.setState({ errorSteps })
  }

  render() {
    const steps = getSteps()
    const { activeStep } = this.state

    return (
      <div>
        <Stepper activeStep={activeStep} alternativeLabel>
          {steps.map((label, i) => (
            <Step key={label}>
              <StepLabel error={errorSteps.includes(i)}>
                {label}
              </StepLabel>
            </Step>
          ))}
        </Stepper>

        <MaterialUIForm activeStep={activeStep} onFieldValidation={this.updateErrorSteps} onSubmit={this.submit}>
          {activeStep === 0 &&
            <React.Fragment>
              <TextField label="Name" name="name" value="" required />
              <Button variant="raised" onClick={this.clickNext}>Next</Button>
            </React.Fragment>
          }

          {activeStep === 1 &&
            <React.Fragment>
              <TextField label="Address" name="address" value="" required />
              <Button variant="raised" onClick={this.clickBack}>Back</Button>
              <Button variant="raised" type="submit">Submit</Button>
            </React.Fragment>
          }
        </MaterialUIForm>
      </div>
    )
  }
}

Dynamic array fields (notice the deletefieldrow prop on the "Remove Row" button):

import MaterialUIForm from 'react-material-ui-form'
import formData from 'form-data-to-object'
 

class MyForm extends React.Component {
  state = {
    rows: [{ _id: _.uniqueId() }],
    onSubmitValues: null,
  }

  addRow = () => {
    const { rows } = this.state
    rows.push({ _id: _.uniqueId() })
    this.setState({ rows })
  }

  removeRow = (index) => {
    const { rows } = this.state
    if (rows.length > 1) {
      rows.splice(index, 1)
      this.setState({ rows })
    }
  }

  submit = (values, pristineValues) => {
    // you can parse values to turn:
    // rows[0][label]: "label"
    // into:
    // rows: [{ label: "label" }]
    const parsedValues = formData.toObj(values)
  }

  render() {
    const steps = getSteps()

    return (
      <MaterialUIForm onSubmit={this.submit}>
        {this.state.rows.map((row, i) => (
          <Fragment key={row._id}>
            <TextField label="Label" name={`rows[${i}][label]`} value="" required />
            <TextField label="Value" name={`rows[${i}][value]`} value="" />
            { this.state.rows.length > 1 &&
              <Button onClick={()=> this.removeRow(i)} deletefieldrow={`rows[${i}]`}>Remove Row</Button>
            }
          </Fragment>
        ))}
        
        <Button variant="raised" onClick={this.addRow}>Add row</Button>
        <Button variant="raised" color="primary" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Custom components with custom handlers:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  uploadFile = (event) => {
    console.log(event.target.files)
  }

  render() {
    return (
      <div>
        <MaterialUIForm>
          {'Upload file: '}
          <input accept="image/*" style={{ display: 'none' }} id="raised-button-file" multiple type="file" onChange={this.uploadFile} />
          <label htmlFor="raised-button-file">
            <Button variant="raised" component="span">Upload</Button>
          </label>
        </MaterialUIForm>
      </div>
    )
  }
}

Contributing

As this is a new project, contributions are most welcome. Feel free to clone the repo and extend the module. If you find any bugs please feel free to raise a bug open an issue. Collaborators are also welcome - please send an email to [email protected].

License

This project is licensed under the terms of the MIT license.

react-material-ui-form's People

Contributors

c-higgins avatar galki avatar voletiswaroop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

react-material-ui-form's Issues

Demo not running

Hi,

I try to run the demo, however it is showing an error when running the installation. Below the log with the error utput

0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli '/usr/local/Cellar/node/14.13.0/bin/node',
1 verbose cli '/usr/local/bin/npm',
1 verbose cli 'run',
1 verbose cli 'dev'
1 verbose cli ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'predev', 'dev', 'postdev' ]
5 info lifecycle [email protected]predev: [email protected]
6 info lifecycle [email protected]
dev: [email protected]
7 verbose lifecycle [email protected]dev: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]
dev: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/samuel/Group Project/Material_UI_Projects/demo/node_modules/.bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/Library/Apple/usr/bin
9 verbose lifecycle [email protected]dev: CWD: /Users/samuel/Group Project/Material_UI_Projects/demo
10 silly lifecycle [email protected]
dev: Args: [
10 silly lifecycle '-c',
10 silly lifecycle 'webpack-dev-server --mode development --entry=./examples/Root --open'
10 silly lifecycle ]
11 silly lifecycle [email protected]dev: Returned: code: 1 signal: null
12 info lifecycle [email protected]
dev: Failed to exec dev script
13 verbose stack Error: [email protected] dev: webpack-dev-server --mode development --entry=./examples/Root --open
13 verbose stack Exit status 1
13 verbose stack at EventEmitter. (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16)
13 verbose stack at EventEmitter.emit (events.js:314:20)
13 verbose stack at ChildProcess. (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack at ChildProcess.emit (events.js:314:20)
13 verbose stack at maybeClose (internal/child_process.js:1047:16)
13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:287:5)
14 verbose pkgid [email protected]
15 verbose cwd /Users/samuel/Group Project/Material_UI_Projects/demo
16 verbose Darwin 19.6.0
17 verbose argv "/usr/local/Cellar/node/14.13.0/bin/node" "/usr/local/bin/npm" "run" "dev"
18 verbose node v14.13.0
19 verbose npm v6.14.8
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] dev: webpack-dev-server --mode development --entry=./examples/Root --open
22 error Exit status 1
23 error Failed at the [email protected] dev script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]

eh? what? how?

I honestly don't know how to begin using this library. The README looks like cryptic "lorem ipsum" to me.

Seems to skip validation when enter key is pressed

Whenever I press on the submit button, it validates fine. However, when I press enter, it submits the form without validating.

<MaterialUIForm onSubmit={this.submit}
        validation={{ messageMap: customMessageMap, validators}}  className={classes.container}>

        <FormGroup>

          <FacebookLoginButton />
          <GoogleLoginButton />

          <TextField
            autoFocus
            value=""
            type="email"
            name="email"
            label="Email Address"
            className={classes.textField}
            data-validators="isRequired,isEmail"
            onChange={this.customInputHandler}
            margin="normal"
          />

          <TextField
            type="password"
            name="password"
            label="Password"
            value=""
            className={classes.textField}
            data-validators="isRequired, isPassword"
            onChange={this.customInputHandler}
            margin="normal"
          />

          <FormControlLabel
            control={<Checkbox name="rememberMe" color="default" defaultChecked={this.state.rememberMe} onChange={this.updateRememberMe} />}
            label="Remember Me"
          />

          <Button type="submit" color="default" variant="raised">
            Login
          </Button>

        </FormGroup>

      </MaterialUIForm>

Plus, it seems that customToggleHandler doesn't work with FormControlLabel. I might be doing it wrong though. Everything returns invalid.

<FormControlLabel 
control={
<Checkbox name="rememberMe" color="default" value="yes" onChange={this.customToggleHandler } />
}
label="Remember Me"
/>

Doesn't work on latest MUI version

It seems the data structure of the MUI components has changed for name. When using a TextField, the error 'FieldClone does not support native elements' will be thrown. This is because you are checking

    if (fieldComp.type.name === undefined) {
      throw new Error('FieldClone does not support native elements');
    }

However, the name now resides in fieldComp.type.options.name

Unable to import default validations and messageMap

I have not been able to import the default field validations and messageMap following the demo example. I'm trying to do this from a typescript based React application. Can you give an example that imports directly from the component using this rather than via the src/index.js file?

TextField doesn't update if value is changed

I have a form where the value for a TextField is updated after the form is initial rendered; however, the TextField value does not display the updated value when it is within the MaterialUIForm. I am using mobx and the component is observing the user object used below for the value. If I put that same value code in a

, it updates correctly. I suspect this has something to do with the field cloning. Is there some way to get this to work?

<TextField
label="First name"
type="text"
data-validators="isRequired"
value={user ? user.firstName : ""}
/>

First Name: {user ? user.firstName : ""}

Error: FieldClone does not support native elements

Hi guys,

Great work here, but i am having an issue following the example for nested fields.

I receive the following error

Error: FieldClone does not support native elements

Any ideas how to fix this?

My package.json

  "dependencies": {
    "@material-ui/core": "^4.3.2",
    "@material-ui/icons": "^4.2.1",
    "@material-ui/styles": "^4.3.0",
    "final-form": "^4.18.4",
    "lodash": "^4.17.15",
    "node-sass": "^4.12.0",
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-final-form": "^6.3.0",
    "react-material-ui-form": "^1.1.4",
    "react-scripts": "3.1.0",
    "styled-components": "^4.3.2"
  },

Reset form on submit

Hi

Excellent forms processor, I was wondering how to reset the form after a submit has been completed, ie just mimicking the Reset Button on your example.
Thanks

Finbar

The MaterialUIForm doesn't see children if they're wrapped in a <Grid />

Hello,

I'm building a for that's wrapped in material-ui Grid elements. Unfortunately, I can't seem to combine it with your form, because it simply doesn't see the input children.

I checked the source code really fast - from what I've seen, you only check children 1 level down? Since the grid elements are wrapped in at least 2 containers (Grid container and grid item), maybe that's where the issue lies?

I guess I'm not the only one using grids in my forms. It would be very helpful if you solved this issue.

How to prevent validation when clicking non-submit buttons?

When clicking the Cancel button, it is confusing to see validated fields flash red briefly as the dialog is closing even though they are still in a pristine state. Is there a way to prevent field validation from occurring when clicking on a button other than the submit button? Alternatively, is there a way to only do validation when the submit button is clicked?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.