Skip to content

Instantly share code, notes, and snippets.

@bensu
Created August 19, 2015 19:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bensu/8dcb79cf698b3fafb950 to your computer and use it in GitHub Desktop.
Save bensu/8dcb79cf698b3fafb950 to your computer and use it in GitHub Desktop.
Dropdown Component 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 }
-- 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 -> "Selected"
| otherwise -> 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 ->
let n = length model.options
in
ul [] (map (itemView address model.selected) model.options)
| otherwise -> 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")
]

Mental process when encountering the first new concept:

After using filter I find my first Maybe, through a type mismatch:

Maybe Item vs value.id

where Item : { id : Int, label : String }

Ok, I need to tell the compiler that I will handle the nil case. How do they call nil here? Couldn't find it in the docs as nil or as Maybe. Let's try google "elmlang maybe", I get core/Maybe.elm and find "Nothing". Let's handle Nothing. My first attempt:

if | item == Nothing -> dostuff | otherwise -> dostuff

doesn't work, same error message. I think the problem is in the Item vs value.id, not the Maybe. Then I define anonymous functions as typed functions to tell the compiler that it's just a record with .id but Item. Doesn't work. Hhmm, maybe the if didn't solve the Maybe. Go back to core/Maybe, read how case handles Just and Nothing. Success!

import Html exposing (..)
import StartApp.Simple exposing (start)
import Dropdown
-- 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
update : Action -> Model -> Model
update action model =
case action of
A act ->
{ model | dropdownA <- Dropdown.update act model.dropdownA }
B act ->
{ model | dropdownB <- Dropdown.update act model.dropdownB }
-- 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
]
main =
start
{ model = initState
, update = update
, view = view
}
@dmclean77
Copy link

dropdown.elm doesn't work in 0.18

@dmclean77
Copy link

0.18 doesn't like "module Dropdown where" or "<-" or "if |"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment