2

I would like to build dynamic table using JQuery and then append the table to DOM. Usually I used string concatenation method to build the table. This time I would like to do this with JQuery. One thing that I'm struggling to get is opening/closing tr element while looping over multiple rows. Here is example if my code:

var data = {
  "1": {
    "fname": "Jon",
    "lname": "Wayne",
    "dob": "05/14/1987",
    "status": "Active",
    "color": "Red",
    "team": "Miami"
  },
  "2": {
    "fname": "Tim",
    "lname": "Ryan",
    "dob": "01/23/1967",
    "status": "Inactive",
    "color": "Blue",
    "team": "Chicago"
  },
  "3": {
    "fname": "Jim",
    "lname": "Carey",
    "dob": "11/02/1997",
    "status": "Suspended",
    "color": "Yellow",
    "team": "Denver"
  },
  "4": {
    "fname": "Chuck",
    "lname": "Norris",
    "dob": "09/06/1945",
    "status": "Active",
    "color": "Green",
    "team": "Boston"
  }
}

$('#start').on('click', showRecords);
function showRecords() {
  displayData(1,data);
}

function displayData(fnid,data) {
		var tbl = $('<table>').addClass('display').prop('id','data_tbl'),
			thead = $('<thead>'),
			tbody = $('<tbody>'),
			tr = $('<tr>');
			title = ['First Name','Last Name','DOB','Status','Color','Team'];

		/*** Start: Table Header ***/
		thead.append('<tr>');
		for(var i=0; i < title.length; i++) {
			if(fnid == 1){
				if(i <= 3) {
					thead.append($('<th>').text(title[i]));
				}
			}else{
				thead.append($('<th>').text(title[i]));
			}
		}
		thead.append('</tr>');
		/*** End: Table Header ***/

		/*** Start: Table Body ***/
		for(key in data) {
			tbody.append('<tr>');
			tbody.append($('<td>').text(data[key].fname));
			tbody.append($('<td>').text(data[key].lname));
			tbody.append($('<td>').text(data[key].dob));
			tbody.append($('<td>').text(data[key].status));
			if(fnid !== 1) {
				tbody.append($('<td>').text(data[key].color));
				tbody.append($('<td>').text(data[key].team));
			}
			tbody.append('</tr>');
		}
		/*** End: Table Body ***/

		tbl.append(thead); // Append header section to table.
		tbl.append(tbody); // Append body section to table.
		
    $("#container").empty().append(tbl);
	}
.display {
  width: 500px;
  background-color: red;
}
.display,
.display th,
.display td{
  border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="button" name="start" id="start" value="Start" />
<div id="container"></div>

At first look you would think that everything is fine with the code, but if you open your dev tools and inspect the table elements you will find the issues. There are tr elements in thead and tbody that are empty. These elements should not be there. Can anyone tell me how I can open/close the tr element in JQuery and build the table properly? Thank you.

8
  • You need to create tr append it to thead or tbody and td and th append to tr not to tbody. Commented Apr 24, 2019 at 15:07
  • You don't need to close anything. Just append the elements. (You don't need to construct an HTML string.) Commented Apr 24, 2019 at 15:08
  • Yea @ChrisG is right when you create $('<td>') you are creating DOM element like in inspector so you need to add that element to tr not to tbody, you're not working with string here but same objects like in inspector. Commented Apr 24, 2019 at 15:10
  • Your issue is you are confusing html with DOM Element creation. HTML uses open and close tags to denote the start and stop of an element, because that's all it has. But when you create elements with javascript, that's not an issue. It's up to you to add the needed children to the elements. Commented Apr 24, 2019 at 15:10
  • 2
    Here's the code, fixed: jsfiddle.net/khrismuc/t2rq47gk Commented Apr 24, 2019 at 15:15

3 Answers 3

2

Use Object.keys to loop over your object.

var data = {
  "1": {
    "fname": "Jon",
    "lname": "Wayne",
    "dob": "05/14/1987",
    "status": "Active",
    "color": "Red",
    "team": "Miami"
  },
  "2": {
    "fname": "Tim",
    "lname": "Ryan",
    "dob": "01/23/1967",
    "status": "Inactive",
    "color": "Blue",
    "team": "Chicago"
  },
  "3": {
    "fname": "Jim",
    "lname": "Carey",
    "dob": "11/02/1997",
    "status": "Suspended",
    "color": "Yellow",
    "team": "Denver"
  },
  "4": {
    "fname": "Chuck",
    "lname": "Norris",
    "dob": "09/06/1945",
    "status": "Active",
    "color": "Green",
    "team": "Boston"
  }
}

$('#start').on('click', showRecords);
function showRecords() {
  displayData(1,data);
}

function displayData() {
  const table = $("<table></table>").addClass('display');

  Object.keys(data).forEach(item => {
    const row = $("<tr></tr>");
    Object.keys(data[item]).forEach(key => {
      const rowData = $("<td></td>")
        .addClass("bar")
        .text(data[item][key]);
      row.append(rowData);
    });
    table.append(row);
  });

  $("#container").empty().append(table);
}
.display {
  width: 500px;
  background-color: red;
}
.display,
.display th,
.display td{
  border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="button" name="start" id="start" value="Start" />
<div id="container"></div>

Sign up to request clarification or add additional context in comments.

Comments

1

I would suggest extracting your html out into a template. That way your script is cleaned up and you separate your markup from your logic more so. The following logic uses the created template and then only has to construct the cells for the tbody. It constructs the cells in an array of string using map, which then all the strings get appended to the tbody at once.

var data = {
  "1": {
    "fname": "Jon",
    "lname": "Wayne",
    "dob": "05/14/1987",
    "status": "Active",
    "color": "Red",
    "team": "Miami"
  },
  "2": {
    "fname": "Tim",
    "lname": "Ryan",
    "dob": "01/23/1967",
    "status": "Inactive",
    "color": "Blue",
    "team": "Chicago"
  },
  "3": {
    "fname": "Jim",
    "lname": "Carey",
    "dob": "11/02/1997",
    "status": "Suspended",
    "color": "Yellow",
    "team": "Denver"
  },
  "4": {
    "fname": "Chuck",
    "lname": "Norris",
    "dob": "09/06/1945",
    "status": "Active",
    "color": "Green",
    "team": "Boston"
  }
}

$('#start').on('click', showRecords);

function showRecords() {
  displayData(1,data);
}

function displayData(fnid,data) {
  var template = $('#tableTemplate').html();
  var $table = $(template);
  
  $table.find('tbody').append(
    Object.keys(data[fnid]).map(function(key){
      return '<td>'+ data[fnid][key] +'</td>';
    })
  );
	
  $("#container").empty().append($table);
}
.display {
  width: 500px;
  background-color: red;
}
.display,
.display th,
.display td{
  border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="button" name="start" id="start" value="Start" />
<div id="container"></div>

<script type="text/html" id="tableTemplate">
  <table class="display" id="data_tbl">
    <thead>
      <tr>
        <th>First Name</th>
        <th>Last Name</th>
        <th>DOB</th>
        <th>Status</th>
        <th>Color</th>
        <th>Team</th>
      </tr>
    </thead>
    <tbody>
    </tbody>
  </table>
</script>

3 Comments

I understand that code would be cleaner if I separate my html code. In the other hand now days React, Vue, etc are implementing Virtual DOM and all HTML code is built in JavaScript. I'm just thinking about efficiency int his case as well even this example only have 4 records.
@espresso_coffee If you are building an application from scratch, React, Vue, and the like could be contenders. However, if you have an existing application, it may be more worth while to do templates like this or with handlebars or mustache, rather than pulling in an entire framework and having to rewrite your application.
I agree. In this case I'm working on old application. The only thing that I use is JQuery library. I'm still trying to implement efficient code that is easy for the maintenance at the same time. I know that building html with JavaScript is not considered the best practice in this example.
-2

Object.keys(data).forEach(function(item, key){ data[item].fname });

1 Comment

1. Do you have a description on how to use this? 2. How is different from other answers?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.