Skip to content

Instantly share code, notes, and snippets.

@bonniss
Last active June 16, 2020 11:30
Show Gist options
  • Select an option

  • Save bonniss/4e9ed3a9ccaa391eb520bfdd03efdebd to your computer and use it in GitHub Desktop.

Select an option

Save bonniss/4e9ed3a9ccaa391eb520bfdd03efdebd to your computer and use it in GitHub Desktop.
jQuery Succintly

jQuery succintly code note

Chapter 1. Core jQuery

Basic concept behind jQuery

While some conceptual variations exists (e.g functions like `$.ajax`) in the jQuery API, the central concept behind jQuery is "find something, do something": You select DOM element(s) from an HTML document and then do something with the jQuery methods.

The concept, behind the concept, behind jQuery

I would like to extend the concept to include creating something as well.

Therefore, the concept behind jQuery could be extended to include first creating something new, selecting it, and then doing something with it.

$('<h1></h1>')
  .text('Duy Trung')
  .appendTo('body');

jQuery requires HTML to run in standards mode or almost standards mode

jQuery methods might not work correctly when a browser renders a HTML page in quirks mode. Make sure that the HTML is in valid mode by using valid doctype.

To ensure proper functionality, code examples in this book use the HTML doctype.

<!DOCTYPE html>

Waiting on the DOM to be ready

jQuery fires a custom event name ready when the DOM is loaded and available for manipulation.

Keep in mind that you can attach as many ready() events to the document as you would like. They are executed in the order they were added.

Executing jQuery code when the browser window is completely loaded

Typically, we do not want to wait for the window.onload event. That the point of using a custom event like ready() that will execute code before the window loads, but after the DOM is ready to be traversed and manipulated.

While the custom ready() event is great for executing code once the DOM is available, we can also use jQuery to execute code one the entire Web page (including all assets) is completely loaded.

This can be done by using the load() event method that can be used to invoke a function once the window is completely loaded.

Include all CSS files before including jQuery

You should always include all CSS files before any jQuery code.

Executing jQuery code when DOM is parsed without using ready()

If your JS code does not affect the DOM, you can include it anywhere in the HTML document. This means you can avoid the ready() event altogether if your JS is not dependent on the DOM being intact.

To avoid using the ready() event for the code that operates on the DOM, you can simply place your code in an HTML document before the closing </body> element.

In fact, placing all JS code at the bottom of a page is a proven performance strategy.

Grokking jQuery chaining

Once you have selected something using the jQuery function and created a wrapper set, you can actually chain jQuery methods to the DOM elements contained inside the set. Conceptually, jQuery methods (not all) continue the chain by always returning the jQuery wrapper set, which can then be used by the next jQuery method in the chain.

Breaking the chain with destructive methods

As aforementioned, not all jQuery methods maintain the chain. Method like text() can be chained when used to set the text node of an element. However, text() actually breaks the chain when used to get the text node contained within an element.

Using destructive jQuery methods and exiting destruction using end()

jQuery methods that alter the original jQuery wrapper set selected are considered to be destructive. The reason is that they do not maintain the original state of the wrapper set.

Using the end() method, you can back out of any destructive changes made to the original wrapper set.

Grokking when the key word this refers to DOM element

The keyword this can be used to refer to the current DOM element invoking the event.

Iterating over a set of elements contained in the jQuery wrapper set is somewhat similar to the concept we just discussed. By using the jQuery each() method, we can iterate over each DOM element contained in a wrapper set. This allows access to each DOM element individually, via the usage of the this keyword.

Extracting elements from a wrapper set, using them directly without jQuery

Just because you wrap jQuery functionality around an HTML element does not mean you lose access to the actual DOM element itself. You can always extract an element from the wrapper set and operate on the element via native JS.

$('a').get(0).title = 'jQuery.com';
$('a').attr('href', 'https://bonniss.tk');

As demonstrated, jQuer provides the handy get() method for accessing the DOM elements at a specific index in the wrapper set.

But there is another option here. You can avoid using the get() method by simply using the square bracket array notation on the jQuery object itself.

$('a')[0].title = 'jQuery.com';

Using the get() method without passing it an index is slick as it returns all of the DOM elements into a native array.

Notes

Using get() will end jQuery's chaining. It will take the wrapper set and change it into a simple array of DOM elements that are no longer wrapped with jQuery functionality. Therefore, using the end() method cannot restore chaining after get().

Checking to see if the wrapper set is empty

Use an if statement to check if the wrapper set contains any DOM elements.

if (jQuery('a').get(0)) {
  // do something
}

if (jQuery('a').length) {
  // do another thing
}

Creating an alias by renaming the jQuery object itself

jQuery provides the noConflict() method, which has several uses--namely, the ability to replace $ with another alias. This can be helpful in 3 ways: It can relinquish the use of $ sign to another library, help avoid potential conflicts, and provide the ability to customize the namespace/alias for the jQuery object.

var duytrung = jQuery.noConflict();
alert(duytrung('div').text());

Using .each() when implicit iteration is not enough

For the most part, the majority of the jQuery methods will apply implicit iteration. However, other methods will only apply to the first element in the set. By using the $().each() method to loop over the wrapper set, access each element in the set and process.

<div id="div1">div1</div>
<div id="div2">div2</div>
<div id="div3">div3</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // 3 alerts, one for each div.
    $('div').each(function() {
      // "this" is each element in the wrapper set.
      alert($(this).attr('id'));
      // Could also be written: alert(this.id);
    });
  })(jQuery);
</script>

Element in jQuery wrapper set returned in document order

The selector engine will return results in document order, from top to bottom, as opposed to the order in which the selectors were passed in.

<h1>h1</h1>
<h2>h2</h2>
<h3>h3</h3>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // We pass in h3 first, but h1 appears earlier in
    // the document, so it is first in the wrapper set.
    alert($('h3, h2, h1').get(0).nodeName);
    // Alerts "H1".
  })(jQuery);
</script>

Determining context used by the jQuery function

The default context used by jQuery function when selecting DOM elements is the document element. It is possible to determine the context in which the jQuery function is performing a DOM query by using the context property.

Creating entire DOM structure, including DOM events, in a single chain

By leverage chaining and jQuery methods, you can create not only a single DOM element, but entire DOM structures.

jQuery('<ul></ul>')
  .append(`<li><a href="https://bonniss.tk"></a></li>`)
  .find('a:first')
  .text('Duy Trung Blog')
  .find('a:eq(1)')
  .click(function() {
    return confirm('Leave this page');
  })
  .end()
  .end()
  .appendTo('body');

Chapter 2. Selecting

Custom jQuery filters can select elements when used alone

It is not necessary to provide an actual element in conjunction with a filter, such as $('div:hidden'). It is possible to simply pass the filter alone, anywhere a selector expression is expected.

$(':hidden');
$('div').filter(':even');

Grokking the :hidden and :visible filter

The custom jQuery selector filters :hidden and :visible do not take into account the CSS visibility prop as one might expect. The way jQuery determines if an element is hidden or visible is if the element consumes any space in the documnet.

Using the is() method to return a Boolean value

Using the is() method, we can check the current set against an expression/filter. The check will return true if the set contains at least one elemtn that is selected by the given expression/filter.

<div id="i0">jQuery</div>
<div id="i1">jQuery</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Returns true.
    alert($('div').is('#i1'));
    // Returns false. Wrapper set contains no <div> with id="i2".
    alert($('div').is('#i2'));
    // Returns false. Wrapper set contains no hidden <div>
    alert($('div').is(':hidden'));
  })(jQuery);
</script>

You can pass jQuery more than on selector expression

alert($('div, p, ul, li').text());

Each of these expression selects DOM elements that are all added to the wrapper set.

Create custom filter for selecting elements

The capabilities of the jQuery selector engine can be extended by creating your own custom filters. For example, say we would like to create a filter to select all elements that are absolute positioned.

$.expr[':'].positionAbsolute = function(element) {
  return $(element).css('position') === 'absolute';
};

$(':positionAbsolute');

Differences between filtering by numeric order vs DOM relationships

jQuery provides filters for filtering a wrapper set by an element's numerical context within the set.

These filters are:

  • :first
  • :last
  • :event
  • :odd
  • :eq(index)
  • :gt(index)
  • :lt(index)

Notes

Filters that filter the wrapper set itself do so by filtering elements in the set at a starting point of 0. For example, :eq(0) and :first access the first element in the set. This is in contrast to the :nth-child filter that is one-based indexed, which means using :nth-child(0) will always select nothing.

Using :first will select the first element in the set while :last will select the last element in the set. Remember that they filter the set based on the relationship within the set, but not the elements' relationship in the context of the DOM, so the filters :first, :last and :eq(index) will always return a single element.

With a clear understanding of manipulating the set itself, we can augment out understanding of selecting elements by using filters that select elements that have unique relationships with other elements within the actual DOM.

  • ancestor descendant
  • parent > child
  • prev + next
  • prev + siblings
  • :nth-child(selector)
  • :first-child
  • :last-child
  • :only-child
  • :empty
  • :has(selector)
  • :parent
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<ul>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Remember that text() combines the contents of all
    // elements in the wrapper set into a single string.
    alert('there are ' + $('li').length + ' elements in the set');
    // Get me the first element in the set.
    alert($('li:first').text()); // Alerts "1".
    // Get me the last element in the set.
    alert($('li:last').text()); // Alerts "10"
    // Get me the 6th element in the set, 0 based index.
    alert($('li:eq(5)').text()); // Alerts "6".

    alert($('li:even').text()); // 13579, zero-based indexed
    alert($('li:nth-child(even)').text()); // 246810, one-based indexed
  })(jQuery);
</script>

Selecting elements by id when the value contains meta-character

jQuery selectors use a set of meta-character (e.g. # ~ [] = >) that when used as a literal part of a name (e.g id="#foo[bar]") should be escaped. It is possible to escape characters by placing two backslashes before the character.

// Select the p element which has id "#foo[bar]"
$('p#\\#foo\\[bar\\]');

The complete list of characters that need to be escaped when used as a literal part of a name:

  • #
  • ;
  • &
  • ,
  • .
  • +
  • *
  • ~
  • '
  • :
  • "
  • !
  • ^
  • $
  • [
  • ]
  • (
  • )
  • =
  • >
  • |
  • /

Stacking selector filters

It is possible to stack selector filter - e.g. a[title="jQuery"][href^="http://"].

Other selector filters can be stacked besides just attribute filters.

$('div:last:contains("jQuery")');
$(':checkbox:visible:checked');

Ref: jQuery Selectors

Nesting selector filters

Selector filters can be nested. This enables you to wield filters in a very concise and powerful manner.

// Select all divs that don't have elements with class "jQuery" inside them
$('div:not(:has(.jQuery))');
// Select all divs that are not odd in the set
$('div:not(:odd)');
// Nest and stack filters
$('p').filter(':not(:first):not(:last)');

Grokking the :nth-child() filter

The :nth-child() filter has many uses. For example, say you only want to select every third <li> element contained within a <ul> element. It is possible with the :nth-child() filter.

$('li:nth-child(3n)');

Selecting elements by searching attribute values using regular expressions

jQuery does not support select by regular expression out of the box, however, you can extend the capability of jQuery by this plugin written by James Padolsey.

Difference between selecting direct children vs. all descendants

Direct children elements only can be selected by using the combiner > or by way of the children() traversing method. All descendants can be selected by using the * CSS expression.

<div>
  <p>
    <strong><span>text</span></strong>
  </p>
  <p>
    <strong><span>text</span></strong>
  </p>
</div>

<script>
  (function($) {
    // select all direct children of element with id "specific-div"
    alert($('#specific-div>*').length); // 2

    // select all descendants of element with id "specific-div"
    alert($('#specific-div *').length); // 6
  })(jQuery);
</script>

Selecting direct child elements when a context is already set

It is possible to use the combiner > without a context to select direct child elements when a context has already been provided.

// select only the direct children of the first ul
$('ul:first').find('> li');

Basically, '> element' can be used as an expression when a context has already been determined.


Chapter 3. Traversing

The filter() method is used to filter the current set of elements contained within the wrapper set. Its usage should be left to tasks that require filtering a set of elements that are already selected.

The find() method, on the other hand, can be used to further find descendants of the currently selected elements. Think of find() more like updating or chaging the current wrapped set with new elements that are encapsulated within the elements that are already selected.

Both find() and filter() are destructive methods that can be undone by using end(), which will revert the wrapped set back to its previous state before find() or filter() were used.

The concept to take away is that filter() will only reduce the currently selected elements in the wrapper set while find() can actually create an entirely new set of wrapped elements.

Notes

You can combine the elements in current set to previous set by using addBack() (andSelf() in versions before 3.0) method.

Passing filter() a function instead of an expression

Before you run off and create a custom filter for selecting element, it might make more sense to simply pass the traversing filter() method a function that will allow you to examine each element in the wrapper set for a particular scenario.

Travering up the DOM

You can easily traverse up the DOM to ancestor elements using the parent(), parents() and closest() methods.

Notes

closest() and parents() might appear to have the same functionality, but closest() will actually include the currently selected element in its filtering.

closest() stops traversing once it finds a match, whereas parents() gets all parents and then filters on your optional selector. Therefore, closest() can only return a maximum of one element.

Traversing methods accept CSS expressions as optional arguments

CSS expressions are not only passed to the jQuery function for selecting elements, but they can also be passes to several of the traversing methods.

  • children('expression')
  • next('expression')
  • nextAll('expression')
  • parent('expression')
  • parents('expression')
  • prev('expression')
  • prevAll('expression')
  • siblings('expression')
  • closest('expression'

Chapter 4. Manipulation

Creating, operating, and adding HTML on the fly

You can create HTML markup on the fly by passing the jQuery function a string of raw HTML.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
   (function($){
  alert($('<div><a></a></div>').get(0).nodeName); // Alerts "DIV".
  alert($('<div><a></a></div>').length); // Alerts "1" <div> is in the wrapper set.
  alert($('<div><a></a></div><div><a></a></div>').length); // Alerts "2" <div> are in
  the set.
  })(jQuery);
</script>

It is important to note that when creating DOM structures using the jQuery function, only root elements in the structure are added to the wrapper set.

Grokking the index() method

You can determine the index of an element in the wrapper set by passing the element to the index() method.

$('#nav div').click(function() {
  alert($('#nav div').index(this));
  // or, a nice trick...
  alert($(this).prevAll().length);
});

Grokking the .contents() method

The content() method can be used to find all the child element nodes, including text nodes contained inside of an element.

However, there is a catch. If the retrieved contents contain only text nodes, the selection will be placed inside the wrapper set as a single text node. However, if the contents you are retrieving have one or more element nodes amongst the text nodes, then the contents() method will contain text nodes and element nodes.

Using remove() does note remove elements from wrapper set

When you use remove(), a DOM snippet from the DOM the elements contained in the removed DOM structure are still contained within the wrapper set. You could remove an element, operate on that element, and then actually place that element back into the DOM, all within a single jQuery chain.

Chapter 5. HTML Forms

Disable/enable form elements

Using jQuery, you can easily disable form elements by setting the disabled attribute value of a form element to disabled. To do this, we simply select an input, and then using the attr() method to set disabled attribute.

$(':radio').attr('disabled', true);

To enable a form element, we either set disabled to false or use the removeAttr() method.

$(':radio').removeAttr('disabled');

Determine if a form is disabled or enabled

$('#button1').is(':enabled');
$('#button1:enabled').length;
$('#button1').is(':disabled');
$('#button1:disabled').length;

Selecting/clearing a checkbox or radio

// selecting by setting 'checked' attr
$('input:checkbox,input:radio').attr('checked', 'checked');
// clearing by removing or setting 'checked' to empty string
$('input:checkbox,input:radio').attr('checked', '');
$('input:checkbox,input:radio').removeAttr('checked');
// check 'checked' state
$('input:checkbox,input:radio').is(':checked');
$('input:checkbox,input:radio:checked').length;

How to determine if a form element is hidden

You can determine if a form element is hidden using the :hidden form filter.

<input type="hidden" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Alerts "true".
    alert($('input').is(':hidden'));
    // Or, added to wrapper set if hidden. Alerts "1".
    alert($('input:hidden').length);
  })(jQuery);
</script>

Setting/getting the value of an input element

The val() method can be used to set and get the attribute value of an input element (button, checkbox, radio, image, password, hidden, reset, submit, text)

<input type="button" />
<input type="checkbox" />
<input type="hidden" />
<input type="image" />
<input type="password" />
<input type="radio" />
<input type="reset" />
<input type="submit" />
<input type="text" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('input:button').val('I am a button');
    $('input:checkbox').val('I am a check box');
    $('input:hidden').val('I am a hidden input');
    $('input:image').val('I am an image');
    $('input:password').val('I am a password');
    $('input:radio').val('I am a radio');
    $('input:reset').val('I am a reset');
    $('input:submit').val('I am a submit');
    $('input:text').val('I am a text');
    // Alerts input's value attribute.
    alert($('input:button').val());
    alert($('input:checkbox').val());
    alert($('input:hidden').val());
    alert($('input:image').val());
    alert($('input:password').val());
    alert($('input:radio').val());
    alert($('input:reset').val());
    alert($('input:submit').val());
    alert($('input:text').val());
  })(jQuery);
</script>

Setting/getting the selected option of a select element

Using the val() method, you can set the selected value of a <select> element by passing the val() method a string representing the value assigned to the <option> element.

To get the value of <select> element, use the val() method again to determine which option is selected.

Setting/getting selected options of a multi-select element

<select size="4" multiple="multiple">
  <option value="option1">option one</option>
  <option value="option2">option two</option>
  <option value="option3">option three</option>
  <option value="option4">option four</option>
</select>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Set the value of the selected options.
    $('select').val(['option2', 'option4']);
    // Get the selected values.
    alert(
      $('select')
        .val()
        .join(', ')
    ); // Alerts, "option2, option4".
  })(jQuery);
</script>

Editing select element

jQuery make some of the common tasks associated with editing select elements trivial.

// Add options to a select element at the end.
$('select').append('<option value="">option</option>');
// Add options to the start of a select element.
$('select').prepend('<option value="">option</option>');
// Replace all the options with new options.
$('select').html(
  '<option value="">option</option><option value="">option</option>'
);
// Replace items at a certain index using the :eq() selecting filter to
// select the element, and then replace it with the .replaceWith() method.
$('select option:eq(1)').replaceWith('<option value="">option</option>');
// Set the select elements' selected option to index 2.
$('select option:eq(2)').attr('selected', 'selected');
// Remove the last option from a select element.
$('select option:last').remove();
// Select an option from a select element via its
// order in the wrapper set using custom filters.
$('#select option:first');

Select form element by type

It is possible to select form elements by their type:

  • :text
  • :password
  • :radio
  • :checkbox
  • :submit
  • :image
  • :reset
  • :file
  • :button

Select all form elements

You can select all form elements by using :input form filter. This filter will select more than just input element, it will select any <textarea>, <select> or <button> as well.

<input type="button" value="Input Button" />
<input type="checkbox" />
<input type="file" />
<input type="hidden" />
<input type="image" />
<input type="password" />
<input type="radio" />
<input type="reset" />
<input type="submit" />
<input type="text" />
<select>
  <option>Option</option>
</select>
<textarea></textarea>
<button>Button</button>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Alerts "13" form elements
    alert($(':input').length);
  })(jQuery);
</script>

Chapter 6. Events

Not limited to a single ready() event

It is important to keep inmind that you can declare as many custom ready() events as you would like. You are not limited to attaching a single .ready() event to the document. The ready() events are executed in the order that they are included.

Attaching/removing events using bind() and unbind()

Using the bind() method, you can add any of the following standard handlers to the appropriate DOM elements.

  • blur
  • focus
  • load
  • resize
  • scroll
  • unload
  • beforeunload
  • click
  • dblclick
  • mousedown
  • mouseup
  • mousemove
  • mouseover
  • mouseout
  • change
  • select
  • submit
  • keydown
  • keypress
  • keyup
  • error

To remove standard handlers or custom handlers, we simply pass the unbind() method the handler name or custom handler name that needs to be remove. If no paramaters are passed to unbind(), it will remove all handlers attached to an element.

Notes

jQuery provides several shortcuts to the bind() method for use with all standard DOM events, which excludes custom jQuery events like mouseenter and mouseleave. Using these shortcuts simply involves substituting the event's name as the method name - e.g click(), mouseout(), focus().

You can attach unlimited handlers to a single DOM element using jQuery. jQuery provides the one() event handling method to conveniently bind an event to DOM elements that will be executed once and then removed. The one() method is just a wrapper for bind() and unbind().

jQuery normalizes the event object

Applying event handlers to DOM elements regardless of DOM updates using live()

Using the handy live() event method, you can bind handlers to DOM elements currently in a Web page and those that have yet to be added. the live() method uses event delegation to make sure that newly added/created DOM elements will always respond to event handlers regardless of DOM manipulations or dynamic changes to the DOM.

Using live() is essentially a shortcut for manually having to set up event delegation. For example, using live() we could create a button that creates another button indefinitely.

<button>Add another button</button>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('button').live('click', function() {
      $(this).after('<button>Add another button</button>');
    });
  })(jQuery);
</script>

To remove the live event, we simply use the die() method-e.g. $('button').die().

Notes

live() supports the following handlers: click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup. live() only works against a selector. live() by default will stop propagation by using return false within the function sent to the live() method.

Adding a function to several event handlers

It is possible to pass the event bind() method several event handlers. This makes it possible to attach the same function, written once, to many handlers.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Responds to multiple events.
    $(document).bind('click keypress resize', function(event) {
      alert('A click, keypress, or resize event occurred on the document.');
    });
  })(jQuery);
</script>

jQuery normalizes the event object

This means that when the event object is passed to a function handler, you do not have to worry about browser-specific implementation of the event object. You can use the following attributes and methods of the event object worry-free from browser differences because jQuery normalizes the event object.

Event object attributes

  • event.type
  • event.target
  • event.data
  • event.relatedTarget
  • event.currentTarget
  • event.pageX
  • event.pageY
  • event.result
  • event.timeStamp

Event object methods

  • event.preventDefault()
  • event.isDefaultPrevented()
  • event.stopPropagation()
  • event.isPropagationStopped()
  • event.stopImmediatePropagation()
  • event.isImmediatePropagationStopped()
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $(window).load(function(event) {
      alert(event.type);
    }); // Alerts "load".
  })(jQuery);
</script>

Grokking event namespacing

Often we will have an object in the DOM that needs to have several function tied to a single event handler. For example, let's take the resize handler. Using jQuery, we can add as many function to the window.resize handler as we like.

But what happens when we need to remove only one of these functions but not all of them? Using $(window).unbind('resize') will remove all handlers. By namespacing a handler, we can assign a unique hook to specific function for removal.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $(window).bind('resize', function() {
      alert('I have no namespace');
    });
    $(window).bind('resize.unique', function() {
      alert('I have a unique namespace');
    });
    // Removes only the resize.unique function from event handler
    $(window).unbind('resize.unique');
  })(jQuery);
</script>

Namespacing events gives use the ability to label and remove unique functions assigned to the same handler on a single DOM element.

Notes

There is no limit to the depth or number of namespaces used.

E.g resize.layout.headerFooterContent

Namespacing is a great way of protecting, involing, removing any exclusive handlers that a plugin may require.

Namespacing works with custom events as well as standard events - e.g click.unique or myclick.unique.

Adding a function to several event handler

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Responds to multiple events.
    $(document).bind('click keypress resize', function(event) {
      alert('A click, keypress, or resize event occurred on the document.');
    });
  })(jQuery);
</script>

Cancel default browser behavior with preventDefault()

When a link is clicked or a form is submitted, the browser will invoke its default functionality associated with these events. For example, click an <a> link and the Web browser will attempt to load the value of the <a> href attribute in the current browser window. To stop browser from performing this type of functionality, you can use preventDefault() method of the jQuery normalized event object.

<a href="http://www.jquery.com">jQuery</a>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Stops browser from navigating.
    $('a').click(function(event) {
      event.preventDefault();
    });
  })(jQuery);
</script>

Cancel event propagation with stopPropagation()

Events propagate (a.k.a bubble) up the DOM. When an event handler is fired for any given element, the invoked event handler is also invoked for all ancestor elements. This default behavior facilitates solutions like event delegation. To prohibit this default bubbling, you can use the jQuery normalized event method stopPropagation().

<div><span>stop</span></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('div').click(function(event) {
      // Attach click handler to <div>.
      alert('You clicked the outer div');
    });
    $('span').click(function(event) {
      // Attach click handler to <span>.
      alert('You clicked a span inside of a div element');
      78;
      // Stop click on <span> from propagating to <div>.
      // If you comment out the line below,
      //the click event attached to the div will also be invoked.
      event.stopPropagation();
    });
  })(jQuery);
</script>

Cancelling default behavior and event propagation via return false

Returning false is the equivalence of both preventDefault() and stopPropagation().

<span
  ><a href="javascript:alert('You clicked me!')" class="link">click me</a></span
>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('span').click(function() {
      // Add click event to <span>.
      window.location = 'http://www.jquery.com';
    });
    $('a').click(function() {
      // Ignore clicks on <a>.
      return false;
    });
  })(jQuery);
</script>

Cloning events as well as DOM elements

By default, cloning DOM structures using the clone() method does not additionally clone events attached to the DOM elements being cloned. In order to clone the elements and the events attached to the elements you must pass the clone() method a Boolean value of true.

<button>Add another button</button>
<a href="#" class="clone">Add another link</a>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('button').click(function() {
      var $this = $(this);
      $this.clone(true).insertAfter(this);
      // Clone element and its events.
      $this.text('button').unbind('click'); // Change text, remove event.
    });
    $('.clone').click(function() {
      var $this = $(this);
      $this.clone().insertAfter(this); // Clone element, but not its events.
      $this.text('link').unbind('click'); // Change text, remove event.
    });
  })(jQuery);
</script>

Getting X and Y coordinates of the mouse in the viewport

By attaching a mousemove event to the entire page, you can retrieve the X and Y coordinates of the mouse pointer through pageX and pageY properties of the jQuery normalized event object.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $(document).mousemove(function(e) {
      // e.pageX - gives you the X position.
      // e.pageY - gives you the Y position.
      $('body').html('e.pageX = ' + e.pageX + ', e.pageY = ' + e.pageY);
    });
  })(jQuery);
</script>

Getting X and Y coordinates of the mouse relative to another element

<!-- Move mouse over div to get position relative to the div -->
<div
  style="margin: 200px; height: 100px; width: 100px; background: #ccc; padding:
20px"
>
  relative to this
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('div').mousemove(function(e) {
      //relative to this div element instead of document.
      var relativeX = e.pageX - this.offsetLeft;
      var relativeY = e.pageY - this.offsetTop;
      $(this).html('releativeX = ' + relativeX + ', releativeY = ' + relativeY);
    });
  })(jQuery);
</script>

Chapter 7. jQuery and the Web Browser

Disabling the right-click context menu

Just simply cancel the contextmenu event.

$(document).bind('contextmenu', function() {
  return false;
});

Scrolling the browser window

<head>
  <style>
    li {
      padding-bottom: 500px;
    }
  </style>
</head>
<body>
  <ul>
    <li><a href="#" class="next">Next</a></li>
    <li>
      <a href="#" class="next">Next</a>/<a href="#" class="prev">Previous</a>
    </li>
    <li>
      <a href="#" class="next">Next</a>/<a href="#" class="prev">Previous</a>
    </li>
    <li><a href="#" class="prev">Previous</a></li>
  </ul>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
  <script>
    (function($) {
      $('.next').click(function() {
        $('html, body').animate(
          {
            scrollTop: $(this)
              .parent()
              .next()
              .find('a')
              .offset().top
          },
          1000
        );
      });
      $('.prev').click(function() {
        $('html, body').animate(
          {
            scrollTop: $(this)
              .parent()
              .prev()
              .find('a')
              .offset().top
          },
          1000
        );
      });
    })(jQuery);
  </script>
</body>

Chapter 8. Plugins

Use the $ alias when constructing a plugin

When writing a jQuery plugin, the sme conflict prevention routine used with regular, old jQuery code should be implemented. With this in mind, all plugins should be contained inside a private scope where the $ alias can be used without fear of conflicts or suprising results.

(function($) {
  // can use $ without fear of conflict
})(jQuery);

New plugins attach to jQuery.fn object to become jQuery methods

jQuery.fn is a shortcut or alias for jQuery.prototype. Inside a plugin, this is a reference to the current jQuery object.

(function($) {
  $.fn.count = function() {
    var $this = $(this);
    $this.text('0');
    var myInterval = window.setInterval(function() {
      var currentCount = parseFloat($this.text());
      var newCount = currentCount + 1;
      $this.text(newCount + '');
    }, 1000);
  };
})(jQuery);

Using each() to iterate over the jQuery object and provide a reference to each element in the object using the this keyword

<div id="counter1"></div>
<div id="counter2"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $.fn.count = function() {
      this.each(function() {
        // "this" is the current jQuery object.
        var $this = $(this);
        $this.text('0'); // Sets the counter start number.
        var myInterval = window.setInterval(function() {
          // Interval for counting.
          var currentCount = parseFloat($this.text());
          var newCount = currentCount + 1;
          $this.text(newCount + '');
        }, 1000);
      });
    };
  })(jQuery);
  jQuery('#counter1, #counter2').count();
</script>

Plugin return jQuery object so jQuery methods or other plugins can be chained after using plugins


Chapter 9. Effects

Disable all jQuery effect methods

jQuery.fx.off = true;

Grokking the stop() animation method

It is often necessary to stop an animation currently in progress before starting another. For example, when using the custom mouseenter and mouseleave events (or hover() method), you may unintentionally trigger an element that is already animating due to previous mouseeneter or mouseleave event. This cause a buildup of queued animations, which results in a sluggish interface. To avoid this, simply use stop() method to stop the current animation before starting a new one.

<div
  style="height: 100px; width: 100px; background-color: red; position: absolute;
left: 20px;"
>
  Hover over Me!
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('div').hover(
      function() {
        $(this)
          .stop()
          .animate({ left: 75 }, 'fast');
      },
      function() {
        $(this)
          .stop()
          .animate({ left: 20 }, 'fast');
      }
    );
  })(jQuery);
</script>

Remove the stop() methods from the code and roll the mouse over the element several times to see the ghost animations occur. Continuously rolling over the element in the page will result in animation buildup.

Additionally, it is possible to not only stop the current animation in the queue for the select element but also the entire queue by passing the stop() method a param of true. This will effectively stop all queued animations, active and inactive.

Determining if an element is animating using :animated

<div
  style="height: 100px; width: 100px; background-color: red; color: white"
></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    function recursiveAnimate() {
      $('div').slideToggle('slow', recursiveAnimate);
    }
    recursiveAnimate();
    $('div:animated').text('I am animating');
  })(jQuery);
</script>

Using show(), hide() and toggle() without animation

Using the show(), hide() and toggle() methods with a parameter will cause the elements being shown or hidden to animate by chaining CSS props: height, width, opacity, margin, padding. It is possible to skip the animations for hiding and showing elements simply by not passing any paramaters.

<!DOCTYPE html>
<html lang="en">
  <head>
    <style type="text/css">
      div {
        height: 100px;
        width: 100px;
        background-color: red;
        color: white;
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <div>Click Me (hide animation)</div>
    <div>Click Me (hide no animation)</div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>
      (function($) {
        // Hide with animation.
        $('div:first').click(function() {
          $(this).hide(1000);
        });
        // Hide no animation,
        $('div:last').click(function() {
          $(this).hide();
        });
      })(jQuery);
    </script>
  </body>
</html>

Notes

The jQuery methods hide(), show(), toggle(), slideUp(), slideDown(), slideToggle() when used on elements that have a CSS display value of inline, will be changed to display:block for the duration of the animation.

Grokking sequential and nonsequential animations

It is important to understand the difference between animations that happen simultaneously, and animations that occur in a sequential order over time.

By default, when effect methods are chained, they are added to the queue, and executed sequentially.

<div
  style="height: 100px; width: 100px; background-color: red; position: absolute;
left: 20px; border: 1px solid #ff9933"
>
  Animate me!
</div>
<div
  style="height: 100px; width: 100px; background-color: red; position: absolute;
left: 20px; top: 100px; border: 1px solid #ff9933"
>
  Animate me!
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Each effect is added to a queue and occurs sequentially.
    $('div:first')
      .slideUp('slow')
      .slideDown('slow')
      .hide('slow');
    // Each method is added to a queue and occurs sequentially.
    $('div:last')
      .animate({ width: '200px' }, 1000)
      .animate({ borderLeftWidth: '10px' }, 1000);
  })(jQuery);
</script>

On the other hand, using the animate() method, you can set animations to occur non-sequentially or at the same time by passing all the CSS property changes to a single animate() method call.

<div
  style="height: 100px; width: 100px; background-color: red; position: absolute;
left: 20px; border: 1px solid #ff9933"
>
  Animate me!
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    // Both width and borderLeftWidth properties will animate simultaneously.
    $('div').animate({ width: '200px', borderLeftWidth: '10px' }, 1000);
  })(jQuery);
</script>

animate() is the base, low-level abstraction

The animate() method is the base method that is used to construct all the pre-configured animations. It provides the ability to change the values of style properties.

Here is what you need to know when using this method.

  • Only properties that take numeric values are supported. In other words, you can't animate the value of, say, the backgroundColor property. Also, properties that take more than one value like backgroundPosition can't be animated.

  • em and % are applicable.

  • Relative animations can be specified using "+=" or "-=" in front of the property value.

  • If you specify an animation duration of 0, the animation will immediately set the element to their end state.

  • As a shortcut, if a value of toggle is passed, an animation will simply reverse from where it is and animate to that end.

  • All CSS properties set via a single animate() method will animate at the same time.

Grokking the jQuery fading methods

fadeIn(), fadeOut() and fadeTo() methods:

  • Unlike other effect method, fading methods only adjust the opacity of an element. It is assumed when using these effect methods that any element being faded already has a height and width.

  • Fading animations will fade elements from their current opacity.

  • Using the fadeOut() method will fade an element from its current opacity, and then once 100% faded, it will change the CSS display property of the element to none.

<!-- Elements being faded should have a width and height -->
<div style="height: 100px; width: 100px; background-color: red;"></div>
<button>Fade the rest of the way</button>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
  (function($) {
    $('div').fadeTo('slow', 0.5);
    $('button').click(function() {
      // Fade from current opacity to zero,
      // and then hide element via display:none
      $('div').fadeOut('slow');
    });
  })(jQuery);
</script>

Chapter 10. AJAX

The jQuery ajax() function is the lowest-level abstraction

The jQuery ajax() function is the lowest level of abstraction available for XMLHttpRequests. All the other jQuery AJAX functions, such as load(), leverage the ajax() function. Moveover, jQuery provides some shortcut methods that utilize the ajax():

  • load()
  • get()
  • getJSON()
  • getScript()
  • post()

The point to take away is that while the shortcuts are nice at times, they all use ajax() behind the scenes. And, when you want all the features and customizations that jQuery offers when it comes to AJAX, then you should just use the ajax() method.

jQuery supports cross-domain JSONP

JSON with Padding (JSONP) is a technique that allows the sender of an HTTP request, where JSON is returned, to provide a name for a function that invoked with the JSON object as a parameter of the function. This technique does not use XHR. It uses the script element so data can be pulled into any site. The purpose is to circumvent the same-source policy limitations of XMLHttpRequest.

Using the getJSON() jQuery function, you can load JSON data from another domain when a JSONP callback function is added to the URL.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
   (function($){
  $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=resig&tagmode=all&
  format=json&jsoncallback=?",
  // Using ? just means call the callback function provided.
  function (data) { // Data is the JSON object from Flickr.
  $.each(data.items, function (i, item) { $('<img />').attr("src",
  item.media.m).appendTo('body'); if (i == 30) return false; });
  });
  })(jQuery);
</script>

Stop a browser from caching XHR request

If the content being requested is dynamic, you will make sure that the request is not cached by the browser. One possible solution is to append an unique query string value to the end of the URL.

// Add unique query string at end of the URL.
url: 'some?nocache=' + new Date().getTime();

Another solution, which is more of a global solution, is to set up all AJAX requests by default to contain the no-cache logic we just discussed.

$.ajaxSetup({
  cache: false // True by default. False means caching is off.
});

// Override the global setting when needed
jQuery.ajax({ cache: true, url: 'some', type: 'POST' });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment