thomashoneyman
released this
Assets
2
Formless 0.3.0 introduces a number of significant changes and improvements to the library. These include:
- Breaking: Simplified the component by removing the
submitterfunction and theoutputtype 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 thesubmitterfunction previously. - Breaking: Renamed the
inputscomponent input field toinitialInputsto better reflect what it is used for. - Added a
noValidationfunction which you can provide as yourvalidatorfunction when you do not require any form validation - Improved the
Sendquery 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’squeryandquery’functions. - Breaking: Updated the
Modifyquery to actually take a modification functioninput -> input, instead of simply setting the input. Now, the query helperssetandsetValidateprovide the old modify behavior, and the query helpersmodifyandmodifyValidateaccept a modification function. In addition, this allows you to set a field totouchedand validate it without updating its input withmodifyValidate_ fieldName identity. - Added new
SetAllandModifyAllqueries, 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.Querymodule - Possibly breaking: Restructured the underlying modules, while still re-exporting everything from a top-level
Formlessmodule. 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 Aff2. 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 _nameHowever, 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 notIt 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 identityHandling 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
Formlessmodule previously held all component types, query helpers, and the component itself, as well as re-exporting other modules. Now, theFormlessmodule 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.Specmodule contained all form types, plus lenses to access them. Now, this module has been split so that the types live inFormless.Types.Formand the lenses live inFormless.Retrieve. TheFormless.Retrievemodule also contains functions that were previously inFormless.Spec.Transformbut are used to access fields in the form, along with several new helper functions. - The
Formless.Spec.TransformandFormless.Internalmodules 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.