The Marionette AppRouter
extends the Backbone.Router
to make it easier to construct a large number of routes for your app. This is particularly useful if you want to build a large single-page app while keeping your router's core logic readable.
The Marionette AppRouter is typically used to set up your app when the user loads a specific endpoint directly. Typically, in a single-page app, users will expect to be able to easily navigate back to a section of the application by bookmarking a URL and loading it directly. Let's look at a concrete example:
var Mn = require('backbone.marionette');
var EmailController = {
showEmail: function(email) {
// Look up the email and display it in our main layout
}
};
var EmailRouter = Mn.AppRouter.extend({
controller: EmailController,
appRoutes: {
'emails/:email': 'showEmail'
}
});
Assuming our application is served from the root, whenever the user accesses http://ourapplication.com/#emails/email-subject-line-123
, the method showEmail
will be called with email-subject-line-123
as its argument. This will be covered in more detail below.
The AppRouter uses the appRoutes
option to define how we respond to routes being accessed. To define routes, set the route as your key and the method to call as a string referencing a method on your controller. For more information on route definitions, see the [Backbone documentation][#backbone-routes].
The major difference between appRoutes
and routes
is that we provide callbacks on a controller instead of directly on the router itself. This allows you to define a simpler router and keep your controller logic closer to the modules it interacts directly with:
var Mn = require('backbone.marionette');
var EmailController = require('./emails/controller/email');
var MyRouter = Mn.AppRouter.extend({
controller: EmailController,
// "someMethod" must exist at controller.someMethod
appRoutes: {
'email': 'listEmails',
'email/:email': 'showEmail'
}
});
As the AppRouter
extends Backbone.Router
, you can also define a routes
attribute whose callbacks must be present on the AppRouter
:
var Mn = require('backbone.marionette');
var MyRouter = Mn.AppRouter.extend({
routes: {
'email/:email': 'showEmail'
},
showEmail: function(email) {
// show the email
}
})
See the Backbone documentation for more information about defining routes
.
If you want more control when managing your routes, you can define your routes on router instantiation:
var Mn = require('backbone.marionette');
var EmailController = require('./emails/controllers/email');
var MyRouter = new Mn.AppRouter({
controller: EmailController,
appRoutes: {
'email/': 'listEmails',
'email/:email': 'showEmail'
}
});
In addition to setting the appRoutes
for an AppRouter, you can add app routes at runtime, to an instance of a router. This is done with the appRoute()
method call. It works the same as the built-in router.route()
call from Backbone's Router, but has all the same semantics and behavior of the appRoutes
configuration.
var Mn = require('backbone.marionette');
var MyRouter = Mn.AppRouter.extend({});
var router = new MyRouter();
router.appRoute("/foo", "fooThat");
Also you can specify a controller with the multiple routes at runtime with the processAppRoutes
method. This will preserve the existing controller as well:
var Mn = require('backbone.marionette');
var MyRouter = Mn.AppRouter.extend({});
var router = new MyRouter();
router.processAppRoutes(myController, {
"foo": "doFoo",
"bar/:id": "doBar"
});
App routers can only use one controller
object. You can either specify this directly in the router definition:
var Mn = require('backbone.marionette');
var someController = {
someMethod: function(){ /*...*/ }
};
Mn.AppRouter.extend({
controller: someController
});
The object that is used as the controller
has no requirements, other than it will contain the methods that you specified in the appRoutes
.
A controller can also be an instance of Marionette.Object
- this is useful for cases where you want to access the helper tools of the Object API and pass through information on instantiation.
Marionette allows you to run multiple AppRouters in a single application. It's recommended that you break your routing into multiple sections, each with its own router and/or controller setting up the views for their own components. This will make it much easier to find and manage your route-handling logic as your application grows in complexity.
The Backbone History API monitors the browser's location bar and triggers route changes on your app routers. It also provides a set of methods to change the contents of the location bar manually when you want to expose functionality to your user via a URL:
var Bb = require('backbone');
var Mn = require('backbone.marionette');
var EmailView = require('./email/views/email');
var EmailList = Mn.View.extend({
regions: {
layout: '.layout-hook'
},
showEmail: function(model) {
this.showChildView('layout', new EmailView({model: model}));
Bb.history.navigate('email/' + model.id);
}
});
As stated in the Backbone documentation, navigate
takes an options
argument that lets you trigger
on route change. We recommend against using this as it tends to cause side-effects like making it hard to ensure the route is only navigated to once, or unintentionally firing different route changes.
When the user navigates to a new route in your application that matches a route in your AppRouter
, the route
event will be fired. Listening to this will let you perform extra custom behavior:
var Mn = require('backbone.marionette');
var Controller = require('./email/controller');
var MyRouter = Mn.AppRouter.extend({
controller: Controller,
appRoutes: {
'emails/:email': 'showEmail'
},
onRoute: function(name, path, args) {
console.log('User navigated to ' + path);
}
});
This event handler takes three arguments:
name
- Name of the routepath
- Path that triggered this eventargs
- Arguments passed into the route
© 2017 Muted Solutions, LLC
Licensed under the MIT License.
https://marionettejs.com/docs/v3.2.0/marionette.approuter.html