DEV Community

mirko
mirko

Posted on

Event listeners in Elm

I am a beginner in Elm and to learn it I have started ts-converter, a tiny browser extension to convert timestamps in a readable format. This is one of my daily needs.
I want to use what I have learnt from it, sharing some notes on how to manage event listeners in a Elm application.
I'll use onEnter event in the examples.

Scenario 1: Listen for all application events

To capture a key pressed in the whole application we need to introduce a subscription

What's a subscription ?

A subscription is an operation allowing us to register to an external event.
Creating a subscription we say to Elm runtime that we want to do an action when a particular event is spawned. When the runtime captures an event, produces an update message.

subscriptions _ =
  onKeyPress keyDecoder
Enter fullscreen mode Exit fullscreen mode

A subscription is created on event onKeyPress and when this event will be intercepted by the Elm runtime the function keyCoder will be invoked.

keyDecoder : Decode.Decoder Msg
keyDecoder =
    Decode.map toKey (Decode.field "key" Decode.string)
Enter fullscreen mode Exit fullscreen mode

The event object is serialized as a JSON object and its field key contains the key pressed value, Decode.field "key" Decode.string extracts this number and puts it into a valid Elm value.
The extracted value is then passed to toKey function.

toKey : String -> Msg
toKey keyValue =
    case String.uncons keyValue of
        Just ( char, "" ) ->
            CharacterKey char
        _ ->
            ControlKey keyValue
Enter fullscreen mode Exit fullscreen mode

String.uncons takes a string as a characters array and splits it into its head and tail.
Depending on whether the leading character is an alphanumeric value
or not, produces the related update message.

CharacterKey k ->
     YOUR CODE
ControlKey k ->
     YOUR CODE
Enter fullscreen mode Exit fullscreen mode

The two messages will be managed into the update function.

Scenario 2: Listen for a event bound to a input field

At the moment (v0.19) Elm doesn't support natively onEnter event, but it offers a function on that permits to create a custom event listener.

onEnter: Msg -> Attribute Msg
onEnter msg =
  let 
    isEnter code = 
      if code == 13 then
        Decode.succeed msg
      else
        Decode.fail "not ENTER"
  in
on "keydown" (Decode.andThen isEnter keyCode)
Enter fullscreen mode Exit fullscreen mode

With on "keydown" (Decode.andThen isEnter keyCode) we'll create a listener on keydown event and the Elm runtime will execute (Decode.andThen isEnter keyCode) on its capture.
keyCode is a bultin function of Html.Events module and it returns the value of pressed key as an integer.
isEnter checks if key enter has been pressed (enter value is 13) producing respectively a message for the update function or a failure.

onEnter is used into the input field we will listen for events.

input [ size 20, value (tsToString model.ts), onInput SetTs, onEnter Convert, autofocus True] []

Top comments (0)