I'm developing a mobile application using RequireJS and Backbone.js. I'd like to specify the transition from one page to another by adding data-transition
and data-direction
attributes to each anchor (in the same way as with jQuery Mobile):
<a href="#home" data-transition="slide" data-direction="left">Go to the home page</a>
All my views extend a base view that attaches a click handler to anchors and catches the values of these attributes:
define([
'zepto',
'lodash',
'backbone'
], function ($, _, Backbone) {
'use strict';
BaseView = Backbone.View.extend({
events: {
'click a': 'navigate'
},
navigate: function (e) {
e.preventDefault();
var href = $(e.currentTarget).attr('href'),
transition = $(e.currentTarget).attr('data-transition'),
direction = $(e.currentTarget).attr('data-direction');
Backbone.history.navigate(href, true);
}
});
});
My problem is that I don't know how to pass these values to the route handlers of my router, defined as another module:
define([
'zepto',
'lodash',
'backbone'
], function ($, _, Backbone) {
'use strict';
var Router = Backbone.Thumb.Router.extend({
routes: {
'': 'home'
}
});
var initialize = function () {
var router = new Router();
router.on('route:home', function () {
require(['views/home'], function (HomeView) {
var homeView = new HomeView();
// Get the data-transition and data-direction attributes
// of the clicked anchor here:
// var transition = ???,
// direction = ???;
router.animate(homeView.render().$el, transition, direction);
});
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
Does anyone know a good solution to this problem?
Thank you very much in advance! :-) Best regards,
David
As you may know, Backbone.js is an event driven framework. Every object it defines inherits from the Backbone.Events
object and can send and receive event messages. That means is that the router itself can listen to events.
Since version 0.9.2, the Backbone
global object itself can be used as a mediator for global messenging. Since a view object in the application might not know about the router (it is especially true when using requireJS modules), it is possible to enable communication between these objects using a Mediator.
var router = Backbone.Router.extend({
initialize: function() {
this.listenTo( Backbone, 'page-transition', this.animate );
},
animate: function( href, transition, direction ) {
// Do something interesting with this
}
});
animate
function in the Backbone.events['page-transition']
stack when it is instantiated.Backbone
object triggers the page-transition
event, it will call the router.animate
function with the arguments provided with the event trigger.From anywhere in the application.
Here is an example based on the code from your question:
BaseView = Backbone.View.extend({
events: {
'click a': 'transition'
},
transition: function (e) {
e.preventDefault();
var href = $(e.currentTarget).attr('href'),
transition = $(e.currentTarget).attr('data-transition'),
direction = $(e.currentTarget).attr('data-direction');
Backbone.trigger('page-transition', href, transition, direction );
}
});
Since your router has already registered to the page-transition
event from the Backbone
object, it will call the router.animate
function with the proper arguments.
This pattern can be used everywhere in your Backbone application, these events can be listened by any Backbone extended object, may it be a Collection
, Model
, View
, Router
... You can even create a special mediator with this one liner:
var mediator = _.extend({}, Backbone.Events);
This pattern is very powerful because it promotes full decoupling between modules. Your modules don't have to know who is handling the functionality, they just have to know that it is not their responsibility and warn the application about it by triggering an event.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With