diff --git a/README.md b/README.md index ed06efa..beefb2d 100644 --- a/README.md +++ b/README.md @@ -519,6 +519,98 @@ I could then do a very basic test, and see text on the page! It's ugly as heck, but it's progress! +#### Adding Json + +Now that we've added http, we are going to largely refactor that work to instead +parse a json object. The reason for this is because we want our subscription to +include items from a RESTful API response. For this step, we are generally +going to modify our application according to this [tutorial](https://guide.elm-lang.org/effects/json.html). +The first thing we do is install elm/json: + +```bash +elm install elm/json +``` + +and add an import: + +```elm +import Json.Decode exposing (Decoder, field, string) +``` + +This should compile + +``` +elm make src/Main.elm +``` + +It looks like we also need [html events](https://package.elm-lang.org/packages/elm/html/latest/Html-Events) and [html attributes](https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes): + +```elm +import Html.Attributes exposing (..) +import Html.Events exposing (..) +``` + +We now want to customize our init to, instead of loading a random blob of text, +to return a random cat gif. So we start with this: + +```elm +init : () -> ( Model, Cmd Msg ) +init _ = + ( { counter = 0 + , status = Loading + } + , Http.get + { url = "https://elm-lang.org/assets/public-opinion.txt" + , expect = Http.expectString GotText + } + ) +``` + +And since the second part is the Cmd and then a Msg for it, we just change +that entire thing to some new function we will call `getRandomCatGif` + + +```elm + +init : () -> ( Model, Cmd Msg ) +init _ = + ( { counter = 0 + , status = Loading + } + , getRandomCatGif + ) +``` + +This is also the step where I want to remove the original counter (but still maintain +the nested model with status) so I make these updates: + +```elm +type alias Model = + { status : SubState } + + + +-- Model is record that holds an integer counter, and a status for loading apps +-- init is a function that returns an Int (type Model) + + +init : () -> ( Model, Cmd Msg ) +init _ = + ( { status = Loading } + , getRandomCatGif + ) + + + +-- UPDATE + +type Msg + = MorePlease + | GotGif (Result Http.Error String) + +``` + + ### Formatting and Linting Each of diff --git a/elm.json b/elm.json index c8ebc12..6dfec3d 100644 --- a/elm.json +++ b/elm.json @@ -10,12 +10,12 @@ "elm/core": "1.0.5", "elm/html": "1.0.0", "elm/http": "2.0.0", + "elm/json": "1.1.3", "mdgriffith/elm-ui": "1.1.5" }, "indirect": { "elm/bytes": "1.0.8", "elm/file": "1.0.5", - "elm/json": "1.1.3", "elm/time": "1.0.0", "elm/url": "1.0.0", "elm/virtual-dom": "1.0.2" diff --git a/src/Main.elm b/src/Main.elm index 91edd3e..07d301e 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -4,9 +4,12 @@ import Browser import Element import Element.Background as Background import Element.Input +import Element.Region import Html exposing (Html) +import Html.Attributes exposing (..) +import Html.Events exposing (..) import Http - +import Json.Decode exposing (Decoder, field, string) -- STYLE @@ -47,9 +50,7 @@ type SubState type alias Model = - { counter : Int - , status : SubState - } + { status : SubState} @@ -59,13 +60,8 @@ type alias Model = init : () -> ( Model, Cmd Msg ) init _ = - ( { counter = 0 - , status = Loading - } - , Http.get - { url = "https://elm-lang.org/assets/public-opinion.txt" - , expect = Http.expectString GotText - } + ( { status = Loading } + , getRandomCatGif ) @@ -74,10 +70,9 @@ init _ = type Msg - = Increment - | Decrement - | Reset - | GotText (Result Http.Error String) + = MorePlease + | GotGif (Result Http.Error String) + {-| I think this says that update is a function that takes first a Msg type (e.g., @@ -88,26 +83,19 @@ update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = -- Handle the API request first case msg of - Increment -> - ( { model | counter = model.counter + 1 }, Cmd.none ) - - Decrement -> - ( { model | counter = model.counter - 1 }, Cmd.none ) - - Reset -> - ( { model | counter = 0 }, Cmd.none ) + MorePlease -> + ( { model | status = Loading }, getRandomCatGif ) - GotText result -> + GotGif result -> case result of - Ok fullText -> - ( { model | status = Success fullText }, Cmd.none ) + Ok url -> + ( { model | status = Success url }, Cmd.none ) -- Cmd.none means there is nothing left to do Err _ -> ( { model | status = Failure }, Cmd.none ) - -- APPS @@ -124,36 +112,52 @@ view model = Element.layout [] (Element.column [] [ Element.el [] - (Element.text - (case model.status of - Failure -> - "I was unable to load the text!" - - Loading -> - "Loading..." - - Success fullText -> - fullText - ) - ) - , Element.Input.button + Element.Region.heading 2 + { label = Element.text "Random Cats" } + , viewGif model + ] + ) + +viewGif : Model -> Html Msg +viewGif model = + case model.status of + Failure -> + [ Element.el [] + (Element.text "I could not load a random cat.") + , Element.Input.button [ Background.color marigold ] - { onPress = Just Increment - , label = Element.text "+" + { onPress = MorePlease + , label = Element.text "Try Again" } - , Element.el [] (Element.text (String.fromInt model.counter)) - , Element.Input.button + ] + Loading -> + [ Element.el [] + (Element.text "Loading") + ] + Success url -> + [ Element.el [] + (Element.Input.button [ Background.color marigold ] - { onPress = Just Decrement - , label = Element.text "-" - } - , Element.Input.button - [ Background.color green - ] - { onPress = Just Reset - , label = Element.text "Reset" + { onPress = MorePlease + , label = Element.text "More Please" } - ] - ) + ,Element.image 200 200 url) + ] + + +-- HTTP + + +getRandomCatGif : Cmd Msg +getRandomCatGif = + Http.get + { url = "https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat" + , expect = Http.expectJson GotGif gifDecoder + } + + +gifDecoder : Decoder String +gifDecoder = + field "data" (field "image_url" string)