13

I feel like this question has been asked before but the answers seem pretty specific to each poster.

I'm looking for a way to identify a given element and find the next element that has a particular class. I don't want to have to deal with parent() or children() since I'm parsing through a table and I don't want it to stop at the end of a row or even the end of the table itself (there are two side-by-side).

Is there any way to just search the entire page for the next instance of an element?

BACKGROUND INFO: http://jsfiddle.net/HKkAa/2/

I'm trying to iterate through the bottom table starting at the highlighted cell and applying the "highlight" class to each cell until I reach the end date. I have a way to calculate when I've reached the end date, I just need the magic method to select the next instance of a link.

webo
  • 307
  • 1
  • 3
  • 12
  • You should try to make a smaller testcase, I still dont get what you want to achieve. – Nelson Oct 13 '12 at 12:22
  • My main goal is to add the "highlight" class to each date between the start and end dates and have it work across both months if need be. I can calculate the number of days between the start and the end to determine when the loop should end but I need the logic to select the next date cell (regardless of what row or table element it is in) – webo Oct 13 '12 at 12:31
  • This answer that I wrote for another question might help. http://stackoverflow.com/a/11560428/921204 – techfoobar Oct 13 '12 at 12:32

4 Answers4

14

Edit

For anyone interested, I've plugin-ified this here: https://github.com/techfoobar/jquery-next-in-dom


There is no built-in way of doing this in jQuery if you want it to be completely generic and able to satisfy all/any DOM structure. I once worked out a simple recursive function that does this. It goes like:

function nextInDOM(_selector, _subject) {
    var next = getNext(_subject);
    while(next.length != 0) {
        var found = searchFor(_selector, next);
        if(found != null) return found;
        next = getNext(next);
    }
    return null;
}
function getNext(_subject) {
    if(_subject.next().length > 0) return _subject.next();
    return getNext(_subject.parent());
}
function searchFor(_selector, _subject) {
    if(_subject.is(_selector)) return _subject;
    else {
        var found = null;
        _subject.children().each(function() {
            found = searchFor(_selector, $(this));
            if(found != null) return false;
        });
        return found;
    }
    return null; // will/should never get here
}

And you can call it like:

nextInDOM('selector-to-match', element-to-start-searching-from-but-not-inclusive);

For ex:

var nextInst = nextInDOM('.foo', $('#item'));

will get you the first matching .foo after $('#item') regardless of the DOM structure

Check the original answer here: https://stackoverflow.com/a/11560428/921204

Community
  • 1
  • 1
techfoobar
  • 65,616
  • 14
  • 114
  • 135
  • 1
    That worked great, pretty much a plug and play operation there. Is there a reason why this kind of function isn't included in Jquery already? – webo Oct 13 '12 at 12:53
  • 3
    Maybe they didn't find enough usecases to warrant inclusion in the core. However, i think it'll be rather useful. – techfoobar Oct 13 '12 at 13:11
2

The following code allow you to find the next element that matches a selector, whatever the DOM structure.

$.fn.nextThrough = function(selector) {
    // Our reference will be the last element of the current set
    var $reference = $(this).last();
    // Add the reference element to the set the elements that match the selector
    var $set = $(selector).add($reference);
    // Find the reference position to the set
    var $pos = $set.index($reference);
    // Return an empty set if it is the last one
    if ($set.length == $pos) return $();
    // Return the next element to our reference
    return $set.eq($pos + 1);
}

// Usage example
$(':focus').nextThrough('input:visible').focus();
tzi
  • 8,719
  • 2
  • 25
  • 45
1

Let's assume you are searching for class '.foo'. If you want you can wrap it in a function to be reusable.

var $yourelement;
(...)

var $allElements = $('.foo');
var $nextElement = $allElements[$.inArray($yourElement,$allElements)+1];

This will return $allElements[0] if $yourElement is the last one (making it a circular list)

fmsf
  • 36,317
  • 49
  • 147
  • 195
0

I would use a recursive function like this :

function findNext($element, selector) {
    while ($element) {
        var ne = $element.find(selector);
        if (ne.length) return ne;
        ne = $element.next(selector);
        if (ne.length) return ne;
        $element = $element.parent();
        if ($element.length==0) return null;
        $element = $element.next();
        if ($element.is(selector)) return $element;
    }       
}

It searches the first element next to $element and goes up a level if needed before to advance and dive again

You may test it here (open the console to see the "next" element with a selector).

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758