I am trying to populate a table with data returned from an ajax call. I am using handlebars as the templating engine. I am obviously doing this on the client. I found a lot of questions (here, here and here) asking about populating templates from object arrays. I have tried all of them without success. The last version I tried is as follows.
The template is embedded in a script tag.
<script id="resultTableTpl" type="text/template">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Regd. No.</th>
<th>Type</th>
</tr>
</thead>
<tbody>
{{#each this}}
<tr>
<td>{{id}}</td>
<td>{{regd_id}}</td>
<td>{{type}}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
And this is the call to populate the template.
<script>
$("#submitSearch").on('click', function(e) {
e.preventDefault();
$.getJSON(...)
.done(function(data) {
template = Handlebars.compile($("#resultTableTpl").html());
$("#myDiv").replaceWith(template(data));
})
.fail(function(){
alert("failure");
});
});
</script>
The JSON data that is obtained from the ajax call is:
[
{id: 123, regd_id: "KA-123", type: "3w"}
, {id: 345, regd_id: "KA-345", type: "4w"}
, {id: 567, regd_id: "KA-567", type: "5w"}
]
This should populate the div myDiv with a table. My test JSON data has an array of three objects. The generated table has empty three rows with three columns. What am I missing? I am using the express flavour of handlebars from exphbs.
Related
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!
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.
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>
I successfully fetch data by using $http get from php server. But I have no idea how to display the data in Table form by using ngRepear because all the data is in few different project. I am going to display all the object of data into different row of a table. The following shows data I got from php server.
Following glimpse of code can give you idea
$scope.retrievedData = [];
//retrieve data from your server
//take the data into above scope variable
<table>
<tr ng-repeat = "data in retrievedData">
<td>data.AssetDescription</td>
<td>data.AssetNumber</td>
<td>data.ComputerName</td>
</tr>
</table>
You need to add that data to controller variable:
Controller
function YourController($scope, $http) {
$scope.tableData = [];
$http.get('url').then(function(result) {
$scope.tableData = result.data;
});
}
Template
<table>
<thead>
<tr>
<th>Description</th>
<th>Computer name</th>
<th>Borrow date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in tableData ">
<td>{{row.data.AssetDescription}}</td>
<td>{{row.data.ComputerName}}</td>
<td>{{row.data.borrowDate}}</td>
</tr>
</tbody>
</table>
I have followed the approach "DataTables: Custom Response Handling" by Fabrício Matté. However, my requirement is to avoid rendering of table's rows and columns via callback. Instead, would like to traverse the current ajax request returned json data and render explicit html (tr/td) to have more control. Due to this, currently i see data shown twice on my table. At the same time, i understand that callback is rendering the page related buttons: prev, 1,2 next etc and click events which i would like to reuse and wan't to avoid custom implementation.
JS:
function notificationsCtrl($scope,$http,$resource, DTOptionsBuilder, DTColumnBuilder) {
var vm = this;
vm.notifications = [];
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withOption('serverSide', true)
.withOption('ajax', function(data, callback, settings) {
// make an ajax request using data.start and data.length
$http.get('notifications/list?page=' + (((data.start)/10)+1)).success(function(res) {
// map your server's response to the DataTables format and pass it to
// DataTables' callback
callback({
recordsTotal: 120,
recordsFiltered: 120,
data: res
});
vm.notifications = res;
});
})
.withDataProp('data') // IMPORTANT¹
.withOption('processing', true)
.withPaginationType('full_numbers');
$scope.dtColumns = [
DTColumnBuilder.newColumn('notificationId').withTitle('notificationId'),
DTColumnBuilder.newColumn('createUserId').withTitle('createUserId'),
DTColumnBuilder.newColumn('Language').withTitle('language')
];
}
HTML: sample but actual will require extra processing for some of the td tags
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Language</th>
<th>Last Updated</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="notification in wynkCMSToolApp.notifications">
<td>{{ notification.notificationId }}</td>
<td>{{ notification.title }}</td>
<td>{{ notification.Language }}</td>
</tr>
</tbody>
</table>
If you want to render directly in the HTML, consider using the Angular renderer. However, such renderer does not support the server side processing.
So I recommend you use the server side processing along with the columns.render function.
Here an example of using the render function.
Below is my code:
post.json
[
{
"client_id":"100",
"client_name":"MM Hope House",
"user_fname":"Betty",
"user_lname":"Johnson",
"user_id":"10",
"username":"bjohnson",
"total_web":"$500",
"campaigns":{
"campaign":[{
"id":"23",
"campaign_name":"MM Hope House",
"start_date":"4/15/2015",
"end_date":"6/13/2015",
"goal":"$20,000",
"total_pledges":"$1550",
"total_donations":"$1000"
}],
"pledgees":[{
"pledgee_fname":"Tavonia",
"pledgee_lname":"Evans",
"pledge_email":"tavonia#gmail.com",
"pledge_date":"4/22/2015",
"pledge_amount":"$50.00",
"paid":"$50.00",
"last_pledge":"$50.00"
}],
"donors":[{
"donor_fname":"Pat",
"donor_lname":"Smith",
"donor_email":"patsmith#onlinemediainteractive.com",
"total_cdonation":"$10.00",
"total_ldonation":"$450.00",
"last_donation":"$200.00",
"last_pledge":"$350.00"
}]
}
}
]
My HTML code:
<script>
function PostsCtrlAjax($scope, $http) {
$http({method: 'POST', url: 'assets/js/posts.json'})
.success(function(data) {
console.log(data);
$scope.posts = data;
})
.error(function(data, status) {
$scope.posts = data || "Request failed";
});
}
</script>
My HTML code where I want to populate data:
<thead>
<tr>
<th>Campaign ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Amount</th>
<th>Email ID.</th>
<th>Pledge Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="post in posts" >
<td>{{post.id}}</td>
<td>{{post.pledgee_fname}}</td>
<td>{{post.pledgee_lname}}</td>
<td>{{post.pledge_amount}}</td>
<td>{{post.pledge_email}}</td>
<td>{{post.pledge_date}}</td>
I am trying to get client_id pleg_fname from array, but do not know how to.
Your pledgess object is an array of objects so you should do this instead and your entire JSON is contained within an array so you need the first element which will be your entire object and you call it with posts[0] and then you specify the object you are trying to iterate : pledgees.
<tr ng-repeat="post in posts[0].campaigns.pledgees" >
<td>{{posts[0].campaigns.campaign[0].id}}</td>
<td>{{post.pledgee_fname}}</td>
<td>{{post.pledgee_lname}}</td>
<td>{{post.pledge_amount}}</td>
<td>{{post.pledge_email}}</td>
<td>{{post.pledge_date}}</td>
Edit
You're right, I totally missed that array. See this plunker where I tested it http://plnkr.co/edit/dvdnjv2mN2gljQGI9Lls?p=preview
Edit 2
If you want the campaign ID just add this (updated the original code with this change)
{{posts[0].campaigns.campaign[0].id}}
Because of your posts object contains an array of one element, you should use posts[0] to get the first (and the only one) element. Moreover, your pledgees array is inside a campaigns object, so posts[0] become posts[0].compaigns.pledgees.
You should try this :
<tr ng-repeat="post in posts[0].campaigns.pledgees" >
<td>{{post.id}}</td>
<td>{{post.pledgee_fname}}</td>
<td>{{post.pledgee_lname}}</td>
<td>{{post.pledge_amount}}</td>
<td>{{post.pledge_email}}</td>
<td>{{post.pledge_date}}</td>
</tr>
EDIT:
And, if you want the id from the campagin object at the same index than your pledgee item, you have to add track by $index to posts[0].campaigns.pledgees. So it's become posts[0].campaigns.pledgees track by $index.
So, now with $index you get the right index to get the right campaign ID in the campaign object with {{posts[0].campaigns.campaign[$index].id}}
And the result is :
<tr ng-repeat="post in posts[0].campaigns.pledgees track by $index" >
<td>{{posts[0].campaigns.campaign[$index].id}}</td>
<td>{{post.pledgee_fname}}</td>
<td>{{post.pledgee_lname}}</td>
<td>{{post.pledge_amount}}</td>
<td>{{post.pledge_email}}</td>
<td>{{post.pledge_date}}</td>
</tr>
You can see the result here : http://jsfiddle.net/Fieldset/y1asxm61/1/
I have a table using angularjs where I want to loop through an array to print specific headers from a json object. The header prints out fine, but the problem comes when I try to use a variable from my nested ng-repeat as a json selector. If you replace the inner ng-repeat with the commented section below it, it will work.
Table:
<table>
<thead>
<th ng-repeat="column in tableHeader">{{column}} <a ng-click="sort_by(column);"><i class="glyphicon glyphicon-sort"></i></a></th>
</thead>
<tbody>
<tr ng-repeat="data in filtered>
<td ng-repeat="column2 in tableHeader">{{data.column2}}</td>
<!-- <td>{{data.Environment}}</td>
<td>{{data.HostIP}}</td>
<td>{{data.ServiceName}}</td>
<td>{{data.Status}}</td>
<td>{{data.StartTime}}</td>
<td>{{data.Capacity}}</td>
<td>{{data.Txn}}</td>
<td>{{data.Errors}}</td>
<td>{{data.Build}}</td>
<td>{{data.Project}}</td>
<td>{{data.Author}}</td>
<td>{{data.ModifyDate}}</td>
<td>{{data.Port}}</td>
<td>{{data.BasePath}}</td> -->
</tr>
</tbody>
</table>
Array located in controller:
$scope.tableHeader = ['Environment', 'HostIP', 'Status', 'ServiceName', 'StartTime', 'Capacity', 'Txn', 'Errors', 'Build', 'Project', 'Author', 'ModifyDate', 'Port', 'BasePath'];
I think you're looking for {{data[column2]}}. Since column2 is just the string value of the property you want, treat data like an associative array in this case to get the property you're trying to display.
column2 was created by the ng-repeat and is what you want. Note {{column2}}:
<td ng-repeat="column2 in tableHeader">{{column2}}</td>