I am having a huge brain fart with efficiency right now.
The idea here is if I have a static table
(unfortunately formatted this way with the data I've received), how would I appropriately append
a select option dropdown
with every value from the table categorized easily?
I currently have it working, but it seems as if I could make it more efficient than my current statement. I have the feeling with all the DOM
manipulation I have going on, if I tried to use this on a table with thousands of items it would lag the browser. Let's get to the code.
JS Fiddle: http://jsfiddle.net/z2V2p/1/
HTML:
<table id='data'>
<tr>
<td>Item 1</td>
<td>Value 1</td>
<td>Prop 1</td>
</tr>
<tr >
<td>Item 2</td>
<td>Value 2</td>
<td>Prop 2</td>
</tr>
<tr >
<td>Item 3</td>
<td>Value 3</td>
<td>Prop 3</td>
</tr>
</table>
<select id="item"></select>
<select id="value"></select>
<select id="prop"></select>
Javascript/jQuery:
$('tr td').each(function() {
var $this = $(this);
var text = $this.text();
var select = '<option value="'+text+'">'+text+'</option>';
switch($this.index()){
case 0:
$('#item').append(select);
break;
case 1:
$('#value').append(select);
break;
case 2:
$('#prop').append(select);
break;
default:
alert('Unexpected Error.');
}
});
So, I suppose the questions are:
- Is there any easy way to make this more efficient?
- Perhaps utilizing an
array
to cache the values, andappend
them from that? - Or is there an easier method of using
index
of the items instead of myswitch case
that would render quicker and be more expandable for furthertd
s if they were implemented?
I appreciate all of the help.
I've considered just ultimately converting the darn table to a json
object, but I figured I'd reach out here first. (this will deploy thousands of times per week, and I don't want anything hard coded.)
Looking for a way to add every TD
in its index
of its TR
to be appended to an existing select option
based on the index
value.
Basically re-categorize columns of td
elements.
2 Answers 2
First little thing: var names are important. So
var option = '<option value="'+text+'">'+text+'</option>';
Second and main. When we are making webapps with JS, the main perfomance rule is:
Reduce access to DOM
I tried you code with 15000 tr's in Firefox and Chrome. I wrapped you code with
console.time('DOM');
...
console.timeEnd('DOM');
Results was:
- Chrome - about 5000ms
- Firefox - about 20000ms
Then i replaced $.append()
with just strings concatenation
console.time('String');
var itemOptions = '', valueOptions = '', propOptions = '';
$('tr td').each(function() {
var $this = $(this);
var text = $this.text();
var option = '<option value="'+text+'">'+text+'</option>';
switch($this.index()){
case 0:
itemOptions += option;
break;
case 1:
valueOptions += option;
break;
case 2:
propOptions += option;
break;
default:
alert('Unexpected Error.');
}
});
$('#item').append(itemOptions);
$('#value').append(valueOptions);
$('#prop').append(propOptions);
console.timeEnd('String');
Results:
- Chrome - about 1100ms (bravo, Chrome :))
- Firefox - about 4000ms
If you will change your data source to a JSON or something, next optimisation will not need, but you can set first argument of .each()
method (index of all td elements) to avoid using .index()
. I noticed about 300-500ms of speed increase. So the last version is
console.time('String');
var itemOptions = '', valueOptions = '', propOptions = '';
$('tr td').each(function(index) {
var $this = $(this);
var text = $this.text();
var option = '<option value="'+text+'">'+text+'</option>';
var modulo = index % 3;
switch(modulo){
case 0 :
itemOptions += option;
break;
case 1:
valueOptions += option;
break;
case 2:
propOptions += option;
break;
default:
alert('Unexpected Error.');
}
});
$('#item').append(itemOptions);
$('#value').append(valueOptions);
$('#prop').append(propOptions);
console.timeEnd('String');
Results:
- Chrome - about 850ms
- Firefox - about 3500ms
We can do some thing like this http://jsfiddle.net/z2V2p/11/
<script>
var dataArray = [];
dataArray[0] = ['item','Item 1','Item2','Item3','Item4'];
dataArray[1] = ['value','Value 1','Value 2','Value 3','Value 6','Value 5'];
dataArray[2] = ['prop','Prop 1','Prop 2','Prop 3','Prop 6','Prop 5','Prop 6'];
</script>
by this way we will remove the table and now the dom will be happy :)
if you noticed the id of the select had been added to the array now we can remove the switch too by this code:
for(i=0; i < dataArray.length; i++){
$select = $('#'+dataArray[i][0]);
for(i2=1; i2 < dataArray[i].length; i2++){
var option = '<option value="'+dataArray[i][i2]+'">'+dataArray[i][i2]+'</option>';
$select.append(option);
}
}
but now we have a problem with loop inside loop.
-
\$\begingroup\$ Well, the idea is to capture every item inside of a 500 3
td
(3 items)table
. I don't want to hard code 500 values inside my code... \$\endgroup\$Nicholas Hazel– Nicholas Hazel2014年02月06日 05:15:34 +00:00Commented Feb 6, 2014 at 5:15 -
\$\begingroup\$ My point being, if I use a function to convert this table into different arrays, isn't that harder to accomplish than my code for the
client
? I mean, findDOM
objects intoarray
, thenparse
array
intoDOM
seems like duplicate effort. \$\endgroup\$Nicholas Hazel– Nicholas Hazel2014年02月06日 05:21:00 +00:00Commented Feb 6, 2014 at 5:21 -
\$\begingroup\$ We might as well just $domObject = $domObject(converted) right...? \$\endgroup\$Nicholas Hazel– Nicholas Hazel2014年02月06日 05:33:21 +00:00Commented Feb 6, 2014 at 5:33
-
\$\begingroup\$ So what i understand now that we have: formatted data as
table
> 3tr
> multipletd
and we cannot change this format, are me right ? \$\endgroup\$Saad Shahd– Saad Shahd2014年02月06日 05:49:08 +00:00Commented Feb 6, 2014 at 5:49 -
\$\begingroup\$ Well, I'm happy to use this as it works in .42s when live with 40k items. I just like to expand. So, how can we make it .10 seconds by removing a step of DOM manipulation? Answering your Q, pretend its 10,000
tr
and all have 3td
items. Its just an efficiency question, as I feel I could expand theswitch
case more manageable and expandable. \$\endgroup\$Nicholas Hazel– Nicholas Hazel2014年02月06日 05:50:54 +00:00Commented Feb 6, 2014 at 5:50