Need help with elm-route-url?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.
rgrempel

Description

Router for single-page-apps in Elm

205 Stars 16 Forks MIT License 82 Commits 11 Opened issues

Services available

Need anything else?

elm-route-url

This is a module for routing single-page-apps in Elm, building on the

elm-lang/navigation
package.

Rationale

Essentially, elm-route-url helps you to keep the URL displayed in the browser's location bar in sync with the state of your app. As your app changes state, the displayed URL changes to match. If the user changes the URL (through a bookmark, the back/forward button, or typing in the location bar), then your app changes state to match.

So, there are two things going on here:

  • Mapping changes in our app's state to changes in the browser's location.
  • Mapping changes in the browser's location to changes in our app's state.

Now, you can already arrange for these things to happen using

elm-lang/navigation
. Furthermore, there are already a wealth of complementary packages, such as:

So, what does elm-route-url do differently than the others? First, I'll address this practically, then philosophically.

Mapping changes in the app state to a possible location change

If you were using

elm-lang/navigation
directly, then you would make changes to the URL with ordinary commands. So, as you write your

update
function, you would possibly return a command, using
modifyUrl
or
newUrl
.

Now, you can make this work, of course. However, the

update
function isn't really the perfect place to do this. Your update function looks like this:
update : Message -> Model -> (Model, Cmd Message)

But you don't really need to know the

Message
in order to compute a new URL for the location bar. After all, it doesn't matter how you got there -- all you want to ensure is that the URL reflects the final state of your model. (For instance, consider a module with an
Increment
message and a
Decrement
message. The URL doesn't care which way you arrived at a particular state).

Furthermore, every state of your model really ought to correspond with some URL. That is, given some state of your model, there must be something that you'd like to have appear in the URL. Or, to put it another way, what appears in the URL really ought to be a function of your state, not the last message you received.

So, elm-route-url asks you to implement a function with a different signature:

delta2url : Model -> Model -> Maybe UrlChange

What you get is the previous model and the new model. What you're asked to produce is possibly a change to the URL. (The reason you get both the old and new model is because sometimes it helps you decide whether to create a new history entry, or just replace the old one).

There are a couple of possible advantages to this way of doing things:

  • Less clutter in your

    update
    function.
  • You just calculate the appropriate URL, given the state of your app. elm-route-url automatically avoids creating a new history entry if the URL hasn't changed.

  • elm-route-url also automatically avoids an infinite loop if the change in the app's state was already the result of a URL change.

Of course, you can solve those issues with your own code. However, if you use elm-route-url, you don't have to.

Mapping location changes to messages our app can respond to

If you use the official navigation package in Elm 0.18 directly, you react to location changes by providing an argument to

Navigation.program
which converts a
Location
to a message your app can deal with. Those messages are then fed into your
update
function as the
Location
changes.

On the surface, elm-route-url works in a similar manner, except that it asks you to implement a function which returns a list of messages. (This is possibly a convenience when you need multiple messages to react to the URL change, though of course you could also redesign your app to do multiple things with a single message).

location2messages : Location -> List Message

location2messages
will also be called when your
init
function is invoked, so you will also get access to the very first
Location
.

So, that is similar to how

Navigation
works. The difference is that
Navigation
will send you a message even when you programmatically change the URL. By contrast, elm-route-url only sends you messsages for external changes to the URL -- for instance, the user clicking on a link, opening a bookmark, or typing in the address bar. You won't get a message when you've made a change in the URL due to your
delta2url
function, since your state is already in sync with that URL -- no message is required.

Philosphically

You can, if you are so inclined, think about those differences in a more philosophical way. There is a thread on the Elm mailing list where Erik Lott gives an excellent summary. The question, he says, is whether the address bar should drive the model, or whether the model should drive the address bar. For more details, read the thread -- it really is a very good summary.

Another nice discussion of the philosophy behind elm-route-url is in a blog post by Amitai Burstein, under the heading URL Change is not Routing

API

For the detailed API, see the documentation for

RouteUrl
and
RouteHash
(there are links to the right, if you're looking at the Elm package site).

The

RouteUrl
module is now the "primary" module. It gives you access to the whole
Location
object, and allows you to use the path, query and/or hash, as you wish.

The main thing that elm-route-url handles is making sure that your

location2messages
and
delta2url
functions are called at the appropriate moment. How you parse the
Location
(and construct a
UrlChange
) is pretty much up to you. Now, I have included a
RouteUrl.Builder
module that could help with those tasks. However, you don't need to use it -- many other approaches would be possible, and there are links to helpful packages above. For my own part, I've been using evancz/url-parser recently to implement
location2messages
.

The

RouteHash
module attempts to match the old API of elm-route-hash as closely as possible. You should be able to re-use your old
delta2update
and
location2action
functions without any changes. What will need to change is the code in your
main
module that initializes your app. The
RouteHash
module will probably be removed in a future version of elm-route-url, so you should migrate to using
RouteUrl
at an appropriate moment.

Examples

I've included example code which turns the old Elm Architecture Tutorial (upgraded to Elm 0.18) into a single-page app. I've included three variations:

  • Using the new
    RouteUrl
    API with the full path.
  • Using the new
    RouteUrl
    API with the hash only.
  • Using the old
    RouteHash
    API.

Note that the example code makes heavy use of the

RouteUrl.Builder
module. However, as noted above, you don't necessarily need to use that -- a variety of alternative approaches are possible.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.