Skip to content

Releases: thomashoneyman/purescript-halogen-formless

v1.0.0-rc.1

29 Aug 16:51
97aaa24
Compare
Choose a tag to compare
v1.0.0-rc.1 Pre-release
Pre-release

This release updates Formless to Halogen 5 and includes new template files contributed by @JordanMartinez. All changes for Halogen 5 are found in #46.

v0.5.2

05 Dec 17:38
d2ea403
Compare
Choose a tag to compare

Formless now cancels long-running validations when a new debouncer is triggered in order to avoid a data race issue in async validations. (@thomashoneyman)

v0.5.1

05 Dec 05:55
3448316
Compare
Choose a tag to compare

Fix oversight where reset_ and reset would reset the entire form, instead of only resetting the given field (@crcornwell)

v0.5.0

30 Nov 06:08
2e0abc4
Compare
Choose a tag to compare

This release introduces debouncing for fields that have expensive or long-running validation. If you don't want to run validation on every key press, but you don't want to run validation on blur, then you can use the new asyncSetValidate and asyncModifyValidate functions to debounce validations for however long you wish. See the new async example to see this in practice.

Major Changes

  • You can now debounce async validation on a field when using the ModifyValidate query, which has been updated to (optionally) take a number of milliseconds for debouncing. This lets you selectively debounce expensive validation.

  • There are now new helpers called asyncModifyValidate, asyncSetValidate, which let you assign n milliseconds to debounce the given field. Modify, Validate, and ValidateAll do not run with a debouncer. The existing modifyValidate and setValidate functions run as usual.

  • There is now a new data type for result field: FormFieldResult. This type lets you inspect whether the field is NotValidated, Validating (use this to show a spinner, if you’d like), Error, or Success. The type includes instances for Functor, Apply, Applicative, Bind, etc.; prisms to access the two constructors containing data, and helper functions like toMaybe and fromEither.

  • Due to the new result type, the prisms for accessing a form field have been updated and renamed to _FieldInput, _FieldResult, etc instead of _Input, _Result. This is necessary because some prisms have the same name and would cause conflicts when exported. The outer functions are unchanged, so almost all code should work as before.

  • Users will probably have to update helper functions that operate on the result field because of these changes. When updating the Formless examples I just had to update a single showError helper function.

  • The Initialize query is now actually used for initialization, and LoadForm is used to load a new form remotely.

v0.4.1

26 Nov 15:56
Compare
Choose a tag to compare

Patch release which updates dependencies to explicitly include purescript-generics-rep. Any currently-building project will continue to build, but new projects will avoid the issue in which the build would fail if no other dependency required purescript-generics-rep.

v0.4.0

24 Oct 01:47
225dd6c
Compare
Choose a tag to compare

This release adds two new helper functions:

  • setValidateAll, which allows you to set all values of a form and also trigger validation on them all
  • modifyValidateAll, which allows you to apply update functions to all values of a form and also trigger validation

In addition, it adjusts all setAll / modifyAll variants to take a record of raw inputs, rather than a record of InputField. This enables you to do this:

F.setAll_ { a: 1, b: "hello" }

instead of this:

F.setAll_ $ F.wrapInputFields { a: 1, b: "hello" }

v0.3.1

22 Oct 20:07
Compare
Choose a tag to compare

This minor patch updates the version of purescript-heterogeneous to latest to take advantage of its functional dependency improvements and ensure Formless users are able to stay on the latest version.

v0.3.0

22 Oct 16:22
1a8504d
Compare
Choose a tag to compare

Formless 0.3.0 introduces a number of significant changes and improvements to the library. These include:

  • Breaking: Simplified the component by removing the submitter function and the output type parameter. Now, on submission, you simply receive the output fields of form you put into the component, and you can transform it after the fact exactly as you would have done with the submitter function previously.
  • Breaking: Renamed the inputs component input field to initialInputs to better reflect what it is used for.
  • Added a noValidation function which you can provide as your validator function when you do not require any form validation
  • Improved the Send query so that you can send actions AND requests to an external component within Formless, instead of only being able to send actions. This now has parity with Halogen’s query and query’ functions.
  • Breaking: Updated the Modify query to actually take a modification function input -> input, instead of simply setting the input. Now, the query helpers set and setValidate provide the old modify behavior, and the query helpers modify and modifyValidate accept a modification function. In addition, this allows you to set a field to touched and validate it without updating its input with modifyValidate_ fieldName identity.
  • Added new SetAll and ModifyAll queries, which allow you to set or modify all input fields in your form at once.
  • Added new helper queries for every public query in the library, namespaced under a new Formless.Query module
  • Possibly breaking: Restructured the underlying modules, while still re-exporting everything from a top-level Formless module. If you previously used import Formless as F, this will not break any code.

Migrating from 0.2.0 to 0.3.0

Most of these changes are new capabilities that expand the library or under-the-hood improvements that won’t affect existing code. However, there have been breaking changes. Most importantly, #26 removed the submitter function and the output type parameter. In addition, several modules have been restructured; any users who simply import Formless as F will be unaffected, but users who import from specific modules will need to update their imports.

Handling the new submission format

To update code that previously used the submitter function, you’ll need to take three actions:

1. Remove the output type from all Formless types

The output type is no longer used in Formless. Instead, you should transform your form type into your desired output after receiving the Submitted message.

-- In old code, Formless took both the form type and the
-- type you wanted to parse to after submission.
data Query a = Formless (F.Message' ContactForm Contact) a
type ChildQuery = F.Query' ContactForm Contact Aff

-- Now, Formless simply takes the form type.
data Query a = Formless (F.Message' ContactForm) a
type ChildQuery = F.Query' ContactForm Aff

2. Remove the submitter function from component input

The submitter function is no longer used. Instead, any manipulations you need to do to your form record after successful submission should be done in your eval handler for the Submitted message.

-- Previously, Formless took four inputs
{ inputs, validators, submitter, render }

-- Now, it no longer takes the submitter function, and `inputs`
-- has been renamed to `initialInputs`
{ initialInputs, validators, render }

3. Either delete the submitter function altogether, or move it to the handler for the Submitted message

The submitter function ended up being used mostly to unwrap output fields and nothing else, causing unnecessary clutter in the component type. Now, any transformations or actions you need to take on the form once submitted are simply done when you handle the Submitted message.

-- In old code, you didn't need to do anything to handle the
-- `Submitted` message because your submitter function had
-- already run.
eval (Formless (F.Submitted contact) a) = a <$ do
  H.liftEffect $ logShow (contact :: Contact)

-- Now, Formless won't transform your output beyond validating
-- it and taking the successfully-parsed values for each
-- field. You can simply move your submitter function to
-- this handler.
eval (Formless (F.Submitted formOutputs) a) = a <$ do
    let contact = F.unwrapOutputFields formOutputs
    H.liftEffect $ logShow (contact :: Contact)

Handling the new modify vs. set queries

In 0.2.0, the modify queries didn’t actually allow you to provide modification functions to run on a form field’s input. Instead, it simply set the value of the field. Now there is support for modify to take a modification function, and a new query, set, to perform the old setting behavior.

This means that ALL uses of modify and modifyValidate will need to be replaced with set and setValidate to preserve their behavior.

For example:

-- Old: uses modifyValidate to set the value of the field
-- to whatever the user enters
HE.onValueInput $ HE.input $ F.modifyValidate _name

-- New: uses setValidate instead
HE.onValueInput $ HE.input $ F.setValidate _name

However, this opens up new functionality. You no longer have to get current input, transform it, and then set it in the form; you can provide a modification function instead:

-- Old: Get the input out, modify it, then set it.
HE.onChange $ HE.input_ $ F.modify _enable (not $ F.getInput _enable form)

-- New: Simply provide the modification function you want
HE.onChange $ HE.input_ $ F.modify _enable not

It also enables a solution for #32: Force validation on non-dirty fields?. To force validation on a non-dirty field, you can use modifyValidate with identity as the modification function:

-- This will set a field to a dirty state and run validation
F.modify _fieldName identity

Handling the new send functionality

In 0.2.0, you could only send actions through Formless to components embedded within the form. Now you can send requests or actions freely. To support this, the Send query was updated:

-- Old
| Send cs (cq Unit) a

-- New
| Send cs (cq a)

You can continue to use send to send actions, but you can also send requests, too:

x <- H.query unit $ F.send Email (H.request Typeahead.GetItems)
_ <- H.query unit $ F.send Email (H.action Typeahead.Clear)

Uses of the send function should continue to work as-is, but uses of the send' function will no longer require H.action to be specified:

-- Old
H.query' CP.cp1 unit $ H.action $ F.send' ...

-- New
H.query' CP.cp1 unit $ F.send' ...

Handling renames and module restructuring

A number of modules have been restructured to better organize the library and make functionality clearer. If you use import Formless as F, none of these changes will affect you and your imports will work as usual. However, if you previously were importing from specific modules, you will need to update your imports.

The module changes include:

  1. The Formless module previously held all component types, query helpers, and the component itself, as well as re-exporting other modules. Now, the Formless module simply re-exports other modules. The component types live in Formless.Types.Component, the query helpers live in Formless.Query, and the component lives in Formless.Component.
  2. The Formless.Spec module contained all form types, plus lenses to access them. Now, this module has been split so that the types live in Formless.Types.Form and the lenses live in Formless.Retrieve. The Formless.Retrieve module also contains functions that were previously in Formless.Spec.Transform but are used to access fields in the form, along with several new helper functions.
  3. The Formless.Spec.Transform and Formless.Internal modules have been split into several modules. Internal transformations have been moved to Formless.Transform.Internal. All transformations that operate on a row type are in Formless.Transform.Row, and all transformations that operate on a record type are in Formless.Transform.Record. Functions that are not actually transformations but are simply ways to retrieve values from the form have been moved to Formless.Retrieve.
  4. All other modules have remained untouched and operate as before.

v0.2.0

12 Aug 00:20
28477b6
Compare
Choose a tag to compare

This release represents a major change to Formless and brings in the following functionality:

  • You can now generate a record of symbol proxies from your Form type, reducing boilerplate

  • Validation and modification is now performed on a per-field basis with variants, rather than on the entire form using lenses; this fixes the limitation in Formless where validation would run across all fields when any field was changed and makes effectful validation possible.

  • Validators have access to the full form state on each run, as well as are able to access parent state for values from other forms to validate against.

  • FormSpec has been renamed to InputField; InputField has been renamed to FormField

  • There is a new Validation type which wraps a function from your overall form to a particular field input to some Either error output result. Polyform and purescript-validation adapters have been removed, as you can simply use the toEither functions from those libraries to make them compatible with Formless.

  • The Polyform example has been removed.

  • There are now modify, modifyValidate, and validate helpers which will create a correct Formless query from a symbol proxy for these major controls. See the overview for more information. There are also modify_, modifyValidate_, and validate_ versions which specify a Unit result for the query.

v0.1.1

31 Jul 07:46
f3a24b8
Compare
Choose a tag to compare

Adds the ability to generate a record of SProxy from a form. This is useful to avoid boilerplate when writing large forms with lots of fields.

newtype Form f = Form
  { name :: f Void String String
  , email :: f Void String String
  , city :: f Void Int String
  , other :: f Int String Int
  }
derive instance newtypeForm :: Newtype (Form f) _

proxies :: Proxies Form
proxies = mkSProxies (FormProxy :: FormProxy Form)