Created
September 10, 2016 22:19
-
-
Save markhamburg/e3b9af785d06ed392e4498e569045b25 to your computer and use it in GitHub Desktop.
Move the private state into a dictionary. I feel like I'm starting to re-invent elm-parts/elm-mdl.
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 (..) | |
import Dict | |
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 | |
, counterPrivate : Dict.Dict String CounterPrivate | |
} | |
type Msg | |
= ToCounter String CounterMsg | |
| SetValue Int | |
init : Int -> Model | |
init value = | |
{ value = value | |
, counterPrivate = Dict.empty | |
} | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ viewCounterWithIdent "A" model | |
, viewCounterWithIdent "B" model | |
] | |
viewCounterWithIdent : String -> Model -> Html Msg | |
viewCounterWithIdent ident model = | |
Html.App.map (ToCounter ident) <| viewCounter model.value (getCounterPrivate ident model) | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
ToCounter ident cmsg -> | |
let | |
counterPrivate = | |
getCounterPrivate ident model | |
(newPrivate, maybeMsg) = | |
updateCounter SetValue model.value cmsg counterPrivate | |
in | |
model | |
|> maybeUpdate maybeMsg | |
|> setCounterPrivate ident newPrivate | |
SetValue newValue -> | |
if model.value == newValue then | |
model | |
else | |
{ model | |
| value = newValue | |
, counterPrivate = | |
model.counterPrivate | |
|> Dict.map (\key private -> updateCounterPrivate newValue private) | |
} | |
maybeUpdate maybeMsg model = | |
maybeMsg | |
|> Maybe.map (\msg -> update msg model) | |
|> Maybe.withDefault model | |
-- Create the private data for counters on demand. We will store | |
-- them if they actually change. | |
getCounterPrivate : String -> Model -> CounterPrivate | |
getCounterPrivate key model = | |
case Dict.get key model.counterPrivate of | |
Just x -> x | |
Nothing -> initCounterPrivate model.value | |
setCounterPrivate : String -> CounterPrivate -> Model -> Model | |
setCounterPrivate ident private model = | |
{ model | counterPrivate = Dict.insert ident private model.counterPrivate } | |
-- 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