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.