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.div_
[ 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
]
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.
Error found:
in module SystemPage.NetworkEdit
at src/SystemPage/NetworkEdit.purs:130:14 - 136:10 (line 130, column 14 - line 136, column 10)
No type class instance was found for
Prim.RowList.RowToList ( address :: forall a t. Category a => a t t
, dns :: forall a t. Category a => a t t
, gateway :: forall a t. Category a => a t t
, mode :: forall a t. Category a => a t t
, ntp :: forall a t. Category a => a t t
)
t6
The instance head contains unknown type variables. Consider adding a type annotation.
For reference, doing each field individually with F.modifyValidate works fine.
In any case, I was aiming for a generic solution that would work for any record type without having to list the fields, something akin to sequenceRecord that you showed me yesterday. I’ll ultimately need to do a lot of dialog boxes like this, so I’m seeking to put some nice generic infrastructure together. Another option for me is to patch Formless to bend it to my will.
You can from time to time run into issues with polymorphic types in records; I’m curious what happens if you do an explicit function instead? ie.
eval $ F.modifyValidateAll
{ mode: \x -> x
, address: \x -> x
, gateway: \x -> x
, ...
}
If you are going to be writing functions that operate on arbitrary records (as with sequenceRecord), I suspect you’ll have a much better time using https://github.com/natefaubion/purescript-heterogeneous instead of writing everything from scratch yourself with Cons / RowToList.
I do need to get a handle on row types and heterogeneous; that stuff is still magic to me. Thanks for all your help and pointing me in a good direction.