I'm trying to follow Organizing your application using Modules (require.js I'm struggling to understand how routing works.
I cannot get simple binding to work for index:
// Filename: router.js
define([
'jquery',
'underscore',
'backbone',
'views/projects/list'
], function ($, _, Backbone, ProjectListView) {
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'': 'index'
}
});
var initialize = function () {
var app_router = new AppRouter();
app_router.on('index', function () {
alert("index"); // this never gets called
});
Backbone.history.start();
return app_router;
};
return {
initialize: initialize
};
});
When page is loaded nothing happens. This however works:
// Filename: router.js
define([
'jquery',
'underscore',
'backbone',
'views/projects/list'
], function ($, _, Backbone, ProjectListView) {
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'': 'index'
},
index: function() { alert("works"); }
});
var initialize = function () {
var app_router = new AppRouter;
Backbone.history.start();
return app_router;
};
return {
initialize: initialize
};
});
Am I missing something?
Ok, so this is how it's done:
var initialize = function () {
var app_router = new AppRouter();
app_router.on("route:index", function () {
alert("hello world");
});
Backbone.history.start();
return app_router;
};
Related
Backbone version 1.1.2
Require version 2.0.2
//My main file
require.config({
paths: {
jquery: 'assets/js/libs/jquery/jquery-1.9.1.min',
underscore: 'assets/js/libs/underscore/underscore-min',
backbone: 'assets/js/libs/backbone/backbone-min',
bootstrap: 'assets/js/libs/bootstrap/bootstrap.min',
text : 'assets/js/libs/require/text',
mustache: 'assets/js/libs/mustache/mustache'
},
shim: {
'backbone': {
deps: ['jquery','underscore'],
exports: 'Backbone'
},
'bootstrap': {
deps: ['jquery']
}
}
});
require([
// Load our app module and pass it to our definition function
'assets/js/app',
], function(App){
App.initialize();
});
//My App file
define([
'jquery',
'underscore',
'backbone',
'assets/js/router'
], function($, _, Backbone, Router){
var initialize = function(){
Router.initialize();
}
return {
initialize: initialize
};
});
//My Router File
define([
'jquery',
'underscore',
'backbone',
'assets/js/views/trabajadores/list'
], function($, _, Backbone, TrabajadoresListView){
var AppRouter = Backbone.Router.extend({
routes:{
'':'mostrarTrabajadores',
'trabajadores': 'mostrarTrabajadores'
},
mostrarTrabajadores: function(){
var trabajadoresListView = new TrabajadoresListView();
trabajadoresListView.render();
}
});
var initialize = function(){
var app_router = new AppRouter;
Backbone.history.start();
};
return {
initialize: initialize
};
});
I'm a inspection the code and when the following code line executes "var app_router = new AppRouter; ", the console says: Uncaught TypeError: undefined is not a function.
The Router it's not working for me.why?
You can declare your route actions inside the initialize method. Just use the following:
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:index', function() {
console.log('index route');
});
return {
initialize: initialize
};
});
Just make sure you follow the format "route:Action" in the Router's 'on()' method.
Something odd is going on with my Backbone project. I'm rebuilding it as AMD and I'm having to change some variable names to get it working again. I have a collection I'm passing into a view, but when I console.log the collection, I get both the object and null.
Here is my view:
define([
'jquery',
'underscore',
'backbone',
'models/tableModel',
'collections/tablesCollection',
'views/tablesView',
'views/tableView'
],
function($, _, Backbone, tableModel, tablesCollection, tableView) {
var tv = Backbone.View.extend({
tagName: 'div',
initialize: function() {
console.log(this.collection);
this.collection.on('reset', this.render, this);
this.template = this.options.template;
this.url = this.collection.url;
},
render: function() {
//tablesCollection.collection.each(this.addOne, this);
return this;
},
addOne: function(model) {
var t = new tableView({ model: model, template: this.template, url: this.url });
this.$el.append(t.render().el);
return this;
},
stripQueryString: function(url) {
return url.split('?')[0];
}
});
return tv;
});
You'll see the console.log several lines down in the project. Here is what I get in Firebug as a result:
Both cite the same line number. Here is what's in the object:
What is going on here? Why am I getting two results for the same thing? One of them is what I want and the other one isn't.
EDIT:
Here is where I instantiate the view:
define([
'jquery',
'underscore',
'backbone',
'models/tableModel',
'collections/TablesCollection',
'views/tablesView',
'views/tableView'
], function($, _, Backbone, TableModel, tablesCollection, tablesView, tableView) {
var t = new tablesCollection(null, { url: 'main-contact'} );
var tables = new tablesView({ collection: t, template: 'main-contact-template'});
$('#web-leads').html(tables.render().el);
});
Here is my collection:
define([
'jquery',
'underscore',
'backbone',
'models/tableModel'
],
function($, _, Backbone, tableModel) {
var tablesCollection = Backbone.Collection.extend({
url: this.url,
model: tableModel,
initialize: function(models, options) {
if (options && options.url) {
this.url = options.url;
}
this.fetch({
success: function(data, options) {
}
});
}
});
return tablesCollection;
});
Two other files:
// Filename: app.js
define([
'jquery',
'underscore',
'backbone',
'router' // Request router.js
], function($, _, Backbone, Router){
var initialize = function(){
// Pass in our Router module and call it's initialize function
Router.initialize();
};
return {
//initialize: initialize <--This is where the second init call was happening.
};
});
Main.js:
require.config({
paths: {
//jquery: 'libs/jquery/jquery-1.8.3.min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min'
}
});
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( 'jquery', [], function () { return jQuery; } );
}
//the "main" function to bootstrap your code
require(['jquery', 'underscore', 'backbone', 'app'],
function () {
var App = require('app');
App.initialize();
// console.log($);
// console.log(_);
// console.log(Backbone);
});
You prior version of the code made more sense than this edited version, as in the prior version you were actually pushing to console.log the object that was giving trouble
// contents of 'that/view/that/gives/me/problems.js'
define([
'jquery',
'underscore',
'backbone',
'models/tableModel',
'collections/tablesCollection',
'views/tablesView',
'views/tableView'
],
function($, _, Backbone, tableModel, tablesCollection, tableView) {
console.log("factory", tablesCollection.collection); // <- you did not have this line. my addition
var tv = Backbone.View.extend({
tagName: 'div',
initialize: function() {
console.log("init", tablesCollection.collection); // <- your prior version. Point of your error
this.collection.on('reset', this.render, this);
this.template = this.options.template;
this.url = this.collection.url;
}
// ...
});
return tv;
});
Now the reason you have it show up twice is because the view you define above is initialized twice somewhere.
First time it's initialized it shows the value as you can see. The second time around the pointer tablesCollection is cleaned up by something and, hence, you have that error.
Now what cleans up tablesCollection and why I don't see anywhere in the code you present. It has likely something to do with re-requiring 'collections/tablesCollection' module somewhere in your code. As I can see from your 'collections/tablesCollection' module code, you REDEFINE the output on every factory call. What I would do is calc it once and serve cached:
// contents of 'collections/tablesCollection.js'
;(function(){
var mythings = {}
function initializer($, _, Backbone, tableModel){
return Backbone.Collection.extend({
url: 'url',
model: tableModel,
initialize: function(models, options) {
// ...
}
});
}
define([
'jquery',
'underscore',
'backbone',
'models/tableModel'
],
function($, _, Backbone, tableModel) {
if (!mythings.tablesCollection){
// this will be done on first run.
mythings.tablesCollection = initializer($, _, Backbone, tableModel)
}
// all others will just return same exact instance of collection class
return mythings.tablesCollection
})
})();
EDIT:
Asked the AMD spec group if there is a chance of 'factory' function rerunning on every require. Immediate answer was "Not likely" but long term answer is "Possible (if asked under different name)"
I added comment lines to the code snippet above indicating what files they are.
I also added a console.log line in the first snippet that should help you understand that the issue you have is NOT with AMD loader. You simply initialize the view twice somewhere.
When you run the code with comment lines like in the top snippet you will see factory log line shoing up only once and init line twice, like in your origianl error screenshot.
You need to trace where you use the view returned in that tv variable. You are initing it twice.
As to what happens to (what clears) reference to tablesCollection in the second run I don't know and don't see anywhere in the snippets you provided.
I've been trying to practice on backbone.js, I found one tutorial online which I was trying to follow (http://backbonetutorials.com/what-is-a-router/) but unfortunately i have problem reaching to my view through the router.
Below is my code
main.js
requirejs.config({
// create local alias for package
paths: {
l : 'my/vehicle',
underscore : 'vendors/underscore',
jqueryui : 'vendors/jquery-ui/js/jquery-ui-1.9.0.custom.min',
backbone : 'vendors/backbone',
bootstrap : 'vendors/bootstrap'
},
shim: {
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
underscore: {
exports: "_"
}
}
})
require(['../../config'], function(core){
require(["l/app"], function(App) {
'use strict';
App.initialize();
});
});
app.js
define(["jquery", "backbone", "l/router"], function($, Backbone, Router) {
var initialize = function(){
// Pass in our Router module and call it's initialize function
Router.initialize();
}
return {
initialize: initialize
};
});
router.js
define([
'jquery',
'underscore',
'backbone',
'l/views/BrowseVehicle'
], function($, _, Backbone, BrowseVehicleView){
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'/browse' : 'showVehicleBrowse',
// Default
'*actions' : 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('showVehicleBrowse', function(){
// Call render on the module we loaded in via the dependency array
console.log('am here');
var BrowseVehicleView = new BrowseVehicleView();
BrowseVehicleView.render();
});
app_router.on('defaultAction', function(actions){
// We have no matching route, lets just log what the URL was
console.log('No route:', actions);
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
views/BrowseVehicle.js
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
var BrowseVehicleView = Backbone.View.extend({
el: $('#vehicle-browse-form'),
render: function(){
// Using Underscore we can compile our template with data
console.log('I reached vehicle browse form');
}
});
// Our module now returns our view
return BrowseVehicleView;
});
There is no error on loading the code, console.log is not printing anything in the view nor in the router inside the routed function. I tried to access my urls using URL/#/browse but not getting the console.log statement.
Can anyone please advise?
In the routes {} definition remove the forward slash in front of browse.
I am trying to achive something like this in backbone js
var AppRouter = Backbone.Router.extend({
routes: {
// MVC like route
':controller': 'defaultRoute',
// MVC like route
':controller/:action': 'defaultRoute',
// MVC like route
':controller/:action/:id': 'defaultRoute',
// MVC like route
':controller/:action/*id': 'defaultRoute'
},
defaultRoute: function (controller, action, id) {
// render view here or
// call another specific route regarding to controller parameter
}
});
var appRouter = new AppRouter;
Backbone.history.start();
So when url is: something.com/#home/index defaultRoute function will get parameters controller="home" and action="index".
I am wondering now how to find view (Backbone.View) in folder "controller/home/index" and instantiate dynamically (and render). Also wondering if better approach would be to have Backbone.Router for each "controller" (I am using name "controller" but it is actually "router").
Any ideas?
UPDATE with possible solution!
I ended up with this
// Filename: router.js
define([
'jquery',
'underscore',
'backbone'
], function ($, _, Backbone) {
var AppRouter = Backbone.Router.extend({
routes: {
// MVC like route
':controller': 'defaultRoute',
// MVC like route
':controller/:action': 'defaultRoute',
// MVC like route
':controller/:action/:id': 'defaultRoute',
// MVC like route
':controller/:action/*id': 'defaultRoute'
},
defaultRoute: function (controllerName, actionName, id) {
controllerName = controllerName || Config.Defaults.Controller;
actionName = actionName || Config.Defaults.Action;
require(["controllers/" + controllerName], function (ctl) {
var code = "ctl." + actionName + "();";
eval(code);
});
}
});
var appRouter = new AppRouter;
Backbone.history.start();
});
And sample controller is this
define([
'jquery',
'underscore',
'backbone'
], function ($, _, Backbone) {
return {
index: function () {
console.log("Action: Index");
},
about: function () {
console.log("Action: About");
}
};
});
It works with this sample. Now trying to solve params binding etc. Need more testing.
At this time I am still investigating but here is the code I am using at the moment:
// Filename: router.js
define([
'jquery',
'underscore',
'backbone'
], function ($, _, Backbone) {
var AppRouter = Backbone.Router.extend({
routes: {
// MVC like route
':controller': 'defaultRoute',
// MVC like route
':controller/:action': 'defaultRoute',
// MVC like route
':controller/:action/:id': 'defaultRoute',
// MVC like route
':controller/:action/*id': 'defaultRoute'
},
defaultRoute: function (controllerName, actionName, id) {
controllerName = controllerName || Config.Defaults.Controller;
actionName = actionName || Config.Defaults.Action;
require(["controllers/" + controllerName], function (ctl) {
var code = "ctl." + actionName + "();";
eval(code);
});
}
});
var appRouter = new AppRouter;
Backbone.history.start();
});
So "controller" looks like
// Filename: controllers/home.js
define([
'jquery',
'underscore',
'backbone',
], function ($, _, Backbone) {
return {
index: function () {
require(['views/home/index'], function (view) {
view.render();
});
},
about: function () {
require(['views/home/about'], function (view) {
view.render();
});
}
};
});
Next is to create typical backbone views.
I will post more when I test passing parameters and do some more complicated tests.
JS client side dynamic dependency loading, I think this is still in our dreams.
You can play with very tricky technics like Dynamic Script Loading but even if it looks easy at the beginning it is gonna become in a nightmare (sooner or later).
If you need a technic like this be sure it worths it, you should try to think it again.
About if to use one Router for the whole application or separate it in several Routers by controllers/modules or whatever I have already said my opinion about.
Let's say my app works but I love to learn and to find the best way of doing things.
I really appreciate this post about Reducing Backbone Routers To Nothing More Than Configuration.
And the following bbclonemail which is not using requires.
Actually my implementation is a monolithic block (app.js, router.js).
Here's my questions:
1) What should the router module router.js return?
2) How should I remove The Callback Functions from router.js ?
3) What should the app module app.js return?
4) How should I decouple the app.js in many others apps (for example: main, tasks, projects)
app.js
// app.js
define([
'router'
// some modules
],
function (router, Backbone, HeaderView)
{
"use strict";
var myApp = new Backbone.Marionette.Application();
myApp.addRegions({
header: '#header',
sidebar: '#sidebar',
mainColumn: '#main-column',
rightColumn: '#right-column'
});
myApp.initHeader = function () {
var headerView = new HeaderView();
myApp.header.show(headerView);
}
// many others many views
myApp.start();
myApp.initialize = function() {
router.initialize();
Backbone.history.start();
}
return myApp;
});
router.js
// router.js
define([
// some modules
],
function (Backbone)
{
"use strict";
var AppRouter = Backbone.Marionette.AppRouter.extend({
routes: {
tasks: 'tasks',
projects: 'projects',
// many others keys/values
'*defaults': 'home'
},
getApp: function ()
{
var mainApp;
require(['js/app'], function (app) {
mainApp = app;
});
return mainApp;
},
home: function()
{
var app = this.getApp();
app.initHeader();
app.initSidebar();
app.initTaskDetails();
},
// many others callbacks
});
var initialize = function() {
new AppRouter;
};
return {
initialize: initialize
};
});
For the Router part you should make like this:
router.js
// router.js
define([
'rooterController'
// some modules
],
function (Backbone, rooterController)
{
"use strict";
var AppRouter = Backbone.Marionette.AppRouter.extend({
routes: {
tasks: 'tasks',
projects: 'projects',
// many others keys/values
'*defaults': 'home'
}
});
return new AppRouter({constroller: rooterController})
});