pete-murphy/elm-loadable/1.0.1

NOTE: the latest version is 2.1.0

pete-murphy/elm-loadable

A data type for tracking loadable (and reloadable) data, like data fetched from a backend server.

See an [example in action on Ellie]({{YOUR LINK HERE}}). -->

Installation

elm install pete-murphy/elm-loadable

Design Goals

This package is centered around the Loadable type, which is a minimal extension of RemoteData from krisajenkins/remotedata that adds a "reloading" state to the error and success cases. See this discussion on alternative solutions to this problem for background.

There are many other use cases for extensions on top of RemoteData—you might want to track how many times a request has been attempted, or you might want to attach metadata about when the data was last successfully loaded. The motivation for this package is simply to allow showing stale data while refetching.

Loadable e a is essentially the same as ( Bool, Maybe (Result e a) ). This could be encoded many different ways, for example as the sum type

type Loadable e a
    = NotAsked
    | Loading
    | Failure e
    | FailureReloading e
    | Success a
    | SuccessReloading a

The encoding in this package is intended to make pattern-matching as simple as possible. Using Loadable.value this will often look like

case Loadable.value model of
    Loadable.Empty ->
        -- ...

    Loadable.Success success ->
        -- ...

    Loadable.Failure failure ->
        -- ...

with the option of matching on Loadable.isLoading model in any of the three branches as needed.

Overview

Example usage

type alias Model =
    { todos : Loadable Http.Error (List Todo) }


init : ( Model, Cmd Msg )
init =
    ({ todos = Loadable.notAsked }, fetchTodos )


type Msg
    = UserClickedFetchTodos
    | BackendRespondedWithTodos (Result Http.Error (List Todo))


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UserClickedFetchTodos ->
            ( { model | todos = Loadable.toLoading model.todos }, fetchTodos )

        BackendRespondedWithTodos result ->
            ( { model | todos = Loadable.fromResult result }, Cmd.none )


view : Model -> Html Msg
view model =
    Html.div []
        [ Html.h1 [] [ Html.text "Todos" ]
        , Html.button [ Events.onClick UserClickedFetchTodos ] [ Html.text "Fetch Todos" ]
        , Html.div [ Attributes.classList [ ( "loading", Loadable.isLoading model.todos ) ] ]
            [ case Loadable.value model.todos of
                Loadable.Empty ->
                    Html.text "Loading..."

                Loadable.Success todos ->
                    Html.ul [] (List.map viewTodo todos)

                Loadable.Failure _ ->
                    Html.text "Something went wrong"
            ]
        ]

See this example on Ellie