npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

Iโ€™ve always been into building performant and accessible sites, but lately Iโ€™ve been taking it extremely seriously. So much so that Iโ€™ve been building a tool to help me optimize and monitor the sites that I build to make sure that Iโ€™m making an attempt to offer the best experience to those who visit them. If youโ€™re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, ๐Ÿ‘‹, Iโ€™m Ryan Hefnerย  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If youโ€™re interested in other things Iโ€™m working on, follow me on Twitter or check out the open source projects Iโ€™ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soonโ€“ish.

Open Software & Tools

This site wouldnโ€™t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you ๐Ÿ™

ยฉ 2024 โ€“ย Pkg Stats / Ryan Hefner

@divanov/final-form-calculate

v1.3.2

Published

Decorator for calculating field values based on other field values in ๐Ÿ Final Form

Downloads

1

Readme

๐Ÿ 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

Calculated Fields 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, setHints: {skipNextUpdate: boolean}) => 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.

With setHints, you can instruct final-form-calculate to skip calling next Updates cycle. You can do that with skipHints({skipNextUpdate: true}) in your updates handler.

The reason behind this feature is, in certain scenarious you may have closed loops of fields dependency. E.g. field foo updates field bar, and field bar updates field foo. This will result in infinite loop of updates. By calling this function selectively in the body of updates, foo will update bar, but updates on next update cycle will not be called, so bar will not update foo.

When using this, make sure you update all fields that are dependant on the current field, even if they are recursive dependency.

Example:

{
  field: "foo",
  updates: {
    bar: "foo updated me",
  }
},{
  field: "bar",
  updates: {
    baz: "bar updated me"
  }
}

Updates on foo indirecly will update baz in 2 update cycles.

When using:

{
  field: "foo",
  updates: (value, field, allValues, prevValues, setHints) => {
    setHints({ skipNextUpdate: true })
    return {
      bar: "foo updated me",
    }
  }
},{
  field: "bar",
  updates: {
    baz: "bar updated me"
  }
}

Updates on foo will not trigger update on baz.

In order to make such updates, make them directly from foo.

{
  field: "foo",
  updates: (value, field, allValues, prevValues, setHints) => {
    setHints({ skipNextUpdate: true })
    return {
      bar: "foo updated me",
      baz: "foo updated me",
    }
  }
},{
  field: "bar",
  updates: {
    baz: "bar updated me"
  }
}