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

@domain-schema/formik

v0.0.34

Published

React Forms generator for Domain Schema

Downloads

5

Readme

Domain Schema React Forms with Formik

npm version Twitter Follow

Installation

yarn add @domain-schema/formik @domain-schema/core @domain-schema/validation

or

npm install @domain-schema/formik @domain-schema/core @domain-schema/validation

Usage

NOTE: The current version works properly for the web platform only. React Native forms support will be added soon.

Example

Simple form

This is example how you can generate basic form according to schema:

import DomainSchema, { Schema } from '@domain-schema/core';
import { DomainSchemaFormik } from '@domain-schema/formik';

import { Button, Form, RenderField } from '../my-components';

const userFormSchema =
  class User extends Schema {
    __ = { name: 'User' };
    username = {
      type: String,
      input: {
        label: 'Username'
      }
    };
    email = {
      type: String,
      input: {
        type: 'email',
        label: 'Email'
      },
      email: true
    };
    password = {
      type: String,
      input: {
        type: 'password',
        label: 'Password',
      },
      min: 5
    };
    passwordConfirmation = {
      type: String,
      input: {
        type: 'password',
        label: 'Password Confirmation',
      },
      matches: 'password'
    };
  }

// set components globally for all forms
DomainSchemaFormik.setFormComponents({
  input: RenderField,
  form: Form,
  button: Button
});

const userForm =  new DomainSchemaFormik(userFormSchema);

const UserForm = userForm.generateForm({
  label: 'Save'
});

<UserForm onSubmit={values => {
    // handle submit
  }}>

Complex form

The complex form - it is the form that has the nested schema field which represents relations with other schema. So, when one to one relation established - form with flat structure will be generated by default. Also, you could use fieldType property with form value to explicitly set up such behaviour.

const userFormSchema =
  class User extends Schema {
    __ = { name: 'User' };
    username = {
      type: String,
      input: {
        label: 'Username'
      },
      defaultValue: 'User',
      validators: [
        value => {
          return value.length > 3 ? undefined : 'Must Be more than 3 characters';
        }
      ]
    };
    email = {
      type: String,
      input: {
        type: 'email',
        label: 'Email',
        placeholder: 'User email'
      },
      email: true
    };
    profile = {
      type: Profile
    };
    password = {
      type: String,
      input: {
        type: 'password',
        label: 'Password',
      },
      min: 5
    };
    passwordConfirmation = {
      type: String,
      input: {
        type: 'password',
        label: 'Password Confirmation',
      },
      matches: 'password'
    };
  }

class Profile extends Schema {
  __ = { name: 'Profile' };
  firstName = {
    type: String,
    input: {
      label: 'First Name'
    },
    required: {
      value: true,
      msg: 'Required First Name'
    }
  };
  lastName = {
    type: String,
    input: {
      label: 'Last Name'
    },
    optional: true
  };
  user = {
    type: User
  }
}

const userForm =  new DomainSchemaFormik(userFormSchema);

// set components for particular DomainSchemaFormik instance
userForm.setFormComponents({
  input: RenderField,
  form: Form,
  button: Button
});

// change error messages
DomainValidation.setValidationMessages({
  required: ({fieldName}) => {
    return `Field '${fieldName}' is required`
  }
});

const UserForm = userForm.generateForm(
  {
    label: 'Submit',
    className: 'submit-btn',
    disableOnInvalid: false
  },
  { className: 'my-form' }
);

// Defining onSubmit prop is required
<UserForm onSubmit={(values, formikBag) => {
    // handle submit
  }}>

When established one to many relation, the nested schema field which implements
this relation (Group has many users) will be skipped by default. But for nested schema with belonging relation (User belongs to Group) fieldType select will be applied.

class Group extends Schema {
  __ = { name: 'Group' };
  id = {
    type: DomainSchema.Int
  };
  name = {
    type: String,
    input: {
      label: 'Group Name'
    }
  };
  description = {
    type: String,
    input:{ 
      label: 'Group Description'
    }
  };
  users = {
    type: [User]
  };
}
class User extends Schema {
  __ = { name: 'User' };
  id= {
    type: DomainSchema.Int
  };
  name = {
    type: String,
    input: {
      type: 'text',
      label: 'Username'
    },
  };
  email = {
    type: String,
    input: {
      type: 'email',
      label: 'Email',
      placeholder: 'User email'
    }
  };
  group = {
    type: Group
  };
  password = {
    type: String,
    input: {
      type: 'password',
      label: 'Password'
    },
    min: 5
  };
}

const groupForm =  new DomainSchemaFormik(Group);

// set components for particular DomainSchemaFormik instance
groupForm.setFormComponents({
  input: RenderField,
  select: RenderSelectQuery,
  form: Form,
  button: Button
});

const GroupForm = groupForm.generateForm(
  {
    label: 'Submit',
    className: 'submit-btn',
    disableOnInvalid: false
  }
);

// Defining onSubmit prop is required
<GroupForm onSubmit={(values, formikBag) => {
    // handle submit
  }}>

To prevent generating field use ignore flag.

Using different field types

To pass attributes/properties to the field component use input property in a schema. All fields can take 3 special attributes: onChange, onBlur and type. All other defined attributes will be directly passed to the field component. Attribute name will be define automatically and equals field name from the schema.

  • input - is default field type and it can be omitted

      email = {
        ...
        fieldType: 'input',
        input: {
          type: 'email',
          placeholder: 'User Email'
        }
        ...
      }
      post = {
        ...
        // fieldType: 'input'
        input: {
          placeholder: 'Your post',
          type: 'textarea',
          label: 'Post'
        }
        ...
      }
  • checkbox

      active = {
        ...
        fieldType: 'checkbox',
        input: {
          label: 'Active'
        },
        defaultValue: true
      }
  • select

      role = {
        ...
        fieldType: 'select',
        input: {
          label: 'User role',
          values: ['user', 'admin']
        }
        ...
      }
  • radio

      friend = {
        ...
        fieldType: 'radio',
        input: {
          label: 'Very best friend',
          values: ['Gerald', 'Ashley']
        },
        ...
      }

To prevent the generation of a specific field we can use ignore property

  password = {
      type: String,
      input: {
        type: 'password',
        label: 'Password',
      },
      ignore: true
    };

Field components will get next props:

{
      // all props which were specified in the input property in the schema
      ...,
      onChange, // if the callback was not specified in the input property, the Formik's handleChange will be used
      onBlur, // the same as OnChange
      type, // if the type was not specified in the input property, the fieldType will be used, if the fieldType is missing too, 'text' will be used
      name, //  will be define automatically and equals field name from the schema
      value, // if the defaultValue was not specified, the empty will be used as value
      meta // object with touched and error properties from Formik
}

Buttons

To create a submit button in the form we need to pass object with attributes to the generateForm method. All attributes, that we define in the object will be passed to the button:

  ...
  userForm.generateForm({
    label: 'Submit',
    className: 'submit-btn',
    color: 'primary'
  })

By default, submit button is disabled when form is invalid. To deactivate that behaviour we can define disableOnInvalid as false

  userForm.generateForm({
    label: 'Save',
    disableOnInvalid: false
  })

In some cases, the submit button is not enough for us. We should pass object that has submit and reset propperties. Reset button resets the form-data to its initial values.

  userForm.generateForm({
    submit: {
      label: 'Submit',
      className: 'submit-btn'
    },
    reset: {
      label: 'Reset',
      className: 'reset-btn'
    }
  })

For position styling buttons have the align property which can take on values left or right. By default, value is center.

  userForm.generateForm({
    ...
    align: 'left'
  })

Buttons are wrapped in a div with style display: flex, so that any properties for flex items can be applied to them. For example, the order of the buttons can be changed using order.

  ...
  .submit-btn {
    order: 1
  }
  .reset-btn {
    order: 0
  }
  ...
  userForm.generateForm({
    submit: {
      ...
      className: 'submit-btn'
    },
    reset: {
      ...
      className: 'reset-btn'
    }
  })

Set default field types

Default field types can be set globally.

...
DomainSchemaFormik.setDefaultFormFieldTypes({
    oneToOneFieldType: 'form',
    plainFieldType: 'input',
    oneToManyFieldType: 'select'
});
...

Set form components

Form components can be set in two ways. Globally, for all forms:

...
DomainSchemaFormik.setFormComponents({
  input: RenderField,
  select: RenderSelect,
  checkbox: RenderCheckBox,
  form: Form,
  button: Button
});
...

And locally, for particular DomainSchemaFormik instance:

...
const userForm =  new DomainSchemaFormik(userFormSchema);

userForm.setFormComponents({
  input: RenderField,
  select: RenderSelect,
  checkbox: RenderCheckBox,
  form: Form,
  button: Button
});
...

Form submitting

We should define onSubmit callback which is received values from form fields as values and helper methods as formikBag. More about these methods in official docs FormikBag.

<UserForm onSubmit={(values, formikBag) => {
    // handle submit
  }}>

Generate form fields without form

If we need maximum flexibility, we can generate only fields without the form itself. For that we should use generateFields method instead of generateForm. But note, that you should use Formik manually when you generating fields without form.

const fieldSet = userForm.generateFields();
...
return <form>{fieldSet}</form>;

Custom field generation

We can use custom field, defining fieldType as custom and specified field component in component prop. All necessary props can be provided via input.

  myField = {
    fieldType: 'custom',
    component: MyFieldComponent,
    input: {
      // all props that our component may need
    }
  }

Validation

Please check @domain-scheam/validation documentation.

License

Copyright © 2017-2018 SysGears INC. This source code is licensed under the MIT license.