Reputation: 1943
I have a large table currently consisting of 95x120=11400 TD's and would like to dynamically edit properties such as height and background-color for all the cells from a certain row or column, or even a bunch of rows/columns. I want to do this in order to make the user able to resize rows/columns among other things. What would be a good way of getting that done?
All the TD's in my table does by the way have unique class for row/col eg row1, row2, row3, col1, col2, col3 added dynamically while the table is built up though Javascript.
Upvotes: 1
Views: 803
Reputation: 1943
This can be done really efficiently by modifying css-rules dynamically. It also makes a lot more sense storing common properties i.e. height for a row of cells in a rule rather than storing it all in each element. And it takes up less memory as well.
With a table-layout like the following:
<table>
<tr>
<td class="row1 col1">data</td>
<td class="row2 col2">data</td>
<td class="row3 col3">data</td>
</tr>
<tr>
<td class="row1 col1">data</td>
<td class="row2 col2">data</td>
<td class="row3 col3">data</td>
</tr>
<tr>
<td class="row1 col1">data</td>
<td class="row2 col2">data</td>
<td class="row3 col3">data</td>
</tr>
</table>
We can do something like this:
var numRows=3, numCols=3;
document.getElementsByTagName('head')[0].appendChild(document.createElement('style'));
var sheet=document.styleSheets[1];
//Or instead of creating a new sheet we could just get the first exisiting one like this:
//var sheet=document.styleSheets[0];
var selector, rule, i, rowStyles=[], colStyles=[];
//Create rules dynamically
for (i=0; i<numRows; i++) {
selector=".row"+i;
rule="{height:20px}";
if (sheet.insertRule)
sheet.insertRule(selector+rule, 0);//This puts the rule at index 0
else
sheet.addRule(selector2, rule2, 0);//IE does things differently
rowStyles[i]=(sheet.rules||sheet.cssRules)[0].style;//Remember you have to fetch the rules-array from the sheet and not hold on to the old rules-array, since a new one is created during each insertion. Oh, and IE does things differently again; cssRules instead of rules
}
for (i=0; i<numCols; i++) {
selector=".col"+i;
rule="{background-color:white}";
if (sheet.insertRule)
sheet.insertRule(selector+rule, 0);
else
sheet.addRule(selector2, rule2, 0);
colStyles[i]=(sheet.rules||sheet.cssRules)[0].style;
}
//Now they can be changed real easy and efficiently like this:
//This line changes the height for the second row, simply by modifying their css-rule, not setting a style-height on each element
rowStyles[1].height="50px";
//It is also really easy to adjust properties of rules added from css-file, just iterate through the rules/cssRules-array checking the selectorText-property of each object until the right one is found.
I did a bit of benchmarking and unless I'm going wrong somewhere the difference is quite tremendous. But yeah, apart from the benchmark it really does a huge noticeable difference in the real use case.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<style>
td {
border: 1px solid black;
width: 10px;
height: 10px;
}
</style>
<script src="http://code.jquery.com/jquery-latest.min.js " charset="UTF-8"></script>
</head>
<body>
<table id="table">
<tr id="row">
</tr>
</table>
<script type="text/javascript">
var tr=document.getElementById("row");
for (var i=0; i<300; i++) {
var cell=tr.insertCell(0);
cell.className="cell";
}
var sheet=document.styleSheets[0];
var c2=(sheet.rules||sheet.cssRules)[0].style;
var table=document.getElementById("table");
var startTime;
//First loop
startTime=new Date().getTime();
var c1=$(".cell");
for (var i=0; i<1000; i++) {
c1.height(i);
}
var time1=new Date().getTime()-startTime;
//Second loop
startTime=new Date().getTime();
c1=$(".cell");
for (var i=0; i<1000; i++) {
c1.css("height",i);
}
time2=new Date().getTime()-startTime;
//Third loop
startTime=new Date().getTime();
c1=$(".cell");
document.body.removeChild(table);
for (var i=0; i<1000; i++) {
c1.css("height",i);
}
document.body.appendChild(table);
time3=new Date().getTime()-startTime;
//Fourth loop
startTime=new Date().getTime();
for (var i=0; i<1000; i++) {
c2.height=i+"px";
}
var time4=new Date().getTime()-startTime;
alert ("First:"+time1+" ms\nSecond:"+time2+" ms\nThird:"+time3+" ms\nForth:"+time4+" ms");
</script>
</body>
</html>
Would results from this be misleading for some reason? In that case I can't quite see where I'm going wrong so I'd appreciate feedback. These are the results I get.
Time taken to complete:
Loop 1: This one uses a simple jquery class-selector $(".cell").height(h);
Loop 2: This one is same as above but uses $(".cell").css("height",h) instead. It's faster
Loop 3: Same as above but it removes the table from DOM before modifying, then re-appending it. Seems faster in Firefox at least
Loop 4: This one modifies the css-rules dynamically:
Upvotes: 3
Reputation: 36
You can also do table.rows[0] which gives a array of all TDs in that row. Then loop through it and change as wanted
Upvotes: 1
Reputation: 2822
Pretty simple if all of your cells are labeled with the appropriate classes.
Say you want to change the width of a certain column.
$(".col3").width(newWidth);
Or if you want to change the width of a bunch of columns.
$(".col3,.col5").width(newWidth);
Similarly with
$(".row3,.row5,.row9,.row12").height(newHeight);
Or if you want to change the background color
$(".col3").css("background-color","#ff0000");
Upvotes: 0
Reputation: 324650
When making changes to such a huge structure, it is a good idea to remove it from the document first, so that it only gets re-processed at the end, when you re-insert it.
So, assuming your table is in a variable named table
, you would do this:
var prnt = table.parentNode, nxtsbl = table.nextSibling;
prnt.removeChild(table);
// now do all your modifications, such as looping through rows etc.
prnt.insertBefore(table,nxtsbl);
Upvotes: 1