RobG said:
RobG wrote:
[...]
The code can likely be further optimised - passing around array
references is a bit tricky, I've likely not done the best job of it. The
increase in time is not linear, so there is obviously something more you
can do when the list is greater than say 1,000 names (like setting up
keys for the first letter match).
Had a bit of a play, most (i.e. in nearly all) of the time is consumed
in making the new options.
Also discovered that setting the length of the options attribute to '0'
is quite slow - it is much faster to replace it with a new, empty
element. Note that this saves 100ms for a select with 2,000 options so
for your average select of 10 or 20 options no one will not notice.
It doesn't matter in IE if you set the option length to the new value
then loop through them to modify their attributes or use - new Option()
- to add them one by one, it takes about the same amount of time. The
new Option method is a bit quicker than DOM createElement()...
No feature testing is performed, it should be added.
Final version:
<script type="text/javascript">
var personData =
[
'Smith, John',
'Jones, Mary',
'Zeta, Catherine'
];
// Global to hold current list of options
var currentList = [];
// Replace a select with a new one built from an array
function buildOptions( el, a ){
if ( !el || 'select' != el.nodeName.toLowerCase() ) {
alert('Got a ' + el.nodeName + ', need a \'select\'.');
return false;
}
var j=0, i=a.length;
// for test remove for prod
var f = new Date()
msgTxt += '<br>Start building ' + i + ' options: ' + (f-globTime);
// end test code
// This is the slow bit in IE
if ( i > 0 ) {
var oSel = document.createElement('select');
do {
oSel.options[j] = new Option( a[j], '', false, false );
} while ( ++j < i );
oSel.id = el.id;
// for test remove for prod
var f = new Date()
msgTxt += '<br>Options built: ' + (f-globTime);
// end test code
el.parentNode.replaceChild(oSel, el);
// for test remove for prod
var f = new Date()
msgTxt += '<br>Options added: ' + (f-globTime);
// end test code
}
}
// Copy elements of a to b
function copyArray( a ){
var i = a.length;
if ( i > 0 ){
var b = [];
do {
b[--i] = a
;
} while ( i )
}
return b;
}
// Initialise option list
// el is a select, a is an array of strings to use as options
function initOptions( el, a ){
currentList = copyArray( a );
currentList.sort();
buildOptions( el, currentList );
}
// Filters array 'a' using txt
// Filter from first character, case insensitive
function filterOptions( a, txt ) {
var b = [];
var i = a.length;
if ( i > 0 ) {
var re = new RegExp( '^' + txt, 'i' );
var j = 0;
var found = false;
var stop = false;
do {
found = re.test( a[j] );
if ( found ) {
b.push( a[j] );
if ( !stop ) stop = true;
}
if (!found && stop ) {
// break out of loop when finished finding matches
i = j;
}
} while ( ++j<i )
// If no matches, give b one element
if ( 0 == b.length ) {
b[0] = 'Ooops, no matches';
}
return b;
}
}
</script>
<form action="" id="personSelector">
<input type="button" value="Initialise options" onclick="
globTime = new Date();
msgTxt = '';
initOptions( this.form.allNames, personData );
msg.innerHTML = msgTxt;
"><br>
<input type="text" id="sText">
<input type="button" value="Filter" onclick="
globTime = new Date();
msgTxt = '';
currentList = filterOptions( currentList, this.form.sText.value );
buildOptions( this.form.allNames, currentList );
msg.innerHTML = msgTxt;
">
<input type="button" value="Delete all options" onclick="
var oSel = document.createElement('select');
var x = this.form.allNames;
oSel.id = x.id;
x.parentNode.replaceChild(oSel,x);
">
<select id="allNames">
<option>Not initialised yet
</select>
</form>
<p id="msg">msg</p>
<script type="text/javascript">
// Testing & debugging variables
var msgTxt = ''; // Write messages to this
var msg = document.getElementById('msg');
var globTime = new Date();
</script>