While working on a project with Elm, I needed to include some radio buttons in a Elm generated form. While there is a great example on how to create forms with text inputs in Elm, I couldn’t seem to find examples or documentation on how to handle radio buttons.
Let’s start with setting up the basic skeleton for our simple app.
import Html (..)
import Html.Attributes (..)
import Html.Events (..)
import Signal (..)
-- MODELS
type alias Model = { radio : String }
type Update = NoOp
| Checked String
initialModel : Model
initialModel = { radio = "y" }
-- UPDATE
update : Update -> Model -> Model
update upd model = case upd of
NoOp -> model
Checked selection -> { model | radio <- selection }
-- VIEW
view : Model -> Html
view model = div [ ]
[ text ("You selected: " ++ model.radio)
, yesNoField "yesorno" Checked
]
yesNoField : String -> (String -> Update) -> Html
yesNoField fieldName toUpdate = div [ ]
[ div [ ] [ input [ type' "radio"
, name fieldName
, value "y" ] [ ]
, text "Yes" ]
, div [ ] [ input [ type' "radio"
, name fieldName
, value "n" ]
[ ]
, text "No" ]
]
-- SIGNALS
model : Signal Model
model = foldp update initialModel (subscribe updateChannel)
updateChannel : Channel Update
updateChannel = channel NoOp
-- MAIN
main : Signal Html
main = view <~ model
Going by the form example, we should now add a on
event to the input fields in the yesNoField
.
input [ type' "radio"
, name fieldName
, value "y"
, on "input" targetValue (send updateChannel << toUpdate) ]
However, it seems that the first argument to on
is some kind of event name. This is the correct one when using normal textual input fields, but it doesn’t work with radio buttons.
When faced with this problem, I started looking for other examples with radio buttons or some documentation on what this event name variable could be. Unfortunately I couldn’t find anything. So I decided to dive into some of the compiled Elm code to try and figure out what it should be.
To do this I compiled Radio.elm
with elm-make
and wrote a simple index.html
to manually embed the elm.js
source code and run it.
The source code for the on
function shows that it is nothing more than the VirtualDom.on
function. This on
function is apparently just returning a property, that will be added to the proper HTML tag by Elm, so we need to dig a little deeper.
By searching through the source code on delegator
, I stumbled upon the interesting looking createHandler
and findAndInvokeListeners
functions. By adding console.log(eventName);
at the top of findAndInvokeListeners
I got some interesting output
mousedown
focus
focusIn
mouseup
change
click
I figured change was the way to go. So let’s try it. Change yesNoField
to
yesNoField : String -> (String -> Update) -> Html
yesNoField fieldName toUpdate = div [ ]
[ div [ ] [ input [ type' "radio"
, name fieldName
, value "y"
, on "change" targetValue (send updateChannel << toUpdate)
] [ ]
, text "Yes" ]
, div [ ] [ input [ type' "radio"
, name fieldName
, value "n"
, on "change" targetValue (send updateChannel << toUpdate)
]
[ ]
, text "No" ]
]
When you recompile and refresh, everything should be working.
Is it difficult to get radio buttons working in Elm? No. You just need to add the on "change" targetValue someMessage
attribute to your input
and wire up this message like you would do with any other messages.
The tricky part was in finding the correct value "change"
. As far as I could tell there is no real documentation on the possible values and when to use which ones. Elm might benefit from defining an algebraic data type for this argument.