Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added example usage of the 'update' function. #17

Merged
merged 2 commits into from
Dec 1, 2017
Merged
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
63 changes: 42 additions & 21 deletions src/RemoteData.elm
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,27 @@ where they can be quietly ignored, consider using this. It makes it
easier to represent the real state of a remote data fetch and handle
it properly.


For more on the motivation, take a look at the blog post [How Elm Slays A UI Antipattern](http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html).


To use the datatype, let's look at an example that loads `News` from a feed.

First you add to your model, wrapping the data you want in `WebData`:


``` elm
```elm
type alias Model =
{ news : WebData News }
```

Then add in a message that will deliver the response:

``` elm
```elm
type Msg
= NewsResponse (WebData News)
```

Now we can create an HTTP get:

``` elm
```elm
getNews : Cmd Msg
getNews =
Http.get "/news" decodeNews
Expand All @@ -66,7 +63,7 @@ getNews =

We trigger it in our `init` function:

``` elm
```elm
init : ( Model, Cmd Msg )
init =
( { news = Loading }
Expand All @@ -76,7 +73,7 @@ init =

We handle it in our `update` function:

``` elm
```elm
update msg model =
case msg of
NewsResponse response ->
Expand All @@ -85,16 +82,14 @@ update msg model =
)
```


Most of this you'd already have in your app, and the changes are just
wrapping the datatype in `Webdata`, and replacing the `Http.send` call
with `RemoteData.sendRequest`.

Now we get to where we really want to be, rendering the data and
handling the different states in the UI gracefully:


``` elm
```elm
view : Model -> Html msg
view model =
case model.news of
Expand Down Expand Up @@ -147,10 +142,12 @@ import Task exposing (Task)


{-| Frequently when you're fetching data from an API, you want to represent four different states:
* `NotAsked` - We haven't asked for the data yet.
* `Loading` - We've asked, but haven't got an answer yet.
* `Failure` - We asked, but something went wrong. Here's the error.
* `Success` - Everything worked, and here's the data.

- `NotAsked` - We haven't asked for the data yet.
- `Loading` - We've asked, but haven't got an answer yet.
- `Failure` - We asked, but something went wrong. Here's the error.
- `Success` - Everything worked, and here's the data.

-}
type RemoteData e a
= NotAsked
Expand Down Expand Up @@ -203,6 +200,7 @@ map2 f a b =
result will succeed when (and if) all three sources succeed.

If you need `map4`, `map5`, etc, see the documentation for `andMap`.

-}
map3 :
(a -> b -> c -> d)
Expand Down Expand Up @@ -314,12 +312,13 @@ fromResult result =
{-| Convenience function for dispatching `Http.Request`s. It's like
`Http.send`, but yields a `WebData` response.

``` elm
```elm
getNews : Cmd Msg
getNews =
Http.get "/news" decodeNews
|> RemoteData.sendRequest
```

-}
sendRequest : Http.Request a -> Cmd (WebData a)
sendRequest =
Expand All @@ -339,6 +338,7 @@ they were one.
If either value is `NotAsked`, the result is `NotAsked`.
If either value is `Loading`, the result is `Loading`.
If both values are `Failure`, the left one wins.

-}
append :
RemoteData e a
Expand All @@ -354,7 +354,7 @@ append a b =
For example, if you were fetching three datasets, `a`, `b` and `c`,
and wanted to end up with a tuple of all three, you could say:

``` elm
```elm
merge3 :
RemoteData e a
-> RemoteData e b
Expand All @@ -366,14 +366,14 @@ merge3 a b c =
|> andMap c
```

The final tuple succeeds only if all its children succeeded. It is
still `Loading` if _any_ of its children are still `Loading`. And if
The final tuple succeeds only if all its children succeeded. It is
still `Loading` if *any* of its children are still `Loading`. And if
any child fails, the error is the leftmost `Failure` value.

Note that this provides a general pattern for `map2`, `map3`, ..,
`mapN`. If you find yourself wanting `map4` or `map5`, just use:

``` elm
```elm
foo f a b c d e =
map f a
|> andMap b
Expand All @@ -387,6 +387,7 @@ discussion, "Could you just add `map7`? Could you just add `map8`?
Could you just...".

Category theory points: This is `apply` with the arguments flipped.

-}
andMap : RemoteData e a -> RemoteData e (a -> b) -> RemoteData e b
andMap wrappedValue wrappedFunction =
Expand All @@ -407,6 +408,7 @@ andMap wrappedValue wrappedFunction =
{-| Lift an ordinary value into the realm of RemoteData.

Category theory points: This is `pure`.

-}
succeed : a -> RemoteData e a
succeed =
Expand Down Expand Up @@ -465,6 +467,7 @@ isNotAsked data =

This is fairly low-level. Most people will use `sendRequest` instead
and stay above `Task`s entirely.

-}
fromTask : Task e a -> Task x (RemoteData e a)
fromTask =
Expand All @@ -485,6 +488,23 @@ This function makes it more convenient to reach inside a
`RemoteData.Success` value and apply an update. If the data is not
`Success a`, it is returned unchanged with a `Cmd.none`.

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
EnabledChanged isEnabled ->
let
( settings, cmd ) =
RemoteData.update (updateEnabledSetting isEnabled) model.settings
in
( { model | settings = settings }, cmd )


updateEnabledSetting : Bool -> Settings -> ( Settings, Cmd msg )
updateEnabledSetting isEnabled settings =
( { settings | isEnabled = isEnabled }, Cmd.none )
```

-}
update : (a -> ( b, Cmd c )) -> RemoteData e a -> ( RemoteData e b, Cmd c )
update f remoteData =
Expand Down Expand Up @@ -512,11 +532,12 @@ If you use Monocle, you'll want this, otherwise you can ignore it.

The type signature is actually:

``` elm
```elm
prism : Prism (RemoteData e a) a
```

...but we use the more verbose type here to avoid introducing a dependency on Monocle.

-}
prism :
{ getOption : RemoteData e a -> Maybe a
Expand Down