<select> only shows first char of selected option
Asked Answered
V

8

46

I have a standard select box which I'm populating using jquery by appending options, but for some reason IE9 only shows the first character of the selected option. Needless to say it works perfectly in FireFox and Chrome, but I have to support IE9. I tried the IE9 compatibility modes, but it made no difference, nor does styling the select or option.

Has anyone seen this issue before. What caused it? How did you fix it?

Example of problem in IE9

Simplified code sample:

<select id="selectCCY" ValueColumn="ccyID" DisplayColumn="ccySymbol" ></select>



$.each(res.result, function (key, value) {  
    $('#selectCCY').append('<option value="' + value[$('#selectCCY').attr('ValueColumn')]+ '">' + value[$('#selectCCY').attr('DisplayColumn')] + '</option>');
});

res.result is a simple json array like this:

[{"ccyID":1,"ccySymbol":"GBP"},{"ccyID":2,"ccySymbol":"AUD"},{"ccyID":3,"ccySymbol":"USD"}]

OH BUGGER!!! it works fine in my simplified example, so the problem is somewhere else. Sorry. The original code is to long and complex to paste here, but will let you know when I find the answer.

some time later....

OK, I got the problem down to an ajax call inside a $(selector).each() loop. The loop goes through all select boxes and asyncronously populates the options. If I make it a syncronous call, the select boxes have the correct width and show correctly, but if its an async call the select boxes only show the first char as in the image. still working on this, will get back to you again.

I still want to know what would cause a select box to display incorrectly. I can do workarounds and get it to show correctly, but that doesn't answer the question. It's just a select with options in it, it should always just work, right?

after a weekend of ignoring the issue ....

Right I found a workaround. Before doing the ajax call to populate the select box I first set the css display property to 'none' on it, then populate it and finally when the ajax call and population is complete I just remove the css display 'none' property.

So I still don't know why IE doesn't like me, but we have a solution at least.

Vanadium answered 6/5, 2011 at 8:2 Comment(9)
sigh What does the markup or code you use to populate the select box look like?Ramonitaramos
Just for completeness: What is your jQuery code?Marcin
You can use jsfiddle.net to setup a demo of your code.Doctrine
codez codez codez please we are hungry! ;)Jellaba
"You can use jsfiddle.net to setup a demo of your code." But if you do, be sure to also post the code actually in your question. Not just a link to jsfiddle.net (or jsbin.com).Ramonitaramos
You could try forcing a redraw of the UI after the async call in IE9.Wirth
THis is internet explorer, and to be very honest I don't trust it, this may not be a fault in the code but just a internet explorer errorFrication
For the sake of completeness : I have the same problem with a select of size >0. In this case ALL options are shown with only the first letter visible. As soon as I click on the select or scroll (if there are more options than the size of the select), everything goes back to normal.Jaggers
Heh, you're famous! Question is linked from the knockout.js source code.Dawes
V
17

It is an IE only problem. First set the css display property on the select box to 'none', then populate it via your ajax call, finally when the ajax call is done and the select box is populated remove the css display 'none' property on the select box

Vanadium answered 9/5, 2011 at 7:28 Comment(1)
heh. ya gotta love IE for having those little quirks that make web development so much fun.Refined
H
24

In my case, I didn't have an event hook to hide the select before the ajax request fires, so I had to force a redraw of the select element after the fact. Re-applying the existing width seems to work:

$("select").width($("select").width());
Hockenberry answered 12/7, 2011 at 17:26 Comment(4)
This fixed the issue for me, but introduces another problem in my case: This will set the style attribute of the select item to a width that is too short. My guess is that this line is run before CSS width settings are run, and because this js line sets the inline style, it overrides the CSS.Shulock
This is such a stupid bug. This answer got me to the solution, but I had to do it twice like this: $("#mydropdown").width($("select").width()); $("#mydropdown").width(300);Uncircumcision
Thank you for this. I had to use $('select').css('width', 0).css('width', '').hide().show() to get IE9 to properly update a select multiple where the options would be removed and added dynamically with AngularJS.Hurty
This worked for me, my selected option "Publish Date" was displaying as "Publish" on page load, so i reset select box width in Js on page load and it worked.Sherrisherrie
V
17

It is an IE only problem. First set the css display property on the select box to 'none', then populate it via your ajax call, finally when the ajax call is done and the select box is populated remove the css display 'none' property on the select box

Vanadium answered 9/5, 2011 at 7:28 Comment(1)
heh. ya gotta love IE for having those little quirks that make web development so much fun.Refined
S
11

Based on Jim's answer, I pass the drop-down list into this method:

// force redraw to get around bug in IE.
// NOTE that this removes width from the style attribute.
function forceRedraw(jqueryObject) {
    jqueryObject.css('width', 0);
    jqueryObject.css('width', '');  // remove from style tag
}

This works around the bug in IE, and leaves the width of the element where it was before the method was called as long as the width is specified in CSS, not in the style attribute.

Shulock answered 29/7, 2011 at 12:58 Comment(0)
P
3

I'm using angularjs and also running into this issue in ie8/ie9 This approach/workaround worked for me: e.g. With html looking like this:

<select ng-show="data.showSelect" ng-cloak ng-model="data.model" ng-options="l.id as l.name for l in data.items></select>

I have this code run after data for dropdown is loaded and it fixes the issue

$timeout(function(){$scope.data.showSelect = true;},100);

I suppose you could also wrap this into a directive if you had multiple areas on the site needing this workaround.

Polestar answered 10/3, 2014 at 14:55 Comment(0)
S
1

I had callbacks in my case, so setting the display to none while being populated was not an option for me, however, I was able to elaborate on @Daniel Brinks answer to fix my problem.. Turns out once any item is added and the display is changed from none to nothing, all future added items will be fine.. using jquery and in a widget.. So if you are trying to fix your widget to work in IE this may be useful to you..

in the _create function of the widget:

this.availableFields = $("<select multiple='multiple' name='AvailableFields'></select>")
                                .addClass("ui-fieldselector-available-select")
                                .css("display", "none")
                                .appendTo( this.element );

in the _init function of the widget:

buildAvailableItem - adds to the select

then add to an array that keeps track of the widgets state

var $this = this;
                //IE HACK Part 1--
                $this.buildAvailableItem("Loading...", "Loading..." );
                $this.availableList.push("Loading...");
                //----------------
    //do stuff, here I initialize some functionality, like drag and drop, add click events, etc.
                //IE HACK Part 2--
                $($this.availableFields).css("display", "");
                $this.removeAvailableOption("Loading...");
                //----------------
    // AJAX adding

I normally use a function called addAvailableItem that handles building the item and adding it to the list, but that also triggers an event, and I didn't want an event triggered for the "Loading..." item.

If for some reason someone is using a very slow browser, they will see "Loading..." before it's removed and ajax items are added..

If anyone wants a more copy and paste friendly version let me know

for reference here is build item:

buildAvailableItem: function (display, value)
        {
            $("<option>" + display + "</option>").val(value).appendTo(this.availableFields);
        },
Sublimity answered 26/7, 2011 at 17:45 Comment(0)
G
1

Adding couple of lines the following places (marked in bold as **) in render function of the selectDirective in angular.js worked fine for me. I am looking if there is any other possible solution other than patching angularJS or the forEach given below?

if (existingOption.label !== option.label) {
  lastElement.text(existingOption.label = option.label);
  **lastElement.attr('label', existingOption.label);**
}

and

  (element = optionTemplate.clone())
      .val(option.id)
      .attr('selected', option.selected)
      .text(option.label);
  **element.attr('label', option.label);**

The issue was the label attribute of HTMLOptionElement is not the same as the text attribute if label is blank in IE.

This can be seen verified by adding the following code after the screen has loaded and looking at the web console of FF and IE to see the difference. If you uncomment the last line where the label is set to text it works fine. Alternatively patch angular.js as above.

// This is an IE fix for not updating the section of dropdowns which has ng-options with filters
angular.forEach($("select"), function (currSelect) {
    console.log("1.text ", currSelect.options[currSelect.selectedIndex].text);
    console.log("1.label ", currSelect.options[currSelect.selectedIndex].label);
    //console.log("1.innerHTML ", currSelect.options[currSelect.selectedIndex].innerHTML);
    //console.log("1.textContent ", currSelect.options[currSelect.selectedIndex].textContent);
    //console.log("1.cN.data ", currSelect.options[currSelect.selectedIndex].childNodes[0].data);
    //console.log("1.cN.nodeValue ", currSelect.options[currSelect.selectedIndex].childNodes[0].nodeValue);
    //console.log("1.cN.textContent ", currSelect.options[currSelect.selectedIndex].childNodes[0].textContent);
    //console.log("1.cN.wholeText ", currSelect.options[currSelect.selectedIndex].childNodes[0].wholeText);
    //console.log("1. ", currSelect.options[currSelect.selectedIndex], "\n");

    //currSelect.options[currSelect.selectedIndex].label = "xyz";
    //currSelect.options[currSelect.selectedIndex].label = currSelect.options[currSelect.selectedIndex].text;
});
Griseous answered 14/8, 2014 at 14:12 Comment(0)
T
0

I've just fixed the same issue by changing how the select element was being initialised (dynamically created within a jQuery widget).

Example A

This doesn't work:

var select = $('<select size=7>') // IE9 'first character' bug

This does:

var select = $('<select>').attr('size', 7) // Yay

Example B

Similarly, the following doesn't work:

self.element.append('<select name="mySelect">'); // IE9 'first character' bug

Whereas this will:

var mySelect = $('<select>').attr('name', 'mySelect');
self.element.append(mySelect);

Conclusion

I'd love to be able to explain the above but I'm afraid I can't. Regardless, this might save folk from adding a bunch of CSS hacks to their code unnecessarily.

Tombstone answered 10/3, 2014 at 16:17 Comment(0)
F
0

This is another solution if you want to do it with only CSS:

You can use ch to set the selection width, which takes into account the number of characters. See this example which results in the image below (tested in Chrome v99)

select {
    max-width: 2ch;
    padding-right: 24px;
    box-sizing: content-box;
}

Maybe you need to adjust the 2ch to 2.2ch or something depending on your font.

enter image description here

Ferdinandferdinanda answered 28/3, 2022 at 11:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.