34: Elm With Flags - JSToElm
All Episodes

34: Elm With Flags

So we are at that point when it's time to expand our app to have more than a single component in Elm. A couple weeks ago we started down the path of routing, by refactoring the core of our app, main state and routing, into Elm. This turned out to be a bit more daunting the more we looked into it. So let's try something else...

Elm With Flags - A simpler way.

  • The idea here is we can instantiate our Elm app anywhere in with our React architecture and pass to it a flag of the Route is should use to determine what view to render.

    1. Get the Route passed in to the Elm init as a flag
    2. Get the Elm app to pattern match on that route passed it to determine what view to render.
    3. Take over the world.
  • Updating Elm Program to take a a flag of our intended route

    • Probably not gonna be Home anymore, but all things, so let’s call it Main.Elm this will communicate that this is the entry point of our Elm app.
  • Starting with this:
main : Program Never Model Msg
main =
    Html.program
        { view = view
        , init = init
        , update = update
        , subscriptions = subscriptions
        }
  • And Ending up with this:

main : Program Flags Model Msg
main =
    Html.programWithFlags
        { view = view
        , init = init
        , update = update
        , subscriptions = subscriptions
        }
  • This also means our init : ( Model, Cmd Msg ) method type signature needs to be updated also. It’s going to take the flags, and return the Tuple of Model and Cmd Msg. init : Flags -> ( Model, Cmd Msg )

  • Now on the JS side we need to pass the current url in as a route, and won’t you know it, our React-Elm-Wrapper Component takes a prop called ‘flags’ and will pass it when it init’s our Elm app

initialize = node => {
    if (node === null) return;
    const app = this.props.src.embed(node, this.props.flags);

Part 2 - Elm pattern matching on model.route to render view

  • First this, I’d rather not match on a string. That feels so very JavaScript like. For the incoming route string, it should be a type or Route.
  • So let’s create a function, urlToRoute, that takes a String and returns a type of Route. We make our Route a union type, this will have all the routes possible on it. We’ll have a ‘NotFound’ route if it doesn’t match any of the defined ones.
type Route
    = Home
    | NewNote
    | NotFound


urlToRoute : String -> Route
urlToRoute url =
    case url of
        "/" ->
            Home

        "/notes/new" ->
            NewNote

        _ ->
            NotFound
            
init : Flags -> ( Model, Cmd Msg )
init flags =
    let
        model =
            { notes = []
            , isAuthenticated = False
            , route = urlToRoute flags.route
            }
    in
        model ! [ sendData (FetchNotes "/notes") ]
  • Now our init function takes flags and will assign flags.route which will be of type Route, to model.route.
  • Our view function can now be pattern matched on model.route, and will force us to exhaust all possibles of type Route! That’s a win.
view : Model -> Html Msg
view model =
    case model.route of

The cool part

  • The render method for NewNote Component is now
render() {
    return (
      <Elm src={Main} ports={initPorts(this.context)} flags={{ route: this.props.match.url }} />
    );

Picks

Resources

Follow

Published 26 Apr 2018

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