Forms
Requirements
These forms work only with react stateless components. React hooks should be available.
Installation
npm install @simosol/forms --save
Basic usage
The example, which includes every use case and possible api call.
import * as React from 'react';
import { Form, useForm, useError, useValidated, ValidationRuleSimple } from '@simosol/forms';
import * as rules from '@simosol/forms/lib/rules';
import FormInput, { KeysOfType } from '@simosol/forms/lib/FormInput';
// prepare common rules
const required = rules.required('Field is required'); // accepts message, returns rule function
const email = rules.email('Invalid e-mail'); // accepts message, returns rule function
const ruleNumber = rules.number('Should be a number'); // accepts message, returns rule function
// custom simple validation rule, check min string length
const customRuleMinLength =
(min: number, message: string): ValidationRuleSimple =>
(value: any) => {
if (typeof value !== 'string' || value.length < min) return message;
};
// custom complex rule with dependence of other fields
// one field should be less than other field, if values are numeric
const customRuleLess =
<T, >(otherField: keyof T, message: string) =>
(value: T[keyof T], form: Form<T>) => {
const fieldIsNotEmpty = rules.required()(value) === undefined;
const fieldIsNumber = rules.number()(value) === undefined;
const otherFieldValue = form.getValue(otherField);
const otherFieldValidated = form.isValidated(otherField);
const otherFieldIsNumber = rules.number()(otherFieldValue) === undefined;
if (
fieldIsNotEmpty &&
otherFieldValidated &&
otherFieldIsNumber &&
fieldIsNumber &&
Number(value) >= Number(otherFieldValue)
) {
return message;
}
};
const CompanyRegister = () => {
// prepare data
const data = React.useState(() => ({
companyName: 'Your company name', // pre-filled value
email: '',
revenue: '',
profit: '',
password: '',
passwordConfirm: '',
}))[0];
// create form, using data and validation rules
const form = useForm(
data,
{
companyName: rules.required('Company name is required'), // custom required message
email: [email],
revenue: [required, ruleNumber],
profit: [ruleNumber, customRuleLess('revenue', 'Should be less than revenue')],
password: [rules.required('Password is required'), customRuleMinLength(6, 'Minimum password length is 6')],
passwordConfirm: [
required,
rules.same('password', 'Should be same as password'),
],
},
);
const onSubmitClick = () => {
// if all fields are valid, then do something (send request etc.)
if (form.validateAll()) {
console.log('do something');
}
};
const onErrorClick = () => {
// this is needed, when something went wrong
// show custom email error
form.setError('email', 'E-mail already exists');
};
return (
<div>
<Field field={'companyName'} form={form} label={'Company name'}/>
<Field field={'email'} form={form} label={'E-mail'}/>
<Field field={'revenue'} form={form} label={'Revenue'}/>
<Field field={'profit'} form={form} label={'Profit'}/>
<Field field={'password'} form={form} label={'Password'}/>
<Field field={'passwordConfirm'} form={form} label={'Confirm password'}/>
<div>
<button onClick={onSubmitClick}>Submit</button>
</div>
<div>
<button onClick={onErrorClick}>Error</button>
</div>
</div>
);
};
// simple field component with label and error
const Field = <T, >(
props: { label: string, field: KeysOfType<T, string>, form: Form<T>},
) => {
const { field, label, form } = props;
const error = useError(form, field);
const validated = useValidated(form, field); // if field was validated at least once
const borderColor = validated ? (error ? 'red' : 'green') : 'none';
return (
<div style={{ paddingBottom: 16 }}>
<div>{label}</div>
<div>
<FormInput style={{ borderColor }} field={field} form={form}/>
</div>
<div>{error}</div>
</div>
);
};
export default CompanyRegister;