Form configuration module can be created using [%form]
extension:
module MyForm = [%form
type input;
type output;
...
];
Requirements: Required. Must be a record.
Form input data.
type input = {email: string};
See IO & Basic Usage.
Requirements: Optional.
Attribute for a field with async validation.
type input = {email: [@field.async] string};
// OnChange mode
// Default, use it if you want to be explicit.
type input = {email: [@field.async {mode: OnChange}] string};
// OnBlur mode
type input = {email: [@field.async {mode: OnBlur}] string};
See Async Validation.
Requirements: Optional. If provided, must be an array.
Attribute for a collection field.
type input = {
authors: [@field.collection] array(author),
}
and author = {name: string};
See Collections.
Requirements: Optional.
Dependent fields attribute.
type input = {
a: [@field.deps b] string,
b: string,
};
See Dependent Fields.
Requirements: Optional. If provided, must be a record with the same set of fields as in input
.
Default: input
Form output data.
type output = {email: Email.t};
See IO & Basic Usage.
Requirements: Optional.
Default: string
Type of error messages.
type message = I18n.t;
See Basic Usage & I18n.
Requirements: Optional.
Additional metadata.
type metadata = { items: array(Item.t) };
See Metadata.
Requirements: Optional.
Default: unit
Type of submission error.
type submissionError =
| UserNotFound
| UnknownError;
See Form Submission.
Requirements: Optional int
.
Default: 700
Debounce interval in ms for async validators in OnChange
mode.
let debounceInterval = 1000;
See Async Validation.
Requirements: Required. Must be a record with the same set of fields as in input
/output
.
Validators record.
// Pseudo code
let validators = {
// General field
field: {
strategy: Strategy.t,
validate: input => result('outputValue, message),
},
// Field of collection
fieldOfCollection: {
collection: input => result(unit, message), // or None
fields: {
strategy: Strategy.t,
validate: (input, ~at: int) => result('outputValue, message),
},
},
// Validator with `metadata`
field: {
strategy: Strategy.t,
validate: (input, metadata) => result('outputValue, message),
},
// Async field
asyncField: {
strategy: Strategy.t,
validate: input => result('outputValue, message),
validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
},
// Async field of collection
asyncFieldOfCollection: {
strategy: Strategy.t,
validate: (input, ~at: int) => result('outputValue, message),
validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
},
// Async field with metadata
asyncFieldWithEq: {
strategy: Strategy.t,
validate: (input, metadata) => result('outputValue, message),
validateAsync: ('outputValue, metadata) => Js.Promise.t(result('outputValue, message)),
},
// Async field with eq function
asyncFieldWithEq: {
strategy: Strategy.t,
validate: input => result('outputValue, message),
validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
eq: ('outputValue, 'outputValue) => bool,
},
// Field without validator
fieldWithoutValidator: None,
};
See Validation Strategies, Basic Usage, Async Validation & Collections.
Module created via [%form]
extension exposes useForm
React hook.
React hook.
// General
MyForm.useForm(
~initialInput: MyForm.input,
~onSubmit: (output: MyForm.output, cb: Formality.submissionCallbacks) => unit,
) => MyForm.interface;
// With `metadata`
MyForm.useForm(
~initialInput: MyForm.input,
~metadata: MyForm.metadata,
~onSubmit: (output: MyForm.output, cb: Formality.submissionCallbacks) => unit,
) => MyForm.interface;
Callbacks passed to onSubmit
handler.
type submissionCallbacks = {
notifyOnSuccess: option(input) => unit,
notifyOnFailure: submissionError => unit,
reset: unit => unit,
dismissSubmissionResult: unit => unit,
};
See Form Submission.
Interface to the hook.
type interface = {
input: input,
status: Formality.formStatus(submissionError),
submitting: bool,
dirty: unit => bool,
submit: unit => unit,
dismissSubmissionResult: unit => unit,
dismissSubmissionError: unit => unit,
mapSubmissionError: (submissionError => submissionError) => unit,
reset: unit => unit,
// General form
valid: unit => bool,
// Form with async fields
valid: unit => option(bool),
// General field
update[Field]: ((input, 'inputValue) => input, 'inputValue) => unit,
blur[Field]: unit => unit,
[field]Result: option(result('outputValue, message)),
// Async field
update[Field]: ((input, 'inputValue) => input, 'inputValue) => unit,
blur[Field]: unit => unit,
[field]Result: option(Formality.Async.exposedFieldStatus('outputValue, message)),
// Field of collection
update[CollectionEntry][Field]: (~at: index, (input, 'inputValue) => input, 'inputValue) => unit,
blur[CollectionEntry][Field]: (~at: index) => unit,
[collectionEntry][Field]Result: (~at: index) => option(result('outputValue, message)),
// Collection
add[CollectionEntry]: 'collectionEntryInput => unit,
remove[CollectionEntry]: (~at: index) => unit,
};
Used to update form input for a specific field.
// Field
update[Field]: ((input, 'inputValue) => input, 'inputValue) => unit
// Field of collection
update[CollectionEntry][Field]: (~at: index, (input, 'inputValue) => input, 'inputValue) => unit,
Used to notify hook on blur event for a specific field.
// Field
blur[Field]: unit => unit
// Field of collection
blur[CollectionEntry][Field]: (~at: index) => unit,
Used to display validation result for a specific field.
// Field
[field]Result: option(result('outputValue, message)),
// Async field
type asyncResult =
| Validating('outputValue)
| Result(result('outputValue, message));
[field]Result: option(asyncResult),
// Field of collection
[collectionEntry][Field]Result: (~at: index) => option(result('outputValue, message)),
Used to update collection contents.
// Add entry
add[CollectionEntry]: 'collectionEntryInput => unit,
// Remove entry
remove[CollectionEntry]: (~at: index) => unit,
Current form input. Use it to set values of form fields.
input: MyForm.input
Current form status.
type formStatus =
| Editing
| Submitting(option(MyForm.submissionError))
| Submitted
| SubmissionFailed(MyForm.submissionError);
status: formStatus
bool
value, passed for convenience as it gets derived from the form.status
. Set to true
when form.status
is Submitting
, false
otherwise.
submitting: bool
The function would return true
if any form field was touched, false
otherwise.
dirty: unit => bool
Triggers form submission.
submit: unit => unit
Use it when you want to let a user dismiss alerts with errors from a server or success message without resetting a form. Under the hood, it changes Submitted
or SubmissionFailed
form statuses back to Editing
.
dismissSubmissionResult: unit => unit
Dismisses submission error only.
dismissSubmissionError: unit => unit
Maps over submission error. Useful for animating errors.
mapSubmissionError: (submissionError => submissionError) => unit
Resets the whole form to its initial state.
reset: unit => unit
The function that would report the overall validity of the form.
In forms with async fields, it would return option(bool)
. None
is possible when one of the async fields in Validating
state, i.e. we don't know yet if it's valid or not. Also, keep in mind, if one of the async fields wasn't touched yet, it would perform only local validation.
Use this function with caution since it might introduce noticeable overhead on large forms.
// General form
valid: unit => bool
// Form with async fields
valid: unit => option(bool)