1
votes

In a Backbone JS project, I am trying to listen for events emitted by the router. From the docs:

When the visitor presses the back button, or enters a URL, and a particular route is matched, the name of the action will be fired as an event, so that other objects can listen to the router, and be notified.

Unfortunately, I can't get this to work, no matter if I use on or listenTo to listen for the router events.

The router looks like this:

var appRouter = Backbone.Router.extend({
  routes: {
    '' : 'index',
    'page(/:id)' : 'showPage'
  }
});

app.Router = new appRouter();
Backbone.history.start();

An in a view's initialize function, I try to listen for the events like this:

initialize: function () {
  this.listenTo(app.Router, 'route:showPage', this.myTestFn);
  app.Router.on('route:index', this.myTestFn);
},

To me, this looks correct, but myTestFn is never called.

How do I listen for route events in Backbone JS?

1

1 Answers

2
votes

It depends if you are using hash or standard urls.

Using hash urls

Your setup is correct assuming you are using hash urls. So if you have links like the following ones, your code will work fine:

<a href="#">Index</a>
<a href="#page/1">First page</a>

I have quickly created a jsfiddle with your code and those links here

Using standard urls

More work is needed if you are planning to use standard urls. Basically you will need to:

  1. Initialize Backbone history using HTML5 push state

    Backbone.history.start({pushState: true});
    
  2. Intercept the click events on your links, preventing the browser from sending a full GET request to your server. You could add events to your views or use a global event handler as in this nice article.

  3. Manually tell your backbone router to navigate to the intercepted link url

    app.Router.navigate(href, {trigger: true});
    

For example given the following urls:

<nav class="navLinks">
    <a href="/" class="standardUrlLink">Index</a>
    <a href="/page/1" class="standardUrlLink">First page</a>
</nav>

You could have a view like the following one:

var myView = Backbone.View.extend({
    el: ".navLinks",
    events: {
        "click .standardUrlLink": "standardUrlIntercepted"
    },
    initialize: function () {
      this.listenTo(app.Router, 'route:showPage', this.myTestFn);
      app.Router.on('route:index', this.myTestFn);
    },        
    standardUrlIntercepted: function(event) {
        //Get the link href and manually use backbone to navigate, triggering the route
        var href = $(event.currentTarget).attr("href");
        console.log("standard url intercepted, href=" + href);
        app.Router.navigate(href, {trigger: true});
        //Cancel default event behaviour (sending the GET request)
        return false;
    },
    myTestFn: function(){
        console.log("route called")
    }
});

I have put together a working example using this approach in this fiddle so you can try it.