views:

2121

answers:

5

Here's my goal: do something on an element, an <optgrooup>, if all of its children are invisible.

My code below outlines the in red if it has any invisible children. But I want to do so only if all the children are invisible. If the element has any children that are visible, then don't highlight it.

How can I tweak the jQuery selector to do that?

Thanks in advance.

<select multiple="multiple" name="availableInstanceId" id="availableInstanceId">
<optgroup label="Option Group 1">
   <option >visible item 1</option>
   <option >visible item 2</option>
</optgroup>
<optgroup label="Option Group 2 - Should be highlighted">
   <option style="display:none;">invisible A</option>
   <option style="display: none">invisible B</option>
</optgroup>

<optgroup label="Option Group 3 - Should not be highlighted">
  <option >visible C</option>
  <option style="display: none">invisible D</option>
</optgroup></select>

<script type="text/javascript">
var filterOptions = function(e) {
  // Goal: highlight the <optgroup>'s that have *only* invisible children
  $( '#availableInstanceId > * > *:hidden').parent().css("border","3px solid red");
} 
$(document).ready(function() {
  filterOptions();
});
</script>

Screenshot of image here: http://img144.imageshack.us/img144/556/selectexample.gif

A: 

You'll need to compare an array of all the :visible vs. :hidden

here is some pseudo code

if ($("#element:hidden").length == $("#element:visible").length) {
  // Do  stuff
} ...
Joseph Silvashy
+1  A: 

How about two lines to do it? One to turn it on for every single element, and one to turn it off again for every one with a visible child?

$('#availableInstanceId > *').css("border","3px solid red");
$('#availableInstanceId > * > *:visible').parent().css("border","none");
Samir Talwar
+5  A: 

Assuming you want to exclude elements with no child elements:

 $(":has(*):not(:has(:visible))")

Working example.

Jed Schmidt
+1 So nice I had to abandon my own hacked up rendition of this an put in your code into the example :)
altCognito
Ha, thanks! I'm usually wary of putting so much logic into selectors, but this one was too good to pass up.
Jed Schmidt
Actually, there's a faster way to do this with traversal instead of selection: http://stackoverflow.com/questions/841401/jquery-selection-of-elements-with-no-visible-children/841568#841568
Jed Schmidt
The working example worked fine for me in FF, but not on IE 8 (on XP) - are there known problems with jQuery and IE8?
Glen
Neither of Jed's answers work in IE8, not because jQuery is broken but because IE8 doesn't hide the options!
brianpeiris
Good catch, Brian. Does it work if you use this?$("option") .filter( function return(){ this.style.display == "none" }) .parent().not( $(":visible").parent() )
Jed Schmidt
It doesn't quite work. You have to take it one step further. I've added a community answer with the correct code.
brianpeiris
Awesome! Thanks.
Chris Pietschmann
A: 

This has much better performance than my original answer:

$(":hidden").parent().not( $(":visible").parent() )
Jed Schmidt
+1  A: 

Credit goes to Jed Schmidt. The following code works in IE8.

Note that IE8 does not actually hide the <option> elements despite the display: none style. Also IE8 doesn't seem to accept border styles for <optgroup> elements.

Working sample: http://jsbin.com/aquya (Editable via http://jsbin.com/aquya/edit)

$(document).ready(function() {
  // Prevent CSS inherits
  $("option").css('backgroundColor', 'white')

  $("option")
    .filter(function(){
      return this.style.display == 'none';
    })
    .parent()
    .not($('option').filter(function(){
      return this.style.display != 'none';
    }).parent())
    .css('backgroundColor', 'blue')
    .css('border', '1px solid red'); //this doesn't work in IE8
});
brianpeiris
Thanks, this was great, at least for highlightingUnfortunately, what I really want to do is *hide* the optgroup, not highlight it. I should've said that in the original question - I didn't think it would make a difference, since my main concern was the selector - but it turns out that it does make a difference, since as you mentioned before, IE has a bug with hiding select options (and optgroups - see http://dev.jquery.com/ticket/1100). So it looks like I'm out of luck with IE
Glen
If you don't mind the extra work and complication, you could probably fake it by temporarily deleting the elements you want to hide (I'm guessing, IE might not like that either).
brianpeiris