class Event
Description
The namespace for Prototype's event system.
Events: a fine mess
Event management is one of the really sore spots of cross-browser scripting.
True, the prevalent issue is: everybody does it the W3C way, and MSIE
does it another way altogether. But there are quite a few subtler,
sneakier issues here and there waiting to bite your ankle — such as the
keypress/keydown issue with KHTML-based browsers (Konqueror and
Safari). Also, MSIE has a tendency to leak memory when it comes to
discarding event handlers.
Prototype to the rescue
Of course, Prototype smooths it over so well you'll forget these
troubles even exist. Enter the Event namespace. It is replete with
methods that help to normalize the information reported by events across
browsers.
Event also provides a standardized list of key codes you can use with
keyboard-related events.
The functions you're most likely to use a lot are Event.observe,
Event.element and Event.stop. If your web app uses custom events,
you'll also get a lot of mileage out of Event.fire.
Methods
Class methods
-
element #
Event.element(event) ⇒ Element
Event#element() ⇒ ElementReturns the DOM element on which the event occurred. This method is deprecated, use findElement instead.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
findElement #
Event.findElement(event, expression) ⇒ Element
Event#findElement(expression) ⇒ ElementReturns the first DOM element that matches a given CSS selector — starting with the element on which the event occurred, then moving up its ancestor chain.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
fire #
Event.fire(element, eventName[, memo[, bubble = true]]) ⇒ Event-
memo(?) – Metadata for the event. Will be accessible through the event'smemoproperty. -
bubble(Boolean) – Whether the event will bubble.
Fires a custom event of name
eventNamewithelementas its target.Custom events must include a colon (
:) in their names. -
-
isLeftClick #
Event.isLeftClick(event) ⇒ Boolean
Event#isLeftClick() ⇒ BooleanDetermines whether a button-related mouse event involved the left mouse button.
Keep in mind that the "left" mouse button is actually the "primary" mouse button. When a mouse is in left-handed mode, the browser will report clicks of the right button as "left-clicks."
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
isMiddleClick #
Event.isMiddleClick(event) ⇒ Boolean
Event#isMiddleClick() ⇒ BooleanDetermines whether a button-related mouse event involved the middle mouse button.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
isRightClick #
Event.isRightClick(event) ⇒ Boolean
Event#isRightClick() ⇒ BooleanDetermines whether a button-related mouse event involved the right mouse button.
Keep in mind that the "left" mouse button is actually the "secondary" mouse button. When a mouse is in left-handed mode, the browser will report clicks of the left button as "left-clicks."
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
observe #
Event.observe(element, eventName, handler) ⇒ Element-
element(Element|String) – The DOM element to observe, or its ID. -
eventName(String) – The name of the event, in all lower case, without the "on" prefix — e.g., "click" (not "onclick"). -
handler(Function) – The function to call when the event occurs.
Registers an event handler on a DOM element. Aliased as
Element.observe.Event.observesmooths out a variety of differences between browsers and provides some handy additional features as well. Key features in brief:- Several handlers can be registered for the same event on the same element.
- Prototype figures out whether to use
addEventListener(W3C standard) orattachEvent(MSIE); you don't have to worry about it. - The handler is passed an extended
Eventobject (even on MSIE). - The handler's context (
thisvalue) is set to the extended element being observed (even if the event actually occurred on a descendent element and bubbled up). - Prototype handles cleaning up the handler when leaving the page (important for MSIE memory leak prevention).
observemakes it possible to stop observing the event easily viaEvent.stopObserving.
Although you can use
Event.observedirectly and there are times when that's the most convenient or direct way, it's more common to use its aliasElement.observe. These two statements have the same effect:Event.observe('foo', 'click', myHandler); $('foo').observe('click', myHandler);The examples in this documentation use the
Element#observeform.The Handler
Signature:
function handler(event) { // `this` = the element being observed }So for example, this will turn the background of the element 'foo' blue when it's clicked:
$('foo').observe('click', function(event) { this.setStyle({backgroundColor: 'blue'}); });Note that we used
thisto refer to the element, and that we received theeventobject as a parameter (even on MSIE).It's All About Timing
One of the most common errors trying to observe events is trying to do it before the element exists in the DOM. Don't try to observe elements until after the dom:loaded event or
windowloadevent has been fired.Preventing the Default Event Action and Bubbling
If we want to stop the event (e.g., prevent its default action and stop it bubbling), we can do so with the extended event object's
Event.stopmethod:$('foo').observe('click', function(event) { event.stop(); });Finding the Element Where the Event Occurred
Since most events bubble from descendant elements up through the hierarchy until they're handled, we can observe an event on a container rather than individual elements within the container. This is sometimes called "event delegation." It's particularly handy for tables:
<table id='records'> <thead> <tr><th colspan='2'>No record clicked</th></tr> </thead> <tbody> <tr data-recnum='1'><td>1</td><td>First record</td></tr> <tr data-recnum='2'><td>2</td><td>Second record</td></tr> <tr data-recnum='3'><td>3</td><td>Third record</td></tr> </tbody> </table>Instead of observing each cell or row, we can simply observe the table:
$('records').observe('click', function(event) { var clickedRow; clickedRow = event.findElement('tr'); if (clickedRow) { this.down('th').update("You clicked record #" + clickedRow.readAttribute("data-recnum")); } });When any row in the table is clicked, we update the table's first header cell saying which record was clicked.
Event.findElementfinds the row that was clicked, andthisrefers to the table we were observing.Stopping Observing the Event
If we don't need to observe the event anymore, we can stop observing it with
Event.stopObserving(akaElement.stopObserving).Using an Instance Method as a Handler
If we want to use an instance method as a handler, we will probably want to use
Function#bindto set the handler's context; otherwise, the context will be lost andthiswon't mean what we expect it to mean within the handler function. E.g.:var MyClass = Class.create({ initialize: function(name, element) { this.name = name; element = $(element); if (element) { element.observe(this.handleClick.bind(this)); } }, handleClick: function(event) { alert("My name is " + this.name); }, });Without the
bind, whenhandleClickwas triggered by the event,thiswouldn't refer to the instance and so the alert wouldn't show the name. Because we usedbind, it works correctly. SeeFunction#bindfor details. There's alsoFunction#bindAsEventListener, which is handy for certain very specific situations. (Normally,bindis all you need.)Side Notes
Although Prototype smooths out most of the differences between browsers, the fundamental behavior of a browser implementation isn't changed. For example, the timing of the
changeorblurevents varies a bit from browser to browser.Changes in 1.6.x
Prior to Prototype 1.6,
observesupported a fourth argument (useCapture), a boolean that indicated whether to use the browser's capturing phase or its bubbling phase. Since MSIE does not support the capturing phase, we removed this argument from 1.6, lest it give users the false impression that they can use the capturing phase in all browsers.1.6 also introduced setting the
thiscontext to the element being observed, automatically extending theEventobject, and theEvent.findElementmethod. -
-
pointer #
Event.pointer(event) ⇒ Object
Event#pointer() ⇒ ObjectReturns the absolute position of the pointer for a mouse event.
Returns an object in the form
{ x: Number, y: Number}.Note that this position is absolute on the page, not on the viewport.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
pointerX #
Event.pointerX(event) ⇒ Number
Event#pointerX() ⇒ NumberReturns the absolute horizontal position of the pointer for a mouse event.
Note that this position is absolute on the page, not on the viewport.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
pointerY #
Event.pointerY(event) ⇒ Number
Event#pointerY() ⇒ NumberReturns the absolute vertical position of the pointer for a mouse event.
Note that this position is absolute on the page, not on the viewport.
This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
stop #
Event.stop(event) ⇒ undefined
Event#stop() ⇒ undefinedStops the event's propagation and prevents its eventual default action from being triggered.
Stopping an event also sets a
stoppedproperty on that event for future inspection.This method can be called either as an instance method or as a generic method. If calling as a generic, pass the instance in as the first argument.
-
stopObserving #
Event.stopObserving(element[, eventName[, handler]]) ⇒ Element-
element(Element|String) – The element to stop observing, or its ID. -
eventName(String) – (Optional) The name of the event to stop observing, in all lower case, without the "on" — e.g., "click" (not "onclick"). -
handler(Function) – (Optional) The handler to remove; must be the exact same reference that was passed toEvent.observe(see below.).
Unregisters one or more event handlers.
If
handleris omitted, unregisters all event handlers onelementfor thateventName. IfeventNameis also omitted, unregisters all event handlers onelement. (In each case, only affects handlers registered via Prototype.)Examples
Assuming:
$('foo').observe('click', myHandler);...we can stop observing using that handler like so:
$('foo').stopObserving('click', myHandler);If we want to remove all 'click' handlers from 'foo', we leave off the handler argument:
$('foo').stopObserving('click');If we want to remove all handlers for all events from 'foo' (perhaps we're about to remove it from the DOM), we simply omit both the handler and the event name:
$('foo').stopObserving();A Common Error
When using instance methods as observers, it's common to use
Function#bindon them, e.g.:$('foo').observe('click', this.handlerMethod.bind(this));If you do that, this will not work to unregister the handler:
$('foo').stopObserving('click', this.handlerMethod.bind(this)); // <== WRONGFunction#bindreturns a new function every time it's called, and so if you don't retain the reference you used when observing, you can't unhook that function specifically. (You can still unhook all handlers for an event, or all handlers on the element entirely.)To do this, you need to keep a reference to the bound function:
this.boundHandlerMethod = this.handlerMethod.bind(this); $('foo').observe('click', this.boundHandlerMethod);...and then to remove:
$('foo').stopObserving('click', this.boundHandlerMethod); // <== Right -