React form library with full customizable and extensible. This library help you create form with your own style.
This library doesn't add any style to your form component. It let style of form to your imagination.
npm install react-craftform --save
react-craftform created with HOC in mind. react-craftform provide function called withForm for providing existing form power!
import React from 'react';
import {withForm, validator, hasError} from 'react-craftform';
const MyForm = (props) => {
return (
<form>
<section className="name_section">
<label>Name</label>
<input type="text" className="name" onChange={props.form.handleChange("name")} value={props.form.values['name']}/>
</section>
<p>Name Value: {props.form.values['name']} </p>
<section className="code_section">
<label>Last Name</label>
<input type="text" className="code" onChange={props.form.handleChange("lastname")} value={props.form.values['lastname']} />
</section>
<p>LastName Value: {props.form.values['lastname']} </p>
{hasError(props.form.errors) ? "There is an error" : "No Error, Huley"}
</form>
);
}
export default withForm(MyForm,{
name:["",["required"]],
lastname:["myinitalCode"]
});withForm take 2 parameters. First parameter it takes is your form component. Second parameter is description about your controls.
Let's take a look at withForm function.
export default withForm(MyForm,{
name:["",["required"]],
lastname:["myinitilCode"]
});MyForm component will receive object called forn via props for managing control (eg. handling onChange event, geting value and errors).
Second parameter is object which property name is your control name. Each control name's value is array which for specifying initial value at index 0 and Validators at index 1.
In above code, we tell withForm that it has 2 controls which name are name and lastname. name control have no initial value
and is required and lastname control have initial value which is "initialCode" and is opional.
withForm doesn't update value for you so that you can customize as you want. Instead, it help you by providing form object via props with have method for update value.
form props has handleChange method for updating value. handleChange accept control name.
<input type="text" className="name" onChange={props.form.handleChange("name")} value={props.form.values['name']}/>
<input type="text" className="code" onChange={props.form.handleChange("lastname")} value={props.form.values['lastname']} />You can get value of control by call props.form.values[controlname].
As above exmaple, we pass props.form.values['name'] to input attribute value for name control and props.form.values['lastname'] for lastname control.
You can add validator easily in description object.
import { validator } from 'react-craftform';
...
export default withForm(MyForm,{
name:["",["required",validator.minLength(3)]],
lastname:["myinitilCode",validator.minLength(5)]
});You can use built-in validator provided by this library or create your own validator (I promise it's easy).
Error object will be generated according to specified validators.
You can get error object in props.form.errors[controlname].
Error object has property name indicating what validator that control violate and it's value is detail about the error you can leverage (eg. showing more meaningful error message)
As above example, there'll be initial error for name and lastname controls.
props.form.errors['name']; // { required: true, minLength: {length: 0, minRequired:3 }}
props.form.errors['lastname']; // { maxLength:{length: 12, maxRequired:3 }}You can use error object for showing in error message and/or prevent submit if there's an error. We will explain in Error message section and preventing user submit form section
| Function | String | example of error object |
|---|---|---|
| validator.required | "required" | { required:true } |
| validator.minLength(minRequired) | - | { minLength:{ length:3, minRequired:4 } length is current length of control |
| validator.maxLength(maxRequired) | - | { maxLength:{ length:6, maxRequired:4 } length is current length of control |
Validator is just a function. You can provide your own easily.
...
const haveToBeCat = (val) => {
if(val === "cat"){
return false;
}else{
return {
havetoBeCat:true
}
}
};
export default withForm(MyForm,{
name:["",[haveToBeCat]],
lastname:["myinitilCode",validator.maxLength(3)]
});In the above example, we create function called haveToBeCat. It will be called and provided current value of control to first parameter by library so you can use it to check current value against your specified rule.
When create your own custom validator, just remember 2 things
- if value is valid, just return false.
- if value is invalid, return object which propery name is meaningful name. You will be use that name for showing error message.
haveToBeCat works great but you can refactor haveToBeCat to be more reuseable.
const haveToBeSomething = (word) => {
return (val) => {
if(val === word){
return false;
}else{
return {
havetoBeSomething:{
expectedValue:word,
value:val
}
}
}
}
};
const haveToBeCat = haveToBeSomething("cat");
const haveToBeDog = haveToBeSomething("dog");
export default withForm(MyForm,{
name:["",[haveToBeCat]],
lastname:["myinitilCode",haveToBeDog]
});May functional programing be with you.
You can provide error message by calling errorMessage function. It accept one parameter and return another function which accept error object and return component we provide. It use currying function style.
If you're confused, don't worry just let code exlain itself.
...
import {withForm, validator, hasError, errorMessage} from 'react-craftform';
const MyForm = (props) => {
return (
<form>
<section className="name_section">
<label>Name</label>
<input type="text" className="name" onChange={props.form.handleChange("name")} value={props.form.values['name']}/>
</section>
<p>Name Value: {props.form.values['name']} </p>
{
errorMessage({
minLength:()=>{
return (<p>Please fill control with 5 length</p>);
},
required:()=>{
return (<p>Please fill input</p>);
},
})(props.form.errors['name'])
}
<section className="code_section">
<label>Last Name</label>
<input type="text" className="code" onChange={props.form.handleChange("lastname")} value={props.form.values['lastname']} />
</section>
<p>LastName Value: {props.form.values['lastname']} </p>
{
errorMessage({
minLength:()=>{
return (<p>Please fill control with 5 length</p>);
},
required:()=>{
return (<p>Please fill input</p>);
},
})(props.form.errors['lastname'])
}
</form>
);
}
export default withForm(MyForm,{
name:["",["required"]],
lastname:["",[validator.minLength(5)]]
});It works great but there's duplicated code for name and lastname controls. You can get rid of it by creating function and return invoking errorMessage function.
const errorSpec = errorMessage({
minLength:()=>{
return (<p>Please fill control with 5 length</p>);
},
required:()=>{
return (<p>Please fill input</p>);
}
});
const MyForm = (props) => {
return (
<form>
<section className="name_section">
<label>Name</label>
<input type="text" className="name" onChange={props.form.handleChange("name")} value={props.form.values['name']}/>
</section>
<p>Name Value: {props.form.values['name']} </p>
{
errorSpec(props.form.errors['name'])
}
<section className="code_section">
<label>Last Name</label>
<input type="text" className="code" onChange={props.form.handleChange("lastname")} value={props.form.values['lastname']} />
</section>
<p>LastName Value: {props.form.values['lastname']} </p>
{
errorSpec(props.form.errors['lastname'])
}
</form>
);
}Just assign variable to errorMessage with how to render error message.
You can provide error information easily for showing error message
const errorSpec = (name) => {
return errorMessage({
minLength:()=>{
return (<p>Please fill control {name} with 5 length</p>);
},
required:()=>{
return (<p>Please fill control {name}</p>);
}
});
};
...
const MyForm = (props) => {
return (
...
{
errorSpec('name')(props.form.errors['name'])
}
..
)
}It's the same as built-in validator. Let me show you
const haveToBeSomething = (word) => {
return (val) => {
if(val === word){
return false;
}else{
return {
havetoBeSomething:{
expectedValue:word,
value:val
}
}
}
}
};
const haveToBeCat = haveToBeSomething("cat");
const haveToBeDog haveToBeSomething("dog");
const errorSpec = () => {
return errorMessage({
...
havetoBeSomething:() => {
return (<p>Please fill cat!</p>)
}
});
};It's easy but there's one problem, error message for havetoBeSomething assume to be "cat". How about dog, pig, elephant or whatever?
Luckily we can handle this issue in easy way.
const errorSpec = () => {
return errorMessage({
...
havetoBeSomething:(def) => {
return (<p>Please fill {def.expectedValue}! Now you provide {def.value}</p>)
}
});
};errorMessage will be provided corresponding error object in parameter of function. So you can use it for providing more meaningful error message.
validator.minLength and validator.maxLength are also provide error object. you can look at here
withForm doesn't handle submit form. We want you to have full control.
Provided props to withForm component will go to your form component as well. So you can add callback for onSubmit event via props.
const MyForm = (props) => {
const onSubmit = (evt) => {
evt.preventDefault();
props.onSubmit(props.form.values);
};
return (
<form onSubmit={onSubmit}>
<section className="name_section" >
<label>Name</label>
<input type="text" className="name" onChange={props.form.handleChange("name")} value={props.form.values['name']}/>
</section>
<p>Name Value: {props.form.values['name']} </p>
{
errorSpec()(props.form.errors['name'])
}
<section className="code_section">
<label>Last Name</label>
<input type="text" className="code" onChange={props.form.handleChange("lastname")} value={props.form.values['lastname']} />
</section>
<p>LastName Value: {props.form.values['lastname']} </p>
{
errorSpec()(props.form.errors['lastname'])
}
<button type="submit">Submit</button>
</form>
);
}There's no difference for handling form in normal way, except you can get value from props.form.values which it's object whose properies is control name and it's value is corresponding control value.
You can check there's an error easily with hasError function.
...
const MyForm = (props) => {
const onSubmit = (evt) => {
evt.preventDefault();
if(hasError(props.form.errors)){
window.alert("There's an error");
}else{
props.onSubmit(props.form.values);
}
};
return (
<form onSubmit={onSubmit}>
...
);
}