Code Monkey home page Code Monkey logo

onion-form's Introduction

Onion Form CircleCI Dependency Status

As a developer you are assigned with creating a registration form on Registration page with fields for first name, last name, e-mail and password, validate them and then send all these fields to API. Not again? This package will make your life easier by simplifying the dealing with forms.

yarn add --save onion-form

This package is only meant to be used together with Redux!

TLDR

import { Form, Field, Submit } from 'onion-form';

<Form
  name="signIn"
  onError={({ errors }) => { console.log(errors) }}
  onSubmit={({ values }) => { console.log(values) }}
  validations={{ email: (value) => [((value && !value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)) ? 'wrongFormat' : null)]}}
>
  <Field name='email' type='email' />
  <Field name='password' type='password' />
  <Submit>Sign In</Submit>
</Form>

Usage

// Registration.react.js
import React, { Component } from 'react';
import { Form, Submit, connectField } from 'onion-form';

// validations
const isRequired = (value) => ((!value) ? 'required' : null);
const emailNeedsToContainName = (_, otherValues) => ((!otherValues.email || otherValues.email.indexOf(otherValues.name) === -1) ? 'invalidEmail' : null);
const needLetters = (value) => (value && !value.match(/[a-zA-Z]+/i ? 'needLetters' : null);
const needNumbers = (value) => (value && !value.match(/\d+/i) ? 'needNumbers' : null);

const validations = {
  lastName: [isRequired],
  email: [emailNeedsToContainName],
  password: [needLetters, needNumbers]
};

// You need to have a component which will receive all data by props
// error, hint, label, name, onBlur, onChange, onFocus, onionFormName, tooltip
const BasicInput = (props) => (<input type="text" {...props} />);

// Create your fields (can be used in different forms)
const FirstName = connectField('firstName')(BasicInput);
const LastName  = connectField('lastName')(BasicInput);
const Email     = connectField('email', { type: 'email' })(BasicInput);
const Password  = connectField('password', { type: 'password' })(BasicInput);

export default class RegistrationPage extends Component {

  onSubmit({ values: { firstName, lastName, email, password } }) {
    // apiCall('POST', { firstName, lastName, email, password })
  }

  onError({ errors{ firstName, lastName, email, password } }) {
    // alert, show flash message what ever you need to do when use tryies to
    // submit form and gets validation errors
  }

  render() {
    return (
      <div>
        <h1>Registration</h1>
        <Form
          name="myRegistrationForm"
          onSubmit={this.onSubmit.bind(this)}
          onError={this.onError.bind(this)}
          validations={validations}
        >
          <FirstName label="Your first name" />
          <LastName />
          <Email />
          <Password />
          <Submit>Register</Submit>
        </Form>
      </div>
    )
  }
}

Validations

There are three ways how you can add validations to your form:

  1. Pass an object with validations to the Form component as props (see examples above)
  2. Pass an array of validations to the connectField function: connectField('password', null, [isRequired(), password()])
  3. Specify the validations when the field component is being used:
export default class MyForm extends Component {
  render() {
    return (
      <Form name="myForm">
        <Email validations={[isRequired(), email()]} />
        <Password validations={[isRequired(), password()]}/>
        <Submit>Login</Submit>
      </Form>
    )
  }
}

All validations you specify will be used.

Redux

!You need to add onion form reducer to your reducers and it must be under onionForm first level key!

// store.js
import { createStore, combineReducers } from 'redux';
import { reducer as onionForm } from 'onion-form';

const store = createStore(combineReducers({ onionForm }), {})

Action Creators

We have multiple action creators for communication with reducer: setMultipleFields, setFormFieldProperty, clearForm, clearFormProperty, setFieldValue, setFieldLiveValidation, setFieldError, setFieldApiError All these actions accept formName as the first parameter which needs to match FORM_NAME in <Form name=FORM_NAME/>.

All connected fields get formName from context.

But sometimes you need to communicate with fields from your code and repeating name of the form can be exhausting, so we provide createFormActions(formName) which returns all the actions with formName set.

connectField(FIELD_NAME, DEFAULT_PROPS)(DECORATED_COMPONENT)

DEFAULT_PROPS: can be a plain {} or a function which receives props as the first parameter and needs to return {}. This function gets resolves in render on every rerender. (props) => ({ label: props.msg('key.to.label') })

FIELD_VALUES_FROM_STATE: By default we store these values in redux state:

{
  value: '',
  liveValidation: false,
  error: null,
  apiError: null
}

But you can use setMultipleFields(form, property, values) or setFormFieldProperty(form, field, property, value) to set custom properties which will be then passed to the decorated component as well.

ONION_PROPS: error, hint, label, name, onBlur, onChange, onFocus, onionFormName, tooltip

When you initialize a component in render you can pass the following PASSED_PROPS:

PASSED_PROPS label, onBlur, onFocus, onChange, tooltip, hint, defaultValue They will be transferred to the decorated component. Functions passed by props (onFocus, onChange, onBlur) will get called too, after onion form callbacks.

Passing order of props is: DEFAULT_PROPS -> FIELD_VALUES_FROM_STATE -> ONION_PROPS -> PASSED_PROPS

You can pass defaultValue to component by (PROPS or DEFAULT_PROPS) to set that value to state on componentDid mount when field has no value already set.

connectSubmit(DECORATED_COMPONENT)

You can use connectSubmit which will pass onClick, valid, hasValues, hasErrors and disabled as prop to the decorated component:

// CustomSubmit.react.js
import { connectSubmit } from 'onion-form';

const Button = ({ children, disabled, onClick }) => (
  <button disabled={disabled} onClick={onClick} type="submit">{children}</button>
);

export default const connectSubmit(Button);
  • onClick: callback function for submitting form
  • valid: returns true/false based on fields validations runned against state (errors doesn't need to be in store)
  • hasErrors: returns true if form is invalid (based on state from Redux)

Translations

You need to pass to component function msg('keypath') => string.

Implemetation is your thing but it needs to follow:

msg('key.foo') // returns translation for key.foo
msg(['foo', 'bar']) // returns translation for foo if exists else bar

We use this function to resolve translations for the error, hint, label, tooltip, placeholder props.

error is specific because we are trying to get text by:

const error = field.error || field.apiError;
const errorText = error
  ? msg([`form.${formName}.errors.${error}`, `form.errors.${error}`, `errors.${error}`])
  : '';

others are easier, for example label:

const labelText = label || defaultProps.label || msg([`form.${formName}.${fieldName}.label`, `form.${fieldName}.label`, `${fieldName}.label`]);

!For detailed documentation of all options do yarn test!

Commands

  • yarn test: runs mocha tests
  • yarn test:watch: runs mocha test with watch option
  • yarn coverage: create code coverage report

Made with love by

onion-form's People

Contributors

alcedoatthis avatar honzabrecka avatar imtoo avatar incik avatar janmarsicek avatar kepi74 avatar mikosko avatar ondrejbartas avatar rodan-lewarx avatar tomwagner avatar yavoo avatar zepod avatar

Stargazers

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

Watchers

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

Forkers

czf0321 iq-scm

onion-form's Issues

TypeError: Cannot read property 'oneOfType' of undefined

I'm trying to include onion-form in component
import { Form, Field, Submit } from 'onion-form';
and get an error "TypeError: Cannot read property 'oneOfType' of undefined"

node_modules/onion-form/lib/Form.react.js:270
ScreenShot

React 16.0.0
Immutable 4.0.0-rc.4

How can I fix it?

Unknown props in <input>

error

Warning: Unknown props `onionFieldRegister`, `onionLiveValidate`, `onionOnSubmit`, `field`, `actions`, `error`, `hint`, `onionFormName`, `tooltip` on <input> tag.

Attempting to run the example and a form of my own and receiving this error.

More about this in the docs

Proper clearing form field values

I think that proper way to clean forms values could be set them to undefined value:

value: '',

Now it's clearing to empty string, but this value can be also a user input. And in functionality of setting defaultValue to Input doesn't work correctly. There is one condition which set input fields to defaultValue only if they are undefined:

// Enable to set default value only if value is undefined
if (typeof fieldProps.value !== 'undefined') {
return;
}

So for example if i have one form where some input (eg. select) has defaultValue and i clear this form by action clearForm it clears all values in state with empty string, but default value of this select won't be set because of condition above.

Implement flow-type

Tasks

  • Add flow check into CI workflow (Merged)

  • Implement seamless-immutable instead of immutable (Merged)

  • Add and configurate flow (Merged)

  • Add declarations for node packages (Merged)

  • Type actions (Merged)

  • Type reducers (Tonda's byz)

  • Type components (Tonda's byz)

  • Type helper methods and decorators

  • Create public API for public types

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.