Accessing a particular field
Because you write your form on your own and pass it in to Formless, the component doesn’t have any idea what’s in it. All it knows about is the vague shape of the data.
What I want in particular is the ability to access one particular field in the form in the component. For example, I’d like the user to be able to provide a variant (maybe possible?) or a symbol proxy (not possible) or something that provides access to a single field that I can then use to modify that field only.
For the time being, I supply helper functions that, given a symbol proxy for a field in the form, construct a lens getter or setter that can be applied to the entire thing, and then Formless runs this on the entire form instead of on a particular field. I would much rather that a user could provide an identifier for a particular field and then I can run validation or updates or whatever on just that field.
Why is this a problem? The main reason is that I can’t perform actions on a particular field when only that field changes. For example, say you have an expensive validation to run on a field (some server call) and you only want to run it when that field is blurred. But Formless only lets you provide whole-form transformations, so every time validation for the form as a whole is triggered, your expensive computation will run.
The long version
Why can’t I do this now?
Formless expects you to provide a “Form” type and an accompanying form spec. The form type should be a newtype over a record containing each of the fields in the form, with each field’s error, input, and output type specified. The form spec should be the same set of fields with their initial input values set.
For example:
import Formless as F
newtype Form f = Form { name :: f Err String Name, text :: f Void String String }
derive instance newtypeForm :: Newtype (Form f) _
myFormSpec :: Form F.FormSpec
myFormSpec = Form { name: F.FormSpec "", text: F.FormSpec "" }
-- It can also be generated for you to avoid having to write all the newtypes
myFormSpec' = F.mkFormSpec { name: "", text: "" }
myFormSpec'' = F.mkFormSpecFromRow $ RProxy :: RPoxy (name :: String, text :: String)
Formless has a few types that it can fill in for f
above, like:
newtype InputField e i o = InputField
{ input :: i
, touched :: Boolean
, result :: Maybe (V e o)
}
So it at least knows it can pull out an input, run validation on it, and store the result as well as maintain touched states and so on. Not knowing the contents of the fields is limiting in the query algebra, however, because I pretty much just have access to whatever I can plug in for f
. The two most common queries called are these:
data Query ...
= Modify (form InputField -> form InputField) a
| ModifyValidate (form InputField -> form InputField) a
in which I expect the user to give me a function with which to modify the entire form at once. Validation, similarly, is applied to the entire form at once, and it’s not possible for me to laser in on any particular field. So instead I provide helper functions that, given a symbol proxy for a particular field in your form, will create a lens setter or getter that you can give to Formless to create this form -> form function.