Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js — Call method before/after a route is fired

I want a setup/teardown method to be called before and after a route is fired in my Backbone.js router, respectively. Has anyone created an elegant way of doing this?

like image 271
Levi McCallum Avatar asked Sep 12 '11 22:09

Levi McCallum


5 Answers

_.wrap is not a solution, if You have for example 20 routes you have to wrap them all.

But you can do this with metaprogramming

class Backbone.FlexRouter extends Backbone.Router
  route: (route, name, handler) ->
    super route, name, ->
      @trigger "route:before"
      handler()
      @trigger "route:after"

UPD: I believe in JS it should be something like this (but I didn't tested it)

var rp = Backbone.Router.prototype
rp.routeWithoutEvents = rp.route
rp.route = function(route, name, handler){
  var that = this
  this.routeWithoutEvents(route, name, function(){
    that.trigger("route:before")
    handler()
    that.trigger("route:after")
  })
}
like image 163
Alex Craft Avatar answered Nov 15 '22 22:11

Alex Craft


Have you considered _.wrap?

like image 23
pdoherty926 Avatar answered Nov 16 '22 00:11

pdoherty926


Here is the simple one, overriding the Backbone.Router itself

(function () {
    _.extend(Backbone.Router.prototype, Backbone.Events, {        
        route: function (route, name, callback) {           
            if (!_.isRegExp(route)) route = this._routeToRegExp(route);
            if (!callback) callback = this[name];
            Backbone.history.route(route, _.bind(function (fragment) {               
                var args = this._extractParameters(route, fragment);                
                if (this.before && _.isFunction(this.before)) {
                    this.before(fragment);
                }                
                callback && callback.apply(this, args);
                this.trigger.apply(this, ['route:' + name].concat(args));
                if (this.after && _.isFunction(this.after)) {
                    this.after(fragment);
                }
                Backbone.history.trigger('route', this, name, args);
            }, this));
            return this;
        }
    });
}).call(this);

Focus on the lines

if (this.before && _.isFunction(this.before)) {
    this.before(fragment);
}

AND

if (this.after && _.isFunction(this.after)) {
    this.after(fragment);
}

You can modify the lines according to your needs

And here is the client code using the new Backbone.Router class

var appRouter = Backbone.Router.extend({

routes: {},
before: function(){
   //your code here
   return true;
}

});
like image 34
Shan Niz Avatar answered Nov 15 '22 23:11

Shan Niz


Alexey's answer is almost right, but there are a few subtle things that are missing.

class ApplicationRouter extends Backbone.Router

  route: (route, name, callback = null) ->
    callback = @[name] if ! callback
    super route, name, ->
      @trigger 'route:before'
      result = callback && callback.apply(@, arguments)
      @trigger 'route:after'
      return result
like image 3
Jonathan Tran Avatar answered Nov 15 '22 22:11

Jonathan Tran


This plugin does what you want. It works with 0.5.3. I'm not certain if it works with 0.9.1 yet or not.

https://github.com/angelo0000/backbone_filters

like image 1
Andrew De Andrade Avatar answered Nov 15 '22 22:11

Andrew De Andrade