v0.3.0
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 theoutput
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 thesubmitter
function previously. - Breaking: Renamed the
inputs
component input field toinitialInputs
to better reflect what it is used for. - Added a
noValidation
function which you can provide as yourvalidator
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’squery
andquery’
functions. - Breaking: Updated the
Modify
query to actually take a modification functioninput -> input
, instead of simply setting the input. Now, the query helpersset
andsetValidate
provide the old modify behavior, and the query helpersmodify
andmodifyValidate
accept a modification function. In addition, this allows you to set a field totouched
and validate it without updating its input withmodifyValidate_ fieldName identity
. - Added new
SetAll
andModifyAll
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 usedimport 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:
- The
Formless
module previously held all component types, query helpers, and the component itself, as well as re-exporting other modules. Now, theFormless
module simply re-exports other modules. The component types live inFormless.Types.Component
, the query helpers live inFormless.Query
, and the component lives inFormless.Component
. - The
Formless.Spec
module contained all form types, plus lenses to access them. Now, this module has been split so that the types live inFormless.Types.Form
and the lenses live inFormless.Retrieve
. TheFormless.Retrieve
module also contains functions that were previously inFormless.Spec.Transform
but are used to access fields in the form, along with several new helper functions. - The
Formless.Spec.Transform
andFormless.Internal
modules have been split into several modules. Internal transformations have been moved toFormless.Transform.Internal
. All transformations that operate on a row type are inFormless.Transform.Row
, and all transformations that operate on a record type are inFormless.Transform.Record
. Functions that are not actually transformations but are simply ways to retrieve values from the form have been moved toFormless.Retrieve
. - All other modules have remained untouched and operate as before.