In batman.js, event handlers respond to user interactions like “click” and “submit”. You can use them to modify application state in response to those interactions.
Let’s look at:
- What event handlers are and where they’re defined
- How you can connect handlers to DOM events
- How you can pass arguments to event handlers
- What
@
refers to inside event handlers
What Are Event Handlers?
In short, an event handler can be any function inside the render context.
Usually, this means it’s a prototype function on a view:
class MyApp.ItemsIndexView extends Batman.View
myEventHandler: -> # handle some event
or, it’s a prototype function on a controller:
class MyApp.ItemsController extends MyApp.ApplicationController
myEventHandler: -> # handle some event
Since the main MyApp
is also inside the render context, you can also use class functions on the app as event handlers:
class window.MyApp extends Batman.App
@myEventHandler: -> # handle some event
All of those functions are fair game to be wired up as event handlers.
Hooking up Event Handlers
To connect a function to a DOM event, use the data-event
binding. You can bind to pretty much any event (I don’t know of one that you can’t bind to).
The binding takes the form:
"data-bind-#{eventName}='#{handlerName}'"
For example, to bind a click
event to myEventHandler
on this <button>
:
<button data-event-click='myEventHandler'>Click Me</button>
You can also bind to the submit
event of a <form>
:
<form data-event-submit='saveData'>
<input type='submit'>Save</input>
</form>
Arguments in Event Handlers
Event handlers have two sets of arguments:
- arguments that you pass in via
withArguments
filters - arguments that are automatically passed in by batman.js
Custom Arguments with “withArguments”
You can choose some values to pass in with a withArguments
filter in your binding.
Consider this event handler:
class MyApp.ItemsController extends MyApp.ApplicationContorller
alertItemName: (item) ->
itemName = item.get('name')
alert(itemName)
I could call this with an item
by using a withArguments
filter:
<h1 data-bind='item.name'></h1>
<button data-event-click='alertItemName | withArguments item'>Alert!</button>
You can pass multiple arguments with withArgument
by separating them with commas.
For example, if I want more flexible alerts, I could redefine the event handler to take two arguments:
class MyApp.ItemsController extends MyApp.ApplicationContorller
alertItemName: (item, punctuation) ->
itemName = item.get('name')
alert(itemName + punctuation)
Then, pass two arguments into it, separated with ,
:
<h1 data-bind='item.name'></h1>
<button data-event-click='alertItemName | withArguments item, "!" '>Alert!</button>
<button data-event-click='alertItemName | withArguments item, "?" '>Alert?</button>
<button data-event-click='alertItemName | withArguments item, "." '>Alert.</button>
Note that you must provide both arguments to the handler. If you don’t, batman.js’s automatic arguments will take the place of the missing argument!
Automatic Arguments
When batman.js invokes an event handler, it automatically passes in a few arguments. Here’s a handler that uses the automatic arguments:
class MyApp.ItemsController extends MyApp.ApplicationContorller
myEventHandler: (node, event, view) ->
It’s invoked with:
node
: the DOM node where the event was triggered. For example, a<button>
. If you use the same event handler on different nodes, this value will be different.event
: The event object for the event. If you’re usingbatman.jquery
, it’s the jQuery event object. It contains meta-information about the event.view
: The nearestBatman.View
instance tonode
.
Combining Custom and Automatic Arguments
You can combine custom and automatic arguments. Simply define a handler whose last three arguments are the batman.js automatic arguments:
class MyApp.ItemsController extends MyApp.ApplicationContorller
alertItemName: (item, punctuation, node, event, view) ->
itemName = item.get('name')
alert(itemName + punctuation)
And use withArguments
to pass arguments to the function. You must pass the same number of arguments. For example:
<h1 data-bind='item.name'></h1>
<button data-event-click='alertItemName | withArguments item, "!"'>Alert!</button>
<!-- note the empty string, "" -->
<button data-event-click='alertItemName | withArguments item, ""'>Alert</button>
When batman.js passes arguments to the function, it simply merges the withArguments
array with its automatic array. So, if your withArguments
array is too short, you won’t get the same results.
@
in Event Handlers
When batman.js dispatches an event handler, it looks up the base object where that handler is defined. Then, it uses that object as @
inside the handler.
For example, consider two event handlers. One is defined on a view:
class MyApp.ItemsIndexView extends Batman.View
eventHandlerOne: ->
console.log(@) # => will be the ItemsIndexView instance
The other is defined on a controller:
class MyApp.ItemsController extends App.ApplicationController
eventHandlerTwo: ->
console.log(@) # => will be the ItemsController instance
If you were to hook up those event handlers to buttons:
<button data-event-click='eventHandlerOne'></button>
<button data-event-click='eventHandlerTwo'></button>
then click the buttons, you would see the ItemsIndexView
object and the ItemsController
object in your console:
ItemsIndexView {bindings: Array[7], subviews: Set, _batman: _Batman, viewClass: function, source: "events/index"…}
ItemsController {redirect: function, handleError: function, errorHandler: function, _batman: _Batman, _actionFrames: Array[0]…}
Since batman.js looks up the base object, event handlers behave just like normal functions in the place you define them.