12

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
Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166

1 Answers1

18

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

rofrol
  • 14,438
  • 7
  • 79
  • 77
Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166
  • Yet, could you do without cuts? :) – yevt Apr 03 '16 at 07:36
  • Shortened names of packages. This example helped me a lot, but I had to copypaste it in text editor and change JD to Json.Decode etc... before I could understand it. – yevt Apr 04 '16 at 06:47
  • It would be excellent to see this updated for elm-0.17 if you get the time. I'll try to do it if I feel my understanding of select options is good enough. – MichaelJones May 22 '16 at 10:02
  • 2
    Here's an `onSelect` that works with Elm 0.17: [onSelect gist](https://gist.github.com/chalmagean/c0b2f874bcff728b3db047aa26b4e477) – Cezar Halmagean Sep 27 '16 at 13:29
  • There's an `onSelect` included in `Exts.Html.Events`. Check out http://package.elm-lang.org/packages/krisajenkins/elm-exts/25.13.0/Exts-Html-Events – Jezen Thomas Nov 14 '16 at 19:59