I have been trying and failing to iterate through some JSON Data with Mustache JS in order to populate a table which looks like:
{
"Pay":[
[
"Regular Hours",
"$75.00",
"$75.00"
]
],
"Earnings":[
[
"Regular Earnings",
"$2,277.00",
"$1,200.00"
],
[
"Non Tax Vacation Pay",
"$0.00",
"$50.80"
]
],
"Deductions":[
[
"Other Deduction 5",
"$0.00",
"$50.00"
]
]
}
How would I iterate using Mustache JS in order to have every inner array as rows and the outer array as headers like this:
<tr>
<th colspan="4">Pay</th>
</tr>
<tr>
<td>Regular Hours</td>
<td>75</td>
<td>75</td>
</tr>
<!-- Etc. -->
Any help would be greatly appreciated
This issue has made me consider switching over to handlebars to avoid the need for hacky code. The data being passed in is the JSON input from the original question. This function will format the data into key value pairs, after which the data is rendered by the Mustache template.
function (data) {
var payslipList = JSON.parse(data.d);
formattedData = { 'entries': [] };
for (var property in payslipList) {
if (payslipList.hasOwnProperty(property)) {
formattedData['entries'].push({
'key': property,
'value': payslipList[property]
});
}
}
var tablePayslip = $("#tblPayDetails tbody");
$.each(formattedData, function (id, payslip) {
var template = $('#renderPaystub').html();
var html = Mustache.render(template, payslip);
tablePayslip.append(html);
});
The template to access the key value pairs would look something like this:
<script type="text/template" id="renderPaystub">
{{#.}}
{{#.}}
<tr>
<th colspan="3">{{key}}</th>
</tr>
{{/.}}
{{#value}}
<tr>
{{#.}}<td>{{.}}</td>{{/.}}
</tr>
{{/value}}
{{/.}}
</script>
This template is fairly ugly and ambiguous, if there is a better method to achieve this, feel free to let me know.
Related
I am using a node JS app to send an email using amazon SES using the ses.sendTemplatedEmail API
I have also mentioned the template's pure html file for reference if need be
how do i achieve expected output ? i don't know what is going wrong and why it is using scientific when decimal is specified in JSON
test.js
const aws=require('aws-sdk')
const ses = new aws.SES({ apiVersion: "2020-12-01",region:"us-east-1"});
var a = {
"Items": [
{
"timeSinceInactive": 0.00011574074074074075,
"id": "myid1",
"ssid": "myssid",
"deviceName": "devicename1"
},
{
"timeSinceInactive": 0.00009259259259259259,
"id": "myid2",
"ssid": "myssid2",
"deviceName": "devicename2"
}
]
}
b = JSON.stringify(a)
console.log(b)
async function sesSendEmail(b,ses) {
var params = {
Source: "abc#gmail.com",
Template: "mytemplatename",
Destination: {
ToAddresses: ["xyz#gmail.com"] // Email address/addresses that you want to send your email
},
TemplateData: b,
}
try {
await ses.sendTemplatedEmail(params).promise()
}
catch (err) {
console.log(err)
throw new Error(err)
}
};
function setAwsCredentials() {
awsCredentials = {
region: "us-east-1",
accessKeyId: "",
secretAccessKey: ""
};
aws.config.update(awsCredentials);
console.log("Set credentials successfully")
}
setAwsCredentials()
sesSendEmail(b,ses)
template.html
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
{{#each this}}
<td>
{{this}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
Current output:
timeSinceInactive id ssid deviceName
1.1574074074074075E-4 myid1 myssid devicename1
9.259259259259259E-5 myid2 myssid2 devicename2
desired output
timeSinceInactive id ssid deviceName
0.00011574074074074075 myid1 myssid devicename1
0.00009259259259259259 myid2 myssid2 devicename2
EDIT
I need to sort the data as well so converting it to a string is not a feasible alternative unfortunately.
Note
I am using createTemlate API from Amazon SES which supports handlebars.. so the html code is using handlebars by default... that is causing the issue its making it in scientific notation for some reason how do i make it decimal only ?
You might consider converting the numbers to strings before passing them to the template. That way you have control over the formatting.
To my mind you should switch to a template that is less generic and make a call to a custom helper that would display the number as you want. The template will look like this one :
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
<td>
{{customFormatNumber timeSinceInactive}}
</td>
<td>
{{id}}
</td>
<td>
{{ssid}}
</td>
<td>
{{deviceName}}
</td>
</tr>
{{/each}}
</tbody>
</table>
And here is the custom helper that you could write (this is just an example, probably not the one you want exactly) :
Handlebars.registerHelper('customFormatNumber ', function(item, options) {
retrun item.toPrecision(10)
});
I can't wrap my head around a looping system I need to make to build up a table from json data. This is what I've got so far (tried some other stuff but I think this illustrates it the best way).
Looping through the headers works fine, it's just the cells I can't get to work.
This is my dummy data:
tableMockData = [
{
"header": "TH 1",
"rows": [
"TH1 - row1",
"TH1 -row2",
"TH1 - row3",
"TH1 - row4"
]
},
{
"header": "TH 2",
"rows": [
"TH2 -row1",
"TH2 - row2",
"TH2 - row3",
"TH2 - row4",
]
},
{
"header": "TH 3",
"rows": [
"TH3 -row1",
"TH3 - row2",
"TH3 - row3",
"TH3 - row4",
]
},
{
"header": "TH 4",
"rows": [
"TH4 - row1",
"TH4 - row2",
"TH4 - row3",
"TH4 - row4",
]
}
]
This is my basic loop as starting point:
<tr *ngFor="let row of tableMockData; let i = index">
<td>{{row.rows[i]}}</td>
</tr>
This is my outcome:
This is my desired outcome:
Can someone point me out in the right direction, I know which cell needs to go where but I simply can't wrap my head around how to loop through it.
Thanks
Update:
here is a stackblitz example:
https://stackblitz.com/edit/angular-cdoqwb
Update your Html with below code
<table>
<tr>
<th *ngFor="let row of tableMockData; let i = index">{{row.header}}
</th>
</tr>
<tr *ngFor="let row of tableMockData; let i = index">
<td *ngFor="let row1 of row.rows">
{{row1}}
</td>
</tr>
</table>
You do not properly bind your JSON.
I have a snippets of JSON array as shown below:
[{
"auction_number": "015",
"email": "pete#abc.com",
"first_name": "Peter",
"last_name": "Dan",
"table": 0,
"id": "015"
},
{
"auction_number": "024",
"email": "dan#gog.com",
"first_name": "Dan",
"last_name": "Fain",
"table": 0,
"id": "024"
}
]
Typescript Code:
The typescript (ts) for the above JSON array is shown below. Here attendees is an array object.
attendees: Attendee[];
constructor(public authService: AuthService) {
const str = localStorage.getItem("attendees");
if(str) {
this.attendees = JSON.parse(str);
console.log(str);
}
}
HTML Code:
The HTML code which I have used in order to iterate everything from the JSON array (in the typescript code) is shown below. For some reasons, it is not able to iterate attendees in the HTML.
<tr *ngFor="let row of attendees">
<td class="left">{{ attendees.first_name }} {{ attendees.last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>
Problem Statement:
I am wondering what changes I should make in the HTML code above so that I am successfully able to iterate attendees array. I tried using ngfor directive but somehow it didn't work.
You should reference fields in each row as row.first_name because you set each attendee as let row of attendees. The variable you defined is row.
You are accessing the parent loop again, you should access only the elements of row
<tr *ngFor="let row of attendees">
<td class="left">{{ row .first_name }} {{ row .last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>
I have a scenario to bind a html table using angular js. In my table i need to show an a tag based on another column value(Payment Status). If its fully paid no need to show the a tag, else need to show it for very next element. I am a new one in angular.
<table>
<thead>
<tr>
<th>Month</th>
<th>Installement</th>
<th>PaymentAmount</th>
<th>PaymentDate</th>
<th>Payment Status</th>
<th>Pay</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="row in rowCollection|orderBy:type:reverse|filter:searchKeyword|itemsPerPage:maxsize">
<td>{{row.Month}}</td>
<td>{{row.MonthlyInstallement}}</td>
<td>{{row.PaymentAmount}}</td>
<td>{{row.PaymentDate}}</td>
<td>{{row.PaymentStatus}}</td>
<td ng-if="row.PaymentStatus == 'UNPAID'">
Pay Online
</td>
<td ng-if="row.PaymentStatus == 'FULLY_PAID'">
</td>
</tr>
</tbody>
</table>
function bindFinanceDetails() {
var finUrl = baseurl + 'api/FinancialStatement/GetCarFinanceInfo';
var req = {
method: 'post',
data: {
LoginID: LoginID,
ContractNumber: 11170200669,
CustomerId: 2355898046
},
url: finUrl,
headers: {
RequestedPlatform: "Web",
RequestedLanguage: cookiePreferredLanguage,
Logintoken: $cookieStore.get('LoginToken'),
LoginId: LoginID
}
};
$http(req).then(function(response) {
var getData = response.data.FinanceList;
$scope.rowCollection = getData;
}, function(error) {
toastr.error($filter('translate')('Error Occured'));
});
}
A quite hacky solution will be something like the following (just showing you the needed change in the unpaid td element):
<td ng-if="row.PaymentStatus === 'UNPAID'" ng-show="$index === data.payOnlineIndex"
ng-init="data.payOnlineIndex = (!data.payOnlineIndex || (data.payOnlineIndex > $index)) ? $index : data.payOnlineIndex">
Pay Online
</td>
This way ng-init will run for all unpaid elements, setting the smallest index to the payOnlineIndex variable. ng-show will make sure to only show that one element that has the smallest index.
I encapsulate payOnlineIndex with a data object to keep a stable reference to it. This also requires the following addition to the controller code:
$scope.data = { payOnlineIndex: null };
See a working jsFiddle example here: https://jsfiddle.net/t3vktv0r/
Another option is running your filter and orderBy in the controller, searching for the first occurrence of an "unpaid" row, and marking that element for the "pay online" feature with some flag you can test with ng-if in your view.
I have an Asp.Net MVC 5 web application. I am using JQuery Datatables v1.10.16 to display tabular data within one of the razor views. The data being returned to the datatable is via an ajax call and returning Json.
This is my razor view
<table id="data_table" class="display" style="width:100%">
<thead>
<tr>
<td>Evaluation ID</td>
<td>Applicant Name</td>
</tr>
</thead>
<tfoot>
<tr>
<td>Evaluation ID</td>
<td>Applicant Name</td>
</tr>
</tfoot>
</table>
<script type="text/javascript">
$(document).ready(function () {
$('#data_table').DataTable({
"ajax": '/EvalDashboard/GetEvaluationData',
"dataSrc": 'evaluations',
"columns": [
{ data: 'evaluationID' },
{ data: 'applicantName' }
]
});
});
</script>
This is my method which is called inside the controller EvalDashboard
public JsonResult GetEvaluationData()
{
var evaluations = _evalService.GetAllCecEvaluations(null, null)
.Take(20).Select(x => new
{
evaluationID = x.EvaluationID,
applicantName = x.tblcourseapplicant.FullName
}).ToList();
return Json(evaluations, JsonRequestBehavior.AllowGet);
}
When I run the app, I can see that the method GetEvaluationData() is being called, however, no data is returned to the datatable in the view, I only get a message saying Loading...
I'm not sure if the problem is because I'm returning an annonymous type inside my method.
Could someone please help?
Thanks.
The problem was that I had not included the keyword data inside the Json return statement like so:
return Json(new { data = evaluations }, JsonRequestBehavior.AllowGet);
This fixed the problem I was having.