Link to home
Start Free TrialLog in
Avatar of Isaac
IsaacFlag for United States of America

asked on

TR appendChid() rendering problem

I have the following piece of code that is needed to build and add rows under the right headings in an html table.
var mileStoneHtml="";
		var typeArray = [];
		var headingName = "";
		for(var i =0; i < data.d.results.length; i++) 
		{	
			headingName = data.d.results[i].Milestone_x0020_Type;
			
			if (typeArray.indexOf(headingName) === -1){
				typeArray.push(headingName);
				
				
				tableRow = document.createElement("tr");
				tableRow.id=headingName;
				tableRow.style.backgroundColor = "#EEEEEE";
				tableCol = document.createElement("td");
				tableCol.colSpan = 5;
				tableCol.textContent = headingName;
				tableRow.appendChild(tableCol);				
				console.log(tableRow);
				tbl = document.getElementById("tblMilestone");
				console.log(tbl);
				console.dir(tbl);
				tbl.appendChild(tableRow);
			}
					mileStoneHtml = "<tr>"+
					"<td>"+data.d.results[i].MilestoneDescription+"</td>"+
					"<td>"+data.d.results[i].Planned_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Revised_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Actual_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Milestone_x0020_Type+"</td>"+
				"</tr>";		
				
				var newRow = $("#"+headingName).append(mileStoneHtml);
				console.log(newRow);
//				document.querySelector("#tblMilestone").appendChild(mileStoneHtml);					
		}													

Open in new window


It needs to look like this
User generated image
but it looks like this
User generated image
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Here is a slightly different take on this building on your earlier question
function renderTable(data)
{
  var table = document.getElementById('dataTable');
  // work out the number of columns to span using the cells in the header
  var colspan = table.querySelectorAll('thead tr th').length;

  var currentType = '';
  for (var i = 0; i < data.length; i++) {  
    var current = data[i];
    var row = table.insertRow();
    if (current.type != currentType) {
      var cell = row.insertCell();
      row.className = 'header';
      cell.innerHTML = current.type;
      cell.colSpan = colspan;
      currentType = current.type;
    }
    else {
      for(var j in data[i]){
        var cell = row.insertCell();
        cell.innerHTML = data[i][j];
      }
    }
  }
}

Open in new window


Working sample here
Avatar of Isaac

ASKER

That's great Julian. Thanks but I had to forego using handlebars because when I moved it from my personal site to the clients test environment, it worked until I added handlebar helper functions.  It gave me the following error:
SCRIPT5022: Error: Missing helper: "formatHtml"
formatHtml is a function used to no escape html so it can render my data as html.
I also have one for 'formatDate' as well and the same error would show for that too.

Here are my helpers that I added to my code in include files.
Handlebars.registerHelper("formatHtml", function(property) {
	return new Handlebars.SafeString(property);
});

Handlebars.registerHelper("formatDate", function(property) {
	return moment(property).format("L");
});

Open in new window


Here's the error I see through the deveoloper tool. It points to a line in handlebars.User generated image
Here's how I use formatHtml
<tr> 
	<td><b>Project Scope:</b></td><td> {{formatHtml Project_x0020_Scope}} </td>	 
</tr> 	

Open in new window



On my site, I was using ie 10 and it worked even though the error still showed.  My client uses ie 11, so I'm not sure if that is the reason.

So, I had to redo the code without handlebars and that's why I created this question to add a table row.  If you know of a solution to fix the handlebars error, that would be great.  I would rather use that solution since it's 95% done.

Thanks!
try simplified version

var mileStoneHtml="";
var typeArray = [];
var headingName = "";

for(var i =0; i < data.d.results.length; i++) 
{	
	headingName = data.d.results[i].Milestone_x0020_Type;
	
	if (typeArray.indexOf(headingName) === -1){
		typeArray.push(headingName);
		
		mileStoneHeadHtml = "<tr><td colspan='5' id='" + headingName + "'>" + headingName + "</td></tr>"
		$("#tblMilestone").append(mileStoneHtml);
	}

	mileStoneHtml = "<tr>"+
			"<td>"+data.d.results[i].MilestoneDescription+"</td>"+
			"<td>"+data.d.results[i].Planned_x0020_Date+"</td>"+
			"<td>"+data.d.results[i].Revised_x0020_Date+"</td>"+
			"<td>"+data.d.results[i].Actual_x0020_Date+"</td>"+
			"<td>"+data.d.results[i].Milestone_x0020_Type+"</td>"+
		"</tr>";		
		
	$("#tblMilestone").append(mileStoneHtml);
}	

Open in new window

and if you will not use those rows later, you dont need to put id to those sections... Line 12 I mean...
Avatar of Isaac

ASKER

Your code added the 1 row and left out the heading
Avatar of Isaac

ASKER

Here's what it shows.  Heading and two rows are missing.

User generated image
Avatar of Isaac

ASKER

Correction.  All three rows showed but not the headings as in the image in my initial questions.  sorry about that
Avatar of Isaac

ASKER

User generated image
Avatar of Isaac

ASKER

I'm surprised it's not working.  The developer tool shows the table rows were created.
User generated image
did you check my simplified version ID: 42190774?
Avatar of Isaac

ASKER

That's what I'm using
function complete(data) {
		
		var mileStoneHtml="";
		var typeArray = [];
		var headingName = "";
		for(var i =0; i < data.d.results.length; i++) 
		{	
			headingName = data.d.results[i].Milestone_x0020_Type;
			
			if (typeArray.indexOf(headingName) === -1){
				typeArray.push(headingName);
				
				mileStoneHeadHtml = "<tr><td colspan='5' id='" + headingName + "' style='background-color:#eeeeee'>" + headingName + "</td></tr>";
				console.dir(mileStoneHeadHtml);
				$("#tblMilestone").append(mileStoneHtml);
				
				/*tableRow = document.createElement("tr");
				tableRow.id=headingName;
				tableRow.style.backgroundColor = "#EEEEEE";
				tableCol = document.createElement("td");
				tableCol.colSpan = 5;
				tableCol.textContent = headingName;
				tableRow.appendChild(tableCol);				
				console.log(tableRow);
				tbl = document.getElementById("tblMilestone");
				console.log(tbl);
				console.dir(tbl);
				tbl.appendChild(tableRow);*/
			}
					mileStoneHtml = "<tr>"+
					"<td>"+data.d.results[i].MilestoneDescription+"</td>"+
					"<td>"+data.d.results[i].Planned_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Revised_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Actual_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Milestone_x0020_Type+"</td>"+
				"</tr>";		
				
					$("#tblMilestone").append(mileStoneHtml);//				document.querySelector("#tblMilestone").appendChild(mileStoneHtml);					
		}									
}

Open in new window

sorry you should use

 tbody

$("#tblMilestone").append(mileStoneHtml);

>>>

$("#tblMilestone tbody").append(mileStoneHtml);
ASKER CERTIFIED SOLUTION
Avatar of HainKurt
HainKurt
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Isaac

ASKER

That didn't work.
function complete(data) {
		
		var mileStoneHtml="";
		var typeArray = [];
		var headingName = "";
		for(var i =0; i < data.d.results.length; i++) 
		{	
			headingName = data.d.results[i].Milestone_x0020_Type;
			
			if (typeArray.indexOf(headingName) === -1){
				typeArray.push(headingName);
				
				mileStoneHeadHtml = "<tr><td colspan='5' id='" + headingName + "' style='background-color:#eeeeee'>" + headingName + "</td></tr>";
				console.dir(mileStoneHeadHtml);
				$("#tblMilestone tbody").append(mileStoneHtml);
				
				/*tableRow = document.createElement("tr");
				tableRow.id=headingName;
				tableRow.style.backgroundColor = "#EEEEEE";
				tableCol = document.createElement("td");
				tableCol.colSpan = 5;
				tableCol.textContent = headingName;
				tableRow.appendChild(tableCol);				
				console.log(tableRow);
				tbl = document.getElementById("tblMilestone");
				console.log(tbl);
				console.dir(tbl);
				tbl.appendChild(tableRow);*/
			}
					mileStoneHtml = "<tr>"+
					"<td>"+data.d.results[i].MilestoneDescription+"</td>"+
					"<td>"+data.d.results[i].Planned_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Revised_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Actual_x0020_Date+"</td>"+
					"<td>"+data.d.results[i].Milestone_x0020_Type+"</td>"+
				"</tr>";		
				
					$("#tblMilestone tbody").append(mileStoneHtml);//				document.querySelector("#tblMilestone").appendChild(mileStoneHtml);					
		}									
}

Open in new window

Avatar of Isaac

ASKER

I recreated it in jsfiddle

https://jsfiddle.net/isogunro/9cjrt110/2/

I am trying to achieveUser generated image
Avatar of Isaac

ASKER

It worked! Thanks!
It was mileStoneHeadHtml and not mileStoneHtml
So, I had to redo the code without handlebars and that's why I created this question to add a table row.
I am very confused - I gave you a working sample that does exactly what you want without handlebars which is much simpler than the accepted version.
@Julian

Accepted answer is actually ID: 42190774 + ID: 42190790 + ID: 42190815
same method is used to add header and detail rows, ie

...
if (typeArray.indexOf(headingName) === -1){
  mileStoneHeadHtml = "...";
  $("#tblMilestone tbody").append(mileStoneHeadHtml);
}
mileStoneHtml = "...";
$("#tblMilestone tbody").append(mileStoneHtml);

Open in new window


see demo https://jsfiddle.net/fvkpex5h/
Avatar of Isaac

ASKER

@Julian,

My apologies.  I thought you were referring back to my handlebars question when you said "'Here is a slightly different take on this building on your earlier question".  That's my misunderstanding.
Yes I was referring to the solution I offered you in that question - but updated it to the new requirements.

The sample I posted was a modification from handle bars to normal JavaScript and makes use of the insertRow() and insertCell() methods to create the new row.

The accepted solution will work - but is not optimal in my view.
@Huseyin,

42190667 was posted first, was correct according to requirements and made use of correct JavaScript methods for adding cells and rows.
@Julian

he is already using

$("#tblMilestone").append(mileStoneHtml);

Open in new window


and no need to use any other method for headers...
Thats why I wiped out all those tiny commands and used the same jQuery method for divisions as well...

and optimal means what? slow? who cares, we are not dealing with millions of operations here, just a few...
and it is not noticeable even if you write the most inefficient code here...
like the discussion between

vs using string concat vs stringbuilder in .net!

I made a demo of this for millions of operations and difference is not noticeable :)

so, simple is the best... as I always say...

and I found a demo, results saying even classical way is better :)

using System;
using System.Diagnostics;
using System.Text;

class Test
{
    static readonly string[] Bits = { 
        "small string",
        "string which is a bit longer",
        "stirng which is longer again to force yet another copy with any luck"
    };

    static readonly int ExpectedLength = string.Join("", Bits).Length;

    static void Main()        
    {
        Time(StringBuilderTest);
        Time(ConcatenateTest);
    }

    static void Time(Action action)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        // Make sure it's JITted
        action();
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            action();
        }
        sw.Stop();
        Console.WriteLine("{0}: {1} millis", action.Method.Name,
                          (long) sw.Elapsed.TotalMilliseconds);
    }

    static void ConcatenateTest()
    {
        string x = "";
        foreach (string bit in Bits)
        {
            x += bit;
        }
        // Force a validation to prevent dodgy optimizations
        if (x.Length != ExpectedLength)
        {
            throw new Exception("Eek!");
        }
    }

    static void StringBuilderTest()
    {
        StringBuilder builder = new StringBuilder();
        foreach (string bit in Bits)
        {
            builder.Append(bit);
        }
        string x = builder.ToString();
        // Force a validation to prevent dodgy optimizations
        if (x.Length != ExpectedLength)
        {
            throw new Exception("Eek!");
        }
    }
}

Open in new window


StringBuilderTest: 2245 millis
ConcatenateTest: 989 millis

Open in new window

who cares, we are not dealing with millions of operations here, just a few...
Not much one can say to that really