@domain-schema/formik
v0.0.34
Published
React Forms generator for Domain Schema
Downloads
5
Readme
Domain Schema React Forms with Formik
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 omittedemail = { ... 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.