Attaching controllers

There are a number of ways to attach a controller to your AppRouter, depending on how you use it in your application. This chapter covers the different strategies and why you might want to use each one.

Simple objects

The easiest way to attach a controller is to simple attach an object to the controller key when extending AppRouter as such:

var Router = Marionette.AppRouter.extend({
  appRoutes: {
    'blog/': 'blogList',
    'blog/:entry': 'blogEntry',
    'blog/:entry/comments/:comment': 'blogComment'
  },

  controller: {
    blogList: function() {
      // ...
    },
    blogEntry: function(entry) {
      // ...
    },
    blogComment: function(entry, comment) {
      // ...
    }
  }
});

module.exports = Router;

This method works for simpler controllers that don't have much internal state. We just treat this like any other JavaScript object.

Marionette Object class

If we want a more complex controller, we can use Marionette.Object - a custom object that contains many of the event handling and initializer logic shared with other Marionette components:

var Controller = Marionette.Object.extend({
  blogList: function() {
    // ...
  },
  blogEntry: function(entry) {
    // ...
  },
  blogComment: function(entry, comment) {
    // ...
  }
});


var Router = Marionette.AppRouter.extend({
  appRoutes: {
    'blog/': 'blogList',
    'blog/:entry': 'blogEntry',
    'blog/:entry/comments/:comment': 'blogComment'
  },

  controller: new Controller()
});

module.exports = Router;

We can now have the Object listen to events that occur in the application - for example, we might handle major layout changes like route-changing logic in our controller by listening to events on views. This will reduce the amount of code needed to change route inside the application versus setting up the views on page load.

During initialization

We can also attach a controller during initialize to pass options through the router:

var Controller = Marionette.Object.extend({
  blogList: function() {
    // ...
  },
  blogEntry: function(entry) {
    // ...
  },
  blogComment: function(entry, comment) {
    // ...
  }
});


var Router = Marionette.AppRouter.extend({
  appRoutes: {
    'blog/': 'blogList',
    'blog/:entry': 'blogEntry',
    'blog/:entry/comments/:comment': 'blogComment'
  },

  initialize: function() {
    this.controller = new Controller(this.options);
  }
});

module.exports = Router;

This pattern lets us initialize a router inside our application and pass any options directly through to the controller without having to expose it to the rest of the application.

No Controller

If you're familiar with Backbone, you'll see that the AppRouter is very similar to Backbone's built-in Router class. As you can probably guess, the AppRouter is simply an extension of Backbone.Router so, intuitively, supports the standard Backbone Router behavior.

What this means for our simpler applications is that we can merge the router and controller into a single AppRouter class by setting URLs on the routes key instead of appRoutes. Any methods declared on routes must exist on our router, just as in standard Backbone:

var Router = Marionette.AppRouter.extend({
  routes: {
    'blog/': 'blogList',
    'blog/:entry': 'blogEntry',
    'blog/:entry/comments/:comment': 'blogComment'
  },

  blogList: function() {
    // ...
  },
  blogEntry: function(entry) {
    // ...
  },
  blogComment: function(entry, comment) {
    // ...
  }
});

module.exports = Router;

With the AppRouter, we can mix the two styles in a single routing class.