Giter Site home page Giter Site logo

form's Introduction

@mana-ui/form

Features

Mana form handles four aspects of forms: data management, layout, validation and submit.

  • data management: get values show in each fields with correct controls and update values correctly
  • layout: how each field is rendered: include control, label and error message
  • validation: validate value restrictions & show errors
  • submit: complete form filling

Data Management

  1. When using mana form, an init value should be provided to useForm hook, which returns a form instance, then pass the instance to Form component:
// init value
const form = useForm({ a: "a", b: "b" })
<Form init={form}>...</Form>

The form instance identity is guaranted to be stable and won't change on re-renders.

  1. The form instance returned by useForm hook is useful when you want to get/set data outside of the form.
import {useForm} from '@mana-ui/form'

// init form
const form = useForm({a: 'a', b: 'b'})
<Form init={form}>...</Form>

// get/set value by form:
form.get() // {a: 'a', b: 'b'}
form.set('updated b', 'b') // set property b a new value
form.get('b') // returns 'update b'
  1. subscribe to value changes:
const form = useForm({ a: "a" })
form.listen((v) => console.log(v)) // log value when data changes
  1. useStore (DEPRECATED)

useStore is deprecated, use useForm instead

Layout

  1. Mana form provides default view components, and inject value and onChange:
 <Field name="f" label="F">
// render as <div><label for="f">F <input id="f" value="a"></label></div>

value is fetched by name or path, onChange is same as plain input onChange prop

  1. customize components:

You can override control component by providing control prop a react element, Field will pass value and onChange props to this react element.

<Field
  name="a"
  label="A"
  control={
    <select className="custom-a">
      <option value="a">a</option>
      <option value="b">b</option>
    </select>
  }
/>

If your component don't receive value or onChange prop, you can use render prop function to render your component

<Field
  name="b"
  label="B"
  control={({ get, set }) => {
    return (
      <input
        type="checkbox"
        checked={get()}
        onChange={({ target: { checked } }) => {
          set(checked)
        }}
      />
    )
  }}
/>
  1. define form layout

Usually fields of a form have the same layout, you can define this layout by fieldRender of Form.

<Form
  fieldRender={({ Control, labelElem, id }) => (
    <div className="field">
      <label htmlFor={id} >{labelElem}</label>
      <Control id={id} />
    </div>
  )}
>
  {() => {
    <>
      <Field name="a" label="A" />
      <Field name="b" label="B" />
    </>
  }}
</Form>

// reander as:
<div>
  <div class="field" >
    <label for="a">A</label>
    <input id="a" value="A" />
  </div>
  <div class="field" >
    <label for="b">B</label>
    <input id="b" value="B" />
  </div>
</div>

Or you can provide render to Field, which will overrides fieldRender from Form:

const customRender = (className) => ({ Control, labelElem, id }) => (
  <div className={className}>
    <label htmlFor={id}>{labelElem}</label>
    <Control id={id} />
  </div>
)

<Form
  value={{ a: "A", b: "B" }}
  fieldRender={customRender("field-render")}
>
  {() => (
    <>
      <Field name="a" label="A" />
      <Field name="b" label="B" render={customRender("field-b")} />
    </>
  )}
</Form>

// render as
<div>
  <div class="field-render" >
    <label for="a" />
    <input id="a" value="A" />
  </div>
  <div class="field-b" >
    <label for="b" />
    <input id="b" value="B" />
  </div>
</div>

Validation & Errors

You may define validators by validators prop, and use validators by props other than Field used props:

<Form
  validators={{
    required: (v) => v === "" && "F is required",
  }}
  fieldRender={({ labelElem, Control, error }) => (
    <div>
      <label>{labelElem}</label>
      <div>
        <Control />
        {error}
      </div>
    </div>
  )}
>
  {() => (
    <Field
      name="f"
      label="F"
      validators={{
        maxLength: (v, max) => v.length > max && "F exceeds max length",
      }}
      required // required is not a Field used prop and it enables required rule defined in Form validators
      maxLength={5} // as the same, maxLength enables the rule of Field validator with the param 5
    />
  )}
</Form>

A validator is a function returns a message when a rule is not fullfilled. A validator is enabled when a prop same as the key. The validator function will be invoked with the field value as the first argument and the prop value as the second argument. Enabled validators on a Field will be called by chronological order defined on props.

You can decide how error is shown by fieldRender.

Submit

Form provides sumbit callback by children render prop, when it's called, all enabled validators get invoked, if anyone fails, onSubmit is skipped, otherwise onSubmit is called with form data.

<Form value={{ a: "x", b: "y" }} onSubmit={({value} => {})}>
  {({ submit }) => (
    <>
      <Field name="a" label="A" />
      <Field name="b" label="B" />
      <button onClick={submit}>submit</button>
    </>
  )}
</Form>

FieldSet

FieldSet is used when your form have multi-layer data structure or you need validation of multi-fields.

// multi-layer form
<Form value={{ a: { b: "b", c: "c" } }}>
  <FieldSet name="a">
    <Field name="b" label="B" />
    <Field name="c" label="C" />
  </FieldSet>
</Form>

// multi-fields validation
<Form value={{ a: "a", b: "b" }}>
  <FieldSet
    validators={{
      same: ({ a, b }) => a !== b && "A and B should be same",
    }}
    same
  >
    {({ error }) => (
      <>
        <Field name="a" label="A" />
        <Field name="b" label="B" />
        {error}
      </>
    )}
  </FieldSet>
</Form>

form's People

Contributors

levinqdl avatar

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.