Building dynamic table with handlebars
Solution 1
Based on what you are describing, I think you would have no option other than to build an array of table headers (object keys) by iterating over every object in your array and filtering out all of the duplicates. In other words, you must build an array of all of the unique keys from all of your data objects and these will serve as the column headings in your table. You could use an existing library to help yo do this, like Underscore's .uniq
, but I will provide an example implementation:
var uniqueKeys = data.reduce(function (acc, obj) {
return acc.concat(Object.keys(obj).filter(key => acc.indexOf(key) === -1));
}, []);
Next, we must pass our array of unique keys to our template. The unique keys will be used to create the table headings as well as in lookup operations for each object in data
.
template({
uniqueKeys: uniqueKeys,
data: data
});
Our template must be updated to the following:
<thead>
<tr>
{{#each uniqueKeys}}
<th>{{this}}</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each data}}
<tr>
{{#each ../uniqueKeys}}
<td>{{lookup .. this}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
Note that the line {{lookup .. this}}
is saying, "render the value on the current object in data
at the property with the name of this key in uniqueKeys
.
Also note that I added <tr>
tags within your <thead>
. According to MDN, these are the only permissible tags within a <thead>
.
I have created a fiddle for reference.
Solution 2
Would something like this work for what you're trying to accomplish?
{
"titles": [
"The Room",
"Test"
],
"tableObjs": [{
"director": "Tommy Wiseau",
"genre": "Drama?",
"rating": "1"
},
{
"director": "Tommy Wiseau",
"genre": "Drama?",
"rating": "1"
}
]
}
<thead>
{{#each titles}}
<th>{{@key}}</th>
<!--property name here-->
{{/each}}
</thead>
<tbody>
{{#each tableObjs}}
<tr>
<td>{{this.director}}</td>
<td>{{this.genre}}</td>
<td>{{this.rating}}</td>
<!--property value here-->
</tr>
{{/each}}
</tbody>
Kazura
Updated on June 04, 2022Comments
-
Kazura almost 2 years
I am trying to create a dynamic table with handlebars.js. An example of an object I want to put in the table is:
Object { title: "The Room", director: "Tommy Wiseau", genre: "Drama?", rating: "1"}
The HTML I would like to look like:
<thead> <th>Title</th> <th>Director</th> <th>Genre</th> <th>Rating</th> <th>Edited</th> </thead> <tbody> <tr> <td>The Room</td> <td>Tommy Wiseau</td> <td>Drama?</td> <td>1</td> <td>2017-05-16</td> </tr> </tbody>
My problem is that the user can also add their own table headers, so i can't for example just do:
<td>{{title}}</td>
It has to be done dynamically. I have looked at:
{{#each}}
, but just can't seem to wrap my head around around it. Also, how can I print the property name instead of just the value in an object (like I want in the table headers).<thead> {{#each data}} <th>{{@key}}</th><!--property name here--> {{/each}} </thead> <tbody> {{#each data}} <tr> <td>{{this}}</td><!--property value here--> </tr> {{/each}} </tbody>
This is my template. I feel like I am closing in on the right solution, but I am not sure where I am doing something wrong.
$.getJSON("php/loadItems.php?category=" + selected, function(data) { let source = $("#itemTemplate").html(); let template = Handlebars.compile(source); delete data[0].id $("#tableContainer").append(template(data)); });
This is how I handle the data in my JS. Any help is greatly appreciated!
-
Kazura almost 7 yearsI'm afraid not. Since the user can add stuff themselves I would not be able to know what the property names are. In this instance they might add another category; say "Notes" where they could write what they want. I would have no idea what the property name would be then
-
JohnK about 4 yearsTremendous help! Thank you. Btw you can also get an array of object keys using
Object.assign(summaryObj, obj)
to accumulate keys from eachobj
insummaryObj
, and thenObject. keys(summaryObj)
gives the array of keys.