Backbone router.route isn't setting route - backbone.js

I have the following router defined, but the .route function doesn't seem to be setting. What am I doing wrong? Thanks, in advance, for the help.
# app.js.coffee
initialize: =>
router = new Backbone.Router
router.route "foo/:bar", "baz"
console.log router.routes # returns undefined

The routes you create using Router.route are stored internally in the History object -- they're not added to the Router.routes collection.
They still work though, see here for proof. Note that in this.routes, only the home route is defined, but you're still able to hit the baz route. You can see the baz route if you check Backbone.history.handlers, which is where the routes are actually stored.
var Router = Backbone.Router.extend({
initialize: function() {
this.route("foo/:bar", "baz");
},
routes: {
"": "home"
},
home: function() {
console.log("home hit");
},
baz: function(bar) {
console.log('test hit: ' + bar);
},
});
var router = new Router();
console.log(this.routes);
console.log(Backbone.history.handlers);
Backbone.history.start();
router.navigate("foo/testbar", { trigger: true });
​
Note though, I think you need to use this in your code, because router won't be defined yet inside initialize:
#route "foo/:bar", "baz"

Related

How do I set up Backbone Routes

This is the first time I am using Backbone and I seem to be stuck on the basics, so bear with me.
I just want to use Backbone for Routing, I'm currently testing it within the News section of my site but I can't get the routes to trigger the functions I want.
Here' my code:
var NewsRouter = Backbone.Router.extend({
routes: {
"*news": "init",
"news:tmpl": "loadTemplate",
},
init: function(params) {
//$("#main").load("/news/all");
console.log('news called')
},
loadTemplate: function(tmpl) {
console.log('loadTemplate function called')
}
});
var news_router = new NewsRouter;
Backbone.history.start();
I have this route working fine:
mysite.dev/news/ - console shows "news called"
mystic.dev/news/interviews - should call loadTemplate()
What am I mssing?
You missed slash after "news" in the route for 'loadTemplate':
"news/:tmpl": "loadTemplate",
Note that in your case router is configured only for hash-based navigation (like '#news/interviews' ). You may enable URL-based navigation by specifying additional options for 'start' method:
Backbone.history.start({ pushState: true });
I've tested. This works.
var NewsRouter = Backbone.Router.extend({
routes: {
"news": "init",
"news/:tmpl": "loadTemplate",
},
init: function(params) {
//$("#main").load("/news/all");
alert('news called');
},
loadTemplate: function(tmpl) {
alert('loadTemplate function called: ' + tmpl);
}
});
var news_router = new NewsRouter;
Backbone.history.start();
Only updated below part.
routes: {
"news": "init",
"news/:tmpl": "loadTemplate",
},
Basically, you also need to remove * (asterisk) apart from missing slash as answered by #Vitaliy Fedorchenko.
Backbone code is not as complex as jQuery. It's pretty readable. So best thing is go to code and read rather than finding documentation. I don't understand regex as much, but if you see splatParam variable, I think it is treating asterisk as wild match. Anyone can please correct me if I'm wrong.

Backbone.js route interceptor

I have main app with subapps:
main_app
|-mainRouter.js
|-sub_app
|-subAppRouter.js
subAppRouter.js extends mainRouter.js. subAppRouter.js has handler for route (e.g. /app1/item/). I have no access to subAppRouter.
Here is what I need:
In mainRouter I want to create routing that will handle all URL's from all apps.
It should handle route , make some check and in one case it should continue firing handler from subAppRouter for that url, else it should make redirect (e.g. /app2/somepage).
Could someone helps me with finding the best solution how to do it?
In other words: how to realize interceptor pattern via router in backbone?
Thanks
i will rephrase your question in points
1- you have a main router for common routes
2- you have a specialized router for some app routes
3- you need your main router to choose weather to handle the route of just forward it to sub router
to achieve this i suggest the following
1- create the main router , extending Backbone.Router
var mainRouter = Backbone.Router.extend({
routes:{
'index':'loadIndex',
//other common app routes......
},
loadIndex: function(){
//code to load index
}
});
2- then define the sub router for app,extending the main router, but notice how routes is defined
var subAppRouter = mainRouter.extend({
initialize: function(){
// here we will extend the base routes to not lose default routing, and add app special routing
_.extend(this.routes, {
'subApp/index': 'subAppIndex'
});
},
subAppIndex: function(){
// code to load sub app index
},
});
then you can use the sub router which will contains the base routing also
Here is a good article about subrouting. This works perfect for me.
Include subroute js lib in your project:
<script type="text/javascript" src="backbone.subroute.min.js"></script>
HTML body example:
App1
App2
<div class="app">
</div>
JS Code example:
var MyApp = {};
MyApp.App1 = {
Router: Backbone.SubRoute.extend({
routes: {
"": "init",
"sub1": "sub1"
},
init: function () {
console.log("app1");
$(".app").html($("<h1 />", {text: "App1"}));
$(".app").append($("<a/>", {href: "#app1/sub1", text: "sub1"}));
},
sub1: function () {
console.log("sub1");
$(".app").append($("<h2 />", {text: "sub1"}));
}
})
};
MyApp.Router = Backbone.Router.extend({
initialize: function () {
if(!MyApp.Routers){
MyApp.Routers = {};
}
},
routes: {
"app1/*subroute": "invokeApp1Router",
"app2": "app2"
},
invokeApp1Router: function (subroute) {
if(!MyApp.Routers.App1){
MyApp.Routers.App1 = new MyApp.App1.Router("app1/");
}
},
app2: function () {
console.log("app2");
$(".app").html($("<h1 />", {text: "App2"}));
}
});
$(document).ready(function () {
new MyApp.Router();
Backbone.history.start();
})

Getting actions to fire with backbone

Iv'e set up my first little backbone app with a router to see if i can get some actions firing. I can't. I don't get an error message, but the console.log messages aren't displaying. Is there something more I have to set up to get the app started?
window.BreakfastApp = new (Backbone.Router.extend({
routes: { "": "interest", "products/:type": "products"},
initialize: function(){
console.log("hello world");
},
start: function(){
Backbone.history.start({pushState: true});
},
interest: function(){
console.log('interest')
},
products: function(type){
console.log('product' + type )
},
toppings: function(){
console.log('toppings')
},
results: function(){
console.log('results')
}
}));
$(function(){
BreakfastApp.start();
});
The documentation says:
During page load, after your application has finished creating all of
its routers, be sure to call Backbone.history.start(), or
Backbone.history.start({pushState: true}) to route the initial URL.
In your case something like:
var BreakfastAppRouter = Backbone.Router.extend({
...
});
var router = new BreakfastAppRouter();
Backbone.history.start();
should do the job.

Backbone pushstate history not working

I am using backbone.js routes and i am struggling to make history to work. Here is the code i have:
$(function() {
var AppRouter = Backbone.Router.extend({
routes: {
"/": "initHome",
"home": "initHome",
"projects": "initProjects",
"project/:id" : "initProject"
}
});
// Instantiate the router
var app_router = new AppRouter;
app_router.on('route:initProject', function (id) {
// Note the variable in the route definition being passed in here
getContent("project",id);
});
app_router.on('route:initProjects', function () {
getContent("projects");
});
app_router.on('route:initHome', function () {
getContent("home");
});
// SINGLE PAGE MAGIC
$(document).on("click",".links",function(e) {
var href = $(this).attr("href");
var url = lang + "/" + href;
page = $(this).attr("data-id");
var param = $(this).attr("data-param");
if (typeof(param) == 'undefined') { param = ""; }
if(activepage != href && !main.hasClass("loadingPage")){
loader.show();
firstInit = false;
activepage = href;
res = app_router.navigate(url, true);
getContent(page,param);
}
return false;
});
Backbone.history.start({pushState: true, root: "/karlin/"});
});
Push state is working fine on click, but it wont call getContent() function when i try back/next buttons in the browser. I am an newbie to backbone, so any advice will be helpful.
Change this: res = app_router.navigate(url, true);
To this: app_router.navigate(url, {trigger: true});
I can't see any reason to create a variable "res".
IMHO you've got a convoluted implementation of Backbone. I'd suggest moving your routes to the constructor like so:
var AppRouter = Backbone.Router.extend({
routes: {
"/": "initHome",
"home": "initHome",
"projects": "initProjects",
"project/:id" : "initProject"
},
initProject: function (id) {
// Note the variable in the route definition being passed in here
getContent("project", id);
},
initProjects: function () {
getContent("projects");
},
initHome: function () {
getContent("home");
}
});
// Instantiate the router
var app_router = new AppRouter;
Also, if you set up your routes properly like in the Backbone docs,
routes: {
"help": "help", // #help
"search/:query": "search", // #search/kiwis
"search/:query/p:page": "search" // #search/kiwis/p7
},
you can pass parameters to the routes with traditional links. You can also move your if activePage statement to the router as a helper function for changing pages.
Router.navigate is for rare instances.
I suggest, reading the Backbone docs over and over. I learn something new every time. There's a lot there and Backbone is doing things efficiently already. No need to reinvent the wheel.
Hope this helps!
I second Andrew's answer: your use of routing is a bit odd.
If you're interested in learning more about why, as Andrew says, "Router.navigate is for rare instances", read pages 32-46 here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf
It's part of the sample for my book on Backbone.Marionette.js, but routing concepts remain the same. In particular, you'll learn why the default trigger value is false, and why designing your app routing with that in mind will make your apps better.

loading multiple views in init function breaks one or the other

I'm building my first backbone.js app, and I've run into a problem when trying to initialize my app and display both recipes and a shopping list, both of which are different (yet related) backbone objects.
My init function is
var MyApp= {
Models: {},
Views: {},
Routers: {},
Collections: {},
AppView: {},
Init: function() {
new MyApp.Views.ShoppingList;
new MyApp.Routers.Recipes;
Backbone.history.start();
}
};
Strangely, when I use
new MyApp.Routers.ShoppingList;
new MyApp.Routers.Recipes;
I don't get the shopping list View, I only get the recipes.
I also don't get any errors.
The shopping list router is fairly basic
MyApp.Routers.ShoppingList = Backbone.Router.extend({
routes: {
"": "index",
"shopping_list/:id": "show"
},
index: function(){
console.log('this');
new MyApp.Views.ShoppingList();
}
});
so from what I understand, the app should load the router, and display the view, but I'm not getting that or the console.log.
--------------as requested, here is my 'recipes router'---------------
MyApp.Routers.Recipes = Backbone.Router.extend({
routes: {
"": "index",
"recipes/:id": "show"
},
index: function(){
if(!MyApp.RecipeList){
MyApp.RecipeList = new MyApp.Collections.RecipeList;
MyApp.RecipeList.page = 1;
} else {
MyApp.RecipeList.page++;
}
MyApp.RecipeList.url='/recipes?page='+MyApp.RecipeList.page;
MyApp.RecipeList.fetch({
add: true,
success: function() {
new MyApp.Views.RecipeList({ collection: MyApp.RecipeList});
},
error: function() {
new Error({ message: "Error loading documents." });
}
});
},
show: function(id){
var recipe = MyApp.RecipeList.get(id);
new MyApp.Views.RecipeView({ model: recipe});
},
newRecipe: function(){
new App.Views.Edit({ model: new Recipe() });
},
edit: function(id){
var recipe = new Recipe({ id: id});
recipe.fetch({
success: function(model, resp){
new App.Views.Edit({ model: recipe});
},
error: function(){
new Error({message: "Hey!? Were'd it go? sorry I can't find your recipe"});
window.location.hash = '#';
}
});
}
});
----------------- some progress -----------------------------
I may be wrong, but in commenting out sections of the router, I find that the problem may be caused by my 'routes' as they both have index where the url is empty. Commenting out the 'routes' in one controller/router causes the other controller/router to display.
I've changed the routes so that they are more representative of their namespace
routes{
"recipes" : "recipes"
},
recipes: function()...
but I'm still not getting the right information to display. I'm now trying to figure out if I need an initialize function and what that would look like, or if I've even debugged this properly
--------------------- update, I was using backbone wrong ------------------------
It turns out I believe that I was mis-understanding Routers and was thinking of them more like controllers, so I was calling multiple routers on load, but the page was only loading the last one which pointed to an empty route as you can only request a single url route at a time.
Now I'm loading multiple Views on load and only one router.
After instantiating your view, you still need to render it and add it to the DOM.
index: function(){
console.log('this');
var view = new MyApp.Views.ShoppingList();
//you don't have to append to the whole body, but this is just an example
$('body').append(view.render().el);
}

Resources