Marionette router does nothing even if backbone history is started - backbone.js

I work on an app with Marionette and browserify.
When I start my application, any routes is matched.
My app code :
app.js :
var App = require('./App/SaApp.js');
App.start();
SaApp.js :
var Mn = require('backbone.marionette');
var DashboardRouter = require('./modules/DashboardRouter.js');
var DashboardController = require('./modules/DashboardController.js');
var DashboardMainView = require('./modules/Dashboard/layout/DashboardMainView.js');
var Backbone = require('backbone');
var app = new Mn.Application();
app.addInitializer(function () {
console.log ('addInitializer');
var dashboardMainView = new DashboardMainView({
el: '#main-view'
});
var dashboardRouter = new DashboardRouter({
controller: new DashboardController({
mainView: dashboardMainView
})
});
dashboardMainView.render();
});
app.on("start", function(){
Backbone.history.start();
});
module.exports = app;
DashBoardRouter.js file :
var Mn = require('backbone.marionette');
var DashboardRouter = Mn.AppRouter.extend({
initialize : function () {
console.log ('router')
},
appRoutes: {
"": "indexAction",
"databases/:name":'databaseAction'
},
});
module.exports = DashboardRouter;
And DashBoardController.js :
var Mn = require('backbone.marionette');
var _ = require('underscore');
var LeftPanelView = require('./Dashboard/views/LeftPanelView.js');
var MainPanelView = require('./Dashboard/views/MainPanelView.js');
var TablePanelView = require('./TableBoard/views/TablePanelView.js');
var TableCollection = require('./Dashboard/collection/DatabaseCollection.js');
var DatabaseModel = require('./Dashboard/model/DatabaseModel.js');
var DashboardController = Mn.Controller.extend({
initialize : function(options) {
this.mainView = options.mainView;
console.log ('init')
},
indexAction : function() {
var collection = new TableCollection();
console.log ('fetch')
collection.fetch().done(_.bind(function () {
this.mainView.leftPanel.show(new LeftPanelView({
tableCollection : collection
}));
this.mainView.mainPanel.show(new MainPanelView());
}, this));
},
databaseAction : function (tableName) {
var databaseModel = new DatabaseModel();
databaseModel.urlRoot = 'databases/'+tableName;
databaseModel.fetch().done(_.bind(function() {
var tablePanelViews = new TablePanelView({
model : databaseModel
});
this.mainView.mainPanel.show(tablePanelViews);
}, this));
},
onRoute : function() {
var collection = new TableCollection();
console.log ('on route')
collection.fetch().done(_.bind(function () {
this.mainView.leftPanel.show(new LeftPanelView({
tableCollection : collection
}));
}, this));
}
});
module.exports = DashboardController;
When I start my app, all console.log are displayed in good order but indexAction is never run.
When I build code by browserify command, all is correct.
Thank you for your help.

I'm not sure, but i think you are just missing the controller (controller: myController) in the Approuter. As marionette documentation says:
var MyRouter = new Marionette.AppRouter({
controller: myController,
appRoutes: {
"foo": "doFoo",
"bar/:id": "doBar"
}
});
I know i shoudn't post links on stackoverflow, but anyway it might help you. I have done recently a basic setup with marionette and require. There you might can understand better why is not working in your case:
https://github.com/LucaMele/skeleton-marionette-require-gulp
You should find the info in the file:
https://github.com/LucaMele/skeleton-marionette-require-gulp/blob/master/modules/app.js
row 37 ( controller:new App.Router.Controller() )

Related

How to filter backbone collection to show tags

I'm creating a bookmarking tool that lets you create a list of stored bookmarks from an in-page form. The list will include an identifier tag (eg - Amazon www.amazone.com tag: shopping). From this created list, I want to also have a list showing the various tags that have been named.
This should probably use the filter method, but I cannot seem to get it to filter a correct list; I keep getting each tag listed for each URL created so there are multiple examples of the same tag.
Here is the code that correctly works in creating my form, the resulting URL list, and the module exports. This is from my Views js file:
var $ = require('jquery');
var Backbone = require('backbone');
var listTemplate = require('../../templates/addresslist.hbs');
var formTemplate = require('../../templates/addressform.hbs');
var detailTemplate = require('../../templates/addressdetail.hbs');
var AddressFormView = Backbone.View.extend({
tagName: 'form',
template: formTemplate,
events: {
'submit': 'addAddress'
},
render: function(){
var renderedHtml = this.template();
this.$el.html(renderedHtml);
return this;
},
addAddress: function(event){
event.preventDefault();
this.collection.create({
title: $('#title').val(),
url: $('#url').val(),
tag: $('#tag').val(),
});
$('#title').val('');
$('#url').val('');
$('#tag').val('');
},
});
var AddressListView = Backbone.View.extend({
tagName: 'ul',
initialize: function(){
this.listenTo(this.collection, 'add', this.renderItem);
},
render: function(){
return this;
},
renderItem: function(address){
console.log('address', address);
var addressItem = new AddressItemView({model: address});
this.$el.append(addressItem.render().el);
}
});
var AddressItemView = Backbone.View.extend({
tagName: 'li',
template: listTemplate,
render: function(){
var context = this.model.toJSON();
this.$el.html(this.template(context));
return this;
}
});
var AddressDetailView = Backbone.View.extend({
template: detailTemplate,
render: function(){
this.$el.html('').append(this.template);
return this;
}
});
module.exports = {
'AddressFormView': AddressFormView,
'AddressListView': AddressListView,
'AddressItemView': AddressItemView,
'AddressDetailView': AddressDetailView,
}
My router js file looks like this:
var $ = require('jquery');
var Backbone = require('backbone');
var views = require('./views/addressview');
var models = require('./models/address');
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'detail/:id/': 'detail'
},
initialize: function(){
this.collection = new models.AddressCollection();
},
index: function(){
var addressForm = new views.AddressFormView({collection: this.collection});
$('.app').html(addressForm.render().el);
var addressListing = new views.AddressListView({collection: this.collection});
$('.app').append(addressListing.render().el);
this.collection.fetch();
},
detail: function(addressId){
this.collection.fetch().done(function(){
var address = this.collection.get(addressId);
var addressDetail = new views.AddressDetailView({model: address});
$('.app').html(addressDetail.render().el);
}.bind(this));
},
});
var router = new Router();
module.exports = router;
Create new event in view for multiple tag selection
tagSelected :function(event){
var tags = [<tag1>,<tag2>] //getting from multiple tag selection
var models = _.filter(this.collection.models,function(model){
return tags.indexOf(model.get('tag')) >= 0;
})
this.collection.reset(models);
this.render();
})

Backbone Collections Undefined

In my database, I am simply trying to grab every object from my "countries" array, however when I run it, the console tells me that my collections is undefined.
index.js
var Backbone = require('backbone')
var App = require('./app.js')
var countryCollection = require('./collections/countries');
var countryModel = require('./models/country')
var countryView = require('./views/country-bio');
App.Views.CountryBio = new CountryBioView;
App.Router = Backbone.Router.extend({
routes: {
'bio.html(/)': 'index',
'*actions': 'defaultRoute'
},
index: function() {
console.log(countryCollection)
console.log('this works')
},
defaultRoute: function() {
console.log("404 Page Not Found")
}
})
App.Router = new App.Router;
Backbone.history.start();
Collections
var Backbone = require('backbone');
var App = require('../app');
var Country = require('../models/country');**strong text**
var CountryCollection = Backbone.Collection.extend({
url: 'http://localhost:3000/countries',
model: Country
});
App.Collections.country = new CountryCollection;
module.exports = App.Collections.country;
Models
var Backbone = require('backbone');
var App = require('../app');
App.Models.Country = Backbone.Model.extend({
url: function() {
return 'http://localhost:3000/countries';
}
});
module.exports = App.Models.Country;
Views
var $ = require('jquery');
var Backbone = require('backbone');
var countryBioTemplate = require('../templates/countryBio.hbs');
var App = require('../app');
var CountryBio = Backbone.View.extend({
el: $('main'),
collection: App.Collections.country,
render: function () {
var _this = this;
var countryCollection = this.collection;
console.log(countryCollection)
// Fetch Collection from Server
// countryCollection.fetch().done(function (country) {
// _this.$el.html(countryBioTemplate(country));
// });
}
});
module.exports = CountryBio;

Backbone on route not giving me the route in the callback

I am trying to call the router.on('route', callback) function, but the callback is not provided with the route ...
My router/app:
var Backbone = require('backbone')
Backbone.$ = $
var _ = require('underscore')
var App = Backbone.Router.extend({
// nothing here yet
}, {
instance: null,
getInstance: function () {
App.instance = App.instance || new App
return App.instance
}
})
module.exports = App
Some module using the router:
var IndexView = require('./views/IndexView')
var App = require('../../AppModule/js/main')
var _ = require('underscore')
var Backbone = require('backbone')
Backbone.$ = $
function IndexModule(opts) {
this.app = App.getInstance()
this.indexView = new IndexView({
view: opts.view
})
this.init = function() {
this.app.route('', _.bind(this.indexRoute, this))
this.app.route('testroute#:id', function(id) {
console.log(id)
})
this.app.on('route', _.bind(this.routeChanged, this))
}
this.indexRoute = function() {
this.indexView.render()
}
this.routeChanged = function() {
console.log(arguments)
}
}
module.exports = IndexModule
Somewhere form $(document).ready():
var indexModule = new IndexModule({
view: "someview.html"
})
indexModule.init()
Backbone.history.start({root: '/'});
If I go to testroute/2 I get this result:
["", ["2"]]
Shouldn't the route (testroute) come up in an argument as a string??
Thanks..
Just realized that you have setup the route as testroute/:id. Since id is the only variable here, only that is passed as an argument to the handler. You should try something like :routeName/:id This way, both the route name and id will be passed as arguments.

View with .fetch() not rendering

When I render this view
var MyView = Backbone.View.extend({
/* el : '.myview', used when rendered on router request */
render : function () {
var data = new Data(); /* a collection from ajax request */
var that = this;
data.fetch({
success : function (bla, data) {
var template = _.template( $('#temp').html(), {data: data.players} );
that.$el.html(template);
}
});
}
});
on router request, it works:
var Router = Backbone.Router.extend({
routes : {
'bla' : 'bla'
}
});
var myView = new MyView();
var router = new Router();
router.on('route:bla', function () {
myView.render();
});
But when I want it simply to load with the page, it doesn't:
var myView = new MyView({ el: $(".myview") });
Because in the last line you posted, you missing call to render function.
var myView = new MyView({ el: $(".myview") });
myView.render();
Besides of that, I see the workflow of initialization a bit wiered. Namely, requesting the data inside .render() function, that violates view single responsibility. Something, that I do in my applications.
var Router = Backbone.Router.extend({
routes : {
'bla' : 'bla'
},
bla: function () {
app.BlaApp();
}
});
app.BlaApp = function () {
var collection = new Collection();
collection.fetch({
success: function (collection) {
var view = new app.BlaView({model: collection});
view.render();
}
})
}
app.BlaView = Backbone.View.extend({
render: function () {
var template = // render template based on this.model;
this.$el.html(template);
return this;
}
});

Marrionette.js NoMethodError: Method 'xxx' was not found on the controller but it is there

I'm getting the error: NoMethodError: Method 'go_start' was not found on the controller
The function go_start is only in two places in my project (I searched):
StartRouter.js
define(['marionette'], function(Marionette) {
'use strict';
var StartRouter = {};
StartRouter.Router = Marionette.AppRouter.extend({
appRoutes: {
"start": "go_start"
}
});
return StartRouter;
});
And StartController.js
define(['underscore', 'marionette', 'app/vent',
'text!templates/StartLayout.html', 'views/InspectorStartView','views/InspectorStartView'],
function(_, Marionette, vent, layout, InspectorStartView, PlayerStartView) {
'use strict';
// public module API
var Controller = {};
// private
var Layout = Marionette.Layout.extend({
template: _.template(layout),
regions: {
inspector: "#inspector_choice",
player: "#player_choice"
}
});
// private
var _initializeLayout = function() {
console.log('initializeLayout...');
Controller.layout = new Layout();
Controller.layout.on("show", function() {
vent.trigger("layout:rendered");
});
vent.trigger('app:show', Controller.layout);
};
// controller attach a sub view/ search View
vent.on("layout:rendered", function() {
console.log('layout:rendered =>StartController');
// render views for the existing HTML in the template, and attach it to the layout (i.e. don't double render)
var inspectorStartView = new InspectorStartView();
Controller.layout.inspector.attachView(inspectorStartView);
var playerStartView = new PlayerStartView();
Controller.layout.player.attachView(playerStartView);
});
// controller show inspector in the layout / subview
vent.on('show:inspector', function(inspectorStartView) {
// console.log('show books event');
Controller.layout.inspector.show(inspectorStartView);
});
// controller show inspector in the layout / subview
vent.on('show:player', function(playerStartView) {
// console.log('show books event');
Controller.layout.inspector.show(playerStartView);
});
// public API
Controller.go_start = function(term) { **//<-- function go_start**
_initializeLayout();
//vent.trigger("search:term", term);
};
return Controller;
The really strange part is that Crome shows the error happening on line 77 of App.js which is:
app.addInitializer(function(options) {
// configure for loading templates stored externally...
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function(templateId) {
// Marionette expects "templateId" to be the ID of a DOM element.
// But with RequireJS, templateId is actually the full text of the template.
var template = templateId;
// Make sure we have a template before trying to compile it
if (!template || template.length === 0) {
var msg = "Could not find template: '" + templateId + "'";
var err = new Error(msg);
err.name = "NoTemplateError";
throw err;
}
return template;
};
// Connect controllers to its router via options
// init router's router/controller
new options.router.Router({
controller: options.homeController
});
// init loginRouter's router/controller
new options.loginRouter.Router({
controller: options.loginController
});
// init helpRouter's router/controller
new options.helpRouter.Router({
controller: options.helpController //<-- Line 77
});
// init startRouter's router/controller
new options.startRouter.Router({
controller: options.startController
});
// init inspectorRouter's router/controller
new options.inspectorController.Router({
controller: options.inspectorController
});
// init playerRouter's router/controller
new options.playerRouter.Router({
controller: options.playerController
});
});
// export the app
return app;
});
The Help router and controller:
// HelpRouter.js
define(['marionette'], function(Marionette) {
'use strict';
var HelpRouter = {};
HelpRouter.Router = Marionette.AppRouter.extend({
appRoutes: {
"help": "go_help"
}
});
return HelpRouter;
});
<!-- routes/HelpController.js -->
define(['underscore', 'marionette', 'app/vent', 'text!templates/HelpLayout.html'],
function (_, Marionette, vent, layout) {
'use strict';
// public module API
var Controller = {};
// private
var Layout = Marionette.Layout.extend({
template: _.template(layout),
regions: {
faq: "#"
}
});
// private
var _initializeLayout = function () {
console.log('initializeLayout...');
Controller.layout = new Layout();
Controller.layout.on("show", function () {
vent.trigger("layout:rendered");
});
vent.trigger('app:show', Controller.layout);
};
// public API
Controller.go_help = function () {
_initializeLayout();
};
return Controller;
});
Anyone see what I'm doing wrong?
Here is something that I didn't think was supposed to happen:
// Includes Desktop Specific JavaScript files here (or inside of your Desktop router)
require(["app/App",
"routers/HomeController", "routers/StartController", "routers/LoginController",
"routers/InspectorController", "routers/PlayerController", "routers/HelpController",
"routers/DesktopRouter", "routers/LoginRouter", "routers/StartRouter",
"routers/InspectorController", "routers/PlayerController", "routers/HelpRouter" ],
function(App,
HomeController, StartController, LoginController, InspectorController, PlayerController, HelpController,
DesktopRouter, LoginRouter, HelpRouter, StartRouter, InspectorRouter, PlayerRouter) {
var options = {
homeController: HomeController,
startController: StartController,
loginController: LoginController,
helpController: HelpController,
inspectorController: InspectorController,
playerController: PlayerController,
router: DesktopRouter,
startRouter: StartRouter,
loginRouter: LoginRouter,
helpRouter: HelpRouter,
inspectorRouter: InspectorRouter,
playerRouter: PlayerRouter
};
App.start(options);
});
So I am requiring all my routers and controllers but when I run that code in the debugger I have some items that are undefined:
options: Object
helpController: Object
helpRouter: Object
homeController: Object
go_home: function () {
__proto__: Object
inspectorController: undefined
inspectorRouter: undefined
loginController: Object
loginRouter: Object
playerController: undefined
playerRouter: Object
router: Object
Router: function (){ parent.apply(this, arguments); }
__proto__: Object
startController: Object
go_start: function (term) {
__proto__: Object
startRouter: undefined
__proto__: Object
HomeController: Object
StartController: Object
StartRouter: undefined
DesktopRouter: Object
InspectorController: undefined
Why are some undefined? The StartRouter and StartController have the go_start function. The HelpRouter/Controller doesn't and shouldn't have go_start but it is throwing an error
All suggestions welcome.
Andrew
Looks like your RequireJS imports are out of order. The HelpRouter variable maps to the "routers/StartRouter" module, and all subsequent modules are off-by-one.
The AMD import format can easily lead to this types of simple errors that can take ages to debug, because that's somehow the place you never think to look. That's why I prefer the simplified CommonJS wrapper syntax provided by RequireJS:
define(function(require) {
var HomeController = require('routers/HomeController'),
StartController = require('routers/StartController'),
//etc...
});
For those of you just tuning in here is the working solution as proposed by fencliff.
// Includes Desktop Specific JavaScript files here (or inside of your Desktop router)
define(function(require) {
var App = require("app/App"),
// Routers with its controller
DesktopRouter = require("routers/DesktopRouter"),
HomeController = require("routers/HomeController"),
StartRouter = require("routers/StartRouter"),
StartController = require("routers/StartController"),
LoginRouter = require("routers/LoginRouter"),
LoginController = require("routers/LoginController"),
InspectorRouter = require("routers/InspectorRouter"),
InspectorController = require("routers/InspectorController"),
PlayerRouter = require("routers/PlayerRouter"),
PlayerController = require("routers/PlayerController"),
HelpRouter = require("routers/HelpRouter"),
HelpController = require("routers/HelpController");
var options = {
homeController: HomeController,
router: DesktopRouter,
startController: StartController,
startRouter: StartRouter,
loginController: LoginController,
loginRouter: LoginRouter,
inspectorController: InspectorController,
inspectorRouter: InspectorRouter,
playerController: PlayerController,
playerRouter: PlayerRouter,
helpController: HelpController,
helpRouter: HelpRouter
}
App.start(options);
return function() {};
});
I was a bit uncertain about returning an empty function but that is the only example I saw and it works. :-D

Resources