Elm備忘録 ~Html.Keyedの活用[前編]~
- type=fileのinput要素で活用する
- type=file, inputの仕様
- 同じファイルを二度連続で選択したときonChangeが発火しない(changeしてないからその通りっちゃあそのとおり)
- これでは困ることがある
- 別のフォームでの入力値が変わったときにinput要素でたとえ同じファイルでももう一度onChangeしてほしい!
- 別のフォームでの入力でバリデーションの条件変わったりとかあるでしょ?あったのよ
Html.Keyedを使って別のフォームの入力値が変わったときにinput要素を再生成させることで切り抜ける
-
Html.Keyed.nodeはHtml要素を生成させるための関数(ざっくりいうとね)だが、Html.nodeと違うのは第三引数
- Html.nodeは List (Html msg)
- Html.Keyedは List (String, Html msg)
- になっている。2つとも要素のchildrenを指定できる引数となっている
- Keyedのほうはchildrenとその各要素対してStringでkeyを指定する
- keyが指定されるとどうなるのか?VirtualDomのDiffを計算するフェーズでKeyが一致しなければ要素が再生成されることになる
- なのでfile=typeのinput以外のフォームによる入力値をkeyにすることで、それが変わるとfile=typeのinputは再生されて、同じファイルを選択したときにも再びonChangeが発火する
before
type Msg
= ChangedCategory String
| SelectedFile String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChangedCategory category ->
( { model | selectedCategory = category }, Cmd.none )
SelectedFile filePath ->
( { model | selectedFilePathMessage = Just (filePath ++ "|category:" ++ model.selectedCategory) }, Cmd.none )
---- VIEW ----
filePathMessage : Maybe String -> Html msg
filePathMessage strM =
strM |> Maybe.withDefault "ファイルが選択されてません" |> Html.text
view : Model -> Html Msg
view model =
div []
[ Html.div
[]
[ Html.input [ onInput SelectedFile, Html.Attributes.type_ "file" ] []
, model.selectedCategory
, filePathMessage model.selectedFilePathMessage
]
, Html.div []
[ Html.text "ファイル種類: "
, Html.select [ onInput ChangedCategory ]
[ Html.option [ Html.Attributes.value "csv" ]
[ Html.text "csv"
]
, Html.option [ Html.Attributes.value "tsv" ]
[ Html.text "tsv"
]
, Html.option [ Html.Attributes.value "plain" ]
[ Html.text "plain"
]
]
]
]
- after
type Msg
= ChangedCategory String
| SelectedFile String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChangedCategory category ->
( { model | selectedCategory = category }, Cmd.none )
SelectedFile filePath ->
( { model | selectedFilePathMessage = Just (filePath ++ "|category:" ++ model.selectedCategory) }, Cmd.none )
---- VIEW ----
filePathMessage : Maybe String -> Html msg
filePathMessage strM =
strM |> Maybe.withDefault "ファイルが選択されてません" |> Html.text
view : Model -> Html Msg
view model =
div []
[ Keyed.node "div" -- 変わったよ!
[]
[ ( model.selectedCategory, Html.input [ onInput SelectedFile, Html.Attributes.type_ "file" ] [] )
, ( model.selectedCategory, filePathMessage model.selectedFilePathMessage )
]
, Html.div []
[ Html.text "ファイル種類: "
, Html.select [ onInput ChangedCategory ]
[ Html.option [ Html.Attributes.value "csv" ]
[ Html.text "csv"
]
, Html.option [ Html.Attributes.value "tsv" ]
[ Html.text "tsv"
]
, Html.option [ Html.Attributes.value "plain" ]
[ Html.text "plain"
]
]
]
]