Search code examples
elm

How to handle Enter key press in input field?


I built a simple app for learning purposes and want to be able to dispatch an action when the user presses Enter key in input field

view : Model -> Html Action
  view model = 
    let 
      items = List.map (\ item -> li [] [ text item ]) model.items
    in
      div [] [
       input [ onInput Change, value model.content ] [],
       button [ onClick Add ] [ text "Submit" ],
       ul [] items
      ]

Here is the view code. I hope it will be enough to explain my intent for you. What I'd like to have is ability to dispatch some action when user presses the Enter key while he is entering some text to input field.


Solution

  • You can manually bind to the keydown event with the generic on handler. Elm does currently not support onKeyDown handlers out of the box - but they are planned in the future.

    It looks like the spec is moving away from event.keyCode and towards event.key. Once this is supported in more browsers, we may add helpers here for onKeyUp, onKeyDown, onKeyPress, etc. (Source)

    Until then you can simply write your own handler and use keycode 13 (enter) to perform your actions. Open the following ellie-app to see how it works. Just enter some text in the input box and press enter to see the current state reflected in the div below the input box.

    import Html exposing (text, div, input, Attribute)
    import Browser
    import Html.Events exposing (on, keyCode, onInput)
    import Json.Decode as Json
    
    
    main =
      Browser.sandbox 
      { init = 
        { savedText = ""
        , currentText = ""
        }
      , view = view
      , update = update
      }
    
    
    view model =
      div [] 
      [ input [onKeyDown KeyDown, onInput Input] []
      , div [] [ text ("Input: " ++ model.savedText) ]
      ]
    
    onKeyDown : (Int -> msg) -> Attribute msg
    onKeyDown tagger =
      on "keydown" (Json.map tagger keyCode)
    
    
    type Msg 
      = NoOp
      | KeyDown Int
      | Input String
    
    
    update msg model =
      case msg of
    
        NoOp ->
          model
    
        KeyDown key ->
          if key == 13 then
            { model | savedText = model.currentText }
          else
            model
    
        Input text ->
          { model | currentText = text }