Nick
Nick

Reputation: 6025

jQuery: quickest way to determine if at least one child in a container is visible

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

Answers (5)

Samson
Samson

Reputation: 2821

var isVisible;
$(this.children('div')).each(function() {
    if ($(this).is(":visible")) {
        isVisible = true;
        return false;
    }
});

Upvotes: 0

Adil
Adil

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.

  1. Width and height is zero
  2. style.display is none

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

Rob W
Rob W

Reputation: 349102

JSPerf of all methods on this page

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

qwertymk
qwertymk

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;
    }
}

source

Upvotes: 1

algiecas
algiecas

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

Related Questions