Created: 2021-11-18 22:51
DISCLAIMER: the contents of this article are not correct, set does turn the touched
property true
. At the moment (2021-12-21) it is not possible to achieve errors on blur with Formless.
In Halogen Formless, form fields (FormFieldRow) have 3 properties 1: the input, which is the value of the field as the user changes it; a result, which is the output; and a touched property which is set to true
on validation or submit.
type FormFieldRow error input output
= ( input :: input
, result :: FormFieldResult error output
, touched :: Boolean
)
These properties, together with the field getters (Formless.Retrieve), can be used to show feedback to the user. A nice practice when building online forms is to show validation errors to users only after they are done with a field. Nobody wants to see Password too short after typing the first character.
Using setValidate (or modifyValidate) as the change handler of an input will trigger the validation right away. As the name implies, it sets or modifies a fields value (the input
) and also validates it, setting touched
to true.
HH.div_
[ HH.input
[ HE.onTextInput $ F.setValidate _name
, HP.value $ F.getInput _name form
]
, if F.getTocuhed _name form && isJust (F.getError _name form)
then
HH.span
[ HP.class_ $ ClassName "text-red"]
[ HH.text "There's an error!" ]
else HH.text ""
]
That, however, has a problem, it shows the error right away =/
Since touched
only is set on validation, a better approach then is to set (or modify) on change and validate on blur. That way the validation only runs when the user moves on to the next field, or submits the form.
HH.div_
[ HH.input
[ HE.onTextInput $ F.set _name
, HE.onBlur $ F.validate _name
, HP.value $ F.getInput _name form
]
, if F.getTocuhed _name form && isJust (F.getError _name form)
then
HH.span
[ HP.class_ $ ClassName "text-red"]
[ HH.text "There's an error!" ]
else HH.text ""
]
There’s still an small problem, since the validation only happens on blur now the error will stay when the user returns to the field to fix it and it will only go away once they take the focus out of the field. Not good, since the user won’t know when the error is fixed.
A better approach would be to run the validation (A.K.A setValidate
) when the field is touched
. Which happens after validate
runs on the first blur.
HH.div_
[ HH.input
[ HE.onTextInput handleChange
, HE.onBlur $ F.validate _name
, HP.value $ F.getInput _name form
]
, if F.getTocuhed _name form && isJust (F.getError _name form)
then
HH.span
[ HP.class_ $ ClassName "text-red"]
[ HH.text "There's an error!" ]
else HH.text ""
]
where handleChange input =
if F.getTouched _name form
then F.setValidate _name input
then F.set _name input
Et voilà!
Now we only show the error after the first blur, and then we always validate on change to make sure the error goes away as soon as the user makes the right changes.