We have a new Elm Radio episode today: Use the Platform. We explore how the pendulum has swung away from using platform primitives and how it’s swinging back towards using them in the frontend world, and we discuss what that means for your Elm code.
When I heard the episode, I felt kind of sheepish that form and form fields handling in Elm doesn’t exactly “use the platform”
We busy ourselves storing user input values even though the browser’s form field components manages their own state (the values we store after we process the user input String, e.g. into Time.Posix, is fine though)
Our form fields don’t need (and probably doesn’t have) name attribute, maybe unless it’s a radio button
Then I recall a really old DOM api that I used long ago: document.forms actually contains all the forms on the page and their current values.
Could we… just Json.Decode that data structure to retrieve the form values managed by the browser components? Then we can totally avoid (1). In fact, this means unless a field actually needs special Elm handling (e.g. conversion into custom types) we don’t actually need to handle the field (wiring up value model.currentValue, onInput, …). So number of msg no longer grows with the number of form fields
form id, field names are now stringly typed, but I suppose some api design elbow grease could require supplying a custom type + toString function instead?
passing document.forms around the app is still a big no no imo. always use a parseDontValidate function to extract the values and store/pass those values around instead
As a decoder for window.document, means NativeForm itself is not actively involved in setting form field values. However you get it working, NativeForm can retrieve all the values from checked boxes correctly.
You manage the list of addresses the usual way and map them each into input fields.
As long as the form field name attribute is the same, will get be getting back a ManyValues (List String) from NativeForm.valuesDict. See mycheckbox related code.
Or you could provide unique name attribute for each, e.g. rails-style "address[1]", and extract them (see Raw output section in the demo app)
Hello @choonkeat, thanks for the discussion! It’s cool to see your exploration here.
I’ve been exploring “using the platform” more for my upcoming elm-pages v3 release as well. For elm-pages v3, there are several benefits that come with that approach
You can start out simple (no Model state for forms is possible, as you describe)
You can progressively enhance form state with client validation and Model state, while still using the form values as the basis of the page, and for serializing the data
The form submissions work before the JS hydrates for the page
I’ll share more on this soon along with a release announcement!
I’ve been trying to use the submitter from Html.Events.onSubmit, because that captures an additional nuance of forms which is that the button that triggers the submission will pass along its name/value pair in the form submission if it has those attributes.
I’m still finalizing some details of the API to take advantage of this, but one of the neat things about using the platform here is that you can progressively enhance the built-in browser form submission behavior to do form submissions client-side, while emulating the built-in browser form submission behavior. This makes it more robust (works while hydrating), but also reduces glue code because you can use this platform behavior to send data to the server.
One note here, I think it’s worth distinguishing between “use the platform” as the only thing you can use, vs. the basis of what you build (progressive enhancement). You can also think of this as graceful degradation. Users with different experiences (assistive devices, slow connections, small screens, certain permissions disabled) should still be able to use the web application’s core features. They may miss out on some bells and whistles, but should be able to accomplish the core workflows.