npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-mobforms

v1.0.1

Published

Automatically create mobx stores from forms

Downloads

1

Readme

react-mobforms

Installation

npm install react-mobforms

Note that react-mobforms has mobx and mobx-react as required peer dependencies

Usage

Form field decorator

Form fields come in a few flavors:

  • String

    @formField('myField', String, '')
    export default class MyField extends FieldComponent {
  • Number

    @formField('myField', Number, 0)
    export default class MyField extends FieldComponent {
  • String array

    @formField('myField', [String], [''])
    export default class MyField extends FieldComponent {
  • Number array

    @formField('myField', [Number], [0])
    export default class MyField extends FieldComponent {

Functional usage

formField can also be used as a composable function, as such:

class MyField extends FieldComponent {
  /* your implementation */
}

export default formField('name', String, '')(MyField)

Effect of the formField decorator

The formField decorator exposes two fields to the wrapped component.

  • this.formState -- The state of the entire form that this field is a member of
  • this.fieldValue -- The value of the field defined by the decorator call

For example: If the decorator was used as @formField('myField', Number, 10)

  • this.fieldValue will be a number with a starting value of 10
  • this.fieldValue is equivalent to this.formState.myField

Basic examples

If not provided, the type and default value are String and ''. For instance, in the following example the field on formState will be called firstName, be a string, and start with a value of ''.

import * as React from 'react'
import { formField, FieldComponent } from 'react-mobforms'

@formField('firstName')
export default class FirstName extends FieldComponent {
  render () {
    return (
      <input
        placeholder='First Name'
        value={this.fieldValue}
        onChange={ev => this.fieldValue = ev.currentTarget.value}
      />
    )
  }
}

You can also set a default value for the field. In this example, the field on formState will be called lastName, and will also be a string, but will instead start with a value of 'Doe'.

import * as React from 'react'
import { formField, FieldComponent } from 'react-mobforms'

@formField('lastName', String, 'Doe')
export default class LastName extends FieldComponent {
  render () {
    return (
      <input
        placeholder='Last Name'
        value={this.fieldValue}
        onChange={ev => this.fieldValue = ev.currentTarget.value}
      />
    )
  }
}

In the following example, the field on formState is called age, is a number, and starts with a value of 18.

import * as React from 'react'
import { formField, FieldComponent } from 'react-mobforms'

@formField('age', Number, 18)
export default class Age extends FieldComponent {
  render () {
    return (
      <input
        placeholder='Age'
        value={`${this.fieldValue || ''}`}
        onChange={ev => this.fieldValue = parseInt(ev.currentTarget.value, 10)}
      />
    )
  }
}

Form decorator

The form decorator can be used as such:

@form
export default class Form extends FormComponent {

It can also be used as a composable function:

class MyForm extends FormComponent {
  /* your implementation */
}

export default form(MyForm)

Effect of the form decorator

The form decorator exposes a single field to the wrapped component.

  • this.formState -- The state of the the form and all of its fields
    • this.formState will have all of the fields defined by its children (and their children)

In the following example, let's assume that FirstName, LastName, and Age are defined as above:

import * as React from 'react'
import { form, FormComponent } from 'react-mobforms'

import FirstName from './FirstName'
import LastName from './LastName'
import Age from './Age'

@form
export default class UserForm extends FormComponent {
  render () {
    return (
      <form onSubmit={onSubmit}>
        <FirstName />
        <LastName />
        <Age />
        <button type='submit'>Submit</button>
      </form>
    )
  }

  onSubmit = () => {
    console.log(this.formState)
  }
}

In this example, formState will have firstName, lastName, and age as fields, with starting values of '', 'Doe', and 18, respectively. Whenever any of these fields is updated, the change is automatically propagated down to all of the children that consume the property.

Replacing formState

Sometimes, you will want your form to contain information that is not strictly the defaults for each of the fields. Let's say you already have a user with firstName, lastName, and age. If you want to replace what is in the existing formState, you simply write this.formState = user. Note that only the fields defined by the form's fields will be copied to this.formState. In the prior example, if you were to write this.formState = { foo: 'bar' }, this would set firstname, lastName, and age to undefined, but would not copy the foo property, because it is not a field defined by the form.

In practical terms, you can expose a prop from your form component which allows you to replace the defaults. For example:

@form
export default class UserForm extends FormComponent {
  componentDidMount () {
    this.formState = this.props.defaultState
  }
  /* rest of implementation */
}

In this way, if rendered as <UserForm defaultState={user} />, then the fields from user would replace the defaults for all of the form fields whose field name matches one from user.

Hidden fields

For fields that don't directly appear in your form, you can use the HiddenField component. This component has three props:

  • name -- The name of the field in formState
  • type -- One of String, Number, [String], or [Number]
  • defaultValue -- The default value for the field

When using the HiddenField component, all three of these props are required.

You can use this to drive other components using the hidden field. For example:

@formField('primaryLanguage', String, 'English')
class PrimaryLanguage extends FieldComponent {
  render () {
    const { languages } = this.formState

    return languages.map(language => (
      <label key={language}>
        <input
          type='radio'
          name='primaryLanguage'
          value={language}
          onChange={this.onChange}
        />
        {language}
      </label>
    ))
  }

  @action onChange = (ev) => {
    this.fieldValue = ev.currentTarget.value
  }
}

@form
export default class MyForm extends FormComponent {
  render () {
    return (
      <form>
        <HiddenField name='languages' type={[String]} defaultValue={['English', 'Deutsch', 'Français', 'Español']} />
        <PrimaryLanguage />
      </form>
    )
  }
}

Additional examples

For more examples, see the examples directory.

Planned features

  • Fields can be marked as non-enumerable, thus making them not appear in JSON.stringify(formState)
  • Forms can also be fields in parent forms, allowing for nested form structure
  • Field-level validation
  • Custom field types