J'ai construit une application simple à des fins d'apprentissage et je veux pouvoir envoyer une action lorsque l'utilisateur appuie sur la touche Enter
dans le champ de saisie
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
]
Voici le code de vue. J'espère que ce sera suffisant pour vous expliquer mon intention. Ce que j'aimerais avoir, c'est pouvoir envoyer une action lorsque l'utilisateur appuie sur la touche Enter
pendant qu'il entre du texte dans le champ de saisie.
Vous pouvez lier manuellement à l'événement keydown
avec le gestionnaire générique on
. Elm ne prend actuellement pas en charge les gestionnaires onKeyDown
prêts à l'emploi - mais ils sont prévus à l'avenir.
Il semble que la spécification s'éloigne de event.keyCode et se dirige vers event.key. Une fois que cela est pris en charge dans plus de navigateurs, nous pouvons ajouter des assistants ici pour onKeyUp, onKeyDown, onKeyPress, etc. ( Source )
Jusque-là, vous pouvez simplement écrire votre propre gestionnaire et utiliser le code clé 13 (entrée) pour effectuer vos actions. Ouvrez ce qui suit ellie-app pour voir comment cela fonctionne. Entrez simplement du texte dans la zone de saisie et appuyez sur Entrée pour voir l'état actuel reflété dans la div sous la zone de saisie.
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 }
Il existe une bonne solution simple pour gérer onEnter
dans la version Elm de 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)
Les réponses ci-dessus étaient très bonnes - mais stockant chaque lettre dans le Model
à chaque pression de touche - n'est pas toujours une bonne idée.
Par exemple, dans mon cas, j'ai un strucutre fileSystem
- et je veux modifier n'importe quel nom - peu importe comment il est imbriqué - sur doubbleclick
. Je ne peux pas faire reconstruire la vue fileSystem
à chaque pression de touche . C'est lent.
J'ai trouvé qu'il est préférable de recevoir la valeur d'entrée - uniquement lorsque l'utilisateur appuie sur Entrée ..
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)
Remarque: Si vous effectuez un débogage dans le temps - vous pas verrez chaque lettre apparaître telle qu'elle a été tapée. Mais tout le texte à la fois - car il n'y avait qu'un seul msg .. Selon ce que vous faites - cela peut être un problème. Sinon, profitez :)
Vous pouvez utiliser quelque chose comme ceci dans votre élément input
, cela déclenchera le message donné si la touche Entrée est enfoncée:
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
Si vous souhaitez utiliser le package communautaire Html.Events.Extra
http://package.Elm-lang.org/packages/Elm-community/html-extra/latest/Html-Events-Extra#onEnter c'est très simple.
(En supposant que vous souhaitez envoyer le message Add
lorsque la touche Entrée est enfoncée.)
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
]
J'ai aimé la réponse d'Alon et je l'ai répété un peu pour créer un attribut qui répond à <enter>
et <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)