views:

98

answers:

3

I hate to admit it but I'm stuck trying to figure out how to do this.

e.g. pretending you have the following structure:

<div>
  ...
  <div>
    <ul>
      <li>
        <a href="..."><img class="foo"/></a><!-- "previous" -->
      </li>
      <li>
        <a href="..."><img class="bar"/></a>
      </li>
      <li>
        <a href="..."><img class="foo"/></a><!-- I'm at this node -->
      </li>
      <li>
        <a href="..."><img class="baz"/></a>
      </li>
      <li>
        <a href="..."><img class="foo"/></a><!-- "next" 1 -->
      </li>
    </ul>
  </div>
  ...
  <div>
    <ul>
      <li>
        <a href="..."><img class="foo"/></a><!-- "next" 2 -->
      </li>
      <li>
        <a href="..."><img class="baz"/></a>
      </li>
      <li>
        <a href="..."><img class="foo"/></a><!-- "next" 3 -->
      </li>
      <li>
        <a href="..."><img class="bar"/></a>
      </li>
    </ul>
  </div>
</div>

I'm in a jQuery event handler related to the highlighted "foo" node above. I want to find the "next" img element that is a "foo".

There's 2 problems though.

  1. I only want to select "foo" elements that are further in the DOM than the current node I'm at (e.g. the "previous" foo's, and the current foo are not desired)
  2. Although I've shown the nesting as a following a precise pattern, the generated code is/could be nested at any level... thus I can't just do .parent().parent().parent().siblings().find()... etc.

If you can imagine that every time the browser adds a node to the DOM it increments a counter and assigns the node that index... that you could retrieve... what I want is:

var here = $(this).getIndexInDOM();//e.g. returns 347
$('img.foo').each(function(){
  if($(this).getIndexInDOM() > here){//is this past our current index?
    doSomething($(this));//use it
    break;
  }
});

The .getIndexInDOM() method obviously doesn't exist in jQuery... but I'm curious if anyone has a solution to get the "next" element I'm after.

The only solution I can think of at the moment is really in-elegant and would perform pretty lousy when in the latter half of the images in the DOM...

//using vanilla JavaScript
var thisImg = theCurrentImageIHave;//some reference to the DOM element
var found = false;
for(var i=0;i<document.images.length;i++){
  if(found){
    if(document.images[i].className == 'foo'){
      doSomething(document.images[i]);
      break;
    }
  } else {
    if(document.images[i] == thisImg){
      found = true;
    }
  }
}
+1  A: 
JasCav
`next()` only searches siblings, I thought?
Isaac Lubow
JasCav - `.next()` only works for siblings. Read the question again. OP states *"I'm in a jQuery event handler related to the highlighted "foo" node above."* There are no siblings to the highlighted `.foo`. Some sort of *up then over* traversal is needed. :o)
patrick dw
@JasCav - according to the docs http://api.jquery.com/next/ .next() only traverses the siblings of the current node (this in my example, it would only find "next 1"... if "next 1" wasn't there, it wouldn't find "next 2" or "next 3")
scunliffe
@scunliffe @patrick @Isaac - You're all correct. :-( I fail. Updated my answer. I think that's correct (I've used it before to solve a similar problem.) I'm not the best jQuery-er in the world. I'm learning too. Thank you for the correction.
JasCav
Hmmm, .gt() might work here... I would still need to iterate over the full set to find out my "current" index first though I guess.
scunliffe
@scunliffe - Yeah. That is a bit of a downside. I wasn't sure if you were already keeping track in some way (like maybe you were inside an each() statement where you can track the index easily enough). I hope this at least points you in the correct direction.
JasCav
+2  A: 

Inside the click handler, try this:

Example: http://jsfiddle.net/QVphP/ (click a blue box to add a border to the next one)

var $foo = $('img.foo');  // get all .foo images

var idx = $foo.index( this );  // get the index position of "this"
                               //    relative to all the .foo images found

var next = $foo.eq( idx + 1 ); // grab the .foo for the incremented index
patrick dw
@patrick dw - awesome! the .index() is exactly what I need here... and if I were using jQuery v1.4 I'd jump on it in a heartbeat ;-) but alas I'm not there yet so I'll need to loop a bit to get the index myself.
scunliffe
@scunliffe - jQuery 1.4 is not required when you're passing a DOM element (as in the example above). The two other uses of `.index()` require 1.4. :o) Here's the same example, but using `jQuery 1.3.2` instead: http://jsfiddle.net/QVphP/1/
patrick dw
oh, man I've been staring at my code too long, you're right... .index(element) is supported in jQuery 1.0+ time to add a fix to my fix ;-)
scunliffe
A: 

Check out this jsfiddle. Click any image with a red border (foo) and the next red border (the next foo) will change to yellow.

Depending on how many foos you have in the page, this solution could be a bit of a performance hit. But since you aren't on 1.4 yet, this will work.

Nate Pinchot
Nate - OP was mistaken about needing 1.4. Your solution would work, but you wouldn't really need to use anything quite so complicated using `.data()`. Here's your example updated: http://jsfiddle.net/Bs2M5/2/ It just uses `==` to compare the DOM elements. :o)
patrick dw
@patrick very nice :)
Nate Pinchot