How to implement a slider in elm

Updated to Elm 0.19 from banncee's update to 0.18 from Simon H's original answer

import Browser
import Html exposing (Attribute, div, text, input)
import Html.Attributes as H exposing (..)
import Html.Events exposing (on, onInput)

type alias Model = Int

type Msg
    = Update String

init : Model
init = 0

update : Msg -> Model -> Model
update (Update v) model =
    case String.toInt v of
        Just i -> i
        Nothing -> model

view model =
  div []
    [ input
      [ type_ "range"
      , H.min "0"
      , H.max "20"
      , value  <| String.fromInt model
      , onInput Update
      ] []
    , text <|String.fromInt model
    ]

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

The basic idea is to have one canonical representation of the number in your model. Whenever it changes (that would be an action), you don't care where the change came from, you just update the model. And then you render both the text area and the slider based on the value of the number in the model. (We're talking a single text field with just the number, not a free form paragraph box, right?)

Hope that helps!


It's not that hard in fact. This code shows how to set the value of the two input types. See ellie for example

Update for 0.19

type alias Model =
    Int


type Msg
    = Update String


update : Msg -> Model -> Model
update (Update v) model =
    String.toInt v |> Maybe.withDefault 0


view model =
    div []
        [ input
            [ type_ "range"
            , Attrs.min "0"
            , Attrs.max "20"
            , value <| String.fromInt model
            , onInput Update
            ]
            []
        , text <| String.fromInt model
        ]

Update for 0.18

import Html exposing (Attribute, div, text, input)
import Html.Attributes as H exposing (..)
import Html.Events exposing (on, onInput)
import Json.Decode exposing (string, map)
import String

type alias Model = Int

type Msg
    = Update String

update : Msg -> Model -> Model
update (Update v) model =
    String.toInt v |> Result.withDefault 0

view model =
  div []
    [ input
      [ type_ "range"
      , H.min "0"
      , H.max "20"
      , value <| toString model
      , onInput Update
      ] []
    , text <| toString model
    ]

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

Update for 0.17

import Html exposing (Attribute, div, text, input)
import Html.App as Html
import Html.Attributes as H exposing (..)
import Html.Events exposing (on, onInput)
import Json.Decode exposing (string, map)
import String

type alias Model = Int

type Msg
    = Update String

update : Msg -> Model -> Model
update (Update v) model =
    String.toInt v |> Result.withDefault 0

view model =
  div []
    [ input
      [ type' "range"
      , H.min "0"
      , H.max "20"
      , value <| toString model
      , onInput Update
      ] []
    , text <| toString model
    ]

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

** Original O.16 version **

import Html exposing (div, text, input)
import Html.Attributes as H exposing (..)
import Html.Events as E 

mbox = 
  Signal.mailbox "0"

view v =
  let 
    evth = E.on "change" E.targetValue (Signal.message mbox.address)
  in
  div [] 
    [ input 
      [ type' "range"
      , H.min "0"
      , H.max "20"
      , value v
      , evth
      ] []
    , input
      [ type' "text", value v, evth ] []
    ]


main =
  Signal.map view mbox.signal

From Simon H's original answer, Update for Elm 0.18:

import Html exposing (Attribute, div, text, input, beginnerProgram)
import Html.Attributes as H exposing (..)
import Html.Events exposing (on, onInput)

type alias Model = Int

type Msg
    = Update String

update : Msg -> Model -> Model
update (Update v) model =
    String.toInt (Debug.log "" v) |> Result.withDefault 0

view model =
  div []
    [ input
      [ type_ "range"
      , H.min "0"
      , H.max "20"
      , value <| toString model
      , onInput Update
      ] []
    , text <| toString model
    ]

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

Tags:

Elm