DEV Community

Ivan V.
Ivan V.

Posted on

1

Handling HTML Forms with Mobx and Dumba.js library

In this short post, I'm going to walk you through how I'm handling HTML forms with Mobx.js. I've developed my own little library (~2.4Kb) for handling HTML forms with Mobx, which makes the forms fully reactive. It supports fields that depend on other fields and asynchronous validation.

You can checkout the demo that shows pretty much all the functionality of the library or check out the source (library and demo)on github

Usage

To use the library we need to create the schema object, which declares what fields exist and what validation tests to use for every field.
In the example below we are going to create a schema with only one field (email) and that field will have only one validation (there could be an array of validations), that will check if the field value is a valid email address.

import { createField, createValidation } from 'dumba'
import isEmail from 'validator/lib/isEmail'

const schema = {
  email: createField({
    value: 'admin@example.com',
    validations: createValidation(
      (str: string) => isEmail(str),
      'Not a valid email'
    )
  })
}
Enter fullscreen mode Exit fullscreen mode

After we create the schema, we use the Form class to create the class instance that will be connected to the actual HTML form. Form instance accepts the schema.

import { Form } from 'dumba'
import { schema } from './schema'
const form = new Form(schema)
Enter fullscreen mode Exit fullscreen mode

When the form instance is created, we use it to connect the fields to the actual HTML form. The form will have all the fields from the schema e.g.

const form = new Form(schema)
form.fields.email.value // field value
form.fields.email.onChange //field change event handler to connect to html input
form.fields.email.errors // array of validation errors (if any)

// also there are properties and methods on the form instance itself

form.isValid // boolean if the form is valid
form.isSubmitting// boolean if form is in the process of submitting
form.isValidating // boolean if the form is in the process of validating (async validations)
form.handleSubmit // submit the form function
Enter fullscreen mode Exit fullscreen mode

Now, let's connect the form to the Material UI TextField as an example

//using material ui just as an example
import TextField from '@material-ui/core/TextField'
import { observer } from 'mobx-react-lite'
import { Form } from 'dumba'
import { schema } from './schema'

//declare it outside of the component, usual Mobx rules apply.
const form = new Form(schema)

const FormDemo = observer(function FormDemo() {
  //form submit function
  const handleOnSubmit = () =>
    form.handleSubmit((form: Form) => Promise.resolve(true))

  return (
    <form onSubmit={handleOnSubmit} autoComplete="off" noValidate>
      <TextField
        type="text"
        id="email"
        name="email"
        label="Email"
        // disable while submit is in progress or async validation is running
        disabled={form.isSubmitting || form.isValidating} 
        value={form.fields.email.value}
        onChange={form.fields.email.onChange}
        onBlur={form.fields.email.onChange}
        // mark field as invalid (if there are any email errors)
        error={!!form.fields.email.errors.length}
        helperText={<DisplayErrors errors={form.fields.email.errors} />} // display error text
        autoComplete="off"
      />
      <Button //form submit button
        variant="contained"
        color="primary"
        type="submit"
        disabled={
          // disable button while submit or async validation is in progress or form is invalid or not yet validated
          form.isSubmitting ||
          form.isValidating ||
          !form.isValid ||
          !form.isValidated
        }
      >
        Submit
      </Button>
    </form>
  )
})
Enter fullscreen mode Exit fullscreen mode

And that's the gist of it. There is a lot more you can do with the library. For example, you can create fields that depend on other fields.

In the next example, we are going to create two schema fields location and numPeople. The latter will depend on the former which means that every time the location field value changes, a validation test for numPeople will also run.

const schema: SchemaType = {
  location: createField({
    value: 'beach' // or pool
  }),
  numPeople: createField({
    value: '',
    dependsOn:['location'] // depends on the location field above
    validations: [
      createValidation(
        (partyPeople: number, _field: Field, locationDependancy?: Field) => {
          if (locationDependancy?.value === 'pool') {
            if (partyPeople > 20) {
              return 'max pool party attendance is 40' // error message
            }
            return true //valid
          }
          if (locationDependancy?.value === 'beach') {
            if (partyPeople > 200) {
              return 'max beach party attendance is 200' // error message
            }
            return true //valid
          }
        }
      )
    ]
  })
}
Enter fullscreen mode Exit fullscreen mode

This little library has sped up my form handling workflow considerably, so I've decided to open source it.
I hope you find it useful.

Demo

Demo source

Library

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay