Tuesday, October 18, 2011

A Default Route in Backbone.js

‹prev | My Chain | next›

Tonight, I take a break from my Backbone.js collection caching exercise to fix a routing bug. Ever since I set up routing in my app, I have been getting double renders when starting on a page that matched a route (e.g. /#month/2011-10).

One of the renders arises from the Collection fetch in the app initialization:

      // Setup the appointments collection
      var year_and_month = Helpers.to_iso8601(new Date()).substr(0,7),
          appointments = new Collections.Appointments(undefined, {date: year_and_month});

      // Setup the views
      new Views.Application({collection: appointments});

      appointments.fetch():
The other came from the call to setDate() (which also calls fetch) in the matching route:
      var Routes = Backbone.Router.extend({
        routes: {
          "month/:date": "setMonth"
        },

        setMonth: function(date) {
          console.log("[setMonth] %s", date);
          draw_calendar(date);
          appointments.setDate(date);
        }
      });
Tonight, I hope to figure out how to set up a default Backbone route to avoid the initialization fetch. Maybe this is as simple as setting an empty string route?
      var Routes = Backbone.Router.extend({
        routes: {
          "": "setDefault",
          "month/:date": "setMonth"
        },

        setDefault: function() {
          console.log("[setDefault]")
        },

        setMonth: function(date) {
          console.log("[setMonth] %s", date);
          draw_calendar(date);
          appointments.setDate(date);
        }
      });
Looking for the console.log() output in Chrome's Javascript, I see that I have, indeed, matched my default route:
So I set the window.location to the current month: 2011-10 (which is the first 7 characters of the ISO 8601 date):

      var Routes = Backbone.Router.extend({
        routes: {
          "": "setDefault",
          "month/:date": "setMonth"
        },

        setDefault: function() {
          console.log("[setDefault]");
          var month = Helpers.to_iso8601(new Date).substr(0,7);
          window.location = '/#month/' + month;
        },

        setMonth: function(date) {
          console.log("[setMonth] %s", date);
          draw_calendar(date);
          appointments.setDate(date);
        }
      });
And that works! When I access the root URL (http://localhost:3000) without any path info, this default route kicks in and directs me to October:
That was easy. I really should have at least tried that the night I first ran into trouble. Ah well.

Day #178

2 comments:

  1. I realize that this is an old post, but instead of using `window.location`, wouldn't it be better to use `this.navigate("month/"+month, {trigger: true, replace: true})`? That way there isn't an extra item in the browser history and it can handle both pushState and hashTag routing. I'm still very new to Backbone, so please correct me if needed.

    ReplyDelete
    Replies
    1. You are correct. Not only is this post old, but it also from my own early days of backbone coding. I eventually figured this out (http://japhr.blogspot.com/2011/11/dont-set-windowlocation-in-backbonejs.html), so you're already doing better than I was at this point :)

      Delete