Как обращаться с нажатием клавиши ввода в поле ввода?
Я создал простое приложение для учебных целей и хочу иметь возможность отправлять действие, когда пользователь нажимает клавишу 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
, пока он вводит какой-либо текст в поле ввода.
Ответы
Ответ 1
Вы можете вручную привязать событие keydown
к общему обработчику on
. Elm в настоящее время не поддерживает обработчиков onKeyDown
из коробки, но они планируются в будущем.
Похоже, что спецификация отходит от event.keyCode и к event.key. Когда это поддерживается в более браузерах, мы можем добавить сюда помощников для 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 }
Ответ 2
Есть хорошее, простое решение для обработки onEnter
в Elm-версии TodoMVC:
import Html exposing (..)
import Html.Events exposing (keyCode)
import Json.Decode as Json
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)
Ответ 3
Вышеуказанные ответы были очень хорошими - но сохранение каждой буквы в Model
при каждом нажатии клавиши не всегда является хорошей идеей.
Например, в моем случае у меня есть fileSystem
-образный strucutre - и я хочу редактировать любое имя - независимо от того, как он вложен - на 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 not ESC"
decodeESC =
JD.andThen isESC E.keyCode
in
E.on "keydown" (JD.map (\key -> tagger) decodeESC)
Примечание. Если вы выполняете отладочную работу во времени - вы будете не видеть каждую букву, появляющуюся по мере ее ввода. Но весь текст сразу - потому что был только один msg. В зависимости от того, что вы делаете - это может быть проблемой. Если нет, наслаждайтесь:)
Ответ 4
Вы можете использовать что-то подобное в своем элементе input
,
это запустит данное сообщение, если нажать клавишу ввода:
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
Ответ 5
Мне понравился ответ Алона, и я немного повторил его, чтобы создать атрибут, который отвечает <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
-- Enter (13) or ESC (27)
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)
Ответ 6
Если вы хотите использовать пакет сообщества Html.Events.Extra
http://package.elm-lang.org/packages/elm-community/html-extra/latest/Html-Events-Extra#onEnter, это очень просто.,
(Предполагая, что вы хотите отправить сообщение Add
когда нажата клавиша ввода.)
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
]