Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: Documented Event.observe and Event.stopObserving, including vaga…
…ries about change events across browsers. [#6 state:resolved]
- Loading branch information
Showing
1 changed file
with
184 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -389,8 +389,143 @@ | |
|
||
/** | ||
* 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]]. | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
tjcrowder
Author
Contributor
|
||
* | ||
* `Event.observe` smooths 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) or | ||
* `attachEvent` (MSIE); you don't have to worry about it. | ||
* * The handler is passed an _extended_ [[Event]] object (even on MSIE). | ||
* * The handler's context (`this` value) is set to the instance of the element being observed | ||
This comment has been minimized.
Sorry, something went wrong.
kangax
Collaborator
|
||
* (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). | ||
* * `observe` makes it possible to stop observing the event easily via [[Event.stopObserving]]. | ||
* | ||
* Although you can use `Event.observe` directly and there are times when that's the most | ||
* convenient or direct way, it's more common to use its alias [[Element#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#observe]] form. | ||
* | ||
* <h4>The Handler</h4> | ||
* | ||
* 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 `this` to refer to the element, and that we received the `event` object | ||
* as a parameter (even on MSIE). | ||
* | ||
* <h4>It's All About Timing</h4> | ||
* | ||
* 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 | ||
* [[document.observe dom:loaded]] event or `window` `load` event has been fired. | ||
* | ||
* <h4>Preventing the Default Event Action and Bubbling</h4> | ||
* | ||
* 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#stop]] method: | ||
* | ||
* $('foo').observe('click', function(event) { | ||
* event.stop(); | ||
* }); | ||
* | ||
* <h4>Finding the Element Where the Event Occurred</h4> | ||
* | ||
* 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.getAttribute("data-recnum")); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
* } | ||
* }); | ||
* | ||
* When any row in the table is clicked, we update the table's first header cell saying which | ||
* record was clicked. [[Event#findElement]] finds the row that was clicked, and `this` refers | ||
* to the table we were observing. | ||
* | ||
* <h4>Stopping Observing the Event</h4> | ||
* | ||
* If we don't need to observe the event anymore, we can stop observing it with | ||
* [[Event.stopObserving]] (aka [[Element#stopObserving]]). | ||
* | ||
* <h4>Using an Instance Method as a Handler</h4> | ||
* | ||
* If we want to use an instance method as a handler, we will probably want to use | ||
* [[Function#bind]] to set the handler's context; otherwise, the context will be lost and | ||
* `this` won'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`, when `handleClick` was triggered by the event, `this` wouldn't | ||
* refer to the instance and so the alert wouldn't show the name. Because we used `bind`, it | ||
* works correctly. See [[Function#bind]] for | ||
* details. There's also [[Function#bindAsEventListener]], which is handy for certain very | ||
* specific situations. (Normally, `bind` is all you need.) | ||
* | ||
* <h4>Side Notes</h4> | ||
* | ||
* 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 `change` | ||
* or `blur` events varies a bit from browser to browser. | ||
* | ||
* <h4>Changes in 1.6.x</h4> | ||
* | ||
* Prior to Prototype 1.6, `observe` supported 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 `this` context to the element being observed, automatically | ||
* extending the [[Event]] object, and the [[Event#findElement]] method. | ||
* | ||
* Registers an event handler on a DOM element. | ||
**/ | ||
function observe(element, eventName, handler) { | ||
element = $(element); | ||
|
@@ -424,12 +559,59 @@ | |
|
||
/** | ||
* 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 to [[Event.observe]] (see below.). | ||
* | ||
* Unregisters one or more event handlers. | ||
* | ||
* If `handler` is omitted, unregisters all event handlers on `element` | ||
* for that `eventName`. If `eventName` is also omitted, unregisters _all_ | ||
* event handlers on `element`. | ||
* event handlers on `element`. (In each case, only affects handlers registered via Prototype.) | ||
* | ||
* <h4>Examples</h4> | ||
* | ||
* 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(); | ||
* | ||
* <h4>A Common Error</h4> | ||
* | ||
* When using instance methods as observers, it's common to use [[Function#bind]] on 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)); // <== WRONG | ||
* | ||
* [[Function#bind]] returns 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 | ||
**/ | ||
function stopObserving(element, eventName, handler) { | ||
element = $(element); | ||
|
Shouldn't that be an "event listener"?