Reverting Chains with end() and addBack()
In this page:
$(selector).find(child).action().end().action();
$(selector).find(child).addBack().action();
Using end()
Calling .end() undoes the most recent filtering or traversal step in a chain, restoring the selection jQuery held right before it. This lets you branch off from a selection, do something, then return to continue working with the original set.
Example: Using end()
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<section id="demo">
<ul id="list"><li class="a">One</li><li>Two</li></ul>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
$("#runBtn").click(function() {
const result = $("#list").find(".a").css("color", "red").end().find("li").length;
$("#output").text(JSON.stringify(result));
});
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
});
</script>
</body>
</html>
Chaining with end()
end() is helpful when one long chain needs to work on multiple levels of related elements -- find a child, act on it, end() back to the parent, then find a different child -- without breaking the chain into separate statements.
Example: Chaining with end()
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
#box { background:steelblue; color:#1a1a1a; padding:10px; border-radius:4px; display:inline-block; margin:10px 0; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<section id="demo">
<div id="box"><p class="a">A</p><span class="b">B</span></div>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
$("#runBtn").click(function() {
$("#box").find(".a").css("color", "red").end().find(".b").css("color", "blue");
});
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
});
</script>
</body>
</html>
Using addBack()
addBack() adds the previous selection back into the current set instead of fully discarding it, combining both selections together. This differs from end(), which discards the current step; addBack() keeps both the current and prior elements.
Example: Using addBack()
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<section id="demo">
<ul id="list"><li>One</li><li class="a">Two</li></ul>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
$("#runBtn").click(function() {
const set = $("#list").find("li").filter(".a").addBack();
$("#output").text(set.length);
});
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
});
</script>
</body>
</html>
end() vs addBack()
end() moves back to the previous selection, dropping whatever the last traversal or filter step added. addBack() instead merges the previous selection into the current one, so you end up with elements from both steps combined.
Example: end() vs addBack()
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<section id="demo">
<ul id="list"><li>One</li><li class="a">Two</li></ul>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
$("#runBtn").click(function() {
$("#output").empty();
$("#output").append($("<div>").text("end(): " + $("#list").find("li").filter(".a").end().length));
$("#output").append($("<div>").text("addBack(): " + $("#list").find("li").filter(".a").addBack().length));
});
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
});
</script>
</body>
</html>
Traversal Chain Practice
These methods help keep complex traversal chains readable by avoiding repeated variable assignments just to remember an earlier selection. A long chain that dips into children, filters them, and returns to the parent stays as one continuous statement.
Example: Traversal Chain Practice
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
#box { background:steelblue; color:#1a1a1a; padding:10px; border-radius:4px; display:inline-block; margin:10px 0; }
button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
#resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
#output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
#demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
#demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
#demo :where(table) { border-collapse:collapse; }
#demo :where(td, th) { border-radius:0; }
#demo :where(input, select, textarea) { margin:4px 0; }
</style>
</head>
<body>
<button id="runBtn">Run</button>
<button id="resetBtn">Reset</button>
<section id="demo">
<div id="box"><p class="a">A</p></div>
</section>
<div id="output"></div>
<script>
var original = $("#demo").html();
$("#runBtn").click(function() {
$("#box").find(".a").css("color", "red").end().css("border", "1px solid black");
});
$("#resetBtn").click(function() {
$("#demo").html(original);
$("#output").empty();
});
</script>
</body>
</html>
- Expecting
.end()to undo every earlier step, when it only reverts the single most recent filter or traversal in the chain. - Using
.end()after a method that does not change the selection, such as.addClass(), and ending up one step further back than intended. - Confusing
.addBack()with.end();.addBack()merges the previous set into the current one, while.end()replaces the current set with the previous one.
- DOM traversing moves from one element to related elements: ancestors, descendants, and siblings.
- Filtering,
is(), andhas()narrow and test sets of elements. each(), mapping, andend()withaddBack()iterate over matches and control jQuery chains.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: