Created
September 10, 2016 21:49
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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