Skip to content

Latest commit

 

History

History
473 lines (369 loc) · 10.4 KB

12-API.md

File metadata and controls

473 lines (369 loc) · 10.4 KB

API

Configuration

Form configuration module can be created using [%form] extension:

module MyForm = [%form
  type input;
  type output;
  ...
];

type input

Requirements: Required. Must be a record.

Form input data.

type input = {email: string};

See IO & Basic Usage.

input field attributes

@field.async

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.

@field.collection

Requirements: Optional. If provided, must be an array.

Attribute for a collection field.

type rec input = {
  authors: @field.collection array<author>,
}
and author = {name: string};

See Collections.

@field.deps

Requirements: Optional.

Dependent fields attribute.

type input = {
  a: @field.deps(b) string,
  b: string,
};

See Dependent Fields.

type output

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.

type message

Requirements: Optional.
Default: string

Type of error messages.

type message = I18n.t;

See Basic Usage & I18n.

type metadata

Requirements: Optional.

Additional metadata.

type metadata = { items: array<Item.t> };

See Metadata.

type submissionError

Requirements: Optional.
Default: unit

Type of submission error.

type submissionError =
  | UserNotFound
  | UnknownError;

See Form Submission.

let debounceInterval

Requirements: Optional int.
Default: 700

Debounce interval in ms for async validators in OnChange mode.

let debounceInterval = 1000;

See Async Validation.

let validators

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.

Rendering

Module created via %form extension exposes useForm React hook.

useForm

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;

submissionCallbacks

Callbacks passed to onSubmit handler.

type submissionCallbacks = {
  notifyOnSuccess: option<input> => unit,
  notifyOnFailure: submissionError => unit,
  reset: unit => unit,
  dismissSubmissionResult: unit => unit,
};

See Form Submission.

interface

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,
};

Update handlers

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,

Blur handlers

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,

Field result

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>>,

Collection handlers

Used to update collection contents.

// Add entry
add[CollectionEntry]: 'collectionEntryInput => unit,

// Remove entry
remove[CollectionEntry]: (~at: index) => unit,

input

Current form input. Use it to set values of form fields.

input: MyForm.input

status

Current form status.

type formStatus =
  | Editing
  | Submitting(option<MyForm.submissionError>)
  | Submitted
  | SubmissionFailed(MyForm.submissionError);

status: formStatus

submitting

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

dirty

The function would return true if any form field was touched, false otherwise.

dirty: unit => bool

submit

Triggers form submission.

submit: unit => unit

dismissSubmissionResult

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

dismissSubmissionError

Dismisses submission error only.

dismissSubmissionError: unit => unit

mapSubmissionError

Maps over submission error. Useful for animating errors.

mapSubmissionError: (submissionError => submissionError) => unit

reset

Resets the whole form to its initial state.

reset: unit => unit

valid

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>