与 Elm 和 Select 一起工作

19

我尝试通过自定义示例来理解elm的工作原理。

durationOption duration =
  option [value (toString duration) ] [ text (toString duration)]

view : Model -> Html Msg
view model =
  Html.div []
    [ h2 [] [ text "Month selector"]
    , select []
      (List.map durationOption [1..12])    
    ]

这是一个使用select的简单示例。我希望每次更改月份值时,它会将该值乘以10。根据文档,似乎没有像onChangeonSelect这样的事件,我是否需要使用on创建我的事件?

5个回答

43
使用 Elm 0.18.0 + elm-lang/html 2.0.0 版本,onInput 事件(参见下面的代码)可以正常工作(参考官方 Elm 示例)。同时请注意整数范围表示法的差异(使用 List.range 0 12 而不是 [0..12])。
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)


main =
  Html.beginnerProgram
    { model = model
    , view = view
    , update = update
    }



-- MODEL


type alias Model =
  { duration : Int
  }


model : Model
model =
  Model 0



-- UPDATE


type Msg
    = SetDuration String


update : Msg -> Model -> Model
update msg model =
  case msg of
    SetDuration s ->
      let result =
        String.toInt s
      in
        case result of
          Ok v ->
            { model | duration = v }
            
          Err message ->
            model


-- VIEW


view : Model -> Html Msg
view model =
  div []
    [ select [ onInput SetDuration ]
             (List.range 0 12 |> List.map intToOption)
    , div [] [ text <| "Selected: " ++ (toString model.duration) ]         
    ]


intToOption : Int -> Html Msg
intToOption v =
  option [ value (toString v) ] [ text (toString v) ]

5
这个回答不能标记为答案吗?这样会方便很多,麻烦少得多。 - Daniel Kaplan
5
目前oninput不像onChange那样跨浏览器兼容,可惜。http://caniuse.com/#search=oninput - Eric G
2
除了 Opera Mini 以外的所有浏览器都可以兼容。 - Robert Fischer
3
在Internet Explorer中,select元素不会触发onInput事件,因此其兼容性比@RobertFischer所建议的更有限。 - CoderDennis

24

更新: onInput可以使用, 可以查看下面另一个回答的0.19版本可用代码:https://dev59.com/FFoU5IYBdhLWcg3wg3Oo#41516493

是的,你需要使用on来处理change事件。如果你查看内置在Elm中的其他事件处理程序源代码,比如onClick,你会发现它们都是使用on函数构建的。

这里有一个例子,它使用elm-community/html-extra提供的targetValueIntParse将选项中的字符串值转换为整数。

已更新至Elm 0.18版。

import Html exposing (..)
import Html.Events exposing (on)
import Html.Attributes exposing (..)
import Json.Decode as Json
import String
import Html.Events.Extra exposing (targetValueIntParse)


main =
    beginnerProgram { model = { duration = 1 }, view = view, update = update }


durationOption duration =
    option [ value (toString duration) ] [ text (toString duration) ]


view : Model -> Html Msg
view model =
    Html.div []
        [ h2 [] [ text "Month selector" ]
        , select [ on "change" (Json.map SetDuration targetValueIntParse) ]
            (List.map durationOption (List.range 1 12))
        , div [] [ text <| "Selected: " ++ (toString model.duration) ]
        ]


type Msg
    = SetDuration Int


type alias Model =
    { duration : Int }


update msg model =
    case msg of
        SetDuration val ->
            { model | duration = val }

你可以在浏览器中运行此示例:https://runelm.io/c/ahz


谢谢您的回复。我需要更多的技能来理解这段代码发生了什么。 - billyJoe
7
为什么标准库中没有“onChange”函数? - DenisKolodin
1
不要忘记,在 option 元素中使用 Html.Attributes.selected = True 可以确保所选选项始终正确地显示在选择框中。 - Marcelo Lazaroni

2

这里是Elm 0.19的更新:

module Main exposing (main)

import Browser
import Html exposing (..)
import Html.Events exposing (on)
import Html.Attributes exposing (..)
import Json.Decode as Json
import String
import Html.Events.Extra exposing (targetValueIntParse)


main =
    Browser.sandbox { init = { duration = 1 }, view = view, update = update }


durationOption duration =
    option [ value (String.fromInt duration) ] [ text (String.fromInt duration) ]


view : Model -> Html Msg
view model =
    Html.div []
        [ h2 [] [ text "Month selector" ]
        , select [ on "change" (Json.map SetDuration targetValueIntParse) ]
            (List.map durationOption (List.range 1 12))
        , div [] [ text <| "Selected: " ++ (String.fromInt model.duration) ]
        ]


type Msg
    = SetDuration Int


type alias Model =
    { duration : Int }


update msg model =
    case msg of
        SetDuration val ->
            { model | duration = val }

1
这段代码可以在 Elm 0.19.0 上与 Ellie 配合使用:https://ellie-app.com/58wGf2YsR9Ya1 完整代码:
import Browser
import Html exposing (..)
import Html.Events exposing (on)
import Html.Attributes exposing (..)
import Json.Decode as Json
import String
import Html.Events.Extra exposing (targetValueIntParse)

main =
    Browser.sandbox { init = init, view = view, update = update }

init =
    { duration = 1 }

durationOption duration =
    option [ value (String.fromInt duration) ] [ text (String.fromInt duration) ]


view : Model -> Html Msg
view model =
    Html.div []
        [ h2 [] [ text "Month selector" ]
        , select [ on "change" (Json.map SetDuration targetValueIntParse) ]
            (List.map durationOption (List.range 1 12))
        , div [] [ text <| "Selected: " ++ (String.fromInt model.duration) ]
        ]


type Msg
    = SetDuration Int


type alias Model =
    { duration : Int }


update msg model =
    case msg of
        SetDuration val ->
            { model | duration = val }

1

一个使用onInput处理程序的示例(您也可以查看Ellie):

module Main exposing (main)

import Browser import Html exposing (Html, button, div, text, select, option) import Html.Attributes exposing (value, selected) import Html.Events exposing (onInput) import Dict exposing (Dict)

type alias Model =
    { options : Dict Int (String, Bool)
    }


initialModel : Model initialModel =
    { options = Dict.fromList [(0, ("All time", False)), (1, ("One week", True)), (2, ("24h", False))] 
    }


type Msg
    = Select String


update : Msg -> Model -> Model update msg model =
    case msg of
        Select value ->
            case String.toInt value of
                Just selectedID ->
                    let
                        changeSelection id (label, _) =
                            if id == selectedID then
                                (label, True)
                            else
                                (label, False)
                    in
                    {model | options = Dict.map changeSelection model.options}

                Nothing ->
                    model



view : Model -> Html Msg view model =
    let
        toOption (id, (label, isSelected)) =
            option [value (String.fromInt id), selected isSelected] [text label]
    in
    div []
        [ select [onInput Select] (List.map toOption <| Dict.toList model.options)
        , div [] [text "DEBUG"]
        , div [] [text <| Debug.toString model.options]
        ]


main : Program () Model Msg main =
    Browser.sandbox
        { init = initialModel
        , view = view
        , update = update
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接