user1236048
user1236048

Reputation: 5602

Chained selectors in jQuery: apply selector in already filtered results

IGNORE: http://jsfiddle.net/gulcoza/9cVFT/1/

UPDATED FIDDLE: http://jsfiddle.net/gulcoza/9cVFT/4/

The whole code is in the above fiddle, but I will explain here also:

HTML

<ul>
    <li id="e1">1</li>
    <li id="e2" class="hidden">2</li>
    <li id="e3">3</li>
    <li id="e4" class="hidden">4</li>
    <li id="e5">5</li>
    <li id="e6">6</li>
    <li id="e7">7</li>
    <li id="e8">8</li>
    <li id="e9">9</li>
    <li id="e10">10</li>
</ul>

jQuery

console.log(
    $('ul li:visible:nth-child(4n)')
);

My Expected result: li#e6, li#e10 - why? because I want the 4n elements only from the visible ones.

But

Actual Result: I get the 4n element from all only if they are visible.

console.log(
    $('ul li:visible').filter(function(index) {
        if ((index + 1) % 4 ==0) return true;
    })
);

I am interested in any nicer solution than the following one:

console.log(
    $('ul li:visible').filter(function(index) {
        if ((index + 1) % 4 ==0) return true;
    })
);

UPDATED FIDDLE:

http://jsfiddle.net/gulcoza/9cVFT/4/

Why doesn't number 4 work. At the moment filter is called the results should be filtered already, IMHO. :|

// 4 - could be a nice solution
console.log(
    $('ul li:visible').filter(':nth-child(4n)')
);

Why doesn't this work? At $('ul li:visible') moment only the visible one should be available.

Upvotes: 3

Views: 203

Answers (2)

Bill
Bill

Reputation: 3517

As you now know - the best way to do this is your way.

The reason this was not working as you expected is because the :nth-child pseudo selector is selecting elements based on their position within the parent element.

Note also that the selector string is a string of CSS selectors, and are not to do with JavaScript.

I found a good answer on another question about JS/CSS here

I would suggest you create your own method like this:

$.fn.nthChildren = function(n){
    this.filter(function(index) {
        if ((index + 1) % n ==0) return true;
    })
}
console.log(
    $('ul li:visible').nthChildren(4);
);

Upvotes: 1

Ram
Ram

Reputation: 144689

That's because nth-child matches elements on the basis of their positions within a parent element’s list of child elements not on the basis of jQuery Collection (selected elements), in this you have to use filter method, filter method is also faster that chained-string selectors.

This is how the selectors filter the elements:

$('ul li:nth-child(4n):visible') 
//       ^            ^---- [li#e8]
//       |  
//       | --- [li#e4.hidden, li#e8]

$('ul li:visible:nth-child(4n)') 
//       ^            ^---- [li#e8]
//       |  
//       | --- [li#e1, li#e3, li#e5, li#e6, li#e7, li#e8, li#e9, li#e10]
//             [1,     3,     5,     6,     7,     8,     9,     10]

Upvotes: 2

Related Questions