Highlighting current navigation state in Backbone.js application
I want to highlight the current navigation state. Like if the hashchange is #home
, I want to style the 'Home' menu link differently and similarly other links.
Backbone.js fires individual events like route:home
,... route:some-other
when the #home
and other links are clicked. I could not see any common event that will be fired for every hashchange. With th开发者_StackOverflowis I m required to write the state highlight logic by binding to all the route events, which I think is not good solution.
So, I've overridden Backbone.Router.route
in my router sub class/object, like
// override backbone' Router.route method to publish
// common 'route_change' event for any hash change
route : function(route, name, callback) {
Backbone.history || (Backbone.history = new Backbone.History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
Backbone.history.route(route, _.bind(function(fragment) {
var args = this._extractParameters(route, fragment);
callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
// ADDED BY: ManiKanta G
// name: route method
// fragment: route path
// args: any additional args
this.trigger.apply(this, ['route_change'].concat(name, fragment, args));
}, this));
}
This will publish a common route_change
event for every hashchange and passing the name
, fragment
, and other args
using which I m highlighting the state all in a single place.
My question is do I have to override the Backbone method like this or is there any build in mechanism I can use here. If not, I would like to see similar behaviour in Backbone.js
Edit: sample program
Router = Backbone.Router.extend({
routes : {
'': 'root',
'home': 'home',
'about':'about'
},
// app routing methods
root: function () { console.log('root route'); },
home: function () { console.log('home route'); },
about: function () { console.log('about route'); }
});
Router.bind('all', function () {
console.log('all route...');
});
router = new Router();
and, navigating using the above router:
router.navigate('home', true);
output: home route
Update on why the above program is not working:
we should bind for all
event on Router instance
, but not on the Router
itself - so, changing the Router.bind('all', ...
to router.bind('all', ...)
will make the above program work
In backbone 0.5.x you can bind all
event to router instance and the first argument pass to your handler will be route
Here is exemple on jsfiddle, reproduced here:
var dummy = Backbone.Router.extend({
defaultPage: 'messages',
routes: {
'': 'index',
'index': 'index',
'mailbox': 'mailbox'
},
index: function() {
// code here
},
mailbox: function() {
// code here
}
});
var router = new dummy();
router.bind('all', function(route) {
document.write('triggered: ' + route + '<br/>');
});
router.navigate('index', true);
router.navigate('mailbox', true);
Here 's a live example from one of my apps:
routes.bind('all ', function(route, section) {
var $el;
route = route.replace('route: ', '');
$el = $('#nav - ' + route);
// If current route is highlighted, we're done.
if ($el.hasClass('selected')) {
return;
} else {
// Unhighlight active tab.
$('#menu li.selected').removeClass('selected');
// Highlight active page tab.
$el.addClass('selected');
}
});
Here's what I'm doing:
@router.bind 'all', (route) ->
# this triggers twice for every route; ignore the second time
return if route == "route"
# ex: route="route:home", name="home", href="#home"
name = route.replace('route:', '')
# remove the active class on all of the current nav links
$("#menu li.active").removeClass('active')
# add it back to the link that has an href that ends in `name`
$("#menu a[href$='#{name}']").parent().addClass('active')
I faced the problem that the first time a page is loaded, the menu wasn't highlighted as the event came before the binding was initiated. i fixed this by using the history:
$('#menu li.'+Backbone.history.fragment).addClass('active');
精彩评论