Short screencasts to teach you the Elm programming language. Each video tutorial walks through a library, tool, or language feature.
As we add new pages to our application, and data to our model, the complexity and maintainability of our application increases. Using the RemoteData pattern, we can modify our page type to represent only the current, valid state of the app.
Examples Main.elm
``` type Msg = TopStoriesFetched (WebData HomeModel)
type Page = Home (WebData HomeModel)
type alias HomeModel = { topStories : List StoryId }
type alias Model = { page : Page }
update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of TopStoriesFetched webData -> ( { model | page = Home webData }, Cmd.none )
```
Links * Elmseeds Episode 37: RemoteData
It’s time to add some data to our Single Page Application. Because we’re building a Hacker News clone, we’ll use the official Hacker News API to fetch data. We can do this with some simple HTTP requests using elm-lang/http. In this episode we’ll setup our application to automatically load the Top Stories whenever the user launches the application on the home page, or navigates to it from within the app.
Examples Main.elm
``` type StoryId = StoryId String
storyIdDecoder : Decoder StoryId storyIdDecoder = Decode.map (StoryId << toString) Decode.int
topStories : Http.Request (List StoryId) topStories = Http.get "https://hacker-news.firebaseio.com/v0/topstories.json" (Decode.list storyIdDecoder)
setRoute : Location -> Model -> ( Model, Cmd Msg ) setRoute location model = let -- … in case route of Route.Home -> let cmd = Http.send TopStoriesFetched topStories in ( { model | page = Home }, cmd )
```
Links * Official Hacker News API
The next step in our Single Page Application series is to add url routing and navigation. There are two packages we’ll need for this. The first, Navigation, will allow us to handle navigation events and starting the application on a page other than the home page.
The second package, Url-Parser, helps us parse our url’s path into an Elm sum type which we can use to determine which page to render in the view.
Examples shell
```
./node_modules/.bin/webpack-dev-server --history-api-fallback
```
Main.elm
``` setRoute : Location -> Model -> Model setRoute location model = let route = UrlParser.parsePath Route.route location |> Maybe.withDefault Route.Home in case route of Route.Home -> { model | page = Home }
Route.Newest ->
{ model | page = Newest }
```
Links * elm-lang/navigation * evancz/url-parser
This episode begins a series in which we build a Single Page Application (SPA) clone of Hacker News. We’ll call our version Technologist News.
We begin by setting up the most basic application and supporting infrastructure possible. We’ll use Webpack to do our automatic compilation.
Examples app.js
``` import Elm from '../src/Main.elm'
const div = document.getElementById('main') window.main = Elm.Main.embed(div)
```
index.html
```
```
Links * HackerNews API * rtfelman/elm-spa-example * Episode 39: Elm & Webpack
Advent of Code is a “series of small programming puzzles for a variety of skill levels.” It provides a perfect opportunity to challenge ourselves with Elm and build something out of the ordinary.
The video does contain spoilers, so if want to try to solve the problem on your own first, do that before watching this video. No code samples are provided here in order to hide spoilers.
Elm-Live provides automatic compliation, a web server, and live reloading in a convenient package.
If you already use Elm and want to recommend an easy path for others to get started, look no further than Elm-Live.
Examples
``` $ npm install -g elm-live $ elm-live src/Main.elm --output=elm.js --pushstate
```
Elm-Css can be used to write type-safe inline styles or generate Css files that you can include in your application normally.
Examples Styles.elm
``` type Classes = GreenBg | White | Yellow
css : Css.Stylesheet css = Css.stylesheet <| Css.Namespace.namespace "main" [ Css.class GreenBg [ Css.height (Css.px 300), Css.backgroundColor (Css.rgb 51 153 51) ] , Css.class White [ Css.color Colors.white ] , Css.class Yellow [ Css.color (Css.rgb 244 208 107) ] ]
```
View.elm
``` { id, class, classList } = Html.CssHelpers.withNamespace "main"
view : Model -> Html msg view model = Html.header [ class [ GreenBg ] ] [ div [] [ a [ href "/" ] [ span [] [ text "Elm" ] , span [] [ text "seeds" ] ] ] ]
```
Links * rtfeldman/elm-css * Stackoverflow: Run command after webpack build
If you’ve written CSS for more than a week, you know how difficult it is to refactor without breaking something. Style Elements gives you the same safety and peace of mind in your view as you’re used to in the rest of your Elm application.
Examples View.elm
``` type Styles = GreenBg | None
view : Model -> Html msg view model = El.layout styleSheet body
body : Element Styles v msg body = El.column GreenBg [ height (px 300) ] [ header ]
header : Element Styles v msg header = El.row None [ width fill, alignBottom ] [ El.link "/" (El.row None [] [ El.el None [] (El.text "Elm") , El.el None [] (El.text "seeds") ] ) ]
styleSheet : StyleSheet Styles v styleSheet = Style.styleSheet [ Style.style GreenBg [ Style.Color.background (Color.rgb 51 153 51) ] ]
```
Links * mdgriffith/style-elements * An Introduction to Style Elements for Elm
Modeling impossible state is an anti-pattern in Elm, so instead we need to come up with new approaches to model our application. If we want to model a list of items such that one is always selected, we can use the zipper data structure. It enforces that one item is always selected, and is the perfect complement to many UI patterns. In this episode, we use Richard Feldman’s selectlist to clean up problematic code.
Examples Main.elm
``` update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of SelectTab id -> ( { model | tabs = SelectList.select (\u -> u.id == id) model.tabs }, Cmd.none )
```
View.elm
``` view : Model -> Html Msg view model = let befores = model.tabs |> SelectList.before |> List.map (tabView False)
```
Links * rtfeldman/selectlist * Zipper Data Structure
Fragments are reusable chunks of GraphQL queries that can help reduce code duplication across queries. We want to add support for them in our query builder so we can benefit from their reusability.
Examples Main.elm
``` addressFragment : Fragment addressFragment = fragment "Address" address
addressFields : Node -> Node addressFields node = fields addressFragment node
user : Node -> Node user user = user |> prop "id" |> prop "email" |> prop "name" |> node "address" [] addressFields
```
GraphQL.elm
``` type Fragment = Fragment String (Node -> Node)
fragment : String -> (Node -> Node) -> Fragment fragment name func = Fragment name func
fields : Fragment -> Node -> Node fields (Fragment typeName func) parent = let fieldsName = (String.toLower typeName) ++ "Fields"
fragment_ =
newNode ("fragment " ++ fieldsName ++ " on " ++ typeName) []
|> func
(Node node) =
prop ("..." ++ fieldsName) parent
in
Node { node | fragments = fragment_ :: node.fragments }
```
Links * Fragments