Arnaud Chenyensu |||

Checkboxes in Elm

Demo

Source Code

  
    import Browser
    import Html exposing (Html, div, label, input, text, span, button)
    import Html.Attributes exposing (type_, checked)
    import Html.Events exposing (onClick)


    type alias Checkbox a =
      { id: String
      , checked: Bool
      , value: a
      }

    type alias Checkboxes a = List (Checkbox a)

    getChecked : Checkboxes a -> Checkboxes a
    getChecked checkboxes =
      List.filter .checked checkboxes

    getNotChecked : Checkboxes a -> Checkboxes a
    getNotChecked checkboxes =
      List.filter (\c -> not c.checked) checkboxes

    filter : Filter -> Checkboxes a -> Checkboxes a
    filter filt checkboxes =
      case filt of
        Checked ->
          getChecked checkboxes
        NotChecked ->
          getNotChecked checkboxes
        None ->
          checkboxes

    toggle : Checkbox a -> Checkboxes a -> Checkboxes a
    toggle {id} checkboxes =
      List.map (\checkbox ->
        if id == checkbox.id then
          { checkbox | checked = not checkbox.checked }
        else checkbox
      ) checkboxes

    toHtml : (Checkbox a -> msg) -> (a -> String) -> Checkbox a -> Html msg
    toHtml msg toString checkbox =
      label
        []
        [ input
          [ type_ "checkbox"
          , onClick (msg checkbox)
          , checked checkbox.checked
          ]
          []
        , span [] []
        , text (toString checkbox.value)
        ]

    display : (Checkbox a -> msg) -> (a -> String) -> Checkboxes a -> Html msg
    display msg toString checkboxes =
      let
        divs =
          List.map (\checkbox ->
            div
              []
              [ (toHtml msg toString checkbox) ]
          ) checkboxes
      in
        div [] divs


    -- MAIN

    main =
      Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

    type Filter
      = Checked
      | NotChecked
      | None

    type alias Model =
      { checkboxes : Checkboxes String
      , filter : Filter
      }

    type Msg
      = Toggle (Checkbox String)
      | SetFilter Filter

    init : () -> (Model, Cmd Msg)
    init _ =
      let
        model =
          { checkboxes =
            [ { id = "c1"
              , checked = False
              , value = "Checkbox 1"
              }
            , { id = "c2"
              , checked = False
              , value = "Checkbox 2"
              }
            , { id = "c3"
              , checked = False
              , value = "Checkbox 3"
              }
            ]
          , filter = None
          }
      in
        (model, Cmd.none)

    update : Msg -> Model -> (Model, Cmd Msg)
    update msg model =
      case msg of
        Toggle checkbox ->
          ({ model | checkboxes = toggle checkbox model.checkboxes }, Cmd.none)
        SetFilter filt ->
          ({ model | filter = filt }, Cmd.none)

    subscriptions : Model -> Sub Msg
    subscriptions model =
      Sub.none

    view : Model -> Html Msg
    view model =
      div
        []
        [ display (\c -> Toggle c) identity (filter model.filter model.checkboxes)
        , button
          [ onClick (SetFilter None) ]
          [ text "All" ]
        , button
          [ onClick (SetFilter Checked) ]
          [ text "Checked"]
        , button
          [ onClick (SetFilter NotChecked) ]
          [ text "Not checked" ]
        ]