I am trying to create a higher order function to create functions to capture only a specific key code. The code is inspired on Evan's onEnter
function from his todomvc implementation which captures only the enter function.
onKeyCode : Int -> Msg -> Attribute Msg
onKeyCode keycode msg =
let
captureKey code =
if code == keycode then
msg
else
NoOp
in
on "keydown" (Json.map captureKey keyCode)
onEnter = onKeyCode 13
onEsc = onKeyCode 27
And now I want to add that to an input component in the viewer:
input
[ class "edit"
, id ("todo-" toString item.uid)
, value item.message
, onInput (UpdateItem item.uid)
, onBlur (SwitchEditTodo item.uid False)
, onEnter (SwitchEditTodo item.uid False)
, onEsc (UndoEditTodo item.uid)
]
[]
If I only have the onEnter
the code will work as expected but if I add the onEsc
, the onEnter
code is never executed. Where am I doing the mistake? is that a problem with the higher order function context or "on" mapping with multiple values in separate functions?
CodePudding user response:
You are adding two onkeydown
attributes to the input element, and only one of them can win. The second in the list overwrites the first. Were it to use addEventListener
behind the scenes, this would not be the case, but for now we can solve it with a slightly different approach.
You could write a onKeysDown
function that accepts a list of possible key codes and the message they should invoke like this:
onKeysDown : List (Int, Msg) -> Attribute Msg
onKeysDown keys =
let
captureKey code =
List.filterMap (\(k, m) -> if k == code then Just m else Nothing) keys
|> List.head
|> Maybe.withDefault NoOp
in
on "keydown" (Json.map captureKey keyCode)
You could then write shorthand functions for handling specific keys like this:
enter msg = (13, msg)
esc msg = (27, msg)
And now you can use it in your view like this:
input
[ ...
, onKeysDown
[ enter <| SwitchEditTodo item.uid False
, esc <| UndoEditTodo item.uid
]
]
This works because it generates a single keydown
event handler attribute. And while you substitute a predefined tuple for a higher order function, it still gives you just as readable code.