IE, hiding Option Elements with CSS, and Dealing with innerHTML.
Recently I discovered that IE (yes, 6 and 7) will not allow the option element to be hidden. That is, setting the CSS display property to a value of “none” will have no effect on an option element in Internet Explorer. Not to my surprise, most every other browser will allow you to do this. In fact, if you want to change or hide the options of a select form in IE, you have to literally remove the option element or its text node from the DOM. But as you will see, even that method has issues.
In an effort to find a workaround to the “display:none” anomaly, I thought I might be able to take all the HTML found inside the select element and store it in a variable. Then, when I wanted to show the conditional options of the drop-down menu, I could simply inject the appropriate HTML back into the select element by setting its innerHTML property (from the stored variable). In testing this method, it again works great in most modern browsers. IE, of course, is the exception (yes, both 6 and 7). In this case, the reason is that IE will store/change/interrupt the innerHTML string value as it pleases, and not according to how the code was written. In retrieving the innerHTML property, IE will strip all quotes and then change the case of the HTML elements inside the string.
In short, say goodbye to valid XHTML code being injected back into the DOM. That is, if you can get it back into the DOM (IE seems to struggle with this as well). It’s apparent that IE prefers innerHTML to be used for setting a property value and not for getting or manipulating a value.
Please refer to my last post before (or after) this one!
If the mouse pointer changes to a hand when you roll-over an image associated with a story the image upon clicking either links to enlarged version of the image or a website associated with the image.
If you’re simply looking to hide the element, and not remove it from the DOM, you can give it a height of 0. I’m currently building a ‘smart form’ that has elements initially sized to 0 (overflow:hidden) that grow back to size if they’re needed. A function that gradually increases the element’s size adds a little dhtml flair. This should work in all reasonably modern browsers.
Large sections of this form are added with AJAH with no adverse effect, although I can’t view the generated code in IE. Wrapping the form in an extra div seems to prevent IE’s innerHTML-form problems.
Actually Rick, that doesn’t work either. The idea is to hide a particular option, not the whole select. I’ve been waiting to see commments here, as I’ve got this problem right now.
It appears there is no style that can be applied to an option that will cause it NOT to display in IE6.
Unless someone else has something clever to add
If anyone is interested, I’ll share what I ended up doing.
I have two selects one which is to influence the other. One (master) has three options, RED, BLUE, and ALL. The other (target) has a bunch of options, each with a class of either RED or BLUE.
What I wanted to do was use css to display none/block the options by class, so if RED was selected on the master select, then all the options with a class of blue in the target select would hide. Bloody internet explorer put an end to that nice and tidy solution.
One way around this would be to have three selects, (one with all RED, one with all BLUE, and one with BOTH) and toggle the display of the selects. Semantically, however, this makes no sense.
I could also completely rebuild the select from an array, reading in all the options, clearing the select, and then inserting them as needed.
What I ended up doing, is onready/onload (I use jquery) I read all the options.red into a STRING (instead of an array), and all the options.blue into a string. So i have to gobs of text containing all the red and blue options (in proper XHTML).
I listen for onchange on the master select, and whenever it changes, I remove all the options from the target select, and then, depending on the state of the master, use innerHtml on the target select to put the corresponding options back in.
So master select goes to red, all options removed from target, and the variable containing the plaintext for all the red options is placed in the target select.
Does the trick, works Xbrowser, but is still kind of nasty :)
If you use jquery, the real quick and simple answer (which I used) is to use this handy plugin.
That’s a nice plugin, and I looked at it, but it won’t show and hide options.
There is no way to show a item that has been hidden. Once you remove it, its gone.
If i used the “read the options in an array” option, I could indeed use this plugin to move them in and out of the select, but the overhead would be higher.
There is a nice script on this website: 150 Headlines called innerXHTML.js which is a workaround for IE DOM issues you’re having. In this article it is being used for passing valid XHTML to flash unobtrusive flash enhancement but could easily be used for your purposes as well.
(BTW you really should tell people that you’re only accepting Textile markup in your comments form… took me 10 minutes to hunt it down and get my link working ;-p
@James – I’ll check that out…and yes I’ll add a notice. The site has suffered a bit of change due to upgrades, but a new design is coming.
@Andrew – Yup, I had to remove the option element and then add it back in. I found no other way.
Andrew: I also use js to rebuild selects. Instead of strings, I create an object to hold the data for the options. Properties can be created dynamically, without knowing anything about the data, with the object’s prototype property. I also use the DOM instead of innerHTML for something this small. The performance difference is probably negligible.
And here we have it! The Bug!
Thanks for writing this up. I wrote a nice script that uses jquery to limit the choices in a dropdown based on what was chosen in another dropdown. Then I came in this morning and started testing it on IE. Gah, I hate that thing.
Here’s another idea. I could have a hidden copy of the select with all of the options. When I need to hide something, I remove them from the visible copy. When I need to show them, I clone the hidden copy, manipulate it if neccessary, then copy it in, replacing the visible select. I think this can be done with jquery without too much code. Do you think it will work? I’ll give it a try and report back.
It worked. Here’s some of the code I used if anyone’s interested:
function classChange(itemnum, iclass)
{
newsel = $(‘tr.hiddenitem select.itemcomm’).clone();
if (iclass) {
newsel.find(‘option:not(.’ + iclass +’)’).remove();
// We just removed the blank option, so add it back in
newsel.prepend(”“);
}
newsel.attr({id: ‘riitem’ + itemnum, onchange: “setsel(‘riclass” + itemnum + “’,itemclasses[this.value]);”});
itd = $(‘select#riitem’ + itemnum).parent();
itd.empty();
itd.append(newsel);
$(’#riitem’ + itemnum).val(’‘);
}
Man, I hate IE sooooo much!
Anywho, I found a solution that worked for me, perhaps someone else will find a use for it.
You can use javascript to set the index to ‘null’. Unfortunately, not quite as nice as display: none, but this is an MS world in which we live…
document.getElementById(‘selectID’).options[indexNum] = null;
I guess after you do this all the other options will move up to replace it, and you’ll have to rebuild the select if you want it back.
I need to hide and reshow items dynamically and stumbled into the same problem. After three tries I ended up with some IE specific code. It’s a bit hairy but it seems to work.
The general principle is simple. To hide an option I remove it with the jQuery select plugin, keeping track of the sort order. To reshow it I then scan the options to find the right place to add the option, and then add it back in with the add method on the select. This turned out to be much faster than rebuilding the whole select box from scratch with the innerHTML property (.html() in jQuery).
Note that .add in IE takes an integer as the second parameter instead of a DOM object and does not accept null (see here).
Why there is not a standard Javascript pluggin as it is Java or Flash? Can´t the incompatibility problems between browsers be solved taht way? In fact The SVG pluggin included all the Javascript an you could use it instead of the IE Jscript.
Hmmph… not even ie7 fixes this problem! Can’t believe that.
Thanks to Jay for his solution – I still was dissapointed with the quality, but I guess we do have to accept that we live in a world that is mainly windows and ie.
It also does suck that I have to rebuild… oh well.
Oscar F raises some good points here – why is there not a standard javascript plugin?
Another solution:
However you build your options, cache a reference to each option element in the select, along with whatever info will help you determine their visibility.
Then, something like:
function filter (val) {
var re = RegExp( val, “i” );
$(‘option’,select).remove();
$.each(info,
function(i,item) {
if (re.test( item.value )) {
select.append( item.option_obj );
}
});
}
Here, info is an array of data item objects {value, option_obj} so that order of the options is preserved.
Seems pretty fast for me…
Had the display:none problem on Safari, and on Firefox a multi-select by drag would actually select the display:none options (also keyboard traversal follows the hidden options too). So display:none was not an option even on Firefox (on RedHat FC6).
btw- be nice if this edit window for a message were a tad bigger and actually supported Textile as advertised!