Skip to content

Commit 1ced696

Browse files
committed
Merge pull request jquery#102 from stevenhauser/master
Added "Introduction to Events" chapter
2 parents f4d1b5b + 0f8234d commit 1ced696

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
title: Introducing Events
3+
attribution: $jQuery Fundamentals
4+
---
5+
6+
## Introduction
7+
8+
Web pages are all about interaction. Users perform a countless number of actions such as moving their mice over the page, clicking on elements, and typing in textboxes—all of these are examples of events. In addition to these user events, there are a slew of others that occur, like when the page is loaded, when video begins playing or is paused, etc. Whenever something interesting occurs on the page, an event is fired, meaning that the browser basically announces that something has happened. It's this announcement that allows developers to "listen" for events and react to them appropriately.
9+
10+
11+
## What's a DOM event?
12+
13+
As mentioned, there are a myriad of event types, but perhaps the ones that are easiest to understand are user events, like when someone clicks on an element or types into a form. These types of events occur on an element, meaning that when a user clicks on a button for example, the button has had an event occur on it. While user interactions aren't the only types of DOM events, they're certainly the easiest to understand when starting out. MDN has a good reference of [available DOM events](https://developer.mozilla.org/en/DOM/DOM_event_reference).
14+
15+
16+
## Ways to listen for events
17+
18+
There are many ways to listen for events. Actions are constantly occurring on a webpage, but the developer is only notified about them if they're *listening* for them. Listening for an event basically means you're waiting for the browser to tell you that a specific event has occurred and then you'll specify how the page should react.
19+
20+
To specify to the browser what to do when an event occurs, you provide a function, also known as an *event handler*. This function is executed whenever the event occurs (or until the event is unbound).
21+
22+
For instance, to alert a message whenever a user clicks on a button, you might write something like this:
23+
24+
<markup>
25+
<div class="example" markdown="1">
26+
<button onclick="alert('Hello')">Say hello</button>
27+
</div>
28+
</markup>
29+
30+
The event we want to listen to is specified by the button's `onclick` attribute, and the event handler is the `alert` function which alerts "Hello" to the user. While this works, it's an abysmal way to achieve this functionality for a couple of reasons:
31+
32+
1. First, we're coupling our view code (HTML) with our interaction code (JS). That means that whenever we need to update functionality, we'd have to edit our HTML which is just a bad practice and a maintenance nightmare.
33+
2. Second, it's not scalable. If you had to attach this functionality onto numerous buttons, you'd not only bloat the page with a bunch of repetitious code, but you would again destroy maintainability.
34+
35+
Utilizing inline event handlers like this can be considered *obtrusive JavaScript,* but its opposite, *unobtrustive JavaScript* is a much more common way of discussing the topic. The notion of *unobtrusive JavaScript* is that your HTML and JS are kept separate and are therefore more maintainable. Separation of concerns is important because it keeps like pieces of code together (ie HTML, JS, CSS) and unlike pieces of code apart, facilitating changes, enhancements, etc. Furthermore, unobtrustive JavaScript stresses the importance of adding the least amount of cruft to a page as possible. If a user's browser doesn't support JavaScript, then it shouldn't be intertwined into the markup of the page. Also, to prevent naming collisions, JS code should utilize a single namespace for different pieces of functionality or libraries. jQuery is a good example of this, in that the `jQuery` object/constructor (and also the `$` alias to `jQuery`) only utilizes a single global variable, and all of jQuery's functionality is packaged into that one object.
36+
37+
To accomplish the desired task unobtrusively, let's change our HTML a little bit by removing the `onclick` attribute and replacing it with an `id`, which we'll utilize to "hook onto" the button from within a script file.
38+
39+
<markup>
40+
<div class="example" markdown="1">
41+
<button id="helloBtn">Say hello</button>
42+
</div>
43+
</markup>
44+
45+
If we wanted to be informed when a user clicks on that button unobtrusively, we might do something like the following in a separate script file:
46+
47+
<javascript markdown="1" caption="Event binding using addEventListener">
48+
var helloBtn = document.getElementById('helloBtn');
49+
helloBtn.addEventListener('click', function(event) {
50+
alert('Hello.');
51+
}, false);
52+
</javascript>
53+
54+
Here we're saving a reference to the button element by calling `getElementById` and assigning its return value to a variable. We then call `addEventListener` and provide an event handler function that will be called whenever that event occurs. While there's nothing wrong with this code as it will work fine in modern browsers, it won't fare well in versions of IE prior to IE9. This is because Microsoft chose to implement a different method, `attachEvent`, as opposed to the W3C standard `addEventListener`, and didn't get around to changing it until IE9 was released. For this reason, it's beneficial to utilize jQuery because it abstracts away browser inconsistencies, allowing developers to use a single API for these types of tasks, as seen below.
55+
56+
<javascript markdown="1" caption="Event binding using a convenience method">
57+
$('#helloBtn').click(function(event) {
58+
alert('Hello.');
59+
});
60+
</javascript>
61+
62+
The `$('#helloBtn')` code selects the button element using the `$` (aka `jQuery`) function and returns a jQuery object. The jQuery object has a bunch of methods (functions) available to it, one of them named `click`, which resides in the jQuery object's prototype. We call the `click` method on the jQuery object and pass along an anonymous function event handler that's going to be executed when a user clicks the button, alerting "Hello." to the user.
63+
64+
There are a number of ways that events can be listened for using jQuery:
65+
66+
<javascript markdown="1" caption="The many ways to bind events with jQuery">
67+
// Attach an event handler directly to the button using jQuery's
68+
// shorthand `click` method.
69+
$('#helloBtn').click(function(event) {
70+
alert('Hello.');
71+
});
72+
73+
// Attach an event handler directly the to button using jQuery's
74+
// `bind` method, passing it an event string of `click`
75+
$('#helloBtn').bind('click', function(event) {
76+
alert('Hello.');
77+
});
78+
79+
// As of jQuery 1.7, attach an event handler directly to the button
80+
// using jQuery's `on` method.
81+
$('#helloBtn').on('click', function(event) {
82+
alert('Hello.');
83+
});
84+
85+
// As of jQuery 1.7, attach an event handler to the `body` element that
86+
// is listening for clicks, and will respond whenever *any* button is
87+
// clicked on the page.
88+
$('body').on({
89+
click: function(event) {
90+
alert('Hello.');
91+
}, 'button');
92+
93+
// An alternative to the previous example, using slightly different syntax.
94+
$('body').on('click', 'button', function(event) {
95+
alert('Hello.');
96+
});
97+
</javascript>
98+
99+
As of jQuery 1.7, all events are bound via the `on` method, whether you call it directly or whether you use an alias/shortcut method such as `bind` or `click`, which are mapped to the `on` method internally. With this in mind, it's beneficial to use the `on` method because the others are all just syntactic sugar, and utilizing the `on` method is going to result in faster and more consistent code.
100+
101+
Let's look at the `on` examples from above and discuss their differences. In the first example, a string of `click` is passed as the first argument to the `on` method, and an anonymous function is passed as the second. This looks a lot like the `bind` method before it. Here, we're attaching an event handler directly to `#helloBtn`. If there were any other buttons on the page, they wouldn't alert "Hello" when clicked because the event is only attached to `#helloBtn`.
102+
103+
In the second `on` example, we're passing an object (denoted by the curly braces `{}`), which has a property of `click` whose value is an anonymous function. The second argument to the `on` method is a jQuery selector string of `button`. While examples 1–3 are functionally equivalent, example 4 is different in that the `body` element is listening for click events that occur on *any* button element, not just `#helloBtn`. The final example above is exactly the same as the one preceding it, but instead of passing an object, we pass an event string, a selector string, and the callback. Both of these are examples of event delegation, a process by which an element higher in the DOM tree listens for events occuring on its children.
104+
105+
Event delegation works because of the notion of *event bubbling*. For most events, whenever something occurs on a page (like an element is clicked), the event travels from the element it occurred on, up to its parent, then up to the parent's parent, and so on, until it reaches the root element, aka the `window`. So in our table example, whenever a `td` is clicked, its parent `tr` would also be notified of the click, the parent `table` would be notified, the `body` would be notified, and ultimately the `window` would be notified as well. While event bubbling and delegation work well, the delegating element (in our example, the `table`) should always be as close to the delegatees as possible so the event doesn't have to travel way up the DOM tree before its handler function is called.
106+
107+
The two main pros of event delegation over binding directly to an element (or set of elements) are performance and the aforementioned event bubbling. Imagine having a large table of 1000 cells and binding to an event for each cell. That's 1000 separate event handlers that the browser has to attach, even if they're all mapped to the same function. Instead of binding to each individual cell though, we could instead use delegation to listen for events that occur on the parent table and react accordingly. One event would be bound instead of 1000, resulting in way better performance and memory management.
108+
109+
The event bubbling that occurs affords us the ability to add cells via AJAX for example, without having to bind events directly to those cells since the parent table is listening for clicks and is therefore notified of clicks on its children. If we weren't using delegation, we'd have to constantly bind events for every cell that's added which is not only a performance issue, but could also become a maintenance nightmare.
110+
111+
112+
## The event object
113+
114+
In all of the previous examples, we've been using anonymous functions and specifying an `event` argument within that function. Let's change it up a little bit.
115+
116+
<javascript markdown="1" caption="Binding a named function">
117+
function sayHello(event) {
118+
alert('Hello.');
119+
}
120+
121+
$('#helloBtn').on('click', sayHello);
122+
</javascript>
123+
124+
In this slightly different example, we're defining a function called `sayHello` and then passing that function into the `on` method instead of an anonymous function. So many online examples show anonymous functions used as event handlers, but it's important to realize that you can also pass defined functions as event handlers as well. This is important if different elements or different events should perform the same functionality. This helps to keep your code DRY.
125+
126+
But what about that `event` argument in the `sayHello` function—what is it and why does it matter? In all DOM event callbacks, jQuery passes an *event object* argument which contains information about the event, such as precisely when and where it occurred, what type of event it was, which element the event occured on, and a plethora of other information. Of course you don't have to call it `event`; you could call it `e` or whatever you want to, but `event` is a pretty common convention.
127+
128+
If the element has default functionality for a specific event (like a link opens a new page, a button in a form submits the form, etc), that default functionality can be cancelled. This is often useful for AJAX requests. When a user clicks on a button to submit a form via AJAX, we'd want to cancel the button/form's default action (to submit it to the form's `action` attribute), and we would instead do an AJAX request to accomplish the same task for a more seamless experience. To do this, we would utilize the event object and call its `preventDefault` method. We can also prevent the event from bubbling up the DOM tree using `stopPropagation` so that parent elements aren't notified of its occurrence (in the case that event delegation is being used).
129+
130+
<javascript markdown="1" caption="Preventing a default action from occurring and stopping the event bubbling">
131+
$('form').on('submit', function(event) {
132+
event.preventDefault(); // Prevent the form's default submission.
133+
event.stopPropagation(); // Prevent event from bubbling up DOM tree, prohibiting delegation
134+
// Make an AJAX request to submit the form data
135+
});
136+
</javascript>
137+
138+
When utilizing both `preventDefault` and `stopPropagation` simultaneously, you can instead `return false` to achieve both in a more concise manner, but it's advisable to only `return false` when both are actually necessary and not just for the sake of terseness. A final note on `stopPropagation` is that when using it in delegated events, the soonest that event bubbling can be stopped is when the event reaches the element that is delegating it.
139+
140+
It's also important to note that the event object contains a property called `originalEvent`, which is the event object that the browser itself created. jQuery wraps this native event object with some useful methods and properties, but in some instances, you'll need to access the original event via `event.originalEvent` for instance. This is especially useful for touch events on mobile devices and tablets.
141+
142+
Finally, to inspect the event itself and see all of the data it contains, you should log the event in the browser's console using `console.log`. This will allow you to see all of an event's properties (including the `originalEvent`) which can be really helpful for debugging.
143+
144+
<javascript markdown="1" caption="Logging an event's information">
145+
$('form').on('submit', function(event) {
146+
event.preventDefault(); // Prevent the form's default submission.
147+
console.log(event); // Log the event object for inspectin'
148+
// Make an AJAX request to submit the form data
149+
});
150+
</javascript>

0 commit comments

Comments
 (0)