使用榆树和 select

Work with elm and select

我尝试通过自定义示例了解 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 创建我的事件?

更新:onInput 有效,请参阅下面的另一个答案,其中包含 0.19 工作代码:

是的,您将需要使用 on 来处理更改事件。如果您查看 source for other event handlers built into Elm, like onClick,您会发现它们都是使用 on 函数构建的。

这是一个使用 targetValueIntParse from elm-community/html-extra 将字符串值从选项转换为 int 的示例。

更新到 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

供 Elm 新手(像我一样)将来参考:使用 Elm 0.18.0 + elm-lang/html 2.0.0,onInput 事件(见下面的代码)works。 (另请注意 int 范围符号的差异(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) ]

这是 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 }

使用 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
        }

这适用于 Ellie on Elm 0.19.0: 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 }