Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
112 changes: 58 additions & 54 deletions src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -47,9 +50,7 @@ type SubState


type alias Model =
{ counter : Int
, status : SubState
}
{ status : SubState}



Expand All @@ -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
)


Expand All @@ -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.,
Expand All @@ -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


Expand All @@ -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)