Generate URLs using the Ember router service

27 July 2017

For some inexplicable reason, I’ve always felt really excited about having a
proper router service added to Ember.js, ever since the RFC was first
fleshed out, in September of 2015.

Then a few weeks ago, in the release blog post for Ember 2.14 I saw that
the (phase 1) implementation of said router service would be included in the
next release, 2.15. Above that, I also learned that there is already a
polyfill so that you can start using the router service today.

Right, but what is this router service you rave about?

I’m glad you asked :) The router service sits on top of Ember’s router,
which is responsible for “recognizing” routes from the URL, changing the path
according to which route the app is on, transitioning between routes and
calling the different hooks and actions for each route. In short, everything
that is related to routing, although that’d be quite a tautological
definition.

Ember developers mostly interact with the router through instructing it to
transition to a new route (by calling this.transition from a route, or
using the {{link-to}} helper from a template) and by using visit from
acceptance tests.

These are, however, special API methods and there is no coherent way to use
these services through a … service, like you can do for example with Ember
Data’s store or the session service in authentication add-ons.

The router service fills this hole.

Generating paths for a route name

Today, there is no easy way to programmatically get the generated path for a
given route name. Imagine you have the following routes:

, and you want to see what path is generated for the bands.band route for a
band that has the id 24 (my lucky number, if I have to give you one). There
is no easy way to accomplish that - that is, without using the router service.

Sure, but why would you need that? - you might ask. You can just use {{link-to 'bands.band' band}} or this.transitionTo('bands.band', band) and the router will do the right thing. True, but what if I want to share the URL for an answer to a question (imagine Quora or Stack Overflow) without going to the answer’s page and copy-pasting the URL from the address bar manually?

That’s just one of the possible features where you might need this but it’s the one I came across and want to show you.

Sharing URLs to band pages

Being a big fan of (hard) rock and having an app that has bands (instead of answers), the example I’m going to use is sharing URLs to the page of a band. We want it look something like this:

As we currently don’t yet have the router service baked into the stable Ember version, we’ll use the aforementioned polyfill. Let’s install it first:

1

$ ember install ember-router-service-polyfill

We now have access to the router service, so let’s open the controller of the bands route which is where the list gets rendered and inject the servic , like any other one:

(Actually, there is an easier way to achieve the same without the need for the data-band-id attribute. See the UPDATE below).

Let’s see the new button, on line 7. We trigger the shareBandURL when it’s
clicked and set a data attribute with the id of the band. Now, let’s write the
action handler that should generate the URL for that band and then copy it to
the clipboard:

We first identify the element that was clicked and then use its data-band-id attribute to get the band’s id. Now comes the best part. We use the urlFor method on the router service to get the generated path (the method name is a bit deceiving as it doesn’t return the URL, just the path) for the individual band (the bands.band route) and the id. This gives something like /bands/24. We should now prepend the protocol and the host to give us the full URL to copy.

We then proceed to copy this URL to the clipboard, so that it can be pasted. I didn’t find it relevant to show how this is exactly done as I wanted to focus on the Ember routing stuff, but you can find the necessary code here.

Lastly, since the button is embedded in a link (more precisely, a link-to) we prevent the click from bubbling up and causing a transition to the new route. And that is all, we can now share the URL by pasting it to wherever we’d like:

Other things the router service can do for you

I only showed one method of the router service, urlFor, but it has a lot more and I already have an idea about how to show some others through a not totally contrived example. So stay tuned!

UPDATE

As Gabor Babicz correctly pointed out in the comments (thanks, Gabor!), the
data-band-id attribute is not needed as we can pass in the band id directly.

I knew that the action helper takes any number of arguments that will be passed
to the handler, but I didn’t know that the event itself (which we need to stop
its propagation, so that the click doesn’t trigger a route transition) is always passed in as the last parameter to the handler.