Skip to content

Decorator for calculating field values based on other field values in 🏁 Final Form

License

Notifications You must be signed in to change notification settings

final-form/final-form-calculate

Repository files navigation

🏁 Final Form Calculate

NPM Version NPM Downloads Build Status codecov.io styled with prettier

Decorator for 🏁 Final Form that allows you to define calculations that happen between fields, i.e. "When field X changes, update field Y."


Installation

npm install --save final-form-calculate

or

yarn add final-form-calculate

Usage

import { createForm, getIn } from 'final-form'
import createDecorator from 'final-form-calculate'

// Create Form
const form = createForm({ onSubmit })

// Create Decorator
const decorator = createDecorator(
  // Calculations:
  {
    field: 'foo', // when the value of foo changes...
    updates: {
      // ...set field "doubleFoo" to twice the value of foo
      doubleFoo: (fooValue, allValues) => fooValue * 2
    }
  },
  {
    field: 'bar', // when the value of bar changes...
    updates: {
      // ...set field "foo" to previous value of bar
      foo: (fooValue, allValues, prevValues) => prevValues.bar
    }
  },
  {
    field: /items\[\d+\]/, // when a field matching this pattern changes...
    updates: {
      // ...sets field "total" to the sum of all items
      total: (itemValue, allValues) =>
        (allValues.items || []).reduce((sum, value) => sum + value, 0)
    }
  },
  {
    field: 'foo', // when the value of foo changes...
    updates: {
      // ...asynchronously set field "doubleFoo" to twice the value using a promise
      doubleFoo: (fooValue, allValues) =>
        new Promise(resolve => {
          setTimeout(() => resolve(fooValue * 2), 100)
        })
    }
  },
  {
    field: /\.timeFrom/, // when a deeper field matching this pattern changes...
    updates: (value, name, allValues) => {
      const toField = name.replace('timeFrom', 'timeTo')
      const toValue = getIn(allValues, toField)
      if (toValue && value > toValue) {
        return {
          [toField]: value
        }
      }

      return {}
    }
  }
)

// Decorate form
const undecorate = decorator(form)

// Use form as normal

Table of Contents

Example

Example using 🏁 React Final Form.

API

createDecorator: (...calculations: Calculation[]) => Decorator

A function that takes a set of calculations and returns a 🏁 Final Form Decorator.

Types

Calculation: { field: FieldPattern, isEqual?: (any, any) => boolean, updates: Updates }

A calculation to perform, with an optional isEqual predicate to determine if a value has really changed (defaults to ===).

FieldName: string

FieldPattern: FieldName | RegExp | (FieldName | RegExp)[]

A pattern to match a field with.

Updates: UpdatesByName | UpdatesForAll

Either an object of updater functions or a function that generates updates for multiple fields.

UpdatesByName: { [FieldName]: (value: any, allValues: Object, prevValues: Object) => Promise | any }

Updater functions for each calculated field.

UpdatesForAll: (value: any, field: string, allValues: Object, prevValues: Object) => Promise | { [FieldName]: any }

Takes the value and name of the field that just changed, as well as all the values, and returns an object of fields and new values.