Setting Multi-Select Picker Widths in a SharePoint Form Reliably

In an old post, I sketched out how you could set go about Setting Multi-Select Widths in a SharePoint EditForm.aspx Using JavaScript.  The code I posted there worked just fine, but took some manual tweaking every time you wanted to use it.  The basic idea is this: When SharePoint renders the multi-select control, the <div>s which contain the selects have a fixed width of 143px.  (Who knows where *that* number came from?!?!)  This is all well and good in the example below.  All of the states fit well inside the <div>s and are quite legible.

image

But what about the case where the values in your multi-select column are much longer? In the example below, I’m showing a multi-select column which takes its values from the list of Web Services operations which the jQuery Library for SharePoint Web Services currently supports. (Yes, I keep track of things in SharePoint lists.  Isn’t that wonderfully recursive?)  As you can see, it would be very easy to choose the wrong value from among those which start with “GetGroupCollection” unless you scroll to the right.

image

So what I’d like to do is build a function into the jQuery Library for SharePoint Web Services to deal with this better.  It will become an option on $().SPServices.SPCascadeDropdowns, but clearly it will have usefulness just as a standalone function.  I want this new function to work automagically regardless of the font family and font size.

I’ve asked some of the smart design folks I know, like Michael Greene (@webdes03) and Marcy Kellar (@marcykellar) whether they have any ideas.  Since these bright folks didn’t come up with an instant “Oh, you just…” answer, I don’t feel too bad about not seeing an approach immediately.

It’s pretty easy to figure out what the longest possible value is, and the code below works well. The issue is that the 10px multiplier is just a hack. What I’d like to be able to do is determine the average width of a character in the select and multiply by that. For instance, if the select font-size is 20px, then the 10px isn’t going to work well. (Note that I’ve intentionally left the code very verbose below just to show what I’m doing.)

var maxWidth = 0;
$("select:[Title='Web Service Operation selected values']").find("option").each(function() {
  if($(this).html().length > maxWidth) maxWidth = $(this).html().length;
});
$("select:[Title='Web Service Operation possible values']").find("option").each(function() {
 if($(this).html().length > maxWidth) maxWidth = $(this).html().length;
});
$("select:[Title='Web Service Operation possible values']").parent().css("width", 10 * maxWidth + "px");
$("select:[Title='Web Service Operation possible values']").css("width", 10 * maxWidth + "px");
$("select:[Title='Web Service Operation selected values']").parent().css("width", 10 * maxWidth + "px");
$("select:[Title='Web Service Operation selected values']").css("width", 10 * maxWidth + "px");

image
So, does anyone out there have any good ideas about how to decide what that 10px multiplier ought to be? Remember that it needs to work whatever the font-family and font-size are.

UPDATE 2009-12-18 21:30 – I had a thought on this.  It might work to add a hidden <div> to the page that has 100 characters styled exactly the same as the selects, check the width of that <div>, divide by 100 and then use that result as the multiplier.  It wouldn’t be exact, but it ought to be darn close.  I’ll pursue this approach until I hear something smarter, which I no doubt will!