Trying to get a backbone router to work. Having one of those situations where nothing is happening so its difficult to pinpoint the problem.
Is there a way to find out what the Router is actually receiving so that I can try to pinpoint the problem with my routes?
This is the code so far:
// ROUTER
var TheRouter = Backbone.Router.extend({
// ROUTES
routes: {
"": "main",
"/route1/:key": "route1"
},
// INITIALIZE
initialize: function() {
_.bindAll(this);
},
// ROUTES
main: function(){
alert('main');
},
route1: function(key){
alert(key);
}
});
// Create new router
var theRouter = new TheRouter();
// Start history
Backbone.history.start({pushState: true});
Thanks so much!
You can bind to the route event on the Backbone.history. According to the source code you get all the info going into the router from that event, meaning you should be able to console.log it.
You need to remove the slash from the beginning of your second route.
So the
"/route1/:key": "route1"
line becomes
"route1/:key": "route1"
If you are still getting no feedback, make sure you defined your dependent scripts in the correct order (jquery.js, underscore.js, backbone.js, yourRouter.js).
Related
I've hit a head-scratcher with a Backbone.js. The example is on jsfiddle here. I believe the issue is here:
App.Layout = new Backbone.Layout({
// Attach the Layout to the main container.
collection: App.chapters,
el: "body",
initialize: function () {},
beforeRender: function () {
// Add a sub-view for each Chapter
this.collection.each(function (model) {
this.insertView(model.get('id'), new App.ChapterView({
"id": model.get('id')
}));
}, this);
},
views: {
// But if I set the sub-view specifically if works
// "one": new App.ChapterView({id: 'one' })
}
});
In summary, the router should simply activate or deactivate backbone.layoutmanager sub-views based on the path, e.g., /#chapter/one, /#chapter/two, etc.
If I explicitly set the sub-views in App.Layout (see line 49 in the fiddle), the routing works as expected.
However, if I try to add the views by iterating a collection of models in the beforeRender function (line 40; beforeRender is coming from backbone.layoutmanager), they don't appear to be available when the router tries to find the matching view by ID.
Once the page has render, however, the view can be activated with:
App.router.navigate('/chapter/two',{"trigger": true});
Which seems to indicate that the views are properly being added and should be findable by the router with:
App.Layout.getView(name);
No doubt I'm simply overlooking something, or am about to expose my ignorance of the Backbone library. :)
The issue is that you're navigating and rendering out-of-sync. I've updated your code here: http://jsfiddle.net/6h268r7j/55/
It works when you use the declarative approach because those are outside of the render flow, essentially statically added. As soon as you use beforeRender/render you are now in an asynchronous render flow and they won't be available in your router callbacks.
The fix was to simply render the application layout first and then trigger the routing:
App.Layout.render().then(function() {
Backbone.history.start();
});
I've read Derick Bailey's article on Zombies but can't seem to figure it out. I have a backbone application that uses require.js and need to be able to close/destroy a view when I navigate away from it.
There's a lot of ways to initiate a backbone app, but what is the right way when using require to allow for clean up?
And how can I call a close() function on views just before navigating away?
Main.js
require([ "app", "backbone", "router", "facebook"], function(App, Backbone, Router, FB) {
//theres a lot of facebook integration
FB.init({
appId : '********',
version : 'v2.0'
});
//force the page to go to index when first arriving
window.location.hash = "";
new App;
Backbone.history.start();
});
App.js
define([ "backbone", "router" ], function(Backbone, Router){
var App = function () {
Router;
}
return App;
})
Router.js
define([ "backbone", "models/user" ], function(Backbone, User){
var AppRouter = Backbone.Router.extend({
routes: {
//All my routes
},
index: function () {
require([ "views/index", "models/user" ], function (IndexView, UserModel) {
var indexView = new IndexView({ model: UserModel });
})
},
// Remaining route functions
return new AppRouter;
})
That post solves a problem that your code here doesn't have.
The problem (zombie views) only occurs when your views have attached event handlers to a model instance.
var View = Backbone.View.extend({
setup: {
// model instance will now be storing a callback which is bound
// to *this* instance of a view
this.model.on('change', this.render, this);
},
render: function () {
// whatever code that uses the context, `this`
this.$el.innerHTML(this.model.get('title'));
}
});
Then in your app lifetime, the above view got rendered and then the page changed, or whatever happened, and the view is not needed anymore. But there might anything else that is using the model that this view has used – and that model might keep changing and then it will fire a callback for change event, the render method which will point at seemingly non-existent view.
But since that view might not have its element in the DOM anymore, you'll get DOM errors (if for example your render method referenced this.$el.parent()) and the views will remain in memory without you knowing it, eventually causing your page to get slow or even unresponsive.
Since that post was written there's now a new way of attaching event handlers, called listenTo, which makes it easier to stopListening.
There's also now View.prototype.remove method which will remove the view's element from the DOM and also call stopListening which will help in case you used listenTo to attach event handlers for the models.
In Backbone, is there any way to trigger a route event handler, without changing the URL?
What I mean is that I want to trigger a route handler, but I don't want to change the URL.
Hence, I don't want to use
router.navigate(route, {trigger: true});
as this will cause the URL to change.
The router itself is connected to a function. The simple answer is to call the function straight away, simply bypassing the route handling.
Example
(function( $, Backbone ) {
var exports = window.app = window.app || {},
Router = Backbone.Router.extend({
// Here you declare what the routes are in your router
// and what functionality they should trigger.
routes: {
"help" : "help",
"search/:query" : "search",
"search/:query/p:page": "search"
},
// Declare route functions.
help : function() {},
search: function( query, page ) {}
});
// Export the router.
exports.router = new Router();
// Just a dummy object for calling the router.
var cookieMonster = {
init: function() {
// Do something on init.
// End with calling the route help function.
exports.router.help();
}
};
}(jQuery, Backbone));
cookieMonster.init() would in this case end with a call to the help function in the router.
A tip is to look at Backbone Marionette where you have a Controller which has the function logic seperated from the routes, one of many things that make Marionette awesome.
For what its worth, Marionette routing is explained extensively here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf
The strategy that is discussed is separating URL management from application reactions (e.g. switching sub-applications). This means that you're then free to have your app trigger a handler (using a Marionette event) without modifying the URl fragment.
Have you tried Backbone.history.loadUrl(route);?
Just wanted to know, what is the proper way of returning to the index in backbone.js? So this is an outline of my code. I have a router, where it creates an instance of a view and passes the current instance of the router.
var AppRouter = Backbone.Router.extend({
callMasterViefw: function(){
MasterView.initialize(this);
},
})
Inside the MasterView, I create an instance of the MasterView and assign the router to it as well. I have a function, called reRouteToIndex, where basically i want to reroute to the index page.
MasterView= Backbone.View.extend({
render: function(){},
reRouteToIndex(){
this.router.navigate("", {trigger: true,replace: true});
},
});
All this works, but the problem is when I redirect to the index I return to something like www.test.com/index.html/#. Where it is important to note the # at the end. I was wondering if there was a way to route to the original path without the # like this www.test.com/index.html?
You could enable pushState in .navigate() (like .navigate({pushState: true, trigger: true}) but you'll need to configure your webserver to work with mod_rewrite (or equivalent).
I have a simple implementation of Backbone.js which goes like this -
$(document).ready(function(){
Workspace = Backbone.Router.extend({
routes: {
"/getAcademics": "academics"
},
academics: function(){
alert("ok");
$("#content").append("<div>Academics</div>");
}
});
var myWorkspace = new Workspace;
});
The link in the body is given as -
Academics
Though the router routes to the link #/getAcademics but it does not execute the function academics. Any clues as how to rectify this. Am I missing something else.
Thanks
After you instantiate your router, and before you attempt to use any of its routes, you need to call Backbone.history.start(). This will setup a listener for hash changes and call the correct route functions when needed.
You can find more information here: http://documentcloud.github.com/backbone/#History