Let us suppose I have this markup
First
Hi
Hello
Second
The previous answers work fine IF the elements in question are siblings (which they are in the original question) but a more general solution would consider the following scenario:
<div id="top">
<div>
<div>
<h3 id="first">First</h3>
<p>Hi</p>
<p>Hello</p>
</div>
</div>
<div>
<h3 id="second">Second</h3>
<p>Bye</p>
<p>Goodbye</p>
</div>
</div>
A more general solution would be:
$.extend($.fn, {
isBefore: function(sel, context) {
// Get all element within the context.
var all = $(context || document).find("*");
return all.index(this[0]) < all.index($(sel));
},
isAfter: function(sel, context) {
return !this.isBefore(sel, context);
}
});
Where "context" is an optional parameter that merely limits the search area for jQuery to improve performance. I haven't performed any tests but "context" is probably unnecessary since $("*") seems to execute qualitatively fast. Also note that index() will return -1 is either element is not within the context.
$("#first").isBefore("#second");
// Gives the same result as
$("#first").isBefore("#second", "#top");
Of course this all assumes that by "before" and "after" you mean their order in the document model. If you are concerned about their relative positions on the display you would want to examine the elements display coordinates relative to the document as "relative", "fixed" and "absolute" CSS positions make anything possible.
Rocket's solution works fine if sel
is a real selector, if you pass a jquery object though, it won't work.
If you want a plugin that works with both selectors and jquery objects, just use my slightly modified version instead:
(function($) {
$.fn.isAfter = function(sel){
return this.prevAll().filter(sel).length !== 0;
};
$.fn.isBefore= function(sel){
return this.nextAll().filter(sel).length !== 0;
};
})(jQuery);
Kudos to Rocket for the original solution.
I implemented a general isAfter
function, which considers the depth and DOM tree and can correctly determine if a
is after b
even if they are in 2 different subtrees:
<div>
<div>
<p class="first">I come first</p>
</div>
</div>
<div>
<div>
<p class="second">I come second</p>
</div>
</div>
you can find it in my GitHub Repository. Would appreciate your feedback on the code
To see if an element is after another, you can use prev() or prevAll() to get the previous element(s), and see if it matches.
And to see if an element is before another, you can use next() or nextAll() to get the next element(s), and see if it matches.
$.fn.isAfter = function(sel){
return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
return this.nextAll(sel).length !== 0;
}
DEMO: http://jsfiddle.net/bk4k7/
The answer:
$.fn.isAfter = function(sel){
return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
return this.nextAll(sel).length !== 0;
}
Was selecting all previous elements or next elements regardless of the selector (sel) so I made the following modifications that select elements based on class:
$.fn.isAfter = function(sel){
sel = "." + sel.attr("class").replace(/ /g, ".");
return this.prevAll(sel).length !== 0;
}
$.fn.isBefore= function(sel){
sel = "." + sel.attr("class").replace(/ /g, ".");
return this.nextAll(sel).length !== 0;
}
You can use the index() function:
$('p').each(function(){
var index = $(this).index();
if(index > $("#first").index() && index < $("#second").index()) {
// do stuff
}
});