diff --git a/page/events.md b/page/events.md index 665f501c..1fffebe9 100644 --- a/page/events.md +++ b/page/events.md @@ -7,10 +7,10 @@ customFields: value: "tasks" --- jQuery provides simple methods for attaching event handlers to selections. -When an event occurs, the provided function is executed. Inside the function, +When an event occurs, the provided function is executed. Inside the function, `this` refers to the element that was clicked. -For details on jQuery events, visit the +For details on jQuery events, visit the [Events documentation on api.jquery.com](http://api.jquery.com/category/events/). The event handling function can receive an event object. This object can be diff --git a/page/events/event-basics.md b/page/events/event-basics.md index 685d390c..a9485f8d 100644 --- a/page/events/event-basics.md +++ b/page/events/event-basics.md @@ -9,62 +9,62 @@ level: beginner ### Setting Up Event Responses on DOM Elements -jQuery makes it straightforward to set up event-driven responses on page elements. -These events are often triggered by the end user's interaction with the page, -such as when text is entered into a form element or the mouse pointer is moved. -In some cases, such as the page load and unload events, the browser itself will +jQuery makes it straightforward to set up event-driven responses on page elements. +These events are often triggered by the end user's interaction with the page, +such as when text is entered into a form element or the mouse pointer is moved. +In some cases, such as the page load and unload events, the browser itself will trigger the event. -jQuery offers convenience methods for most native browser events. These methods — -including `$.fn.click`, `$.fn.focus`, `$.fn.blur`, `$.fn.change`, etc. — are shorthand -for jQuery's `$.fn.on` method. The on method is useful for binding the same handler +jQuery offers convenience methods for most native browser events. These methods — +including `$.fn.click`, `$.fn.focus`, `$.fn.blur`, `$.fn.change`, etc. — are shorthand +for jQuery's `$.fn.on` method. The `on` method is useful for binding the same handler function to multiple events, when you want to provide data to the event hander, when you are working with custom events, or when you want to pass an object of multiple events and handlers. ``` // Event setup using a convenience method -$('p').click(function() { - console.log('You clicked a paragraph!'); +$( "p" ).click(function() { + console.log( "You clicked a paragraph!" ); }); ``` ``` // Equivalent event setup using the `$.fn.on` method -$('p').on('click', function() { - console.log('click'); +$( "p" ).on( "click", function() { + console.log( "click" ); }); ``` ### Extending Events to New Page Elements -It is important to note that `$.fn.on` can only create event listeners -on elements that exist *at the time you set up the listeners*. Similar elements created -after the event listeners are established will not automatically pick up event behaviors -you've set up previously. For example: - -``` -$(document).ready(function(){ - // Sets up click behavior on all button elements with the alert class - // that exist in the DOM when the instruction was executed - $('button.alert').on('click', function(){ - console.log('A button with the alert class was clicked!'); - }); - // Now create a new button element with the alert class. This button - // was created after the click listeners were applied above, so it - // will not have the same click behavior as its peers - $('button').addClass('alert').appendTo(document.body); +It is important to note that `$.fn.on` can only create event listeners +on elements that exist *at the time you set up the listeners*. Similar elements created +after the event listeners are established will not automatically pick up event behaviors +you've set up previously. For example: + +``` +$( document ).ready(function(){ + // Sets up click behavior on all button elements with the alert class + // that exist in the DOM when the instruction was executed + $( "button.alert" ).on( "click", function() { + console.log( "A button with the alert class was clicked!" ); + }); + // Now create a new button element with the alert class. This button + // was created after the click listeners were applied above, so it + // will not have the same click behavior as its peers + $( "button" ).addClass( "alert" ).appendTo( document.body ); }); ``` -Consult the article on event delegation to see how to use `$.fn.on` so that +Consult the article on event delegation to see how to use `$.fn.on` so that event behaviors will be extended to new elements without having to rebind them. ### Inside the Event Handler Function Every event handling function receives an event object, which contains many -properties and methods. The event object is most commonly used to prevent the -default action of the event via the preventDefault method. However, the event +properties and methods. The event object is most commonly used to prevent the +default action of the event via the `.preventDefault()` method. However, the event object contains a number of other useful properties and methods, including: #### pageX, pageY @@ -86,12 +86,12 @@ Any data that was passed in when the event was bound. For example: ``` // Event setup using the `$.fn.on` method with data -$('input').on( - 'change', - {foo : 'bar'}, // associate data with event binding - function(eventObject) { - console.log('An input value has changed! ', eventObject.data.foo); - } +$( "input" ).on( + "change", + { foo: "bar" }, // associate data with event binding + function( eventObject ) { + console.log("An input value has changed! ", eventObject.data.foo); + } ); ``` @@ -116,52 +116,52 @@ Prevent the default action of the event (e.g. following a link). Stop the event from bubbling up to other elements. In addition to the event object, the event handling function also has access to -the DOM element that the handler was bound to via the keyword `this`. To turn +the DOM element that the handler was bound to via the keyword `this`. To turn the DOM element into a jQuery object that we can use jQuery methods on, we -simply do `$(this)`, often following this idiom: +simply do `$( this )`, often following this idiom: ``` -var $this = $(this); +var $this = $( this ); ``` A fuller example would be: ``` // Preventing a link from being followed -$('a').click(function(eventObject) { - var $this = $(this); - if ($this.attr('href').match(/evil/)) { - eventObject.preventDefault(); - $this.addClass('evil'); - } +$( "a" ).click(function( eventObject ) { + var $this = $( this ); + if ( $this.attr( "href" ).match( /evil/ ) ) { + eventObject.preventDefault(); + $this.addClass( "evil" ); + } }); ``` ### Setting Up Multiple Event Responses -Quite often elements in your application will be bound to multiple events. If -multiple events are to share the same handling function, you can provide the event types +Quite often elements in your application will be bound to multiple events. If +multiple events are to share the same handling function, you can provide the event types as a space-separated list to `$.fn.on`: ``` // Multiple events, same handler -$('input').on( - 'click change', // bind listeners for multiple events - function() { - console.log('An input was clicked or changed!') - } +$( "input" ).on( + "click change", // bind listeners for multiple events + function() { + console.log( "An input was clicked or changed!" ) + } ); ``` -When each event has its own handler, you can pass an object into `$.fn.on` with one or -more key/value pairs, with the key being the event name and the value being the function +When each event has its own handler, you can pass an object into `$.fn.on` with one or +more key/value pairs, with the key being the event name and the value being the function to handle the event. ``` // Binding multiple events with different handlers -$('p').on({ - 'click': function() { console.log('clicked!'); }, - 'mouseover': function() { console.log('hovered!'); } +$( "p" ).on({ + "click": function() { console.log( "clicked!" ); }, + "mouseover": function() { console.log( "hovered!" ); } }); ``` @@ -173,65 +173,65 @@ that you didn't or couldn't know about. ``` // Namespacing events -$('p').on('click.myNamespace', function() { /* ... */ }); -$('p').off('click.myNamespace'); -$('p').off('.myNamespace'); // unbind all events in the namespace +$( "p" ).on( "click.myNamespace", function() { /* ... */ } ); +$( "p" ).off( "click.myNamespace" ); +$( "p" ).off( ".myNamespace" ); // unbind all events in the namespace ``` ### Tearing Down Event Listeners To remove an event listener, you use the `$.fn.off` method and pass in -the event type to off. If you attached a named function to the event, then +the event type to off. If you attached a named function to the event, then you can isolate the event tear down to just that named function by passing it as the second argument. ``` // Tearing down all click handlers on a selection -$('p').off('click'); +$( "p" ).off( "click" ); ``` ``` // Tearing down a particular click handler, using a reference to the function -var foo = function() { console.log('foo'); }; -var bar = function() { console.log('bar'); }; +var foo = function() { console.log( "foo" ); }; +var bar = function() { console.log( "bar" ); }; -$('p').on('click', foo).on('click', bar); -$('p').off('click', bar); // foo is still bound to the click event +$( "p" ).on( "click", foo ).on( "click", bar ); +$( "p" ).off( "click", bar ); // foo is still bound to the click event ``` ### Setting Up Events to Run Only Once Sometimes you need a particular handler to run only once — after that, you may -want no handler to run, or you may want a different handler to run. jQuery +want no handler to run, or you may want a different handler to run. jQuery provides the `$.fn.one` method for this purpose. ``` // Switching handlers using the `$.fn.one` method -$('p').one('click', firstClick); +$( "p" ).one( "click", firstClick ); -function firstClick(){ - console.log('You just clicked this for the first time!'); - // Now set up the new handler for subsequent clicks; - // omit this step if no further click responses are needed - $(this).click(function() { console.log('You have clicked this before!'); }); +function firstClick() { + console.log( "You just clicked this for the first time!" ); + // Now set up the new handler for subsequent clicks; + // omit this step if no further click responses are needed + $( this ).click( function() { console.log( "You have clicked this before!" ); } ); } ``` Note that in the code snippet above, the `firstClick` function will be executed for -the first click on *each* paragraph element rather than the function being removed from +the first click on *each* paragraph element rather than the function being removed from *all* paragraphs when *any* paragraph is clicked for the first time. `$.fn.one` can also be used to bind multiple events: ``` // Using $.fn.one to bind several events -$('input[id]').one('focus mouseover keydown', firstEvent); +$( "input[id]" ).one( "focus mouseover keydown", firstEvent); -function firstEvent(eventObject){ - console.log('A ' + eventObject.type + ' event occurred for the first time on the input with id ' + this.id) +function firstEvent( eventObject ) { + console.log( "A " + eventObject.type + " event occurred for the first time on the input with id " + this.id ); } ``` -In this case, the `firstEvent` function will be executed once *for each event*. For the snippet above, this means -that once an input element gains focus, the handler function will still execute for the first keydown event on that +In this case, the `firstEvent` function will be executed once *for each event*. For the snippet above, this means +that once an input element gains focus, the handler function will still execute for the first keydown event on that element. diff --git a/page/events/event-delegation.md b/page/events/event-delegation.md index 2391af74..dd27e268 100644 --- a/page/events/event-delegation.md +++ b/page/events/event-delegation.md @@ -2,55 +2,47 @@ title : Understanding Event Delegation level: intermediate source: http://jqfundamentals.com/legacy -attribution: +attribution: - jQuery Fundamentals --- Say you have to add new line items to your page, given the following HTML: ``` -
- - + + + ``` -We need to attach the same event handler to multiple elements. In this example we want to attach an event that will log the text of the anchor tag to the console whenever it is clicked. +We need to attach the same event handler to multiple elements. In this example we want to attach an event that will log the text of the anchor tag to the console whenever it is clicked. We can attach a direct bind click event to each `tag is clicked, we expect to see '
was clicked' in the console. -$("p").on( "click", function() { - console.log("
was clicked"); +$( "p" ).on( "click", function() { + console.log( "
was clicked" ); }); ``` @@ -39,8 +39,8 @@ Note the difference between this and the next example. ``` // When a user focuses on or changes any input element, we expect a console message // bind to multiple events -$("div").on( "mouseenter mouseleave", function() { - console.log("mouse hovered over or left a div"); +$( "div" ).on( "mouseenter mouseleave", function() { + console.log( "mouse hovered over or left a div" ); }); ``` @@ -53,16 +53,16 @@ want to show and hide a tooltip on hover, you would use this. `.on()` accepts an object containing multiple events and handlers. ``` -$("div").on({ - mouseenter: function() { - console.log("hovered over a div"); - }, - mouseleave: function() { - console.log("mouse left a div"); - }, - click: function() { - console.log("clicked on a div"); - } +$( "div" ).on({ + mouseenter: function() { + console.log( "hovered over a div" ); + }, + mouseleave: function() { + console.log( "mouse left a div" ); + }, + click: function() { + console.log( "clicked on a div" ); + } }); ``` @@ -71,13 +71,12 @@ $("div").on({ Handling events can be tricky. It's often helpful to use the extra information contained in the event object passed to the event handler for more control. To become familiar with the event object, use this code to inspect it in your browser console after you click on -a `
Loading ...
"); - - // get the twitter data using jsonp - $.getJSON("http://search.twitter.com/search.json?q=" + escape( e.data.term ) + "&rpp=5&callback=?", function( json ) { - $this.trigger( "populate", [ json ] ); - }); - }, - populate: function( e, json ) { - var results = json.results; - var $this = $( this ); - - $this.find("p.loading").remove(); - $.each( results, function( i, result ) { - var tweet = "" + - "" + - result.from_user + - ": " + - result.text + - " " + - result.created_at + - "" + - "
"; - - $this.append( tweet ); - }); - - // indicate that the results - // are done refreshing - $this.removeClass("refreshing"); - }, - remove: function( e, force ) { - if ( !force && !confirm("Remove panel for term " + e.data.term + "?") ) { - return; - } - $( this ).remove(); - - // indicate that we no longer have a panel for the term - search_terms[ e.data.term ] = 0; - }, - collapse: function( e ) { - $( this ).find("li.collapse") - .removeClass("collapse") - .addClass("expand") - .text("Expand"); - - $( this ).addClass("collapsed"); - }, - - expand: function( e ) { - $( this ).find("li.expand") - .removeClass("expand") - .addClass("collapse") - .text("Collapse"); - - $( this ).removeClass("collapsed"); - } + refresh: function( e ) { + // indicate that the results are refreshing + var $this = $( this ).addClass( "refreshing" ); + + $this.find( "p.tweet" ).remove(); + $results.append( "Loading...
" ); + + // get the twitter data using jsonp + $.getJSON( "http://search.twitter.com/search.json?q=" + escape( e.data.term ) + "&rpp=5&callback=?", function( json ) { + $this.trigger( "populate", [ json ] ); + }); + }, + + populate: function( e, json ) { + var results = json.results; + var $this = $( this ); + + $this.find( "p.loading" ).remove(); + $.each( results, function( i, result ) { + var tweet = "" + + "" + + result.from_user + + ": " + + result.text + + " " + + result.created_at + + "" + + "
"; + + $this.append( tweet ); + }); + + // indicate that the results are done refreshing + $this.removeClass("refreshing"); + }, + + remove: function( e, force ) { + if ( !force && !confirm( "Remove panel for term " + e.data.term + "?" ) ) { + return; + } + $( this ).remove(); + + // indicate that we no longer have a panel for the term + search_terms[ e.data.term ] = 0; + }, + + collapse: function( e ) { + $( this ).find( "li.collapse" ) + .removeClass( "collapse" ) + .addClass( "expand" ) + .text( "Expand" ); + + $( this ).addClass( "collapsed" ); + }, + + expand: function( e ) { + $( this ).find( "li.expand" ) + .removeClass( "expand" ) + .addClass( "collapse" ) + .text( "Collapse" ); + + $( this ).removeClass( "collapsed" ); + } }; ``` The Twitter container itself will have just two custom events: -- `getResults` - Receives a search term and checks to determine whether there's +- `getResults` — Receives a search term and checks to determine whether there's already a results container for the term; if not, adds a results container using the results template, set up the results container using the `$.fn.twitterResult` plugin discussed above, and then triggers the `refresh` @@ -389,87 +352,84 @@ The Twitter container itself will have just two custom events: Finally, it will store the search term so the application knows not to re-fetch the term. -- `getTrends` - Queries Twitter for the top 10 trending terms, then iterates +- `getTrends` — Queries Twitter for the top 10 trending terms, then iterates over them and triggers the `getResults` event for each of them, thereby adding a results container for each term. Here's how the Twitter container bindings look: ``` -$("#twitter").on( "getResults", function( e, term ) { - - // make sure we don"t have a box for this term already - if ( !search_terms[ term ] ) { - var $this = $( this ); - var $template = $this.find("div.template"); - - // make a copy of the template div - // and insert it as the first results box - $results = $template.clone() - .removeClass("template") - .insertBefore( $this.find("div:first") ) - .twitterResult({ - "term": term - }); - - // load the content using the "refresh" - // custom event that we bound to the results container - $results.trigger("refresh"); - - search_terms[ term ] = 1; - } +$( "#twitter" ).on( "getResults", function( e, term ) { + // make sure we don't have a box for this term already + if ( !search_terms[ term ] ) { + var $this = $( this ); + var $template = $this.find( "div.template" ); + + // make a copy of the template div + // and insert it as the first results box + $results = $template.clone() + .removeClass( "template" ) + .insertBefore( $this.find( "div:first" ) ) + .twitterResult({ + "term": term + }); + + // load the content using the "refresh" + // custom event that we bound to the results container + $results.trigger( "refresh" ); + + search_terms[ term ] = 1; + } }).on( "getTrends", function( e ) { - var $this = $( this ); - - $.getJSON( "http://search.twitter.com/trends.json?callback=?", function( json ) { - var trends = json.trends; - - $.each( trends, function( i, trend ) { - $this.trigger( "getResults", [ trend.name ] ); - }); - }); + var $this = $( this ); + + $.getJSON( "http://search.twitter.com/trends.json?callback=?", function( json ) { + var trends = json.trends; + $.each( trends, function( i, trend ) { + $this.trigger( "getResults", [ trend.name ] ); + }); + }); }); ``` -So far, we've written a lot of code that does approximately nothing, but that's +So far, we've written a lot of code that does approximately nothing, but that's OK. By specifying all the behaviors that we want our core objects to have, -we've created a solid framework for rapidly building out the interface. +we've created a solid framework for rapidly building out the interface. -Let's start by hooking up our text input and the "Load Trending Terms" button. -For the text input, we'll capture the term that was entered in the input and -pass it as we trigger the Twitter container's `getResults` event. Clicking the -"Load Trending Terms" will trigger the Twitter container's `getTrends` event: +Let's start by hooking up our text input and the "Load Trending Terms" button. +For the text input, we'll capture the term that was entered in the input and +pass it as we trigger the Twitter container's `getResults` event. Clicking the +"Load Trending Terms" will trigger the Twitter container's `getTrends` event: ``` -$("form").submit(function( event ) { - var term = $("#search_term").val(); - $("#twitter").trigger( "getResults", [ term ] ); - - event.preventDefault(); +$( "form" ).submit(function( event ) { + var term = $( "#search_term" ).val(); + $( "#twitter" ).trigger( "getResults", [ term ] ); + event.preventDefault(); }); -$("#get_trends").click(function() { - $("#twitter").trigger("getTrends"); +$( "#get_trends" ).click(function() { + $( "#twitter" ).trigger( "getTrends" ); }); ``` -By adding a few buttons with the appropriate IDs, we can make it possible to +By adding a few buttons with the appropriate ID's, we can make it possible to remove, collapse, expand, and refresh all results containers at once, as shown -below. For the remove button, note how we're passing a value of true to the -event handler as its second argument, telling the event handler that we don't +below. For the remove button, note how we're passing a value of `true` to the +event handler as its second argument, telling the event handler that we don't want to verify the removal of individual containers. ``` $.each([ "refresh", "expand", "collapse" ], function( i, ev ) { - $( "#" + ev ).click( function( e ) { - $("#twitter div.results").trigger( ev ); - }); + $( "#" + ev ).click( function( e ) { + $( "#twitter div.results" ).trigger( ev ); + }); }); -$("#remove").click(function( e ) { - if ( confirm("Remove all results?") ) { - $("#twitter div.results").trigger( "remove", [ true ] ); - } +$( "#remove" ).click(function( e ) { + if ( confirm( "Remove all results?" ) ) { + $( "#twitter div.results" ).trigger( "remove", [ true ] ); + } }); ``` @@ -479,7 +439,7 @@ Custom events offer a new way of thinking about your code: they put the emphasis on the target of a behavior, not on the element that triggers it. If you take the time at the outset to spell out the pieces of your application, as well as the behaviors those pieces need to exhibit, custom events can provide a -powerful way for you to "talk" to those pieces, either one at a time or en +powerful way for you to "talk" to those pieces, either one at a time or en masse. Once the behaviors of a piece have been described, it becomes trivial to trigger those behaviors from anywhere, allowing for rapid creation of and experimentation with interface options. Finally, custom events can enhance code diff --git a/page/events/introduction-to-events.md b/page/events/introduction-to-events.md index 455b9867..2a59c1ac 100644 --- a/page/events/introduction-to-events.md +++ b/page/events/introduction-to-events.md @@ -2,13 +2,13 @@ title: Introducing Events level: beginner source: http://jqfundamentals.com/legacy -attribution: +attribution: - jQuery Fundamentals --- ## Introduction -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. +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. ## What's a DOM event? @@ -44,73 +44,59 @@ To accomplish the desired task unobtrusively, let's change our HTML a little bit 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: ``` -//Event binding using addEventListener -var helloBtn = document.getElementById("helloBtn"); - -helloBtn.addEventListener( "click", function(event) { - - alert("Hello."); +// Event binding using addEventListener +var helloBtn = document.getElementById( "helloBtn" ); +helloBtn.addEventListener( "click", function( event ) { + alert( "Hello." ); }, false ); ``` 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. ``` -//Event binding using a convenience method -$("#helloBtn").click(function( event ) { - - alert("Hello."); - +// Event binding using a convenience method +$( "#helloBtn" ).click(function( event ) { + alert( "Hello." ); }); ``` -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. +The `$( "#helloBtn" )` code selects the button element using the `$` (a.k.a. `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. There are a number of ways that events can be listened for using jQuery: ``` -//The many ways to bind events with jQuery +// The many ways to bind events with jQuery // Attach an event handler directly to the button using jQuery's // shorthand `click` method. -$("#helloBtn").click(function( event ) { - - alert("Hello."); - +$( "#helloBtn" ).click(function( event ) { + alert( "Hello." ); }); // Attach an event handler directly the to button using jQuery's // `bind` method, passing it an event string of `click` -$("#helloBtn").bind( "click", function( event ) { - - alert("Hello."); - +$( "#helloBtn" ).bind( "click", function( event ) { + alert( "Hello." ); }); // As of jQuery 1.7, attach an event handler directly to the button // using jQuery's `on` method. -$("#helloBtn").on( "click", function( event ) { - - alert("Hello."); - +$( "#helloBtn" ).on( "click", function( event ) { + alert( "Hello." ); }); // As of jQuery 1.7, attach an event handler to the `body` element that // is listening for clicks, and will respond whenever *any* button is // clicked on the page. -$("body").on({ - click: function( event ) { - - alert("Hello."); - - } +$( "body" ).on({ + click: function( event ) { + alert( "Hello." ); + } }, "button" ); // An alternative to the previous example, using slightly different syntax. -$("body").on( "click", "button", function( event ) { - - alert("Hello."); - +$( "body" ).on( "click", "button", function( event ) { + alert( "Hello." ); }); ``` @@ -120,9 +106,9 @@ Let's look at the `on` examples from above and discuss their differences. In the 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 occurring on its children. -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. +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, a.k.a. 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. -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. +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 1,000 cells and binding to an event for each cell. That's 1,000 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 1,000, resulting in way better performance and memory management. 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. @@ -132,54 +118,52 @@ The event bubbling that occurs affords us the ability to add cells via AJAX for 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. ``` -//Binding a named function +// Binding a named function function sayHello( event ) { - - alert("Hello."); - + alert( "Hello." ); } -$("#helloBtn").on( "click", sayHello ); +$( "#helloBtn" ).on( "click", sayHello ); ``` 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. -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 occurred 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. +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 occurred 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. -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). +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). ``` -//Preventing a default action from occurring and stopping the event bubbling -$("form").on( "submit", function( event ) { +// Preventing a default action from occurring and stopping the event bubbling +$( "form" ).on( "submit", function( event ) { - // Prevent the form's default submission. - event.preventDefault(); + // Prevent the form's default submission. + event.preventDefault(); - // Prevent event from bubbling up DOM tree, prohibiting delegation - event.stopPropagation(); + // Prevent event from bubbling up DOM tree, prohibiting delegation + event.stopPropagation(); - // Make an AJAX request to submit the form data + // Make an AJAX request to submit the form data }); ``` -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. +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. 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. 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. ``` -//Logging an event's information -$("form").on( "submit", function( event ) { +// Logging an event's information +$( "form" ).on( "submit", function( event ) { - // Prevent the form's default submission. - event.preventDefault(); + // Prevent the form's default submission. + event.preventDefault(); - // Log the event object for inspectin' - console.log( event ); + // Log the event object for inspectin' + console.log( event ); - // Make an AJAX request to submit the form data + // Make an AJAX request to submit the form data }); ``` diff --git a/page/events/triggering-event-handlers.md b/page/events/triggering-event-handlers.md index 0ef21fc0..3ebd44fb 100644 --- a/page/events/triggering-event-handlers.md +++ b/page/events/triggering-event-handlers.md @@ -2,29 +2,28 @@ title : Triggering Event Handlers level: intermediate source: http://jqfundamentals.com/legacy -attribution: +attribution: - jQuery Fundamentals --- -jQuery provides a way to trigger the event handlers bound to an element without any user interaction via the +jQuery provides a way to trigger the event handlers bound to an element without any user interaction via the `.trigger()` method. -## What handlers can be .trigger()'d +## What handlers can be .trigger()'d? -jQuery's event handling system is a layer on top of native browser events. When an event handler is added using -`.on("click",function() {...})`, it can be triggered using jQuery's `.trigger("click")`because jQuery stores a -reference to that handler when it is originally added. Additionally, it will trigger the javascript inside the -"onclick" attribute. The `.trigger()` function cannot be used to mimic native browser events, such as -clicking on a file input box or an anchor tag. This is because, there is no event handler attached using jQuery's +jQuery's event handling system is a layer on top of native browser events. When an event handler is added using +`.on( "click", function() {...} )`, it can be triggered using jQuery's `.trigger( "click" )` because jQuery stores a +reference to that handler when it is originally added. Additionally, it will trigger the JavaScript inside the +`onclick` attribute. The `.trigger()` function cannot be used to mimic native browser events, such as +clicking on a file input box or an anchor tag. This is because, there is no event handler attached using jQuery's event system that corresponds to these events. ``` Learn jQuery ``` - ``` -//This will not change the current page -$("a").trigger("click"); +// This will not change the current page +$( "a" ).trigger( "click" ); ``` ## How can I mimic a native browser event, if not `.trigger()`? @@ -35,8 +34,8 @@ Using these two APIs, you can programmatically create an event that behaves exac The jQuery UI Team created [jquery.simulate.js](https://github.com/eduardolundgren/jquery-simulate/blob/master/jquery.simulate.js) in order to simplify triggering a native browser event for use in their automated testing. Its usage is modeled after jQuery's trigger. ``` -//Triggering a native browser event using the simulate plugin -$("a").simulate("click"); +// Triggering a native browser event using the simulate plugin +$( "a" ).simulate( "click" ); ``` This will not only trigger the jQuery event handlers, but also follow the link and change the current page. @@ -56,32 +55,25 @@ For more information see the [triggerHandler documentation](http://api.jquery.co ## Don't use `.trigger()` simply to execute specific functions While this method has its uses, it should not be used simply to call a function that was bound as a click -handler. Instead, you should store the function you want to call in a -variable, and pass the variable name when you do your binding. Then, you can +handler. Instead, you should store the function you want to call in a +variable, and pass the variable name when you do your binding. Then, you can call the function itself whenever you want, without the need for `.trigger()`. ``` -//Triggering an event handler the right way +// Triggering an event handler the right way var foo = function( event ) { - - if ( event ) { - - console.log( event ); - - } else { - - console.log("this didn't come from an event!"); - - } - + if ( event ) { + console.log( event ); + } else { + console.log( "this didn't come from an event!" ); + } }; -$("p").on( 'click', foo ); +$( "p" ).on( "click", foo ); -foo(); // instead of $("p").trigger("click") +foo(); // instead of $( "p" ).trigger( "click" ) ``` A more complex architecture can built on top of trigger using the [publish-subscribe pattern](http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) using [jQuery plugins](https://gist.github.com/661855). -With this technique, `$.fn.trigger` can be used to notify other sections of code that an application specific event has happened. - +With this technique, `$.fn.trigger` can be used to notify other sections of code that an application specific event has happened.