FormContainer
Notes
A wrapping component for managing field state and form submission.
FormContainer
creates no UI, but passes it's props on to its child, which
is typically a form element. It receives a fields
configuration prop, and decorates it as
fieldsState
. Each field gains dynamic error
, wasChanged
, and wasValid
properties.
A nested input
object maintains properties for the field's associated input
.
i.e. id
, name
, required
, value
, onChange
, onBlur
.
Every change event in the child form
triggers a re-render with updated field
state (including validation).
Props
- children
node
[<div />]
- fieldsshape {required
bool
validatorfunc
}inputobject
[{}]
An object to configure fields using input
names
as the key.Validation can specified for each field in the following ways:
required: true
(default) uses thevalidateExistence
as validatorrequired: false
no validationvalidator
A custom validator function
- focusOnSubmitError
bool
Set focus on the first invalid input during submittals.
- onError
func
[() => {}]
Callback for invalid form submittals. Invoked with validation results for invalid fields.
- onFieldsStateChange
func
[() => {}]
Callback for when the field state has changed. Invoked with
fieldsState
,oldFieldsState
- onFieldUpdateFromEvent
func
[() => {}]
Callback for a when field has been updated from a dom event. Invoked with the
event
,fieldState
. - onSubmit
func
[() => {}]
Callback for valid form submittals. Invoked with form data.
- focusOnInvalidAfterAnimation
bool
Forces
focusOnFirstInvalid
to wait for animations so that focus can be properly applied.
const ExampleFields = ({ fields, isValid }) => {/**** Example of a field state object:* {* error: true, // true when previously valid or the input is blurred* wasBlurred: true,* wasChanged: true,* wasValid: true,* input: {* id: "fieldOne",* name: "fieldOne",* onBlur: handleBlur,* onChange: handleChange,* required: true,* value: ""* }* }*/// console.log('fieldState objects:', fields);const handleClick = () => alert(`This form ${isValid ? 'is' : 'is not' } in a valid state.`)return (<React.Fragment><Field{...fields.fieldOne.input}error={shouldDisplayError(fields.fieldOne)}errorMessage='Please enter a value'className='mb2'>fieldOne</Field><Field{...fields.fieldTwo.input}className='mb2'>fieldTwo (optional)</Field><Field{...fields.fieldThree.input}error={shouldDisplayError(fields.fieldThree)}errorMessage='Please enter digits only'className='mb2'>fieldThree (only digits)</Field><Button type='submit' className='mt2' onClick={handleClick}>Submit</Button></React.Fragment>)};class FormContainerExample extends React.Component {constructor() {super();this.fields = {fieldOne: {},fieldTwo: {required: false},fieldThree: {validator: ({ value }) => {return { error: value === '' || /\D/.test(value) }}}};this.handleSubmit = this.handleSubmit.bind(this);this.handleError = this.handleError.bind(this);}handleSubmit(formData) {// All fields are valid, do something with the formData.// console.log('handleSubmit', formData);}handleError(invalidFields) {// Some fields are not valid.//console.log('handleError', invalidFields);}render() {return (<FormContainerfocusOnSubmitErrorfields={this.fields}onSubmit={this.handleSubmit}onError={this.handleError}><Form requiredIndicatorTextClassName="text-bold"><ExampleFields /></Form></FormContainer>);}}render(<FormContainerExample />);