Handlebars adding items to table template - javascript

I would like to add items from a database into a handlebars.js template.
My template looks like this:
<script id="some-template" type="text/x-handlebars-template">
<table class="mdl-data-table mdl-js-data-table mdl-data-table--selectable mdl-shadow--2dp">
<thead>
<th>Categories</th>
</thead>
<tbody>
{{#categories}}
<tr>
<td>{{categoryName}}</td>
</tr>
{{/categories}}
</tbody>
</table>
</script>
My JS looks like this:
$(document).ready(function() {
$.getJSON("categories.php", function(data) {
let source = $("#some-template").html();
let template = Handlebars.compile(source);
for (let i = 0; i < data.length; i++) {
var output = {
categories: [{
categoryName: data[i].name
}]
};
console.log(output.categories)
$("#sampleArea").html(template(output));
}
});
});
When i use $("#sampleArea").html(template(output)); it only adds the last item in my database. If i use $("#sampleArea").append(template(output)); however it makes two tables; one for each item in my database.
I also tried:
{{#each categories}}
<tr>
<td>{{categoryName}}</td>
</tr>
{{/each}}
but that didn't work either.

You are overwriting the output variable each time you iterate through an item. Try defining the output variable outside the for-loop and push to it inside the loop.
$(document).ready(function() {
$.getJSON("categories.php", function(data) {
let source = $("#some-template").html();
let template = Handlebars.compile(source);
var output = {
categories: []
};
for (let i = 0; i < data.length; i++) {
output.categories.push({
categoryName: data[i].name
});
}
console.log(output.categories)
$("#sampleArea").html(template(output));
});
});

Related

How to Loop through a Table of values in AngularJS

I have a table that is being populated from database through an angularJS array.
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Code</th>
<th>Description</th>
<th>Budget Amount</th>
<th>Actual Amount</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="lineItem in vm.budget.budgetLines">
<td>
{{lineItem.code}}
</td>
<td>#{{lineItem.description}}</td>
<td>{{lineItem.budgetAmount | currency}}</td>
<td><input type="number" class="form-control" ng-model="lineItem.actualAmount" required /></td>
</tr>
</tbody>
</table>
The data population works fine. But if you look at the table, you would notice an input field in the last column. I need to be able to perform an update with changes made to the input for which I need just the 1st and last column for the operation. I used the following approach but it didn't work because it just used the original values with which the table was first populated.
$scope.lineItems = [];
for (var i = 0; i < vm.budget.budgetLines.length; i++) {
var lineItem = vm.budget.budgetLines[i];
$scope.lineItems.push({
'code': lineItem.code,
'actualAmount': lineItem.actualAmount
});
}
So I thought of using pure javascript inside my angular controller to loop through the table rows and push the columns I need in the array like so;
var myTable = document.getElementById("tblValues");
var current, cell;
for (var i = 0; i < myTable.rows.length ; i++) {
var rowItem = myTable.rows[i];
$scope.lineItems.push({
'code': rowItem.cells[1],
'actualAmount': rowItem.cells[4].children[0].value
});
}
But an error is thrown in the console: rowItem.cells[4].children[0] is undefined
Please how can I get this to work just the way I want it?
I got it to work just the way I desired it to.
var myTable = document.getElementById("tblValues");
var current, cell;
$scope.lineItems.length = 0;
for (var i = 0; i < myTable.rows.length ; i++) {
var rowItem = myTable.rows[i + 1];
$scope.lineItems.push({
'code': rowItem.cells[1].innerText,
'actualAmount': rowItem.cells[4].firstChild.value
});
}

Angular is adding an empty array to a 2D array - where/why?

I'm having a bit of a weird problem and there are now 2 people in my office completely stumped by this (so I hope it's not something embarrassingly obvious!).
As an overview, we have a SQLite database that could contain any number of tables, each with any number of rows or columns. We want to display this data in a page in an Electron app.
We have an Angular page in our Electron app (with Express/Node as a backend) which makes some calls to an Express endpoint (which gets data from the SQLite db) and we end up with two 2D arrays of data - one for the table headers ($scope.tableHeaders) and one for the table content ($scope.documentsList).
The code for the calls is below:
$http.get('http://localhost:3000/tableCount').then(function (res) {
if (res.data.numberoftables) {
$scope.count = res.data.numberoftables;
var i;
$scope.documentsList = new Array();
$scope.tableHeaders = new Array();
for (i = 1; i <= $scope.count; i++) {
var tableNo = i;
//loop through tables
***$http.get('http://localhost:3000/doclist/' + tableNo).then(function (resDocs) {
//get table content
if (resDocs.data) {
***$scope.documentsList.push(resDocs.data);
}
});
$http.get('http://localhost:3000/tableColumns/' + tableNo).then(function (resHeads) {
//get table headers
if (resHeads.data) {
$scope.tableHeaders.push(resHeads.data);
}
});
}
}
});
Just for fun, here's our HTML:
<div id="documentTables">
<div ng-repeat="tableID in getNumberArray(count)">
<table st-table="documentsList[tableID]" class="table table-condensed table-hover">
<thead>
<tr st-safe-src="tableHeaders[tableID]">
<th ng-repeat="col in tableHeaders[tableID]">
{{col}}
</th>
</tr>
<tr st-safe-src="tableHeaders[tableID]" colspan="{{tableHeaders[tableID].length}}">
<th colspan="1" ng-repeat="col in tableHeaders[tableID]">
<input id="{{col + 'searchbox' + tableID}}" st-search="col" placeholder="{{col}}" class="input-sm form-control" type="search" />
</th>
</tr>
</thead>
<tbody>
<tr st-safe-src="documentsList[tableID]" ng-repeat="document in documentsList[tableID]">
<td ng-repeat="col in tableHeaders[tableID]">
{{document[col].value}}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="{{tableHeaders[tableID].length}}" class="text-center">
<div st-pagination="" st-items-by-page="10" st-displayed-pages="7"></div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
The problem we're coming across is that no actual data is displayed in the tables. Somewhere between the starred lines (***) in the JS above, an empty array for each table is added. So if we have two tables in our database, we end up with documentsList = Array[4] with documentsList[0] and documentsList[1] being empty arrays. Why/where would this be happening, and how can I fix it?
Note - if you'd like to test this out without our endpoints, try out these variables:
$scope.count = 2;
$scope.tableHeaders = [["TabNo", "Document", "PageNumber", "Date"],["TabNo", "Document", "PageNumber"]];
$scope.documentsList = [];
$scope.documentsList.push(JSON.parse('[{"idANX":1,"pathANX":"Product Overview.pdf","isHeaderANX":1,"isExcludedANX":0,"isNotHyperlinkedANX":0,"isSubHeaderANX":0,"HyperlinkedColumnANX":1,"TabNo":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"1"},"Document":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"Product Overview.pdf","isLastCell":false,"value":"Product Overview"},"PageNumber":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"1 - 2"},"Date":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":true,"value":"18 August 2015"}},{"idANX":2,"pathANX":"Spec.pdf","isHeaderANX":0,"isExcludedANX":0,"isNotHyperlinkedANX":0,"isSubHeaderANX":0,"HyperlinkedColumnANX":1,"TabNo":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"2"},"Document":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"Spec.pdf","isLastCell":false,"value":"Spec"},"PageNumber":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"3 - 4"},"Date":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":true,"value":"1 April 2015"}}]');
$scope.documentsList.push(JSON.parse('[{"idANX":1,"pathANX":"Product Overview.pdf","isHeaderANX":0,"isExcludedANX":0,"isNotHyperlinkedANX":0,"isSubHeaderANX":0,"HyperlinkedColumnANX":1,"TabNo":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"1"},"Document":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"Product Overview.pdf","isLastCell":false,"value":"Product Overview"},"PageNumber":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"1 - 2"}},{"idANX":2,"pathANX":"Spec.pdf","isHeaderANX":0,"isExcludedANX":0,"isNotHyperlinkedANX":0,"isSubHeaderANX":0,"HyperlinkedColumnANX":1,"TabNo":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"2"},"Document":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"Spec.pdf","isLastCell":false,"value":"Spec"},"PageNumber":{"colspan":0,"rowspan":0,"hyperlinkedDoc":"","isLastCell":false,"value":"3 - 4"}}]');
$scope.getNumberArray = function (num) {
var n = new Array(num);
var i;
for (i = 0; i < num; i++) {
n[i] = i;
}
return n;
}
$scope.rowClass = function (row) {
if (row.isSubHeaderANX == 1) {
return 'subheader';
} else if (row.isHeaderANX == 1) {
return 'header';
}
else { return 'doctablerow'; }
}
Also pagination and filtering don't work but that's an issue for when our table actually contains data.
Edit: Probably should have mentioned that this is using angular-smart-table
You should take a look at how asynchronous requests and promises works. To make your code run you could do this: var promises = []; // Creates an array to store the promises
$http.get('http://localhost:3000/tableCount').then(function (res) {
if (res.data.numberoftables) {
$scope.count = res.data.numberoftables;
var i;
$scope.documentsList = new Array();
$scope.tableHeaders = new Array();
var promises = [];
for (i = 1; i <= $scope.count; i++) {
var tableNo = i;
$scope.getHttp(i).then(function(resp){
$scope.documentsList.push(resolutions[0]);
$scope.tableHeaders.push(resolutions[1]);
});
}
}
});
$scope.getHttp = function(tableNo){
var promise;
promise = $http({
url:'http://localhost:3000/doclist/' + tableNo,
method:'get'
});
promises.push(promise);
promise = $http({
url:'http://localhost:3000/tableColumns/' + tableNo,
method:'get'
});
promises.push(promise);
return $q.all(promises);
}
Make the changes accordingly. I did not test it because dont have complete controller.But for sure, if you are looping http, make sure promises are stored.

Put JS object in html <table>

I have a HTML <form> that collects 5 different types of data, this gets place in a Javascript object, which looks like this:
var memberObj = [
{
name: "testname",
prof: "profession",
level: 0,
guild: "guild",
server: "server",
}
];
What I want to is take these object properties and place then into a table, which looks like this:
<table class="table table-striped" id="memberList">
<tr>
<th>Character name</th>
<th>Profession</th>
<th>Level</th>
<th>Guild</th>
<th>Server</th>
</tr>
</table>
I basically want to create a new <tr> for each object and a new <td> for each object.property.
How should I go about doing this? I have looked around on Stack Overflow but not found anything that has helped me.
Just use two for loops to iterate over objects, then columns.
Use jQuery's append function to add html code to the table
var cols = ['name', 'prof', 'level', 'guild', 'server'];
for (var i = 0; i < memberObj.length; i++) {
$('table').append('<tr></tr>');
for (var j = 0; j < cols.length; j++) {
$('table tr:last-child').append('<td>' + memberObj[i][cols[j]] + '</td>');
}
}
Check out a working JSFiddle

Create a table with many rows without push in Knockout js

I'am trying to create a table with a 100 rows but I dont want to use push because then the page gets rendered for each push. The table should be empty at first but when I click a button the table will create all the rows.
The problem here is that I dont se the rows when I click the button. But I can only set self.row = ko.observableArray() once?
JS
RowModel = function(numbers) {
var self = this;
self.numbers = numbers;
}
TableViewModel = function() {
var self = this;
self.rows = null;
self.createRows = function() {
var arr = [];
var numbers = [];
for(var i=0; i < 100; i++){
for(var p=0; p < 4; p++){
numbers[p] = p;
}
arr[i] = new RowModel(numbers);
}
self.rows = ko.observableArray(arr);
}
};
ko.applyBindings(new TableViewModel());
HTML
<button data-bind="click: createRows">Create</button>
<table>
<tbody data-bind="foreach: rows">
<tr>
<td data-bind="text: numbers[0]"></td
<td data-bind="text: numbers[1]"></td>
<td data-bind="text: numbers[2]"></td>
<td data-bind="text: numbers[3]"></td>
</tr>
</tbody>
</table>
Always create the observable up front, and set the data using a function call with the data e.g.
self.rows = ko.observable([]);
Then set the data (not as a push for each, as you correctly said) using:
self.rows(arr);
The full code is here in this fiddle:https://jsfiddle.net/brianlmerritt/y0x0wwy5/

Find table data store in within an array of arrays

I need to get data from a table and store it in an array. Each row of the table should be a new array within an array. Basically the html looks like this:
<table id="contactlisttable">
<tr>
<th>Name</th>
<th>Title</th>
<th>Phone</th>
</tr>
<tr>
<td class="contactlist contactlistlastfirst">Joey</td>
<td class="contactlist contactlisttitle">webdesigner</td>
<td class="contactlist contactlistphone">5555555</td>
</tr>
<tr>
<td class="contactlist contactlistlastfirst">Anthony</td>
<td class="contactlist contactlisttitle">webdesigner</td>
<td class="contactlist contactlistphone">5555555</td>
</tr>
</table>
ect...
Here is my code
jQuery(document).ready(function(){
$(function(){
var $table = $("#contactlisttable"),
$headerCells = $table.find("tr th"),
$myrows = $table.find("tr"); // Changed this to loop through rows
var headers = [],
rows = [];
$headerCells.each(function() {
headers[headers.length] = $(this).text();
});
$myrows.each(function() {
$mycells = $myrows.find( "td.contactlist" ); // loop through cells of each row
cells = []
$mycells.each(function() {
cells.push($(this).text());
});
if ( cells.length > 0 ) {
rows.push(cells);
}
});
console.log(headers);
console.log(rows);
});
});
my current code out puts
[["Waddell, Joey", "webdesigner", "", 15 more...], ["Waddell, Joey", "webdesigner", "", 15 more...],
the desired output would be:
["Name","Title","Phone"]
[["Joey","webdesigner","555555"]
["Anthony","webdesigner","555555"]]
I think this can be simpler:
Live Demo
JS
$(function(){
var results = [];
var row = -1;
$('#contactlisttable').find('th, td').each(function(i, val){
if(i % 3 === 0){ //New Row?
results.push([]);
row++;//Increment the row counter
}
results[row].push(this.textContent || this.innerText); //Add the values (textContent is standard while innerText is not)
});
console.log(results);
});
EDIT
Here's an even better solution (IE9+ compatible). It accounts for variable row lengths unlike my previous solution.
Live Demo
JS
//IE9+ compatable solution
$(function(){
var results = [], row;
$('#contactlisttable').find('th, td').each(function(){
if(!this.previousElementSibling){ //New Row?
row = [];
results.push(row);
}
row.push(this.textContent || this.innerText); //Add the values (textContent is standard while innerText is not)
});
console.log(results);
});

Categories