学習用のシンプルなアプリを作成し、ユーザーが入力フィールドで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
キーを押したときにアクションをディスパッチする機能です。
汎用keydown
ハンドラーを使用して、on
イベントに手動でバインドできます。 Elmは現在onKeyDown
ハンドラーをすぐにサポートしていませんが、将来的には計画されています。
仕様はevent.keyCodeからevent.keyに向かっているようです。これがより多くのブラウザでサポートされると、onKeyUp、onKeyDown、onKeyPressなどのヘルパーをここに追加できます。( Source )
それまでは、単純に独自のハンドラを記述し、キーコード13(Enter)を使用してアクションを実行できます。次の ellie-app を開いて、動作を確認します。入力ボックスにテキストを入力してEnterを押すと、入力ボックスの下のdivに現在の状態が反映されます。
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 }
TodoMVCのELMバージョン でonEnter
を処理するための優れた、簡単な解決策があります。
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)
上記の答えは非常に良かった-しかし、各文字をModel
すべてのキーを押すたびに-常に良いアイデアとは限りません。
たとえば、私の場合、fileSystem
のようなstrucutreがあり、ネストされているかどうかに関係なく、doubbleclick
で任意の名前を編集します。各キーを押すたびに再構成される穴fileSystem
viewを持つことはできません。遅いです。
)入力値を受け取るのが最善であることがわかりました-ユーザーが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)
注:タイムトラベリングデバッグを実行している場合は、not入力されたとおりに表示される各文字が表示されます。しかし、一度にすべてのテキスト-メッセージが1つしかなかったため..実行内容によっては、これが問題になる可能性があります。そうでない場合は、お楽しみください:)
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
コミュニティパッケージを使用する場合はHtml.Events.Extra
http://package.Elm-lang.org/packages/Elm-community/html-extra/latest/Html-Events-Extra#onEnter それは非常に簡単です。
(Enterキーが押されたときに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
]
アロンの答えが好きで、それを少し繰り返して、<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)