Make a multiple select box printable in IE9
Posted by Stephan onRecently I had to solve a small print bug in IE9 that turned out a lot harder than I thought. In short, the problem is as follows: I have a <select multiple="multiple"> on a page, with enough <option>s in it to have a scrollbar. On the screen this is all fine, but when trying to print that box in IE9, the overflowing elements are always visible.
Because I wasn’t able to reproduce it in the browser, here’s an actual photo of a printed multiple select:
The only question on StackOverflow I could find about it only had one (unaccepted) answer with one upvote at the time. This didn’t bring much hope. I tried a couple of CSS solutions, but even giving it a negative z-index and putting a div with a background color and a higher z-index below it wouldn’t hide the overflowing content. Maybe there’s some very elaborate CSS trick to fix it, but instead I went for a jQuery solution.
The script does a few simple things: when called (and the browser is IE), it recreates the content of the <select multiple> but puts it in a <div> instead, transforming each <option> into a checkbox with a label. The checkboxes are hidden, but allow me to easily copy the selected state of each of the options.
A few simple CSS rules serve to recreate the look and feel of the multiple select element as possible. The script also copies the classes on the select onto the div, so that you’re able to style it a bit more.
The script
//jQuery required
$(function() {
if($.browser.msie) return false;
$('select[multiple]').each(function() {
$lPrintableDiv = $('<div data-for="' + this.id + '" />').addClass($(this).attr('class')).addClass('printable');
//update printable on changes
$(this).after($lPrintableDiv).change(function($aEvent){
updatePrintable($aEvent.target);
});
//run once on load
updatePrintable(this);
});
});
function updatePrintable($aTarget) {
var $lSelect = $($aTarget);
var $lSelected = $($aTarget).val();
var $lPrintable = $('[data-for="'+$aTarget.id+'"]');
$($lPrintable).width($lSelect.width()).height($lSelect.height());
$($lPrintable).html('');
$($aTarget).children().each(function($lElm){
$lVal = $(this).val();
$lLabel = $('<label />').text($lVal);
$lOption = $('<input type="checkbox" />').val($lVal);
if($(this).is(':selected'))
$lOption.prop('checked', true);
$lPrintable.append($lOption).append($lLabel);
});
}
The styles
.printable {
border: 1px solid grey;
display: none;
overflow: auto;
}
.printable label {
display: block;
font: .8em sans-serif;
overflow: hidden;
white-space: nowrap;
}
.printable [type="checkbox"] {
display: none;
}
.printable [type="checkbox"]:checked + label {
background: #3399ff;
color: white;
}
@media print {
select[multiple] { display: none; }
.printable { display: inline-block; }
.printable [type="checkbox"]:checked + label { background: grey; }
}
This will style the div just like a regular multiple select, and only show it when you’re in print mode.
And of course, here’s a jsFiddle demo for you to play around with. I commented out the display: none for the printable element so that you can see how it behaves as you update the selections. Comment out the second rule in the JavaScript to be able to test it in another browser than IE.
