Skip to content

Instantly share code, notes, and snippets.

@markhamburg
Created September 10, 2016 21:49
Show Gist options
  • Save markhamburg/48f92aaccc419c4b2a93977d09afa4d7 to your computer and use it in GitHub Desktop.
Save markhamburg/48f92aaccc419c4b2a93977d09afa4d7 to your computer and use it in GitHub Desktop.
This version handles the communication back to the global state by using message generation.
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.App
import Html.Events exposing (..)
type CounterMsg
= Decrement
| Increment
| Push
| Pop
type CounterPrivate =
Private (List Int)
-- Initialize the private data for a counter
initCounterPrivate : Int -> CounterPrivate
initCounterPrivate value =
Private []
-- Update the private data for a counter given a change in
-- the public value
updateCounterPrivate : Int -> CounterPrivate -> CounterPrivate
updateCounterPrivate value old =
old
-- Generate a view for a counter with value stack
viewCounter : Int -> CounterPrivate -> Html CounterMsg
viewCounter value (Private stack) =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (toString value) ]
, button [ onClick Increment ] [ text "+" ]
, button [ onClick Push ] [ text "Push" ]
, button [ onClick Pop, disabled (stack == []) ] [ text "Pop" ]
]
-- Update for a counter with stack
updateCounter :
(Int -> parentMsg) -- config: send setValue messages back
-> Int -- the current counter value
-> CounterMsg -- our message
-> CounterPrivate -- our state
-> (CounterPrivate, Maybe parentMsg)
updateCounter setValue value msg ((Private stack) as private) =
case msg of
Decrement ->
(private, Just <| setValue <| value - 1)
Increment ->
(private, Just <| setValue <| value + 1)
Push ->
(Private <| value :: stack, Nothing)
Pop ->
case stack of
[] -> (private, Nothing)
x :: rest -> (Private rest, Just <| setValue x)
-- Our model will have two view with private stacks working with
-- the same counter
type alias Model =
{ value : Int
, privateA : CounterPrivate
, privateB : CounterPrivate
}
type Msg
= ToA CounterMsg
| ToB CounterMsg
| SetValue Int
init : Int -> Model
init value =
{ value = value
, privateA = initCounterPrivate value
, privateB = initCounterPrivate value
}
view : Model -> Html Msg
view model =
div []
[ Html.App.map ToA <| viewCounter model.value model.privateA
, Html.App.map ToB <| viewCounter model.value model.privateB
]
update : Msg -> Model -> Model
update msg model =
case msg of
ToA cmsg ->
let
(newPrivateA, maybeMsg) =
updateCounter SetValue model.value cmsg model.privateA
newModel =
maybeUpdate maybeMsg model
in
{ newModel | privateA = newPrivateA } -- assume this is more correct
ToB cmsg ->
let
(newPrivateB, maybeMsg) =
updateCounter SetValue model.value cmsg model.privateB
newModel =
maybeUpdate maybeMsg model
in
{ newModel | privateB = newPrivateB } -- assume this is more correct
SetValue newValue ->
if model.value == newValue then
model
else
{ model
| value = newValue
, privateA = updateCounterPrivate newValue model.privateA
, privateB = updateCounterPrivate newValue model.privateB
}
maybeUpdate maybeMsg model =
maybeMsg
|> Maybe.map (\msg -> update msg model)
|> Maybe.withDefault model
-- Wire it up and run it
main =
Html.App.beginnerProgram { model = init 0, view = view, update = update }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment