Form container is a lightweight React form container with validation (written in TypeScript). It allows you to use both HTML5 form validation and custom validation functions.
It provides your child form with 2 objects of props:
form
- all data on your form values, states and errorsformMethods
- methods to bind you input controllers and manipulate the form model
Form Container is available as the form-container
package on npm.
Install it in your project with npm
or yarn
npm install form-container
or
yarn add form-container
form-container
exposes connectForm
function to connect an arbitrary form component (WrappedComponent
).
It does not modify the component class passed to it; instead, it returns a new, connected component class for you to use.
-
[
validators: ValidationRule[]
] (Array): An array of rules can be provided to validate the form model against them. Rules are executed in a sequence that is defined in the array. -
[
formConfig: IFormConfig
] (Object): An object contains initial configuration for the forminitialModel: Partial<T>
— object provides initial values to the form fieldsmiddleware: (props: T) => T & M
— function transforms props passed to the wrapped componentonInputBlur: (e: React.ForcusEvent<any>) => void
— function is called on every blur on an input field within the form. Adding a customonBlur
to the input field itself is not recommended, use this method instead
import * as React from 'react';
// bare minimum import
import { connectForm, IFormProps } from 'form-container';
// IFormProps interface contains the props that are passed down from form-container
interface IProps extends IFormProps {}
export class Form extends React.Component<IProps, {}> {
handleSubmit = (e: any) => {
e.preventDefault();
const { model } = this.props.form;
console.log(model);
}
render() {
const { validationErrors, touched } = this.props.form;
const { bindInput, bindNativeInput } = this.props.formMethods;
return (
<form onSubmit={this.handleSubmit}>
<div>
<label>
Required field
<input
{/* HTML attribute to validate required field */}
required={true}
{/* this is how you bind input to a form-container */}
{...bindNativeInput('test')}
/>
<small>{touched.test && validationErrors.test}</small>
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
);
}
}
// no custom validators
const validators: any[] = [];
const formConfig = {
initialModel: {
test: 'foo'
}
}
// attaching our Form to form-container with validation
export default connectForm(validators, formConfig)(Form);
// components/Form.tsx
import * as React from 'react';
import { connectForm, IFormProps } from 'form-container';
interface IProps extends IFormProps {}
// arbitrary form component
export class Form extends React.PureComponent<IProps, {}> {
render() {
const { validationErrors, touched } = this.props.form;
const { bindInput } = this.props.formMethods;
return (
<form>
<div>
<label>
Test:
<input
{/* this is how you bind input to a form-container */}
{...bindInput('test')}
/>
<small>{touched.test && validationErrors.test}</small>
</label>
</div>
</form>
);
}
}
// custom validator
const hasMoreThanFiveChars: ValidationRule = (
prop,
errorMessage = `${prop} is less than 5 chars`,
type: ValidationType = ValidationType.Error
) => [model => (model[prop] ? model[prop].length >= 5 : true), { [prop]: errorMessage }, type];
// all validators for the form
const validators = [
isRequired('test'), // error by default
hasMoreThanFiveChars('test', null, ErrorType.Warning) // optional for warning
];
// attaching our Form to form-container with validation
export default connectForm(validators)(Form);