77: Hello Darkness My Old Friend - JSToElm
All Episodes

77: Hello Darkness My Old Friend

We revisit an old friend from episode 51 "Elm Routing Maybe" about routing in Elm. Let's see if we've learned anything in the last 20 something episodes?

Routing in Elm

I realize now, just how frustrated people get when learning n framework or language. For me that monster is routing in Elm.

But first, you’re running out of chances to get to Elm in the Spring!!!

Instead of creating our program with Browser.element or Browser.document, we can create a Browser.application to avoid loading new HTML when the URL changes:

ok, cool.

  1. Define some routes, in a Routes.elm file

    1. preferably in it’s own Routes file
  2. Define the routes Parser
-- creating a parser called 'routes'
-- will produce routes of type Route
-- doesn't take any arguments? 
routes : Parser (Route -> a) a
routes =
    Parser.oneOf
        [ Parser.map Home Parser.top
        , Parser.map Account (Parser.s "account")
        ]
  1. Define a match function that will convert a Url and return a Maybe Route.

    1. Maybe Route because you might not have a matching route, right? I think this is where the default case for pattern matching at one point will show the 404.
    2. Be sure we are exposing the Routes(..) and the match function
  2. Back on Main.elm create a Browser application

    1. import Browser exposing (Document, UrlRequest)
    2. import Browser.Navigation as Navigation
    3. We need to describe what to display when when we have a specific type Route. This is where Pages come in. Rather than storing a Route Constructor, we store it’s commutated value as a ‘Page’, thus not having to reevaluate the parse route every time?
    4. Page and Route have different responsibilities. Page is concerned with the state of the current page, managing just that page’s state.
  3. Adding Page and navigationKey to model. what’s a navigationkey?

    1. navigationkey is supplied at runtime.
  4. Update Msg with newRoute and Visit
  5. New Browser.application

    1. onUrlRequest
    2. external requests from UrlRequest
    3. onUrlChange
    4. internal requests to our own domain from UrlRequest
    5. >> forward composition operator

      1. This is going to compose these 2 functions into 1. The result of Routes.Match will get passed to NewRoute in the update for us to handle.
    6. setNewPage helper method
    7. Init needs to be a function now, bc it now supplies the inital Url when the application starts up.
[==================================================] - 1 / 1-- TYPE MISMATCH ------------ /c/Users/jtomc/Documents/Elm/picshare/src/Main.elm

The 1st argument to `application` is not what I expect:

 96|     Browser.application
 97|>        { init = init
 98|>        , view = view
 99|>        , update = update
100|>        , subscriptions = subscriptions
101|>        , onUrlRequest = Visit
102|>        , onUrlChange = Routes.match >> NewRoute
103|>        }

This argument is a record of type:

    { init : () -> Url -> Navigation.Key -> ( Model, Cmd Msg )
    , onUrlChange : Url -> Msg
    , onUrlRequest : UrlRequest -> Msg
    , subscriptions : Model -> Sub Msg
    , update : Msg -> Model -> ( Model, Cmd Msg )
    , view : Model -> Html Msg
    }

But `application` needs the 1st argument to be:

    { init : () -> Url -> Navigation.Key -> ( Model, Cmd Msg )
    , onUrlChange : Url -> Msg
    , onUrlRequest : UrlRequest -> Msg
    , subscriptions : Model -> Sub Msg
    , update : Msg -> Model -> ( Model, Cmd Msg )
    , view : Model -> Document Msg
    }
Detected errors in 1 module.
 @ ./src/index.js 10:0-33 12:0-3
 @ multi ./config/polyfills.js ./scripts/utils/webpackHotDevClient.js ./node_modules/react-error-overlay/lib/index.js ./src/index.js
  1. Errors 😢

    1. Browser Application
    2. Oh, our View is still returning HTML and we’ve told it that we are not returning type DOCUMENT. 😭 🤦‍♀️
  2. Ok. Adding view function to return type Document
  3. Browser.Application let’s us set the title and body

    1. So we are assembling the content we want as a tuple into a record of type Document in our view function using the viewContent function that receives the model.page
  4. IT’S WORKING man that is such a good feeling

Reimplement in yet another project

branching from Meow Notes, the theme ‘Create Content’, wordpress headless CMS, terrible mobile support for it, and micro.blog / indie web as a platform.

The pieces make sense.

  1. Create type Route this is a custom type of our possible routes

  2. We’ve got a routes function that has a type signature Parser (Route -> a) -> a this is all Url.Parser as Parser

    1. Parser.oneOf
    2. Try a bunch of different path parsers.
    3. If there are multiple parsers that could succeed, the first one wins.
    4. Parser.map
    5. Parser.top
    6. A parser that does not consume any path segments.
    7. Parser.s
    8. Parse a segment of the path if it matches a given string. It is almost always used with </> or oneOf. For example:
    9. string
    10. Parse a segment of the path as a String.
    11. (</>)
    12. Parse a path with multiple segments.
  3. Docs and Package Info

Picks

What is a URL?

A URL is defined by Tim Berners-Lee in this document. It is worth reading, but I will try to share some highlights. He shares an example like this:

  https://example.com:8042/over/there?name=ferret#nose
  \___/   \______________/\_________/ \_________/ \__/
    |            |            |            |        |
  scheme     authority       path        query   fragment

Resources

Elm Conf CFP

Elm Programming

React Router Docs

Follow

Published 18 Apr 2019

A show about learning Elm, Functional Programing, and generally leveling up as a JS developer.
JavaScript To Elm on Twitter