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 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:
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 params.id, (err, record) => @set 'product', record edit: (params) -> # mind the fat arrow MyApp.Product.find params.id, (err, record) => @set 'product', record.transaction() index: -> @set 'products', MyApp.Product.get('all')
These values will be accessible as
products in view bindings.
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
@renderin the controller action
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
- Appending the camelized action name
- Looking it up on
Batman.currentApp(the currently-running app)
If a view with the expected name isn't found, batman.js uses a plain
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.
@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
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
"main"is the default yield, but you can render actions into other yields:
edit: (params) -> MyApp.find params.id, (err, record) => @set 'product', record @render(into: 'sidebar')
- Delay the render by calling
@render(false), then calling
@renderwhen you want to render a view:
show: (params) -> MyApp.find params.id, (err, record) => @set 'product', record @render() @render(false) # prevents implicit render