Find the next element that comes later in DOM

Probably better in javascript, but this can sure include jQuery, or any such library.

I want to find the first .next in the example below.

There are a lot of answers to similar questions that suggest nextAll or siblings... Both are useless here:

$(function(){
  $('.result').text(
    $('.origin').nextAll('.next').text()
      || $('.origin').siblings('.next').text()
      || 'both failed'
  )
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="whatever">
  <p class="result"></p>
  <p class="origin">1</p>
</div>
<p class="next">2</p>
<p class="next">3</p>

Also, what'd be the most compatible (browser and library wise) and most performatic (speed and less lines of code) way to do it so?

Answers:

Answer

Based on the awesome answer by @mrtsherman, I wrote this more complete solution and tested it to work on Chrome and Safari:

$(function() {
  $('.result').text(
    $('.origin').below('.next').text()
  );
});

(function($) {
  $.fn.below = function(sel) {
    var $result = $(sel).first();
    if ($result.length <= 0) {
      return $result;
    }
    $result = [];
    var thisIndex = $('*').index($(this));
    var selIndex = Number.MAX_VALUE; // Number.MAX_SAFE_INTEGER is not yet fully supported
    $(sel).each(function(i, val) {
      var valIndex = $('*').index($(val));
      if (thisIndex < valIndex && valIndex < selIndex) {
        selIndex = valIndex;
        $result = $(val);
      }
    });
    return $result;
  };
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="whatever">
  <p class="result"></p>
  <p class="origin">1</p>
</div>
<p class="next">2</p>
<p class="next">3</p>

I will probably try to submit a PR for this on jQuery lib, because I believe...

This should be a core method on jQuery! :P


In fact, I just ran a very simplistic test on this, and it performed even better than nextAll for this simple example. Almost twice as fast! :o

Answer

If you can use IE9+ you can try compareDocumentPosition(). A simple jQuery plugin would look something like this:

$.fn.below = function(selector) {
  var el = this[0],
      compare = $(selector),
      nextEl;

  compare.each(function(i, item) {
    var result = el.compareDocumentPosition(item);
    // get the first one that appears below `this`
    if (result === 4) {
      nextEl = $(item);
      return false;
    }
  });
  return nextEl || $();
};

This could probably be cleaned up/simplified a bit. But it works nicely. Here is a codpen:

http://codepen.io/ZevanRosser/pen/QbjZmr?editors=101

compareDocumentPosition() returns a number which has the following meaning:

(where p1.compareDocumentPosition(p2))

1: No relationship, the two nodes do not belong to the same document.

2: The first node (p1) is positioned after the second node (p2).

4: The first node (p1) is positioned before the second node (p2).

8: The first node (p1) is positioned inside the second node (p2).

16: The second node (p2) is positioned inside the first node (p1).

32: No relationship, or the two nodes are two attributes on the same element.

Note the above was just copied from: http://www.w3schools.com/jsref/met_node_comparedocumentposition.asp

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.