Skip to content

Instantly share code, notes, and snippets.

@paparga
Created December 22, 2015 22:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save paparga/dfe7eaf981884f6af1bc to your computer and use it in GitHub Desktop.
Save paparga/dfe7eaf981884f6af1bc to your computer and use it in GitHub Desktop.
Dropdown in Elm
module Dropdown where
import List exposing (..)
import Html exposing (..)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick, onBlur)
-- MODEL
type alias Item =
{ label : String
, id : Int
}
isSelected : Int -> Item -> Bool
isSelected id item =
id == item.id
type alias Model =
{ options : List Item
, selected : Int
, open : Bool
}
-- UPDATE
type Action = Click | Blur | Select Int
update : Action -> Model -> Model
update action model =
case action of
Click -> { model | open = not model.open }
Blur -> { model | open = False }
Select a -> { model | selected = a
, open = False }
outMenu : Model -> Model
outMenu model =
update Blur model
-- VIEW
itemView : Signal.Address Action -> Int -> Item -> Html
itemView address selected item =
div [ onClick address (Select item.id)
, onBlur address Blur
, itemStyle
]
[ text (if selected == item.id
then "Selected"
else item.label )]
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ button [ onClick address Click
, itemStyle
]
(let selectedItem = head (filter (isSelected model.selected) model.options)
in
[ text (case selectedItem of
Just value -> value.label
Nothing -> "Select")
])
, if model.open
then
let n = length model.options
in
ul [] (map (itemView address model.selected) model.options)
else div [] [ text "" ]
]
itemStyle : Attribute
itemStyle =
style
[ ("font-size", "14px")
, ("border-style", "solid")
, ("border-width", "1px")
, ("width", "70px")
]
countStyle : Attribute
countStyle =
style
[ ("font-size", "20px")
, ("font-family", "monospace")
, ("display", "inline-block")
, ("width", "50px")
, ("text-align", "center")
]
import Html exposing (..)
import StartApp exposing (start)
import Dropdown
import Effects
import Task
import Mouse
import Keyboard
-- Model --
dropdownA : Dropdown.Model
dropdownA = { open = False
, selected = 0
, options = [ { id = 1, label = "Abeja" }
, { id = 2, label = "Boa" }
, { id = 3, label = "Cuervo" }
]
}
dropdownB : Dropdown.Model
dropdownB = { open = False
, selected = 0
, options = [ { id = 4, label = "Azul" }
, { id = 5, label = "Bordo" }
, { id = 6, label = "Celeste" }
]
}
type alias Model =
{ dropdownA : Dropdown.Model
, dropdownB : Dropdown.Model
}
initState : Model
initState = { dropdownA = dropdownA
, dropdownB = dropdownB
}
-- Update --
type Action
= A Dropdown.Action
| B Dropdown.Action
| Out
| NoOp
onlyModel : Model -> ( Model, Effects.Effects Action )
onlyModel m = (m, Effects.none)
update : Action -> Model -> ( Model, Effects.Effects Action )
update action model =
case action of
A act ->
onlyModel { model | dropdownA = Dropdown.update act model.dropdownA }
B act ->
onlyModel { model | dropdownB = Dropdown.update act model.dropdownB }
Out ->
onlyModel { model
| dropdownA = Dropdown.outMenu model.dropdownA
, dropdownB = Dropdown.outMenu model.dropdownB }
NoOp ->
onlyModel model
-- View --
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ Dropdown.view (Signal.forwardTo address A) model.dropdownA
, Dropdown.view (Signal.forwardTo address B) model.dropdownB
]
-- INPUTS
isEsc : Bool -> Action
isEsc esc =
if esc == True
then Out
else NoOp
inputs : List (Signal Action)
inputs =
[ Signal.map (\_ -> Out ) Mouse.clicks
, Signal.map isEsc (Keyboard.isDown 27)
]
-- MAIN
init = (initState, Effects.none)
app = start
{ init = init
, view = view
, update = update
, inputs = inputs
}
main =
app.html
port tasks : Signal (Task.Task Effects.Never ())
port tasks =
app.tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment