Home

Awesome

npm version

hyperapp-forms

Hyperapp form state management library

Heavily inspired by redux-form

Installation

npm i -S hyperapp-forms

Usage

Import

Add the imported actions object contents to the main actions object.


import forms from 'hyperapp-forms';

..

const actions = {
  ..

  ...forms,
};

..

app(state,actions,view,document.body);

Field components

Wrap your input components with the Field decorator.

Textbox.js

import { h } from 'hyperapp';
import {Field} from "hyperapp-forms";

const Textbox = ({ input, type, name, title, disabled }) => {
  const showError = (input.touched || input.submitted) && !!input.error;
  return (
    <label>
      {title}
      <input type={type}
             name={name}
             value={input.value}
             disabled={disabled}
             onchange={input.onchange}
             onfocus={input.onfocus}
      />
      {showError && <sup>{input.error}</sup>}
    </label>
  );
};

export default Field(Textbox);

The attributes the Field decorator adds to the component are:

AttributeTypeDescription
formstringThe form's name
namestringThe field's name
validatefunction(form, name, values) : ObjectA validate function to run after change

Actions

changeAndValidate({ form, name, value, validate })

Changes a value for a certain field, also runs the validate function and updates the sync errors accordingly.

validate is a callback with the following structure validate(form, name, values) (see explanation above).

touch({ form, name })

Sets the field as been touched.

startSubmit({ form })

Sets the form's status to be submitting

stopSubmit({ form, errors })

Sets the form's status to be not submitting, and apply server errors by matching field names.

Selectors

SelectorDescription
getFormValues(state, form)Get an object with the form values
isSubmitting(state, form)Is the form submitting
isValid(state, form)Is the form valid (are there any errors)
wasSubmitted(state, form)Was the form submitted at least once (useful for showing errors)
getFieldValue(state, form, field)Get a certain field value
getFieldError(state, form, field)Get a certain field error
isFieldTouched(state, form, field)Was field touched (useful for showing errors)

Submission and error handling

handleSubmit(state, actions, form, callback)

Use handleSubmit in the form's onsubmit (or any button's callback, see example below),

Supply a callback function which will return a promise, which at first will start the form's submission automatically.

And once resolved or rejected will stop the form's submission.

The callback function needs to be in the following structure:

callback(values, actions) : Promise

The resolve or reject argument should be

Usage example

Checkout a working example: hyperapp-less-boilerplate


const signIn = (values, actions) => new Promise((resolve, reject) => {
  setTimeout(() => {
    if (values.username === 'test') {
      actions.login.login();
      resolve();
    }
    else {
      reject({ username: 'Not "test"!'});
    }
  }, 2000);
});

const validate = (form, name, values) => {

  let errors = null;

  const usernameInvalid = !/^t/.test(values.username);
  if (usernameInvalid) {
    if (!errors) errors = {};
    errors.username = 'not starting with t!';
  }

  const passwordInvalid = !values.password;
  if (passwordInvalid) {
    if (!errors) errors = {};
    errors.password = 'password is required!';
  }

  return errors; // if everything is valid, returns null
};


export default (state, actions) => {

  const submitting = isSubmitting(state, 'login');

  return (
    <form onsubmit={handleSubmit(state, actions, 'login', signIn)}>

      <h2>Login to your account:</h2>

      <Textbox type="text" form="login" name="username" title="Username" disabled={submitting} validate={validate}/>
      <Textbox type="password" form="login" name="password" title="Password" disabled={submitting} validate={validate}/>

      <Checkbox form="login" name="rememberMe" title="Remember me" disabled={submitting}/>

      <button disabled={submitting}>Sign In</button>

      {submitting && <div data-loader />}

    </form>
  );
});