I'm building an app with Backbone, Marionette and RequireJS and I'd like to run by some more experienced people if the Application startup could be refined/improved in any way.
Folder structure:
index.html
js/
collections/
libs/
backbone.js
marionette.js
require.js
...
models/
views/
app.js
init.js
router.js
Currently the app's bootstrapping is as follows.
index.html defines the requireJS entry-point as:
<script data-main="js/init" src="js/libs/require.js"></script>
init.js does the RequireJS configuration and:
require(['app'], function(App){
App.start();
});
The App module in app.js:
App = new Backbone.Marionette.Application();
App.addInitializer(function (options) {
// initialize the Router; will only setup the routes and corresponding callbacks; not history.start()
App.router = new Router();
// initialize Marionette regions
App.addRegions({
'header': '#header',
'main': '#main',
'footer': '#footer'
});
});
App.on('start', function(options) {
Backbone.history && Backbone.history.start() || console.error('No "Backbone.history" to .start()');
});
return App;
The Router module in router.js:
return Backbone.Router.extend({
routes: {
'panel/:handle': 'showPanel',
},
showPanel: function (handle) {
require(['app'], function (App) {
App.main.show(new Panel_v({userHandle: handle}));
});
}
});
Is there a way to make the Router module less convoluted? I worked out this way to solve the cyclic dependency problem formed by App->Router->App.
Any other suggestions?
I've come to this solution lately, joining up App and Router in the main.js file:
App.js
define(['marionette'], function(Marionette) {
var App;
App = new Backbone.Marionette.Application();
App.vars = {};
App.addRegions({
headerRegion: "#header-region",
mainRegion: "#main-region",
footerRegion: "#footer-region",
dialogsRegion: "#dialogs"
});
App.vent.on("routing:started", function() {
Backbone.history.start();
});
return App;
});
Router.js
define(['marionette', 'app'], function(Marionette, App) {
var appRouter, routerController;
routerController = {
showViaggi: function() {
return require(['modules/viaggi/viaggi'], function(Viaggi) {
App.Modules.viaggi = new Viaggi();
return App.Modules.viaggi.start();
});
}
};
return appRouter = Backbone.Marionette.AppRouter.extend({
appRoutes: {
'viaggi': 'showViaggi'
},
controller: routerController
});
});
And the Main.js, my initial script loaded with Require.js
define(['app', 'routers/appRouter'], function(App,appRouter) {
App.addInitializer(function() {
App.Router = new appRouter;
return App.vent.trigger("routing:started");
});
return App.start();
});
Related
I have a Marionette project and I try to make it work with Browserify.
My app.js:
var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;
Marionette = require('backbone.marionette');
var Controller = require("./controller");
var Router = require("./routes");
var App = new Marionette.Application();
...
App.addRegions({
header: "#header_region",
side_menu: "#side_menu_region",
main: "#main_region",
footer: "#footer_region"
});
...
var controller = new Controller({});
App.addInitializer(function(options){
...
var router = new Router({
controller : controller
});
});
App.on("start", function(){
Backbone.history.start();
});
App.start({});
module.exports = App;
My controller.js:
var headerView = require('./header/view');
var sideMenuView = require('./side_menu/view');
module.exports = function() {
var Controller = Marionette.Controller.extend({
showHome: function(){
var header_view = new headerView();
App.header.show(header_view);
var side_menu_view = new sideMenuView();
App.side_menu.show(side_menu_view);
}
});
return Controller;
}
My routes.js:
module.exports = function() {
var Route = Marionette.AppRouter.extend({
appRoutes: {
'': 'showHome'
}
});
return Route;
}
My browserify command:
browserify app.js -o bundle.js
For some reason, I can't get into my showHome function inside the controller.
So when I go to my site, I get an empty page without any errors in the console.
Does anybody know what am I missing?
Thanks, Alex
I have my application set up in the following way. It does not allow me to trigger any "java-script routes"- after loading the page-- after I navigate to this page with a sub-domain extension to the url I enter.
//Create App
App = new Backbone.Marionette.Application();
//APP Regions
App.addRegions({
displayRegion: "#displayRegion"
});
//Routing controller
someController = {
usersarea: function () {
App.displayRegion.show(userList_ITEM);
alert('Users');
},
login: function () {
App.displayRegion.show(login_view);
alert('Login View');
}
};
//Router
MyRouter = new Marionette.AppRouter({
controller: someController,
appRoutes: {
"users": "usersarea",
"login": "login",
}
});//MyRouter
// Application Views
userList_ITEM_proto = Backbone.Marionette.ItemView.extend({
template: "#userList_ITEM"
});
login_view_proto = Backbone.Marionette.ItemView.extend({
template: "#login_view"
});
//Before STARTS
App.on('initialize:before', function () {
if (!Backbone.History.started) Backbone.history.start();
alert('It works');
login_view = new login_view_proto;
userList_ITEM = new userList_ITEM_proto;
});
//After START
App.on('initialize:after', function (options) {
console.log('Initialization Finished');
});
//At Start
App.on('start', function (options) {
alert('It works');
});
App.start();
You're trying to use view instances in someController before you've instantiated them.
http://jsfiddle.net/ddL4n/28/
You have a number of dependency issues in this script and should consider using Marionette's modules or Require.js to manage them.
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;
};
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.
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})
});