Batman.js is no longer in production at Shopify and is not actively maintained.

This website is left for reference (and for old times' sake).


Batman.Controller is the C in MVC. Controllers have actions which are are dispatched by the router.

Controllers are instantiated once (internally, by batman.js) and all controller actions are invoked on the same contoller instance while the app is running.

Controller Actions

Controller actions are functions that:

  • prepare data to display by interacting with the app's models.
  • render views, either implicitly or explicitly.

(Controller actions may also redirect.)

Controller actions may be bound by name to URLs. The controller action name is determined by:

  • Downcasing the first letter of the class name
  • Removing "Controller" from the class name
  • Appending "#"
  • Appending the name of the action (ie, the function name).

For example, this controller action:

class MyApp.ProductReviewsController extends Batman.Controller
  index: -> # ...

would have this name for routing:


Preparing Data

Controllers prepare data for views by interacting with models and setting them on themselves. Here are some common actions for preparing data:

class MyApp.ProductsController extends MyApp.ApplicationController
  routingKey: 'products'
  new: ->
    @set 'product', new MyApp.Product

  show: (params) ->
    # mind the fat arrow
    MyApp.Product.find, (err, record) =>
      @set 'product', record

  edit: (params) ->
    # mind the fat arrow
    MyApp.Product.find, (err, record) =>
      @set 'product', record.transaction()

  index: ->
    @set 'products', MyApp.Product.get('all')

These values will be accessible as product or products in view bindings.

Rendering Views

Controller actions can render views in two ways:

  • implicitly, by allowing batman.js to infer the view and render it after the action body is executed
  • explicitly, by calling @render in the controller action

Implicit Rendering

If you don't call @render in your controller action, batman.js will render a view for you. It will look up a view class by:

  • Camelizing the controller's routingKey
  • Appending the camelized action name
  • Appending View
  • Looking it up on Batman.currentApp (the currently-running app)

For example,


would render


If a view with the expected name isn't found, batman.js uses a plain Batman.View instead.

In fact, this lookup is built into @render, so if you call @render without passing a view option, batman.js will look up a class this way.

Explicit Rendering

Calling @render in a controller action gives you more control over how the view is rendered. If you don't provide a view options, batman.js will look up a default view as described in "Implicit Rendering".

By explicitly rendering, you can:

  • Render a non-default view by passing a view option to @render:
      new: ->
        @set 'product', new MyApp.Product
        # use the edit view for new products, too:
        @render(view: MyApp.ProductsEditView)
  • Render into other yields by passing an into option to @render. "main" is the default yield, but you can render actions into other yields:
      edit: (params) ->
        MyApp.find, (err, record) =>
          @set 'product', record
        @render(into: 'sidebar')
  • Delay the render by calling @render(false), then calling @render when you want to render a view:
      show: (params) ->
        MyApp.find, (err, record) =>
          @set 'product', record
        @render(false) # prevents implicit render

Help us improve our documentation!

Contributions to this page are welcome on Github. If you find a problem but you cannot fix it, please open an issue.

Discussion regarding batman.js documentation is also welcome on our mailing list.