web-dev-qa-db-fra.com

Comment gérer la pression de la touche Entrée dans le champ de saisie?

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.

24
SuperManEver

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 }
20
dotcs

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)
17
bowsersenior

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 :)

5
AIon

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
4
Tosh

Si vous souhaitez utiliser le package communautaire Html.Events.Extrahttp://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
      ]
3
NateW

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)
2
Simon H