Last update: 2026-04-24
|
|
Breaking Changes
Some method names changed in v7.x |
- API Overview & Conventions
- Configuration Methods
- getConfig()
- setConfig(
config,options) - setFieldsConfig(
config,options) - getFieldsConfig()
- setFieldDefaults(
config) - getFieldDefaults(
key) - setFieldConfig(
fieldname,config,options) - getFieldConfig(
fieldname) - setFieldValidation(
fieldname,config) - getFieldValidation(
fieldname) - isRequired | isFieldRequired(
fieldname) - setRequired | setFieldRequired(
fieldname,enable) - isDisabled | isFieldDisabled(
fieldname) - setDisabled | setFieldDisabled(
fieldname,enable) - setDefaultDisabled(
enable) - isReadOnly | isFieldReadOnly(
fieldname) - setReadOnly | setFieldReadOnly(
fieldname,enable) - setDefaultReadOnly(
enable)
- Field Validation Methods
- Field Error-Message Methods
- Form 'Data' Methods
- Field 'Value' Methods
- Form 'State' Methods
- Form Rendering Methods
- Form-Field Helpers & Handlers
FormManager ("FM") has an extensive API. Everything can be done programmatically, providing control of data, form-state, events, and form fields.
FM exposes only 'methods' — it has no 'properties'.
All data, state and configuration caches are private so they cannot
be directly mutated.
All modifications are performed with getter and setter methods
so everything can be kept synchronized.
You can also attach custom methods or properties to a FM object.
For example, adding a form.submit() method is simpler and more semantic
than passing extra callback props…
// Create a form-manager instance and load the data
this.form = FormManager(this, formConfig, props.data)
// Attach form.submit() and form.refresh() methods
this.form.submit = this.submitChanges
this.form.refresh = this.fetchLatestData
// Pass only a 'form' prop to all subcomponents
<FormSectionOne form={this.form} />
<FormSectionTwo form={this.form} />FM obeys the configuration rules specified. This can be updated on-the-fly using configuration API methods. FM can also integrate seamlessly with custom logic or helpers.
Many getter & setter methods have similar names, except that
one is 'singular' (eg: getValue) and
one is 'plural' (eg: getValues).
These are different methods with different argument signatures.
-
Singular method-names usually apply to one specific field, so the first argument is always a fieldname.
-
Plural method-names usually apply to all fields -or- multiple fields, so the first argument is an object, an array, or nothing!
// GETTERS
const username = form.getValue('username') // One value
// OR
const fieldValues = form.getValues() // All field values
const username = fieldValues.username
// SETTERS
form.setValue('username', 'john-smith')
form.setValue('email', 'john-smith@gmail.com')
// OR
form.setValues({
username: 'john-smith',
email: 'john-smith@gmail.com'
})Some methods have alternate, shorter alias names to aid code brevity, like:
-
isFieldDisabled→isDisabled -
getMuiFieldProps→allMuiProps -
getValue→value -
getError→error
These are especially useful when used repeatedly in markup, like:
<TextField label="First Name" {...form.allMuiProps("firstName")} />
<TextField label="Middle Name" {...form.allMuiProps("middleName")} />
<TextField label="Last Name" {...form.allMuiProps("lastName")} />All setter methods return the FormManager object so multiple commands can be chained. This is just a convenience — it does not change how the methods work.
form.setFieldRequired('phone')
form.validate('phone')
// Is the same as...
form.setFieldRequired('phone')
.validate('phone')An alias-name can be specified for any field. This helps normalize fieldnames across different datasets, and simplifies the concatenated names required for nested data fields.
An alias can be passed to any FM method. In the examples below, each pair of commands are equivalent — one using the full fielname and one the aliasName. Note how the alias makes code easier to write and read.
// Set an aliasName for a deeply nested field
const formConfig = {
fields: {
'profile.contacts.primaryPhone': {
aliasName: 'phone'
}
}
}
const phone = form.getValue('profile.contacts.primaryPhone')
const phone = form.getValue('phone')
form.setFieldDisabled('profile.contacts.primaryPhone')
form.setFieldDisabled('phone')
<TextField
label="Phone"
{...form.allMuiProps('profile.contacts.primaryPhone')}
/>
<TextField label="Phone" {...form.allMuiProps('phone')} />Every aspect of FM is controlled by the form-configuration. Normally you provide a set of configuration options when you create a FM instance for a form. However all configuration is dynamic, and can be changed at any time. The most common configuration changes have special methods to simplify things. For example, changing field validation rules, disabling one or all fields, changing the error-messages (eg: a different language), etc.
-
@returns: Deep-clone of the entire form-configuration {object}
const formConfig = form.getConfig()
-
-
config* {object}
An object containing some form configuration. -
options{object}-
options.replace{boolean} @default:false
By default the passedconfigdata is merged with the existing form configuration.
Pass{ replace: true }to replace the entire form config.
-
@returns: FormManager {object}
Modifies the form configuration.
The config structure is the same as the initial form configuration. See FormManager Configuration for details.
-
-
-
config* {object|array<object>}
An object containing somefieldsconfiguration. -
options{object}-
options.replace{boolean} @default:false
By default the suppliedconfigdata is merged with the existing field config.
Pass{ replace: true }to replace the config of each field specified.
-
@returns: FormManager {object}
Modifies the configuration of multiple form fields.
The config structure is the same as the initial formfieldsconfiguration. See FormManager Configuration for details.form.setFieldConfig( 'password', { disabled: true } )
-
-
@returns: Fields Config {object}
💡Use getFieldConfig(fieldname)to get a field-config using an alias-name.const allConfig = getFieldsConfig() // Fields config is keyed by REAL fieldnames, not aliases const emailConfig = allConfig['profile.primaryEmail'] // Read field data const emailAlias = emailConfig.aliasName // "email" const emailRequired = emailConfig.validation.required
-
-
config* {object}
An object containing somefieldDefaultsconfiguration.
@returns: FormManager {object}
Modifies the configuration for field-defaults.
The config structure is the same as the initial formfieldDefaultsconfiguration. See FormManager Configuration for details.form.setFieldDefaults({ validateOnChange: true, cleaning: { trim: true, trimInner: true } })
-
-
-
key* {string}
A simple key or a concatenated path like"cleaning.trim"
@returns: A fields-default value {any}
const allFieldsDisabled = form.getFieldDefaults('disabled')
-
-
-
fieldname* {string} -
config* {object}
An object containing some field configuration. -
options{object}-
options.replace{boolean} @default:false
By defaultconfigdata is merged with existing configuration.
Pass{ replace: true }to replace the entire field config.
-
@returns: FormManager {object}
Modifies the configuration of a single form field.
The config structure is the same as the initial configuration for a field. See FormManager Configuration for details.form.setFieldConfig('password', { disabled: true })
-
-
-
fieldname* {string}
@returns: Field Configuration {(object|undefined)}
Returns a copy of current field configuration.
Can be used to inspect the current settings, or as a starting point for creating an updated config.// Get the field configuration const emailConfig = form.getFieldConfig('email') // Read some values from the config data const { dataType, inputType, inputFormat } = emailConfig const { required, minLength } = emailConfig.validation
-
-
-
fieldname* {string} -
config* {object}
A validation configuration — the same as for the initial form-config.
See FormManager Configuration for details.
@returns: FormManager {object}
setFieldValidation( 'username', { required: true, minLength: 8, maxLength: 24 } )
-
-
-
fieldname* {string}
@returns: Field Validation Configuration {object}
Returns a copy of current field validation configuration.
Can be used to inspect the current settings, or as a starting point for creating an updated config.const passwordValidationConfig = getFieldValidation('password')
-
-
-
fieldname* {string}
@returns: true|false {boolean}
const isEmailRequired = form.isRequired('email')
-
-
-
fieldname* {string} -
enable{boolean} @default:true
Pass a falsey value to make field not required
@returns: FormManager {object}
// Set Email field to be required form.setRequired('email') form.setRequired('email', true) // Set Email field to be not-required form.setRequired('email', false)
-
-
-
fieldname* {string}
@returns: true|false {boolean}
Returns the derived state of field-disabled.
ReturnsfieldDefaults.disabledvalue iffieldConfig.disabledis not explicitly set.const isEmailDisabled = form.isDisabled('email')
-
-
-
fieldname* {string} -
enable{boolean} @default:true
Pass a falsey value to make field not disabled
@returns: FormManager {object}
// Set Email field to be disabled form.setDisabled('email') form.setDisabled('email', true) // Un-set Email disabled - will now follow fieldsDefault form.setDisabled('email', false)
-
-
-
enable{boolean} @default:true
Pass a falsey value to make fields default not disabled.
@returns: FormManager {object}
handleSubmit() { const { form } = this // Disable ALL form fields while submitting form.setDefaultDisabled(true) form.validateAll().then(isValid => { if (isValid) { // post the data... } else { // Re-enable all form fields form.setDefaultDisabled(false) } } }
-
-
-
fieldname* {string}
@returns: true|false {boolean}
Returns the derived state of field-readOnly.
ReturnsfieldDefaults.readOnlyvalue iffieldConfig.readOnlyis not explicitly set.const isEmailReadOnly = form.isReadOnly('email')
-
-
-
fieldname* {string} -
enable{boolean} @default:true
Pass a falsey value to make field not readOnly
@returns: FormManager {object}
// Set Email field to be read-only form.setReadOnly('email') form.setReadOnly('email', true) // Un-set Email read-only - will now follow fieldsDefault form.setReadOnly('email', false)
-
-
-
enable[.small]#{boolean} @default:true
Pass a falsey value to make field default not readOnly
@returns: FormManager {object}
💡Material-UI < 4.x does not pass-through the readOnly attribute from props, so do this explicitly if you use readOnly.
See the example below.// Set all fields to be read-only setDefaultReadOnly() setDefaultReadOnly(true) // Remove default readOnly state for all fields setDefaultReadOnly(false) // Explicitly set input.readOnly for Material-UI < 4.x <TextField label="Username" {...form.allMuiProps('username')} inputProps={{ readOnly: form.isReadOnly('username') }} />
-
Validation can be configured for fields that require it,
inside a validation key in the field configuration.
Validation can be changed or overridden programatically.
-
-
fieldname{string}
@returns: Validation-Promise {Promise}
💡If no fieldname is passed, then is same as calling validateAll().Manually trigger validation of a single form-field.
form.validate('password')
-
-
@returns: FormManager {object}
Manually trigger validation of ALL form-fields.
form.validateAll()
|
ℹ️
|
See Configuration Methods for validation configuration methods. |
|
💡
|
It is easier and less error-prone to use the field-level error-handling features than to manually manage errors via error-setter methods. |
Error-Messages are part of form configuration so can be changed on-the-fly like all configuration. This can be used to switch error-message languages. (See example below.)
-
-
errorMessages* {object}
@returns: FormManager {object}
import { englishErrors, frenchErrors } from './formErrorMessages' function setErrorLanguage( language ) { form.setErrorMessages( `${language}Errors` ) }
-
-
-
fieldname* {string}
@returns: true|false {boolean}
form.validate('password') // If not already validated const passwordFieldHasError = form.hasError('password')
-
-
@returns: true|false {boolean}
form.validateAll() // If not already validated const formHasSomeErrors = form.hasErrors()
-
-
fieldname* {string} -
options{object}-
options.asArray{object} @default:false
Return field-errors as an array instead of a concatenated string.
-
Get error(s) for one field, as a string or an array.
By default errors are returned as a linebreak-delimited string so it can be rendered as-is. If returned as an array, errors must be iterated.@returns: FormManager {object}
// Add a "whiteSpace" style so text line-breaks render correctly, // plus cosmetic styles so errors looks nice <div style={{ whiteSpace: 'pre-line', lineHeight: '1.3em', color: 'red' }}> {form.error('password')} </div> // Get errors as an array and render them one-by-one {form.hasError('password') && <ul> { const arrErrors = form.getError('password', { asArray: true }) } {arrErrors.map( error => ( <li>{error}</li> )} </ul> }
-
-
-
fieldname* {string} -
type* {string}
A validation type like "required", "minLength", "custom", etc. -
errorMessage{string|array<string>}
A single error-message or an array of error-messages.
If a falsey value or an empty array is passed, it means clear the error of this type.
@returns: FormManager {object}
ℹ️Error messages use a templating system with variable replacement:
-
{name}is replaced with the field’sdisplayName,aliasNameorname -
{value}is replaced with the field-value being validated
form.setError( 'username', 'custom', // The '{name}' param will be replaced with "Username" '{name} can contain only letters and dashes' )
-
-
-
errors* {object}
An object of errors with fieldnames as keys and error-types as subkeys. If no error-type keys exists, it is assumed to becustom. -
options{object}-
options.merge{object} @default:true
By default the passed errors are merged with existing errors.
Passmerge: falseto replace all existing errors.
-
@returns: FormManager {object}
💡You can use alias-names as field keys, even though real fieldnames are used internally to cache field errors. form.setErrors( { username: { require: 'A username is required' }, password: { minLength: 'Passwords must be at least 8 characters', // Any 'key' can be used for custom errors anything: 'Passwords should contain at least one symbol' }, // This will become a 'custom' error-type email: 'Please enter an email address' }, { merge: false } )
-
-
-
fieldname* {string}
@returns: FormManager {object}
Remove all errors from a single field — every validation-type.
form.clearError('username')
-
-
-
fieldnames{array<string>}
Clears all errors for all fieldnames in this array.
If no fieldnames passed, then same as callingclearAllErrors().
@returns: FormManager {object}
// Clear specific fields form.clearErrors([ 'username', 'password' ]) // Clear all fields form.clearErrors() // is same as form.clearAllErrors()
-
The 'form data' is the source for 'field values'.
Generally you only use 'data' methods when setting form data from the server,
or preparing to post data to the server.
Also see Field 'Value' Methods
-
@returns: All data {object}
// Get and submit all data - after validating it form.validateAll() .then(isValid => { if (isValid) { const formData = form.data() postToServer( formData ) } // If validation failed, field-errors will display }
-
-
fieldname* {string}
@returns: Field value (cloned) {any}
const phone = form.data('phone')
-
-
-
data* {object}
@returns: FormManager {object}
ℹ️When 'data' is set, it also updates the initial-data cache, so a form.reset()will retain this value.
To set temporary values, usesetValue()instead.form.setData({ phone: '6045551212', email: 'john.smith@gmail.com' })
-
-
-
fieldname* {string} -
value{any}
@returns: FormManager {object}
ℹ️When 'field-data' is set, it also updates the initial-data cache, so a form.reset()will retain this value.
To set temporary values, usesetFieldValue()instead.form.setFieldData('phone', '6045551212')
-
-
-
fieldname* {string} Pass a fieldname to check whether that field is unchanged
@returns: true|false {boolean}
Returns clean-state for a single field or entire form.
const isDataChanged = !form.isClean()
-
-
-
fieldname* {string} Pass a fieldname to check whether that field is changed
@returns: true|false {boolean}
Returns dirty-state for a single field or entire form.
const isDataChanged = form.isDirty()
-
The 'field values' are the raw value props of the form-fields.
Values may differ from 'form data' in data-type or format.
If you 'set' a value, it will be coerced into the format
set in the field’s configuration.
Also see Form 'Data' Methods
-
-
fieldname* {string} -
options{object}-
options.clean{boolean} @default:false
Apply cleaning to field value before returning it.
-
@returns: Field value {any}
const phone = form.getValue('phone', { clean: true })
-
-
@returns: Form-field values {object}
Returns a deep-clone of form values to preserve immutability.
const formValues = form.values()
-
-
fieldname* {string} -
value* {any} -
options{object}-
options.validate{boolean} @default:false
Validate the field after setting the new value.
-
Value is automatically converted to the correct data-type and reformatted as specified in the field configuration.
@returns: FormManager {object}
form.setValue('phone', '604-555-1212', { validate: true })
-
-
-
values* {object}
An 1-level object with fieldnames as keys and field-values as values. -
options{object}-
options.clean{boolean} @default:false
Clean the value per the config settings. -
options.validate{boolean} @default:false
Validate the field after setting the new value.
-
Field-values is a single-level object so nested keys must use a dot-delimited format like
'user.profile.homePhone'. However field alias-names can also be used as keys.@returns: FormManager {object}
form.setValues( { // 'phone' is the aliasName for 'user.profile.homePhone' phone, '604-555-1212', 'user.profile.nickname': 'symore', rememberMe: true }, { validate: true } )
-
-
-
key* {string}
The key to get from form-state. Nested values can be specified using a dot-delimited key likecategory.selected. Can also pass a fieldname-alias here. -
options{object}-
options.clone{boolean} @default:false
Return a shallow-clone of the state value, if applicable. -
options.cloneDeep{boolean} @default:false
Return a deep-clone of the state value, if applicable.
-
@returns: State-value {any}
Returns a value from form-state, or undefined if key/path does not exist.
// Add user data to form-state form.setState('user', this.props.userProfile) // Read nested data from form-state const username = form.state('user.nickname')
-
-
-
key* {string}
The key to set in form-state. Nested values can be set by passing a dot-delimited key likecategory.selected. Can also pass a fieldname-alias here. -
value{any}
Anything can be stored in form-state.
If no value is passed, the specified key will be deleted. -
options{object}-
options.update{boolean} @default:true
Re-render component after updating state. -
options.clone{boolean} @default:true
Shallow-clone the new state value, if applicable. -
options.cloneDeep{boolean} @default:false
Deep-clone the new state value, if applicable. (overrides 'clone')
-
@returns: FormManager {object}
Sets a value in FM state so is accessible everywhere.
// Add user data to form-state form.setState('user', this.props.userProfile) // Remove user data from form-state form.setState('user', undefined) // or just form.setState('user')
-
-
@returns: FormManager {object}
Forces a re-render of the component FM is inside.
A render is automatically triggered when necessary. However, if you programmatically change form configuration, you need to manually trigger an update for the changes to take effect. This method provides that, and also increments the form revision value.form.update()
-
@returns: Revision {integer}
UID useful for forcing component re-rendering.
If usingReact.PureComponentor a customshouldComponentUpdate(), some prop must change to trigger a component render. Since the form-manager object/prop never changes, another prop is needed to force component updates. The form revision number provides this prop. It increments each time anything in FM changes — including every keystroke!<FormFields form={this.form} rev={this.form.revision()} />
These methods are generally used only in form-field props, but the event handlers can also be triggered programmatically.
-
-
fieldname* {string} -
options{object}-
options.inputType{string} @default:null
Allows overriding theinputTypeset in field configuration.
-
@returns: Data-related props {object}
This helper returns many props, including value & name, input attributes, aria attributes, and event handlers.
<label> <input {...fieldProps('password'} /> Remember Me </label> <Switch label="Remember Me" {...fieldProps('password'} />
-
-
-
fieldname* {string}
@returns: Error-related props {object}
This helper is specific to Material-UI components.
This returns only:error={hasError(fieldname)}andhelperText={getError(fieldname)}<TextField label="Full Name" {...form.fieldProps('name')} {...form.muiErrorProps('name')} /> // Is the same as... <TextField label="Full Name" {...form.allMuiProps('name')} />
-
-
-
fieldname* {string} -
options{object}
Options are passed-through tofieldProps(); see below.
@returns: FormManager {object}
This helper is specific to Material-UI components.
It returns the combined fields from:fieldProps(fieldname)(any field) andmuiErrorProps(fieldname)<TextField label="Password" {...allMuiProps('password')} />
-
-
-
event_or_fieldname* {string} — either:-
event{Event}
The DOM Event object returned if bound to onChange, etc. -
fieldname{string}
Fieldname, for calling this handler manually.
-
-
value{any}
Value, for calling this handler manually
(event.target.valueused if a value not passed)
@returns: FormManager {object}
<input name="note" onChange={form.onChange} /> <DatePicker onChange={date => form.onChange('birthdate', date)} />
-
-
-
event_or_fieldname* {string} — either:-
event{Event}
The DOM Event object returned if bound to onChange, etc. -
fieldname{string}
Fieldname, for calling this handler manually.
-
-
value{any}
Value, for calling this handler manually
(event.target.valueused if a value not passed)
@returns: FormManager {object}
<input name="note" onChange={form.onBlur} /> <DatePicker onBlur={date => form.onBlur('birthdate', date)} />
-
-
-
event_or_fieldname* {string} — either:-
event{Event}
The DOM Event object returned if bound to onChange, etc. -
fieldname{string}
Fieldname, for calling this handler manually.
-
-
value{any}
Value, for calling this handler manually
(event.target.valueused if a value not passed)
@returns: FormManager {object}
<input name="note" onFocus={form.onFocus} /> <DatePicker onFocus={date => form.onFocus('birthdate', date)} />
-