Как обрабатывать клавишу Enter в поле ввода?

Я построил простое приложение для учебных целей и хочу иметь возможность отправлять действие, когда пользователь нажимает Enter ключ в поле ввода

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
      ]

вот код, вид. Надеюсь, этого будет достаточно, чтобы объяснить вам мои намерения. Что я хотел бы иметь возможность отправлять некоторые действия, когда пользователь нажимает на Enter ключ, когда он вводит текст в поле ввода.

6 ответов


вы можете вручную привязать к keydown событие с родовыми on обработчик. Вяз в настоящее время не поддерживает onKeyDown обработчики "из коробки" - но они планируются в будущем.

похоже, что спецификация удаляется от события.ключ и к событию.ключ. Как только это будет поддерживаться в других браузерах, мы можем добавить помощников здесь для onKeyUp, onKeyDown, onKeyPress и т. д. (источник)

а пока вы можете просто написать свой собственный обработчик и используйте keycode 13 (enter) для выполнения ваших действий. Скопируйте следующий код вelm-lang.org/try или открыть https://runelm.io/c/pld чтобы увидеть, как это работает. Просто введите текст в поле ввода и нажмите enter, чтобы увидеть текущее состояние, отраженное в div под полем ввода.

import Html exposing (text, div, input, Attribute)
import Html exposing (beginnerProgram)
import Html.Events exposing (on, keyCode, onInput)
import Json.Decode as Json


main =
  beginnerProgram 
  { model = 
    { 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 }

есть хорошее, простое решение для обработки onEnter на вяз версия TodoMVC:

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

выше ответы были очень хорошими, но хранение каждая буква на Model на каждой клавише нажмите - это не всегда хорошая идея.

например в моем случае у меня есть fileSystem - like strucutre - и я хочу редактировать любое имя-независимо от того, насколько оно вложено - on doubbleclick. Я не могу получить дыру fileSystem вид реконструируется с каждым нажатием клавиши. Это ЛаГГи.

я обнаружил, что это лучший для получения входного значения-только когда пользователь нажимает Enter..

type Msg =
    | EditingStarted
    | EditingFinished String
    | CancelEdit

input [ whenEnterPressed_ReceiveInputValue EditingFinished, whenEscPressed_CancelOperation CancelEdit, onBlur CancelEdit ] []

update msg model =
    case msg of
        EditingFinished inputValue ->
            { model | name = inputValue }
        CancelEdit -> ...


whenEnterPressed_ReceiveInputValue : (String -> msg) -> H.Attribute msg
whenEnterPressed_ReceiveInputValue tagger =
  let
    isEnter code =
        if code == 13 then
            JD.succeed "Enter pressed"
        else
            JD.fail "is not enter - is this error shown anywhere?!"

    decode_Enter =
        JD.andThen isEnter E.keyCode
  in
    E.on "keydown" (JD.map2 (\key value -> tagger value) decode_Enter E.targetValue)


whenEscPressed_CancelOperation : msg -> H.Attribute msg
whenEscPressed_CancelOperation tagger =
  let
    isESC code =
        if code == 27 then
            JD.succeed "ESC pressed"
        else
            JD.fail "it's not ESC"

    decodeESC =
        JD.andThen isESC E.keyCode
  in
    E.on "keydown" (JD.map (\key -> tagger) decodeESC)

Примечание: Если вы делаете время путешествия отладки-вы будете не см. каждую букву, появляющуюся так, как она была напечатана. Но весь текст сразу - потому что было только одно сообщение.. В зависимости от того, что вы делаете - это может быть проблемой. Если нет, наслаждайтесь :)


вы можете использовать что-то подобное в своем input элемент, это вызовет данное сообщение, если клавиша enter будет нажата:

onEnterPressed : msg -> Attribute msg
onEnterPressed msg =
  let
    isEnter code =
      if code == 13 then Ok () else Err ""
    decodeEnterKeyCode = Json.customDecoder keyCode isEnter
  in on "keydown" <| Json.map (\_ -> msg) decodeEnterKeyCode

мне понравился ответ Алона и немного повторил его, чтобы создать атрибут, который отвечает на <enter> и <esc>

onEscEnter : String -> (String -> msg) -> Attribute msg
onEscEnter originalValue tagger =
    let
        handleKey : Int -> Jdec.Decoder Int
        handleKey code =
            if L.member code [ 13, 27 ] then
                -- ESC or Enter
                Jdec.succeed code
            else
                Jdec.fail "something to ignore"

        combiner : Int -> String -> msg
        combiner keyCode tgtVal =
            if keyCode == 13 then
                tagger tgtVal
            else if keyCode == 27 then
                tagger originalValue
            else
                Debug.crash "onEscEnter"

        keyCodeDecoder : Jdec.Decoder Int
        keyCodeDecoder =
            Jdec.andThen handleKey keyCode
    in
        on "keydown" (Jdec.map2 combiner keyCodeDecoder targetValue)

Если вы готовы использовать общий пакет Html.Events.Extra http://package.elm-lang.org/packages/elm-community/html-extra/latest/Html-Events-Extra#onEnter это очень легко.

(предполагая, что вы хотите отправить Add сообщение при нажатии клавиши Enter.)

import Html.Events.Extra exposing (onEnter)

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