Low footprint client-side routing using crossroads.js

For my current pet project I was looking for some way to reproduce the routing systems provided by, say, AngularJS to quote but one. Not that I have anything against Angular mind you, au contraire! But sometimes you don’t need an army to get the job done, right?

So I headed towards the excellent microjs website, and after browsing around a little I decided to go with crossroads.

Crossroads

Why this one, you might ask? Well, there are a few things that made me believe that this micro framework might be solid, even before trying it out. For example the main site is clean, simple and well laid out. There’s plenty of documentation and examples, which is always a good thing. According to GitHub it hasn’t been updated for a while now… But that’s not necessarily a bad thing, because that might also mean that the project is stable (remember, we’re talking micro frameworks here, not Spring or Hibernate!). It has also been favorably referred by a few posts, such as this one at StackOverflow.

Finally, it bears a feature that is very important to me: it does one thing and one thing only.

One thing only

This means that all that crossroads do is routing. It does not load a new page, it does not load data, it does not even monitor if your URL has changed. But that is a good thing because, as it is clearly explained by the framework author, it means you are not tied to any specific technology: you can use it with any framework you want. Nice!

Tracing routes

Let’s try this. We start by grabbing crossroads and js-signals, the framework’s only dependency, and include them in our project.

<script src="js/signals.min.js" type="text/javascript"></script> 
<script src="js/crossroads.min.js" type="text/javascript"></script>

We can now define our routes using crossroads. The first one will be the route to the application’s main page.

crossroads.addRoute('/', function() {

});

Hey, what did you expect?“. As we said already, crossroads does one thing only: it routes. The code above declares the main route ‘/’. If that pattern is matched, the handler function is executed. What’s in the handler function? Whatever you want, really, but most likely whatever code you need to display the page.

Let’s add the second route. Let’s say that the application must display the details of a user with a given ID:

crossroads.addRoute('/user/{userId}', function(userId) {

});

The route contains a path parameter, which is the ID of the user. This path parameter is passed to the handler function so that the right user details can be displayed.

Notice how RESTful the route looks? As far as I know, you are not forced to go REST when using crossroads. But really, it’s an invitation that’s hard to turn down!

Finally, let’s define what happens if none of the routes are matched:

crossroads.bypassed.add(function(request) {
    console.error(request + ' seems to be a dead end...');
});

A simple message to the console will do for the moment.

Giving directions

Now that routes are defined, we need to submit a request to see if crossroads can match it. For that purpose, we invoke the parse() method:

crossroads.parse(window.location.href);

Well, the above won’t work. Indeed, crossroads will not try to extract the path. It’s not its job, remember? So we have to be able to submit something the framework can work with. We need to extract a route from the URL.

One way of doing this is to use the hash (#) symbol to indicate where the route is located in the URL, for example:

www.myapp.com/#/user/123

So we need to implement the code that will extract the route /user/123 and submit it to crossroads. Okay then:

var route = '/';
var hash = window.location.hash;
if (hash.length > 0) {
    route = hash.split('#').pop();
}
crossroads.parse(route);

The code above is able to extract what we need from the submitted URL.

Tell me when

So far the routing will work when we type the URL in the browser. But what happens when our application wants to link to another page? For the routing to work, the parse() method must be invoked every time the URL changes. Thankfully we can use event listeners for that purpose:

window.addEventListener("hashchange", function() {

});

The function above will be executed every time the hash part of the URL changes. Neat!

Putting it all together

Okay, so the whole code to implement our routing might look something like this:

// Define the routes
crossroads.addRoute('/', function() {
    $('#routeContent').load('main.html');
});
crossroads.addRoute('/user/{userId}', function(userId) {
    $('#routeContent').load('user/details.html');
});
crossroads.bypassed.add(function(request) {
    console.error(request + ' seems to be a dead end...');
});

//Listen to hash changes
window.addEventListener("hashchange", function() {
    var route = '/';
    var hash = window.location.hash;
    if (hash.length > 0) {
        route = hash.split('#').pop();
    }
    crossroads.parse(route);
});

// trigger hashchange on first page load
window.dispatchEvent(new CustomEvent("hashchange"));

The crossroads.parse() method is invoked each time the URL hash changes. If the route is matched, the code inside the matching handler function is executed. In our example, the handler’s code uses jQuery to load and insert a given page under the routeContent element. When the user types the URL in the browser the first time, we still need to examine the URL hash in order to display the right page, hence the dispatchEvent() method invocation for triggering a “hashchange” event.

And voilà, here our routing system! It might not hold up for big web applications, but I’d say it should go just fine for small to medium-sized ones.

Would you have done it differently? Well feel free to suggest your solution in the comments below.

Cheers!

 

4 comments

  1. Flo Reply
    17/12/2014 at 15:02

    Thanks for the guide 😉

  2. vijay Reply
    06/02/2015 at 16:49

    Thanks for the article. It is very informative.

    How do you handle if I have a link in the application where I would like to show a bootstrap modal? How do you bypass the routing mechanism?

    • codesandnotes Reply
      09/02/2015 at 13:01

      Hello Vijay!
      Not sure I have all the info to answer your question, but I’ll assume here that you have an HTML link which, when clicked on, needs to display a Bootstrap Modal (I’m guessing jschr bootstrap modal?).
      One way would be to use a “javascript:void()” value for the link’s href attribute, then register an event listener on the link (see here or use the jQuery equivalent) and when your link is clicked call a JavaScript method that fires up your modal.
      You should also be able to disable the mechanism: instead of using the url hash (“#”) as a cue that it’s a routing request, you can use “!”, or “#!”, or whatever you fancy. This way all URLs not having that set of characters will be handled normally.
      Hope this helps!

Leave A Comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked

This site uses Akismet to reduce spam. Learn how your comment data is processed.