views:

15290

answers:

2

Hi All,

Thanks for reading. I'm a bit new to jQuery, and am trying to make a script I can include in all my websites to solve a problem that always drives me crazy...

The problem: Select boxes with long options get cut off in Internet Explorer. For example, these select boxes: http://discoverfire.com/test/select.php

In Firefox they are fine, but in IE, the options are cut off to the width of the select when they drop down.

The solution: What I am looking to do, is create a script that I can include in any page that will do the following:

  1. Loop through all the selects on the page.

  2. For each select: A. Loop through its options. B. Find the width of the longest option. C. Bind a function to expand the select to that width on focus (or maybe click...). D. Bind a function to shrink to it's original width on blur.

I've managed to do most of step #2 for one select box.

I found that getting the options width was a problem (especially in IE), so I looped through and copied the text of each option to a span, measured the span width, and used the longest one as the width the select will be expanded to. Perhaps somebody has a better idea.

Here is the code

<script type='text/javascript'>

      $(function() {

         /*
         This function will:
            1. Create a data store for the select called ResizeToWidth.
            2. Populate it with the width of the longest option, as approximated by span width.

         The data store can then be used
         */
         // Make a temporary span to hold the text of the options.
         $('body').append("<span id='CurrentOptWidth'></span>");

         $("#TheSelect option").each(function(i){

            // If this is the first time through, zero out ResizeToWidth (or it will end up NaN).
            if ( isNaN( $(this).parent().data('ResizeToWidth') ) ) {
               $(this).parent().data( 'OriginalWidth', $(this).parent().width() );
               $(this).parent().data('ResizeToWidth', 0);

               $('CurrentOptWidth').css('font-family', $(this).css('font-family') );
               $('CurrentOptWidth').css('font-size', $(this).css('font-size') );
               $('CurrentOptWidth').css('font-weight', $(this).css('font-weight') );

            }

            // Put the text of the current option into the span.
            $('#CurrentOptWidth').text( $(this).text() );

            // Set ResizeToWidth to the longer of a) the current opt width, or b) itself. 
            //So it will hold the width of the longest option when we are done
            ResizeToWidth = Math.max( $('#CurrentOptWidth').width() , $(this).parent().data('ResizeToWidth') );

            // Update parent ResizeToWidth data.
            $(this).parent().data('ResizeToWidth', ResizeToWidth)

          });

         // Remove the temporary span.
         $('#CurrentOptWidth').remove();

         $('#TheSelect').focus(function(){
            $(this).width( $(this).data('ResizeToWidth') );
         });

         $('#TheSelect').blur(function(){
            $(this).width( $(this).data('OriginalWidth') );
         });


           alert( $('#TheSelect').data('OriginalWidth') );
           alert( $('#TheSelect').data('ResizeToWidth') );

      });


   </script>

and the select:

<select id='TheSelect' style='width:50px;'>
   <option value='1'>One</option>
   <option value='2'>Two</option>
   <option value='3'>Three</option>
   <option value='42,693,748,756'>Forty-two billion, six-hundred and ninety-three million, seven-hundred-forty-some-odd..... </option>
   <option value='5'>Five</option>
   <option value='6'>Six</option>
   <option value='7'>Seven...</option>
</select>

Hopefully this will run for you if you want to run it, or you can see it in action here: http://discoverfire.com/test/select.php.

What I need help with: This needs a bit of polish, but seems to work ok if you specify the select box.

However, I don't seem to be able to figure out how to apply it to all select boxes on the page with a loop. So far, I have this:

$('select').each(
   function(i, select){
      // Get the options for the select here... can I use select.each...?
   }
);

Also, is there a better way to get the length of the longest option for each select? The span is close, but not very exact. The problem is that IE returns zero for the option widths of the actual selects.

Any ideas are very welcome, both for the questions asked, and any other improvements to my code.

Thanks!!

+5  A: 

To modify each select, try this:

$('select').each(function(){

  $('option', this).each(function() {
    // your normalizing script here

  })

});

The second parameter (this) on the second jQuery call scopes the selecter ('option'), so it is essentially 'all option elements within this select'. You can think of that second parameter defaulting to 'document' if it's not supplied.

msmithstubbs
Thanks! Bit of clarification - would I bind the focus to the select like option.focus(function(){.....});?
Eli
+3  A: 

I was able to replicate your results for all selects on a page in IE7 using this code, which I find much simpler than the span method you are using, but you can replace the "resize" function with whatever code suits your needs.

function resize(selectId, size){
    var objSelect = document.getElementById(selectId);
    var maxlength = 0;
    if(objSelect){
     if(size){
      objSelect.style.width = size;
     } else {
      for (var i=0; i< objSelect.options.length; i++){
       if (objSelect[i].text.length > maxlength){
        maxlength = objSelect[i].text.length;
       }
      }
      objSelect.style.width = maxlength * 9;
     }
    } 
}

$(document).ready(function(){
    $("select").focus(function(){
     resize($(this).attr("id"));
    });
    $("select").blur(function(){
     resize($(this).attr("id"), 40);
    });
});
Wayne
this is a good idea, although it hard-codes an assumption of fixed-width 9-pixel-wide font. You should probably include the currentoptwidth div part for portability
Jimmy