ajax333221 ajax333221 - 4 days ago 4
Javascript Question

Merging multiple columns as the table structure is written

I am trying to group multiple columns on my table by collapsing them into a single column and then use a UL list to separate the categories:

enter image description here

For this, what I am doing is adding a boolean to toggle the start/stop stacking, like this:

cols[0][0]="Name";
cols[0][1]=true; //<--toggler

cols[1][0]="Age";
cols[1][1]=false;

cols[2][0]="[M/F]";
cols[2][1]=false;

cols[3][0]="E-mail";
cols[3][1]=true;//<--toggler


However, using this method I have some problems:


  1. I haven't managed to make two consecutive groups: [A][B+C][D+E][F]

  2. the code is pretty hard to read, also to understand exactly what the toggle does






My code to write the head is the following:

document.writeln("<table><thead><tr>");

tmp = "<th>#";
flag = false;

for(i = 0; i < cols_len; i++){
if(cols[i][1]){ //if stack-toggler
if(flag){
tmp += "</th><th>-";
}

flag = !flag;
}

if(!flag){
tmp += "</th><th>" + cols[i][0];
}
}

if(flag){
tmp += "</th><th>-";
}

document.writeln(tmp + "</th></tr></thead><tbody>");


And then for the body of the table:

for(i = 0; i < 20; i++){ //some number of rows
if(i){
document.writeln("</tr>");
}

document.writeln("<tr><td>" + i + "</td>");

tmp = "";
flag = false;

for(j = 0; j < cols_len; j++){
if(cols[j][1]){ //if stack-toggler
if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
tmp = "";
}

flag = !flag;
}

if(flag){
tmp += "<strong>" + cols[j][0] + ":</strong><br>";
}

tmp += "<td>...</td>";

if(!flag){
document.writeln(tmp);

tmp = "";
}
}

if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
}
}

document.writeln("</tr></tbody></table>");


»The full code and demo can be found in this jsFiddle.

I feel this is the wrong approach, it sucks in every way and more importantly, I can't have two or more consecutive groups!, after I start stacking columns, whenever I want to stop, the next column must be alone (and not another group).

I have played around with the booleans and it is simply impossible, I can't figure it out, I already reduced the code to the most readable way and tried to rewrite parts of it but I keep getting the same results.

Answer

I made a slight change to the data model. Instead of "toggle" the boolean says if the next guy stacks or not (that is if it is true then put the next one below me.)

So the data looks like this:

/*0:caption, 1:stack-toggler*/
cols[0][0]="Name";
cols[0][1]=true; //<--stack next below

cols[1][0]="Age";
cols[1][1]=true; //<--stack next below

cols[2][0]="[M/F]";
cols[2][1]=false;

cols[3][0]="E-mail";
cols[3][1]=false; 

cols[4][0]="Website";
cols[4][1]=false;

cols[5][0]="Notes";
cols[5][1]=false;

And then the code can be simple -- like this (a trick I used, you can change the loop variable internal to the loop -- so we only loop on the outer loop when we change columns.)

for(i = 0; i < 20; i++){ //some number of rows
    buildHTML("<tr><td>" + i + "</td>");

    for(j = 0; j < cols_len; j++){
        buildHTML("<td>");

        if (cols[j][1]) {
            buildHTML("<ul>"+cols[j][0]+"</ul>");

            // loop till we are at the penultimate 
            while (cols[j+1][1]) {
               j++;  
               buildHTML("<ul>"+cols[j][0]+"</ul>");
            }

            j++;                
            buildHTML("<ul>"+cols[j][0]+"</ul>");

        }
        else {
            buildHTML(cols[j][0]);
        }    
        buildHTML("</td>");
    }
    buildHTML("</tr>");
}

buildHTML("</tbody></table>");

I did not bother with the header, you can figure that out I'm sure.

Here is the fiddle:

http://jsfiddle.net/eajQy/3/

Of course with javascript you can get fancy. Since what you really have is an array of arrays for the columns you could represent that like this:

// array of arrays -- one element std, 2 or more a list 
newcols = [ ["Name","Age","[M/F]"] , ["E-Mail"] , ["Website"], ["Notes"] ];

Then to make your table you could use map and join like this:

buildHTML("<tr><td>" + i + "</td>");

strArray = $.map(newcols, function (anArray) { 
   if (anArray.length == 1) {
      return "<td>"+anArray[0]+"</td>";
   } 
   else {
     return "<td><ul>"+anArray.join("</ul><ul>")+"</ul></td>";
   }
});

buildHTML(strArray.join(""));

buildHTML("</td></tr></tbody></table>");

Here is a fiddle:

http://jsfiddle.net/eajQy/4/

Single line solution (because every question should have a single line solution):

http://jsfiddle.net/eajQy/5/

Comments