Reputation: 6025
What is the quickest way to determine if at least one child div
in a div
container is visible?
I've been using this:
if ($this.children('div:visible').length) {...
but it's slow because it examines all the children (of which there are a lot).
I'm guessing the fastest method will stop searching as soon as it's found the first visible element, but whatever is fastest wins :)
BTW:
My actual situation is a major container which contains about 100 minor containers, each of which contain up to 100 elements. I want to determine which minor containers have at least one visible element. The elements at the bottom are being hidden and shown by various classes.
Thanks.
Upvotes: 1
Views: 1919
Reputation: 2821
var isVisible;
$(this.children('div')).each(function() {
if ($(this).is(":visible")) {
isVisible = true;
return false;
}
});
Upvotes: 0
Reputation: 148150
Try this, Use each for iterating and returning false on match could decrease the iteration could.
isAtleastVisible = false;
$this.children('div').each(function (){
if($(this).is(':visible') == true)
{
isAtleastVisible = true;
return false; //This will break each loop at the first visible div
}
});
if(isAtleastVisible)
alert("atleast one is visible");
else
alert("None is visible");
This will increase the performance and it depends on the the first occurrence of visible div. If it is first one out of hundred only one iteration will be required and if it is hundredth out of hundred then hundred iteration will be required and there will not be any performance increase.
As @Rob W explained in answer about the working of is('visible') which shows the function checks the visibility by these parameters.
You can use one of these to increase performance suppose the elements are hidden by setting display = none. This condition could replace jQuery method .is(':visible') == true with javascript statement .style.display == 'block'
isAtleastVisible = false;
$this.children('div').each(function (){
if(this.style.display == 'block')
{
isAtleastVisible = true;
return false; //This will break each loop at the first visible div
}
});
Upvotes: 1
Reputation: 349102
.each()
and .is(':visible')
is the slowest method. My/qwertymk's method turns out to be faster than the OPs solution, in the case that all elements are visible. However, when all elements are hidden, the original method seems to be optimal.Edited: The reason that my original method is faster is that it used .find('>' + selector)
, where .children()
has to be used (which loops through all children, and checks whether the element matches a selector).
Since div
is a natively supported selector, and the test case does not contain deeply nested elements, my solution turned out to be fast. But after normalizing it, it looks almost equal to qwertymks solution. The JSPerf of these two solutions will show that his solution is slightly faster, because it has one less function call.
The solutions on this page are generic: The code below can be optimized for specific cases (such as the fact that the selector is just a tag): http://jsfiddle.net/kFZJs/
To speed up the progress, split up the selector, because :visible
is not a native CSS selector.
The preferred solution should use as few jQuery as possible, because the desired solution has to be performant. To do so, examine the logic of :visible
.
The original function contains jQuery.support.reliableHiddenOffsets
. This can safely be stripped in favour of performance when your childs are not table cells (which is only used in IE8-).
Now, write a jQuery plugin (it's not expensive):
(function($) {
$.fn.hasAtLeastOneVisibleChild = function(selector) {
var $col = this.children(selector), i, elem;
for (i=0; i<$col.length; i++) {
var elem = $col[i];
if (elem.offsetWidth !== 0 || elem.offsetHeight !== 0) {
return true;
}
}
return false;
};
})(jQuery);
// Usage:
$this.hasAtLeastOneVisibleChild('div'); // True or false
Upvotes: 5
Reputation: 35284
Do it youself:
var $container = $('#container'), $children = $container.children(), found = false;
for (var i = 0; i < $container.length; i++) {
var elem = $children[i];
if (!( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none")){
found = true;
break;
}
}
Upvotes: 1
Reputation: 2128
One way would be to iterate through children by using each(). But this will be as slow as your code if the visible element is the last one :)
Another option would be to check the height of the container.
if($('#container').height() > 0) { ... }
If the children takes space (height), then the container will have height > 0 as well.
Upvotes: 3