Questions about validating fields in Halogen Formless

I need some help with 2 issues in Halogen Formless.

First issue:
I have a form with an optional Boolean field that requires no validation.
When I run the app in the browser, I see state.validity as Incomplete and only when the field is touched the state.validity updates to Valid.
Since the form only contains one optional field, I expect to see the form to be in Valid state, by default, without touching field.

type MyType = 
    { processTask   :: Boolean
newtype Form r f = Form (r
    (  processTask   :: f Void Boolean Boolean
{ validators: Form  { processTask:  F.noValidation
render state =
        [ HH.input
            [ HP.type_ HP.InputCheckbox
            , HP.checked $ F.getInput _processTask state.form
            , HE.onChecked $ Just <<< F.set _processTask
        , HH.label_ [ HH.text " Create or update task" ]
        , HH.text $ show state.validity

Here is a basic working example

The second issue:
In the same form above, I added a FileUpload field with a validation that checks if the user has selected a file or not.
The compiler complains about Eq typeclass is not implemented for type File.

import Web.File.File (File)

type MyType = 
    { processTask   :: Boolean
    , selectedFile  :: File

newtype Form r f = Form (r
    (  processTask   :: f Void      Boolean Boolean
    ,  selectedFile  :: f V.Exists  File    File

I’m not sure if this issue has anything to do with Halogen Formless, but is there a way to validate a field of type File?


As far as the first issue goes you can call modifyValidate on your optional fields when the form initializes. You’d add an Initialize action like ordinary Halogen, and when you evaluate it you can do:

-- A helper function that calls `F.handleAction` with your custom `handleAction` and `handleEvent`,
-- which in your case was `F.raiseResult`.
eval = F.handleAction handleAction F.raiseResult

handleAction = case _ of
  Initialize ->
    -- this will preserve the field's value, but run the validation on
    -- it, leaving it in a 'touched' state.
    eval $ F.modifyValidate _processTask identity

I’ll admit this is a pretty clunky way to do things, though it will allow you to guard the submit button on valid state. The reason Formless doesn’t automatically pick up optional fields is that Formless doesn’t run your validation until a field is touched (or the form is submitted), so it doesn’t know whether a field is valid or not until then.

As far as issue 2: Formless requires an Eq instance for the input type so that it can track if the field is dirty (if it’s been changed from its original state).

There’s an existing issue for file uploads in Formless. That has some information that can help you, but please also feel free to add to that issue. Ultimately this is a flaw with how Formless works, and there is an issue to migrate to Halogen Hooks which should help make some of these rough edges better.