tags:

views:

178

answers:

8

I have bits of horrible code I have to deal with

...
<div class="container">
   ...
    <tr>
    <td width="100" height="50">
         <a class="swaps"><img src="http://www.blah.jpg" alt="Some Title" id="1"></a></span></td>
    </tr>
   <tr>
    <td width="100" height="50">
        <a class="swaps"><img src="http://www.blah2.jpg" alt="Another title" id="2"></a></span></td>
    </tr>
</div>

If I use

var thisone = $("#container .swaps:first")

to select the first one (with id 1) why do I have trouble selecting

thisone.next()?

A: 

You're using :first, which cuts the set down to one, so there is no "next". You could try using :first-child instead.

Chad Birch
A: 

In your example thisone.next() should actually get nothing because there is no sibling (at the same level) to the original selection. What you want is the children of thisone, that is an img, using thisone.children("img").

rmarimon
+4  A: 

The HTML is the real one? I don't see any element with id "container" and you're doing

$("#container .swaps:first")

Also, if it's the real HTML, you should fix it a little (close the img tag, and add the opening tag for the span before the </TD>)

Supposing that your HTML is OK this should work for your scenario.

var thisone = $("#container .swaps:first");
thisone.children();

The IMG is not sibling of the anchor, is a child.

Claudio Redi
That returns a blank, unfortunately...?
Rio
+1  A: 

Because, as Jquery docs says:

The :first pseudo-class is equivalent to :eq(0). It could also be written as :lt(1). While this matches only a single element, :first-child can match more than one: One for each parent.

Try using .children() as in $(selector).children();

Ben
+1  A: 

the next() method checks siblings for matches...in your scenario there are no other siblings with .swaps class...try $("#container .swaps")

John Hartsock
A: 

Your selector should be

var thisone = $("div.container a.swaps:first");
var img = thisone.children(img);

Also your id is invalid. You can't start an id with a number.

rahul
A: 

First off, I know it isn't your code, but IDs should never start with or only contain a number.

I'm not sure what you are trying to do, but I think it would be easier if you just iterate through all the .swaps like this:

$('#container .swaps').each(function(){
 var swapImg = $(this).find('img');
 // do something else
})
fudgey
+1  A: 

jQuery's next() function returns the next sibling as they appear in the DOM tree (not in jQuery resultset) for all matched elements. So calling

$("#container .swaps:first")

gets the first anchor, and calling next() on it returns undefined as it has no next sibling. I think you might want to implement the Iterator pattern if you want to access the nodes successively by calling next().

The jQuery object is an array of items. You could just store the current index in a variable, and increment it after getting the next element.

// Naive way
var items = $("#container .swaps");
var i = 0;
items[i++] // first <a>
items[i++] // second <a>

Here are two implementations that wrap the above functionality using the Iterator pattern - one that works as a jQuery plugin, the other is basically a separate function. Both work the same:

// Iterator function
function Iterator(list) {
    var results = list;
    var i = 0;

    this.next = function() {
        return results[i++];
    };

    return this;
}

// Usage
var iterator = Iterator($("#container .swaps"));
iterator.next() // first <a>
iterator.next() // second <a>

The second one is almost identical to the first one, but is used a jQuery plugin instead:

// jQuery plugin
$.fn.iterator = function() {
    var i = 0;

    this.next = function() {
        return this[i++];
    };

    return this;
};

// Usage
var iterator = $("#container .swaps").iterator();
iterator.next() // first <a>
iterator.next() // second <a>

Javascript 1.7 has some cool features in generators and iterators for doing just this, but it's not still not widespread - only Firefox supports it as far as I know.

Anurag
Thank you for a very comprehensive answer.
Rio