如何在 Elm lang 中使用 select(下拉)标签

How to use select (dropdown) tag in Elm lang

我想使用以下代码在我的 elm 应用程序中呈现简单的下拉菜单,但它没有按预期工作。我想保留联合类型 Role 并尽可能避免使用字符串。

在 Elm 中使用下拉菜单的最佳方式是什么?我还没有找到任何例子。

import Html exposing (..)
import Html.App exposing (beginnerProgram)
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import Json.Decode

main =
  beginnerProgram
    { model = initialModel
    , view = view
    , update = update
    }

initialModel =
  { role = None
  }

type Role
  = None
  | Admin
  | User

type alias Model = 
  { role: Role
  }

type Msg
  = SelectRole Role


update msg model =
  case msg of
    SelectRole role ->
      { model | role = role }


view : Model -> Html Msg
view model =
  div
    []
    [ select
        [ ]
        [ viewOption None
        , viewOption Admin
        , viewOption User
        ]
    , pre [] [ text <| toString model ]
    ]



viewOption : Role -> Html Msg
viewOption role =
  option
    [ onClick (SelectRole role) ]
    [ text <| toString role ]

onClick 处理程序实际上不适用于 option 元素。相反,您需要捕获 change 事件并查看 JSON targetValue 以查看选择的内容。

我会先删除 onClick 处理程序,然后设置 option 标记的 value 属性:

viewOption : Role -> Html Msg
viewOption role =
  option
    [ value <| toString role ]
    [ text <| toString role ]

现在您需要一个 JSON 解码器,它可以获取事件的 targetValue 字符串并将其转换为 Role:

targetValueRoleDecoder : Json.Decode.Decoder Role
targetValueRoleDecoder =
  targetValue `Json.Decode.andThen` \val ->
    case val of
      "Admin" -> Json.Decode.succeed Admin
      "User" -> Json.Decode.succeed User
      "None" -> Json.Decode.succeed None
      _ -> Json.Decode.fail ("Invalid Role: " ++ val)

现在您只需将其添加到 select change 事件处理程序:

    [ select
        [ on "change" (Json.Decode.map SelectRole targetValueRoleDecoder)
        ]
        [ viewOption None
        , viewOption Admin
        , viewOption User
        ]

我们必须求助于字符串的事实仅仅是必须将 DOM 事件中的值转换为有效联合类型的产物。您仍然希望将 Role 保留为联合类型;您现在只需要针对每个联合类型创建 JSON 解码器,因为 Elm(还)不支持任何类型的自动字符串到联合类型函数。