DOM Manipulation
Creating DOM elements
Section titled “Creating DOM elements”The jQuery function (usually aliased as $) can be used both to select elements and to create new elements.
var myLink = $('<a href="http://stackexchange.com"></a>');You can optionally pass a second argument with element attributes:
var myLink = $('<a>', { 'href': 'http://stackexchange.com' });'<a>' —> The first argument specifies the type of DOM element you want to create. In this example it’s an anchor but could be anything on this list. See the specification for a reference of the a element.
{ 'href': 'http://stackexchange.com' } —> the second argument is a JavaScript Object containing attribute name/value pairs.
the ‘name’:‘value’ pairs will appear between the < > of the first argument, for example <a name:value> which for our example would be <a href="http://stackexchange.com"></a>
Manipulating element classes
Section titled “Manipulating element classes”Assuming the page includes an HTML element like:
<p class="small-paragraph"> This is a small <a href="https://en.wikipedia.org/wiki/Paragraph">paragraph</a> with a <a class="trusted" href="http://stackexchange.com">link</a> inside.</p>jQuery provides useful functions to manipulate DOM classes, most notably hasClass(), addClass(), removeClass() and toggleClass(). These functions directly modify the class attribute of the matched elements.
$('p').hasClass('small-paragraph'); // true$('p').hasClass('large-paragraph'); // false
// Add a class to all links within paragraphs$('p a').addClass('untrusted-link-in-paragraph');
// Remove the class from a.trusted$('a.trusted.untrusted-link-in-paragraph').removeClass('untrusted-link-in-paragraph').addClass('trusted-link-in-paragraph');Toggle a class
Given the example markup, we can add a class with our first .toggleClass():
$(".small-paragraph").toggleClass("pretty");Now this would return true:
$(".small-paragraph").hasClass("pretty")
toggleClass provides the same effect with less code as:
if($(".small-paragraph").hasClass("pretty")){ $(".small-paragraph").removeClass("pretty");}else { $(".small-paragraph").addClass("pretty"); }toggle Two classes:
$(".small-paragraph").toggleClass("pretty cool");Boolean to add/remove classes:
$(".small-paragraph").toggleClass("pretty",true); //cannot be truthy/falsey
$(".small-paragraph").toggleClass("pretty",false);Function for class toggle (see example further down to avoid an issue)
$( "div.surface" ).toggleClass(function() { if ( $( this ).parent().is( ".water" ) ) { return "wet"; } else { return "dry"; }});Used in examples:
// functions to use in examplesfunction stringContains(myString, mySubString) { return myString.indexOf(mySubString) !== -1;}function isOdd(num) { return num % 2;}var showClass = true; //we want to add the classExamples:
Use the element index to toggle classes odd/even
$( "div.gridrow" ).toggleClass(function(index,oldClasses, false), showClass ) { showClass if ( isOdd(index) ) { return "wet"; } else { return "dry"; }});More complex toggleClass example, given a simple grid markup
<div class="grid"> <div class="gridrow">row</div> <div class="gridrow">row</div> <div class="gridrow">row</div> <div class="gridrow">row</div> <div class="gridrow">row</div> <div class="gridrow gridfooter">row but I am footer!</div></div>Simple functions for our examples:
function isOdd(num) { return num % 2;}
function stringContains(myString, mySubString) { return myString.indexOf(mySubString) !== -1;}var showClass = true; //we want to add the classAdd an odd/even class to elements with a gridrow class
$("div.gridrow").toggleClass(function(index, oldClasses, showThisClass) { if (isOdd(index)) { return "odd"; } else { return "even"; } return oldClasses;}, showClass);If the row has a gridfooter class, remove the odd/even classes, keep the rest.
$("div.gridrow").toggleClass(function(index, oldClasses, showThisClass) { var isFooter = stringContains(oldClasses, "gridfooter"); if (isFooter) { oldClasses = oldClasses.replace('even', ' ').replace('odd', ' '); $(this).toggleClass("even odd", false); } return oldClasses;}, showClass);The classes that get returned are what is effected. Here, if an element does not have a gridfooter, add a class for even/odd. This example illustrates the return of the OLD class list. If this else return oldClasses; is removed, only the new classes get added, thus the row with a gridfooter class would have all classes removed had we not returned those old ones - they would have been toggled (removed) otherwise.
$("div.gridrow").toggleClass(function(index, oldClasses, showThisClass) { var isFooter = stringContains(oldClasses, "gridfooter"); if (!isFooter) { if (isOdd(index)) { return "oddLight"; } else { return "evenLight"; } } else return oldClasses;}, showClass);Other API Methods
Section titled “Other API Methods”jQuery offers a variety of methods that can be used for DOM manipulation.
The first is the .empty() method.
Imagine the following markup:
<div id="content"> <div>Some text</div></div>By calling $('#content').empty();, the inner div would be removed. This could also be achieved by using $('#content').html('');.
Another handy function is the .closest() function:
<tr id="row_1"> <td><button type="button" class="delete">Delete</button></tr>If you wanted to find the closest row to a button that was clicked within one of the row cells then you could do this:
$('.delete').click(function() { $(this).closest('tr');});Since there will probably be multiple rows, each with their own delete buttons, we use $(this) within the .click() function to limit the scope to the button we actually clicked.
If you wanted to get the id of the row containing the Delete button that you clicked, you could so something like this:
$('.delete').click(function() { var $row = $(this).closest('tr'); var id = $row.attr('id');});It is usually considered good practise to prefix variables containing jQuery objects with a $ (dollar sign) to make it clear what the variable is.
An alternative to .closest() is the .parents() method:
$('.delete').click(function() { var $row = $(this).parents('tr'); var id = $row.attr('id');});and there is also a .parent() function as well:
$('.delete').click(function() { var $row = $(this).parent().parent(); var id = $row.attr('id');});.parent() only goes up one level of the DOM tree so it is quite inflexible, if you were to change the delete button to be contained within a span for example, then the jQuery selector would be broken.
Sorting elements
Section titled “Sorting elements”To sort elements efficiently (all at once and with minimal DOM interruption), we need to:
- Find the elements
- Sort based on a set condition
- Insert back in the DOM
<ul id='my-color-list'> <li class="disabled">Red</li> <li>Green</li> <li class="disabled">Purple</li> <li>Orange</li></ul>var $myColorList = $('#my-color-list');
// Elements one layer deep get .children(), any deeper go with .find()var $colors = $myColorList.children('li');/** * Bind $colors to the sort method so we don't have to travel up * all these properties more than once. */var sortList = Array.prototype.sort.bind($colors);
sortList(function ( a, b ) {
// Cache inner content from the first element (a) and the next sibling (b) var aText = a.innerHTML; var bText = b.innerHTML;
// Returning -1 will place element `a` before element `b` if ( aText < bText ) { return -1; }
// Returning 1 will do the opposite if ( aText > bText ) { return 1; }
// Returning 0 leaves them as-is return 0;});// Put it right back where we got it$myColorList.append($colors);Make it cute
Section titled “Make it cute”Add a sort button
Section titled “Add a sort button”<!-- previous HTML above --><button type='button' id='btn-sort'> Sort</button>Set the initial value of sorting direction
Section titled “Set the initial value of sorting direction”var ascending = true;Cache our DOM elements and sortList() out here to minimize our DOM processing
Section titled “Cache our DOM elements and sortList() out here to minimize our DOM processing”var $myColorList = $('#my-color-list');var $colors = $myColorList.children('li');var sortList = Array.prototype.sort.bind($colors);Wrap everything up in a doSort() function
Section titled “Wrap everything up in a doSort() function”// Put the sortList() and detach/append calls in this portable little thingvar doSort = function ( ascending ) {
sortList(function ( a, b ) { // ... });
$myColorList.append($colors);};Add click handler for $('#btn-sort')
Section titled “Add click handler for $('#btn-sort')”$('#btn-sort').on('click', function () { // Run the sort and pass in the direction value doSort(ascending);
// Toggle direction and save ascending = !ascending;});All together now
Section titled “All together now”var ascending = true;
var $myColorList = $('#my-color-list');var $colors = $myColorList.children('li');var sortList = Array.prototype.sort.bind($colors);
var doSort = function ( ascending ) {
sortList(function ( a, b ) {
var aText = a.innerHTML; var bText = b.innerHTML;
if ( aText < bText ) { return ascending ? -1 : 1; }
if ( aText > bText ) { return ascending ? 1 : -1; }
return 0; });
$myColorList.append($colors);
};
$('#btn-sort').on('click', function () { doSort(ascending); ascending = !ascending;});Bonus
Multi-level sorting (grouping sorted elements)
Section titled “Multi-level sorting (grouping sorted elements)”// ...
var doSort = function ( ascending ) {
sortList(function ( a, b ) {
// ...initial sorting...
}).sort(function ( a, b ) {
// We take the returned items and sort them once more var aClass = a.className; var bClass = b.className;
// Let's group the disabled items together and put them at the end
/** * If the two elements being compared have the same class * then there's no need to move anything. */ if ( aClass !== bClass ) { return aClass === 'disabled' ? 1 : -1; } return 0; });
// And finalize with re-insert $myColorList.append($colors);};
// ...Can you take it one step further?
Add another button to toggle disabled group sorting
Section titled “Add another button to toggle disabled group sorting”.html()
Section titled “.html()”You can use this method to replace all of the HTML within the selector. Assuming you have an html element like this
<div class="row"> <div class="col-md-12"> <div id="information"> <p>Old message</p> </div> </div></div>You could use .html(). to remove and add an alert or informational text to alert users all with one line.
$("#information").html("<p>This is the new alert!</p>");