MOBILE

jQuery 1.3 : Altering the journey: the event object

8/21/2012 4:14:54 PM
We have already seen one situation in which event bubbling can cause problems. To show a case in which .hover() does not help our cause, we'll alter the collapsing behavior we implemented earlier.

Suppose we wish to expand the clickable area that triggers the collapsing or expanding of the style switcher. One way to do this is to move the event handler from the label, <h3>, to its containing <div> element:

$(document).ready(function() {
$('#switcher').click(function() {
$('#switcher .button').toggleClass('hidden');
});
});

This alteration makes the entire area of the style switcher clickable to toggle its visibility. The downside is that clicking on a button also collapses the style switcher after the style on the content has been altered. This is due to event bubbling; the event is first handled by the buttons, then passed up to the DOM tree until it reaches the <div id="switcher">, where our new handler is activated and hides the buttons.

To solve this problem, we need access to the event object. This is a JavaScript construct that is passed to each element's event handler when it is invoked. It provides information about the event, such as where the mouse cursor was at the time of the event. It also provides some methods that can be used to affect the progress of the event through the DOM.

To use the event object in our handlers, we only need to add a parameter to the function:

$(document).ready(function() {
$('#switcher').click(function(event) {
$('#switcher .button').toggleClass('hidden');
});
});

Event targets

Now we have the event object available to us as the variable event within our handler. The property event.target can be helpful in controlling where an event takes effect. This property is a part of the DOM API, but is not implemented in all browsers; jQuery extends the event object as necessary to provide the property in every browser. With .target, we can determine which element in the DOM was the first to receive the event—that is, in the case of a click event, the actual item clicked on. Remembering that this gives us the DOM element handling the event, we can write the following code:

$(document).ready(function() {
$('#switcher').click(function(event) {
if (event.target == this) {
$('#switcher .button').toggleClass('hidden');
}
});
});

This code ensures that the item clicked on was <div id="switcher">, not one of its sub‑elements. Now clicking on buttons will not collapse the style switcher, and clicking on the switcher's background will. However, clicking on the label, <h3>, now does nothing, because it too is a sub‑element. Instead of placing this check here, we can modify the behavior of the buttons to achieve our goals.

Stopping event propagation

The event object provides the .stopPropagation() method, which can halt the bubbling process completely for the event. Like .target, this method is a plain JavaScript feature, but cannot be safely used across all browsers. As long as we register all of our event handlers using jQuery, though, we can use it with impunity.

We'll remove the event.target == this check we just added, and instead add some code in our buttons' click handlers:

$(document).ready(function() {
$('#switcher .button').click(function(event) {
$('body').removeClass();
if (this.id == 'switcher-narrow') {
$('body').addClass('narrow');
}
else if (this.id == 'switcher-large') {
$('body').addClass('large');
}
$('#switcher .button').removeClass('selected');
$(this).addClass('selected');
event.stopPropagation();
});
});

As before, we need to add a parameter to the function we're using as the click handler, so we have access to the event object. Then we simply call event.stopPropagation() to prevent any other DOM element from responding to the event. Now our click is handled by the buttons, and only the buttons; clicks anywhere else on the style switcher will collapse or expand it.

Default actions

Were our click event handler registered on a link element (<a>) rather than a generic <div>, we would face another problem. When a user clicks on a link, the browser loads a new page. This behavior is not an event handler in the same sense as the ones we have been discussing; instead, this is the default action for a click on a link element. Similarly, when the Enter key is pressed while the user is editing a form, the submit event is triggered on the form, but then the form submission actually occurs after this.

If these default actions are undesired, calling .stopPropagation() on the event will not help. These actions occur nowhere in the normal flow of event propagation. Instead, the .preventDefault() method will serve to stop the event in its tracks before the default action is triggered.

Calling .preventDefault() is often useful after we have done some tests on the environment of the event. For example, during a form submission we might wish to check that required fields are filled in, and prevent the default action only if they are not. 


Event propagation and default actions are independent mechanisms; either can be stopped while the other still occurs. If we wish to halt both, we can return false from our event handler, which is a shortcut for calling both .stopPropagation() and .preventDefault() on the event.

Event delegation

Event bubbling isn't always a hindrance; we can often use it to great benefit. One great technique that exploits bubbling is called event delegation. With it, we can use an event handler on a single element to do the work of many.

In jQuery 1.3, a new pair of methods, .live() and .die(), have been introduced. These methods perform the same tasks as .bind() and .unbind(), but behind the scenes they use event delegation to gain the benefits we’ll describe in this section. 


In our example, there are just three <div class="button"> elements that have attached click handlers. But what if there were many? This is more common than one might think. Consider, for example, a large table of information in which each row has an interactive item requiring a click handler. Implicit iteration makes assigning all of these click handlers easy, but performance can suffer because of the looping being done internally to jQuery, and because of the memory footprint of maintaining all the handlers.

In our example, there are just three <div class="button"> elements that have attached click handlers. But what if there were many? This is more common than one might think. Consider, for example, a large table of information in which each row has an interactive item requiring a click handler. Implicit iteration makes assigning all of these click handlers easy, but performance can suffer because of the looping being done internally to jQuery, and because of the memory footprint of maintaining all the handlers.

Instead, we can assign a single click handler to an ancestor element in the DOM. An uninterrupted click event will eventually reach the ancestor due to event bubbling, and we can do our work there.

As an example, let's apply this technique to our style switcher (even though the number of items does not demand the approach). As seen above, we can use the event.target property to check what element was under the mouse cursor when the click occurred.

$(document).ready(function() {
event objectevent delegation, example$('#switcher').click(function(event) {
if ($(event.target).is('.button')) {
$('body').removeClass();
if (event.target.id == 'switcher-narrow') {
$('body').addClass('narrow');
}
else if (event.target.id == 'switcher-large') {
$('body').addClass('large');
}
$('#switcher .button').removeClass('selected');
$(event.target).addClass('selected');
event.stopPropagation();
}
});
});

We've used a new method here, called .is(). This method accepts the selector expressions , and tests the current jQuery object against the selector. If at least one element in the set is matched by the selector, .is() returns true. In this case, $(event.target).is('.button') asks whether the element clicked has a class of button assigned to it. If so, we proceed with the code from before, with one significant alteration: the keyword this now refers to <div id="switcher">, so every time we are interested in the clicked button we must now refer to it with event.target.

We can also test for the presence of a class on an element with a shortcut method, .hasClass(). The .is() method is more flexible, however, and can test any selector expression.


We have an unintentional side-effect from this code, however. When a button is clicked now, the switcher collapses, as it did before we added the call to .stopPropagation(). The handler for the switcher visibility toggle is now bound to the same element as the handler for the buttons, so halting the event bubbling does not stop the toggle from being triggered. To sidestep this issue, we can remove the .stopPropagation() call and instead add another .is() test:

$(document).ready(function() {
$('#switcher').click(function(event) {
if (!$(event.target).is('.button')) {
$('#switcher .button').toggleClass('hidden');
}
});
});
$(document).ready(function() {
$('#switcher').click(function(event) {
if ($(event.target).is('.button')) {
$('body').removeClass();
if (event.target.id == 'switcher-narrow') {
$('body').addClass('narrow');
}
else if (event.target.id == 'switcher-large') {
$('body').addClass('large');
}
$('#switcher .button').removeClass('selected');
$(event.target).addClass('selected');
}
});
});


		  
This example is a bit overcomplicated for its size, but as the number of elements with event handlers increases, event delegation is the right technique to use.
Other  
 
Most View
The Review Of Three Seasonic Power Supply Suits (Part 2)
Sellerdeck Business 2013 – Great Ecommerce Software
Setting For Phones Using Windows Phone 8
Web Design: Where To Start (Part 1)
Windows Server 2008 and Windows Vista : GPMC Scripts - GPO Reporting (part 2)
Test Stereo Amplifiers - Driving Your Tunes Forward (Part 2) : Marantz PM6004, Onkyo A-9050
Windows Server 2008 R2 networking : Overview of Windows Server 2008 R2 Networking
ASRock Z77 Extreme3 LGA 1155 Mainboard - Simple, Reasonable And Extraordinary (Part 4)
Windows 8 : Managing Installed and Running Programs (part 2) - Managing the Command Path, Managing File Extensions and File Associations
How Secure Is Your Pin? (Part 1)
Top 10
Sharepoint 2013 : Farm Management - Disable a Timer Job,Start a Timer Job, Set the Schedule for a Timer Job
Sharepoint 2013 : Farm Management - Display Available Timer Jobs on the Farm, Get a Specific Timer Job, Enable a Timer Job
Sharepoint 2013 : Farm Management - Review Workflow Configuration Settings,Modify Workflow Configuration Settings
Sharepoint 2013 : Farm Management - Review SharePoint Designer Settings, Configure SharePoint Designer Settings
Sharepoint 2013 : Farm Management - Remove a Managed Path, Merge Log Files, End the Current Log File
SQL Server 2012 : Policy Based Management - Evaluating Policies
SQL Server 2012 : Defining Policies (part 3) - Creating Policies
SQL Server 2012 : Defining Policies (part 2) - Conditions
SQL Server 2012 : Defining Policies (part 1) - Management Facets
Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 4) - Preventing Internal Servers from Being Filtered