Releases: thomashoneyman/purescript-halogen-formless
v1.0.0-rc.1
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
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
Fix oversight where reset_
and reset
would reset the entire form, instead of only resetting the given field (@crcornwell)
v0.5.0
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
, andValidateAll
do not run with a debouncer. The existingmodifyValidate
andsetValidate
functions run as usual. -
There is now a new data type for result field:
FormFieldResult
. This type lets you inspect whether the field isNotValidated
,Validating
(use this to show a spinner, if you’d like),Error
, orSuccess
. The type includes instances for Functor, Apply, Applicative, Bind, etc.; prisms to access the two constructors containing data, and helper functions liketoMaybe
andfromEither
. -
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, andLoadForm
is used to load a new form remotely.
v0.4.1
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
This release adds two new helper functions:
setValidateAll
, which allows you to set all values of a form and also trigger validation on them allmodifyValidateAll
, 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
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
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.
v0.2.0
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 toInputField
;InputField
has been renamed toFormField
-
There is a new
Validation
type which wraps a function from your overall form to a particular field input to someEither error output
result. Polyform andpurescript-validation
adapters have been removed, as you can simply use thetoEither
functions from those libraries to make them compatible with Formless. -
The Polyform example has been removed.
-
There are now
modify
,modifyValidate
, andvalidate
helpers which will create a correct Formless query from a symbol proxy for these major controls. See the overview for more information. There are alsomodify_
,modifyValidate_
, andvalidate_
versions which specify aUnit
result for the query.
v0.1.1
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)