This one took a little longer than the rest to put together, because I nearly broke my brain trying to figure out how routing worked. I found myriad code samples for setting up and using the router, but no one sample had everything I needed to put together a bare-bones app. Once i finally figured it out, the rest snapped together immediately. So without further ado – First, the Javascript file:
/* define the application */
var app = new Backbone.Marionette.Application();
/* add the main region to the application */
app.addRegions({
appRegion: '#AppBase'
});
/* define the module we will be using to create this app */
app.module('RouteTest',function(module, App, Backbone, Marionette, $, _){
"use strict";
/* the layout for the main view */
module.AppLayoutView = Marionette.LayoutView.extend({
tagName: 'div',
id: 'AppLayoutView',
template: '#template-AppLayoutView',
regions: {
'contentRegion' : '#ContentRegion'
},
ui: {
'navHome' : '#nav-home',
'navInfo' : '#nav-info'
},
events: {
'click #nav-home' : 'onNavHomeClicked',
'click #nav-info' : 'onNavInfoClicked'
},
/* when the view initializes, call initRouter to */
initialize: function() {
this.initRouter();
},
/* once the DOM is ready, start the Backbone history manager.
This will cause the application to synch up with the
current route of the browser, e.g. #home or #info.
This must be called onRender instead of on initialize
because it immediately tries to render the appropriate view
into the contentRegion. Also: If you don't start the backbone
history, the router won't work. */
onRender: function() {
if( ! Backbone.History.started) Backbone.history.start();
},
/* initialize the AppRouter, which synchs the application
to the browser navigation */
initRouter: function() {
// cache reference to 'this' in the module scope
var capturedThis = this;
// assign route handlers to specific routes.
// In this case, 'home' is triggered when the browser
// visits index.html#home. Likewise index.html#info.
// the empty set is for an address with no hash.
var appRouteHandler = {
'' : 'onHomeRoute',
'home' : 'onHomeRoute',
'info' : 'onInfoRoute'
}
// controller which contains the methods which
// are used as route handlers. These are referenced
// in the appRoutes object above.
var appRouterController = {
onHomeRoute: function() {
capturedThis.onHomeNavigated();
},
onInfoRoute: function() {
capturedThis.onInfoNavigated();
}
};
// define an AppRouter constructor
var router = Marionette.AppRouter.extend({});
// create a new instance of the AppRouter
// and assign the routes and controller
var appRouter = new router({
appRoutes: appRouteHandler,
controller: appRouterController
});
},
/* called when the router sees that we have met the criteria
to trigger the 'onHomeRoute' handler */
onHomeNavigated: function() {
// define and display an instance of the HomeLayoutView
var homeLayoutView = new module.HomeLayoutView();
this.contentRegion.show(homeLayoutView);
// update the navigation
this.$el.find('.navButton.active').removeClass('active');
this.ui.navHome.addClass('active');
},
/* called when the router sees that we have met the criteria
to trigger the 'onInfoRoute' handler */
onInfoNavigated: function() {
var infoLayoutView = new module.InfoLayoutView();
this.contentRegion.show(infoLayoutView);
this.$el.find('.navButton.active').removeClass('active');
this.ui.navInfo.addClass('active');
}
});
/* view definition for the 'Home' screen */
module.HomeLayoutView = Marionette.LayoutView.extend({
tagName: 'div',
id: 'HomeLayoutView',
className: 'contentLayout',
template: '#template-HomeLayoutView'
});
/* view definition for the 'Info' screen */
module.InfoLayoutView = Marionette.LayoutView.extend({
tagName: 'div',
id: 'InfoLayoutView',
className: 'contentLayout',
template: '#template-InfoLayoutView'
});
/* add initializer, which fires when the app starts */
module.addInitializer(function(){
var layout = new module.AppLayoutView();
/* show the layout in the region we created at the top of this file */
app.appRegion.show(layout);
});
});
/* when the DOM for this page is available, start the application */
$(document).ready(function() {
app.start();
});
And here is the HTML file, including the templates.
<!doctype html>
<html>
<head>
<title>Backbone/Marionette Routing Example Using AppRouter</title>
<style type="text/css">
body {
background: #ffffff;
}
#AppBase {
width: 600px;
margin: 10px auto;
padding: 0;
}
#AppLayoutView {
float: left;
width: 598px;
margin: 0;
padding: 0;
border: 1px solid #808080;
}
h1 {
margin: 0;
padding: 0;
float: left;
width: 100%;
height: 30px;
text-align: center;
font: 24px/30px courier;
}
#Navigation {
float: left;
width: 100%;
height: 30px;
background: #ededed;
text-align: center;
}
#Navigation a {
font: 16px/30px courier, monospace;
color: #000000;
text-decoration: none;
}
#Navigation .navButton.active {
color: #ff0000;
}
#ContentRegion {
float: left;
width: 100%;
}
.contentLayout {
float:left;
width: 100%;
margin: 0;
padding: 0;
}
#HomeLayoutView {
background: #edffed;
}
#InfoLayoutView {
background: #ededff;
}
.contentLayout h2 {
margin: 0;
padding: 0;
text-align: center;
border-bottom: 1px solid #808080;
background: #ffffff;
}
.contentLayout p {
padding: .5em 1em;
}
</style>
</head>
<body>
<!-- Base element for app -->
<div id="AppBase"></div>
<!-- main layout template -->
<script type="text/template" id="template-AppLayoutView">
<h1>Backbone/Marionette Routing Example</h1>
<div id="Navigation">
<a id="nav-home" class="navButton" href="#home">Home</a> : : :
<a id="nav-info" class="navButton" href="#info">Information</a>
</div>
<div id="ContentRegion">HELLO!</div>
</script>
<!-- home screen template -->
<script type="text/template" id="template-HomeLayoutView">
<h2>Home</h2>
<p>This is the home view</p>
</script>
<!-- info screen template -->
<script type="text/template" id="template-InfoLayoutView">
<h2>Information</h2>
<p>This is a page of information</p>
</script>
<!-- libraries -->
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/underscore.js"></script>
<script type="text/javascript" src="js/backbone.js"></script>
<script type="text/javascript" src="js/backbone.marionette.js"></script>
<!-- app code -->
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
By the way, the missing piece which ended up costing me the better part of a day was the Backbone.history.start() call in the onRender method in the main Layout view.