Search code examples
html-selectselectedindexelm

How to print index of selected option in Elm?


I have a <select> HTML element with 3 options and a <p> element. In the <p> element I want to print index of the currently selected item in <select>. E.g. if I select the first option, it should print 0, if I select the second option, it should print 1, and so on. How do I proceed from the minimal code, which is given below?

import Html as H exposing (Html)
import Maybe
import Signal as S exposing (Address, (<~))

type alias Model = { selected : Maybe Int }
model = { selected = Nothing }

type Action = NoOp | Select Int
update action model =
  case action of
    NoOp -> model
    Select n -> { model | selected <- Just n }

view address model =
  H.div []
     [ H.select [] [ H.option [] [ H.text "0" ]
                   , H.option [] [ H.text "1" ]
                   , H.option [] [ H.text "2" ]
                   ]
     , H.p [] [ H.text <| Maybe.withDefault ""
                   <| Maybe.map toString model.selected ]
     ]

actions = Signal.mailbox NoOp
main = view actions.address <~ S.foldp update model actions.signal

Solution

  • There's a lot of different events in elm-html 2.0.0, but nothing relevant to the <select> HTML element. So you definitely need a custom event handler, which you can create using on. It has a type:

    on : String -> Decoder a -> (a -> Message a) -> Attribute
    

    The event that is triggered every time you select an option inside the <select> is called “change”. What you need is targetSelectedIndex from elm-community/html-extra which ustilizes a selectedIndex property.

    The final code would look like this:

    Updated to Elm-0.18

    import Html exposing (..)
    import Html.Events exposing (on, onClick)
    import Html.Attributes exposing (..)
    import Json.Decode as Json
    import Html.Events.Extra exposing (targetSelectedIndex)
    
    
    type alias Model =
        { selected : Maybe Int }
    
    
    model : Model
    model =
        { selected = Nothing }
    
    
    type Msg
        = NoOp
        | Select (Maybe Int)
    
    
    update : Msg -> Model -> Model
    update msg model =
        case msg of
            NoOp ->
                model
    
            Select s ->
                { model | selected = s }
    
    
    view : Model -> Html Msg
    view model =
        let
            selectEvent =
                on "change"
                    (Json.map Select targetSelectedIndex)
        in
            div []
                [ select [ size 3, selectEvent ]
                    [ option [] [ text "1" ]
                    , option [] [ text "2" ]
                    , option [] [ text "3" ]
                    ]
            , p []
                [ text <|
                    Maybe.withDefault "" <|
                        Maybe.map toString model.selected
                ]
            ]
    
    
    main : Program Never Model Msg
    main =
        beginnerProgram { model = model, view = view, update = update }
    

    You can run it in browser here https://runelm.io/c/xum