Reputation: 71
I'm working on having a multi-select list where you can have items selected and then click an "Up" or "Down" button that will allow you to reorder those items within the list.
I've got a simple self-contained example:
<html>
<head>
<title>Example</title>
<script src="https://www.google.com/jsapi"></script>
<script>
google.load('jquery', '1.4.1');
</script>
</head>
<body>
<select id="selectedDataPoints" multiple="multiple">
<option>Pig</option>
<option>Duck</option>
<option>Dog</option>
<option>Zebra</option>
<option>Snake</option>
<option>Giraffe</option>
<option>Cow</option>
</select>
<input type="button" id="btnReorderUp" value="Up" />
<input type="button" id="btnReorderDown" value="Down" />
</body>
</html>
<script type="text/javascript">
var DataPointSelector = (function() {
var $selectedList = $('#selectedDataPoints');
$('#btnReorderUp').click(function(e) {
moveUp();
e.preventDefault();
});
$('#btnReorderDown').click(function(e) {
moveDown();
e.preventDefault();
});
function moveUp() {
var select = $selectedList[0];
for (var i = 1, n = select.options.length; i < n; i++)
if (select.options[i].selected && !select.options[i - 1].selected)
select.insertBefore(select.options[i], select.options[i - 1]);
}
function moveDown() {
var select = $selectedList[0];
for (var i = select.options.length - 1; i > 0; i--)
if (select.options[i].selected && !select.options[i + 1].selected)
select.insertBefore(select.options[i + 1], select.options[i]);
}
} ());
</script>
However, the Up/Down button takes literally 3-8 seconds to take effect in IE7/8. The first click will sometimes be fast but after that it takes a very long time for the select list to update with the new positions (especially if you have a couple items selected).
This problem is not present in Chrome/FF. I wouldn't have thought this simple reordering would be so intensive!
Does anyone have any information that could be used to help me speed the moveUp/moveDown functions?!
Upvotes: 7
Views: 1637
Reputation: 49104
IE is slow, slow, slow. So you should check your code to minimize unneeded operations.
@Arron Digulla's idea is good. But also you could minimize processor time by the following changes:
function moveUp() {
var select = $selectedList[0];
for (var i = 1, n = select.options.length; i < n; i++)
var selected = select.options[i],
selectedPrior = select.options[i - 1];
// Don't locate obj/array element more than once
if (selected.selected && !selectedPrior.selected) {
select.insertBefore(selected, selectedPrior);
break; // Since we have found the right elements, don't do
} // any further checking
}
Added: Hmmm, I now see that multiple items can be selected. So you then need to move multiple items, yes? In that case the break statement is not right.
Is the IE UI layer trapping you? -- IE tends not to update the screen's appearance until the JS thread has ended. The workaround is to run the timer with 0 sec. That will yield to the IE rendering engine and enable the screen to update.
Upvotes: 2
Reputation: 328584
Instead of moving the existing DOM elements around, recreate the whole <select>
element including all children for IE.
Upvotes: 4