Elm Loadable
This package is an extension of the ideas from this very cool project/blog/talk by Kris Jenkins.
type Loadable error value
= Idle
| Loading
| Success value
| Failure error
| Reloading value
| ReloadFailure error value
It's nice to have context available during data-loading - this package keeps the previous value around until a new one arrives. It can be shown during (or after failing) to reload.
module Main exposing (main)
import Browser exposing (element)
import Element exposing (Element, centerX, centerY, column, el, layout, px, rgb255, text, width)
import Element.Font exposing (color, size)
import Element.Input as I exposing (labelHidden)
import Http exposing (Error, expectJson, get)
import Json.Decode exposing (field, map2, string)
import Loadable as L exposing (Loadable(..), expectUpdate)
import Time exposing (every)
type alias Repo = { name : String, tagline : String }
type Msg = InputAuthor String | InputProject String | PassedSecond | GotRepo (Result Error Repo)
main : Program () { author : String, project : String, repo : Loadable Error Repo, timeout : Int } Msg
main = element { init = init, view = layout [] << view, update = update, subscriptions = subscriptions }
init _ = ( { author = "opvasger", project = "loadable", repo = Loading, timeout = 2 }, Cmd.none )
subscriptions { timeout } = if timeout > 0 then every 1000 (always PassedSecond) else Sub.none
update msg ({ repo, author, project, timeout } as model) =
case msg of
InputAuthor name -> ( { model | repo = expectUpdate repo, author = name, timeout = 2 }, Cmd.none )
InputProject name -> ( { model | repo = expectUpdate repo, project = name, timeout = 2 }, Cmd.none )
GotRepo result -> ( { model | repo = L.update result repo }, Cmd.none )
PassedSecond ->
( { model | timeout = timeout - 1 }, if timeout == 1 then
get { url = "https://api.github.com/repos/" ++ author ++ "/" ++ project
, expect = expectJson GotRepo (map2 Repo (field "name" string) (field "description" string))
}
else Cmd.none )
view { author, project, repo } =
let (r,g,b) = if L.isLoading repo then ( 0, 0,255)
else if L.hasError repo then (255, 0, 0)
else ( 0,255, 0) in
column [ width (px 300), centerX, centerY ]
[ I.text [ color (rgb255 r g b) ] { onChange = InputAuthor, text = author, placeholder = Nothing, label = labelHidden "author" }
, I.text [ color (rgb255 r g b) ] { onChange = InputProject, text = project, placeholder = Nothing, label = labelHidden "project" }
, L.withDefault (text "...") (L.map (\{ name, tagline } -> column [] [ el [ size 50 ] (text name), el [ size 25 ] (text tagline) ]) repo)
]