cant generate the PDF(with all details) using html-pdf in NodeJS - javascript

I am a bit stuck when creating the PDF from the html template. if i use the static entries it does work but i am looking to generate the pdf for multiple items and the items can vary each time, i am not sure if i am missing something any suggestion guys please.
after i added .map function in the pdfTemplate.js file as below to go through each object and get the price, it seems to not working properly
snippet from the main ./documents/pdfTemplate Js file
customer_dataand_Itemsbought.map((eachitem) => {
total = total + eachitem.price;
return ` <tr class="heading">
<td>Bought items:</td>
<td>Price</td>
</tr>
<tr class="item">
<td>First item:</td>
<td>${eachitem.price}$</td>
</tr>
<tr class="item">
<td>Second item:</td>
<td>${eachitem.price}$</td>
</tr>`;
})`
Note: PDF is still generating but missing every bit that i included after the .map function
main ./documents/pdfTemplateJs file
module.exports = (customer_dataand_Itemsbought) => {
//customer_dataand_Itemsbought is array of objects[obj[0],obj[1],...] and at obj[0] is the customer details object and after that each index object contains the customer bought items detail/price
let customer_Name = customer_dataand_Itemsbought[0].user_FirstName;
let receipt_Id = customer_dataand_Itemsbought[0].Invoice_No_latest;
let total_Price;
customer_dataand_Itemsbought.shift();
const today = new Date();
return `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>PDF Result Template</title>
<style>
........
</style>
</head>
<body>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tr class="top">
<td colspan="2">
<table>
<tr>
<td class="title"><img src="https://i2.wp.com/cleverlogos.co/wp-content/uploads/2018/05/reciepthound_1.jpg?fit=800%2C600&ssl=1"
style="width:100%; max-width:156px;"></td>
<td>
Datum: ${`${today.getDate()}. ${today.getMonth() + 1}. ${today.getFullYear()}.`}
</td>
</tr>
</table>
</td>
</tr>
<tr class="information">
<td colspan="2">
<table>
<tr>
<td>
Customer name: ${customer_Name} // this still appears on the PDF
</td>
<td>
Receipt number: ${receipt_Id} // this still appears on the PDF
</td>
</tr>
</table>
</td>
</tr>`;
// here i used the .map function to go through each array object. nothing appears from here onwards on the pdf
customer_dataand_Itemsbought.map((eachitem) => {
total = total + eachitem.price;
return ` <tr class="heading">
<td>Bought items:</td>
<td>Price</td>
</tr>
<tr class="item">
<td>First item:</td>
<td>${eachitem.price}$</td>
</tr>
<tr class="item">
<td>Second item:</td>
<td>${eachitem.price}$</td>
</tr>`;
})`
</table>
<br />
<h1 class="justify-center">Total price: ${total_Price}£</h1>
</div>
</body>
</html>
`;
};
at server.js side
const pdf = require("html-pdf");
const pdfTemplate = require("./documents/pdfTemplate");
pdf.create(pdfTemplate(customer_dataand_Itemsbought), {}).toFile("./filename.pdf", function (err, res) {
if (err) {
console.log(err);
}
});

When you have enclosed map function's body in curly braces - meaning you have multiple statements for processing data, you are expected to return from it explicitly:
customer_dataand_Itemsbought.map((eachitem) => {
total = total + eachitem.price;
return `<tr class="heading">
<td>Bought items:</td>
<td>Price</td>
</tr>
<tr class="item">
<td>First item:</td>
<td>${eachitem.price}$</td>
</tr>
<tr class="item">
<td>Second item:</td>
<td>${eachitem.price}$</td>
</tr>`;
})

Related

How to create excel with data from html pages?

I have an excel spreadsheet template. I need to create excel file from data in html/php page. That is, the data on the html page is scattered throughout the page, and I need to somehow collect all this data (through classes or ids) and place it in certain cells of the table.
I tried a lot of ready-made solutions, for example https://github.com/jmaister/excellentexport/tree/master/test
<html>
<head>
<script type="text/javascript" src="https://unpkg.com/xlsx#0.15.1/dist/xlsx.full.min.js"></script>
</head>
<body>
<table id="tbl_exporttable_to_xls" border="1">
<thead>
<th>Sr</th>
<th>Name</th>
<th>Location</th>
<th>Job Profile</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>
<p>Amit Sarna</p>
</td>
<td>Florida</td>
<td>Data Scientist</td>
</tr>
<tr>
<td>2</td>
<td>
<p>Sagar Gada</p>
</td>
<td>California</td>
<td>Sr FullStack Dev</td>
</tr>
<tr>
<td>3</td>
<td>
<p>Ricky Marck</p>
</td>
<td>Nevada</td>
<td>Sr .Net Dev</td>
</tr>
<tr>
<td>4</td>
<td>
<p>Andrea Ely</p>
</td>
<td>New York</td>
<td>Sr Delivery Mgr</td>
</tr>
<tr>
<td>5</td>
<td>
<p>Sunita Devgan</p>
</td>
<td>Colorado</td>
<td>UiUx Expert</td>
</tr>
</tbody>
</table>
<button onclick="ExportToExcel('xlsx')">Export table to excel</button>
<script>
function ExportToExcel(type, fn, dl) {
var elt = document.getElementById('tbl_exporttable_to_xls');
var wb = XLSX.utils.table_to_book(elt, { sheet: "sheet1" });
return dl ?
XLSX.write(wb, { bookType: type, bookSST: true, type: 'base64' }) :
XLSX.writeFile(wb, fn || ('MySheetName.' + (type || 'xlsx')));
}
</script>
</body>
</html>
Only import from html table is used everywhere.
Sorry for my English, so I'm attaching images for more details.
enter image description here
Tried options
https://codepedia.info/javascript-export-html-table-data-to-excel
https://github.com/jmaister/excellentexport/tree/master/test
https://www.webslesson.info/2021/07/how-to-display-excel-data-in-html-table.html
https://codepedia.info/javascript-export-html-table-data-to-excel
but everywhere there is an import only by html table

Javascript Fetch API not showing results on multiple cards

I have a script that fetches the data from a link and then inserts that in tables and shows it to the user. the script worked fine. but then I decided to make the function more dynamic so I added 2 arguments name and Html div name where the data will display. it worked fine when I called the function the first time but it doesn't show any data on the second call. I'm using PHP for my projects and new to javascript. but I made a similar function in PHP but that works. any suggestions?
function getInfoByCountry(name, displayName) {
fetch("https://something.com/countries/" + name)
.then(res => res.json())
.then(data => {
output = `
<tr>
<td>Total Cases</td>
<td>${data.cases}</td>
</tr>
<tr>
<td>Today Cases</td>
<td>${data.todayCases}</td>
</tr>
<tr>
<td>Deaths</td>
<td>${data.deaths}</td>
</tr>
<tr>
<td>Recovered</td>
<td>${data.recovered}</td>
</tr>
<tr>
<td>Critical</td>
<td>${data.critical}</td>
</tr>
<tr>
<td>Active Cases</td>
<td>${data.active}</td>
</tr>
`;
document.getElementById(displayName).innerHTML = output;
});
}
getInfoByCountry("USA", "USAInfo");
getInfoByCountry("China", "ChinaInfo");
<div class="table-responsive">
<table class="table table-striped mb-0">
<tbody id="ChinaInfo">
</tbody>
</table>
</div>
Add return like this
function getInfoByCountry(name, displayName) {
var display = document.getElementById(displayName);
return fetch("https://smthing.com/countries/"+name)
.then(res => res.json())
.then(data => {
output = `
<tr>
<td>Total Cases</td>
<td>${data.cases}</td>
</tr>
<tr>
<td>Today Cases</td>
<td>${data.todayCases}</td>
</tr>
<tr>
<td>Deaths</td>
<td>${data.deaths}</td>
</tr>
<tr>
<td>Recovered</td>
<td>${data.recovered}</td>
</tr>
<tr>
<td>Critical</td>
<td>${data.critical}</td>
</tr>
<tr>
<td>Active Cases</td>
<td>${data.active}</td>
</tr>
`;
document.getElementById(displayName).innerHTML += output;
}
);
}
getInfoByCountry("USA", "display");
getInfoByCountry("China", "display");
you just need to add return statement for returning output.
here is fiddle you can check function.
function getInfoByCountry(name,displayName) {
debugger;
return fetch("https://jsonplaceholder.typicode.com/posts/"+name)
.then(res => res.json())
.then(data => {
output = `
<tr>
<td>Total Cases</td>
<td>${data.title}</td>
</tr>
<tr>
<td>Today Cases</td>
<td>${data.body}</td>
</tr>
`;
document.getElementById(displayName).innerHTML = output;
});
}
You are adding the result using displayName as id attribute, you should add another one for USAinfo as mentioned in the comments, or a better implementation would be to create the table dynamically and append the result to the container.
function getInfoByCountry(name, displayName) {
fetch("API_URL" + name)
.then(res => res.json())
.then(data => {
output = `
<table class="table table-striped mb-0">
<tbody>
<tr>
<td>Total Cases</td>
<td>${data.cases}</td>
</tr>
<tr>
<td>Today Cases</td>
<td>${data.todayCases}</td>
</tr>
<tr>
<td>Deaths</td>
<td>${data.deaths}</td>
</tr>
<tr>
<td>Recovered</td>
<td>${data.recovered}</td>
</tr>
<tr>
<td>Critical</td>
<td>${data.critical}</td>
</tr>
<tr>
<td>Active Cases</td>
<td>${data.active}</td>
</tr>
</tbody>
</table><hr />
`;
document.getElementById("container").innerHTML += output;
});
}
getInfoByCountry("USA", "USAInfo");
getInfoByCountry("China", "ChinaInfo");
table, td {
border: 1px solid;
}
<div id="container" class="table-responsive">
</div>

nested ng-repeat with open particular index with respect to repeated data

Every time the toggle is clicked, all payments are getting replaced with new payments. My problem is how to maintain the payments of a particular index of every click and show at respective index. please help me out
here is my html
<tbody data-ng-repeat="invoice in relatedInvoices>
<tr>
<td class="td-bottom-border">
{{invoice.PayableCurrencyCode}} {{invoice.PayablePaidAmount | number: 2}}<br />
<small>
<a data-ng-click="isOpenPayablePayments[$index] = !isOpenPayablePayments[$index]; togglePayablePayments(invoice.PayableInvoiceId)">Paid</a>
</small>
</td>
</tr>
<tr data-ng-show="isOpenPayablePayments[$index]">
<td>
<table>
<thead>
<tr>
<th>Transaction Id</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="payment in payablePayments">
<td>{{payment.TransactionId}}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
Here is my javascript
var getPayments = function (invoiceId) {
paymentService.getPayments(invoiceId).then(function (paymentsResponse) {
return paymentsResponse.data;
});
};
$scope.togglePayablePayments = function(invoiceId) {
$scope.payablePayments = getPayments(invoiceId);
};
If I understood correctly, you want to have "payablePayments" for every invoice.
This is working: http://plnkr.co/edit/cj3jxZ?p=info
Try something like
// init at beginning
$scope.payablePayments = [];
$scope.togglePayablePayments = function(invoiceId) {
$scope.payablePayments[invoiceId] = getPayments(invoiceId);
};
and then
<tr data-ng-repeat="payment in payablePayments[invoice.PayableInvoiceId]">
Otherwise you overwrite the object for the preceding invoice.

how can i only use ng-repeat for fill data in html ,not repeat Html's elements?

I want to have an iterative moving over an array of users , and fill every td with a unique user in array, but I dont want to repeat and produce new html code in every ng-repeat's step.
I just want have a moving on the td's and for each one , put a user inside that td.
<!DOCTYPE html>
<html ng-app="fill">
<head>
<?php include "includes/head.php" ?>
<script type="text/javascript">
(function(){
var fill=angular.module("fill",[]);
fill.controller("fillTable",function($scope){
$scope.users=[ {name:"jack"},
{name:"joe"},
{name:"alen"},
{name:"mina"},
{name:"mari"},
{name:"karen"}
];
});
})()
</script>
</head>
<body>
<table ng-controller="fillTable" border=1>
<tbody ng-repeat="user in users">
<tr>
<td>user 1:{{user.name}}</td>
<td>user 2:{{user.name}}</td>
</tr>
<tr>
<td>user 3:{{user.name}}</td>
<td>user 4:{{user.name}}</td>
</tr>
<tr>
<td>user 5:{{user.name}}</td>
<td>user 6:{{user.name}}</td>
</tr>
</tbody>
</table>
</body>
</html>
actually, i have a grid with four columns that i created it by semantic-ui-grid.
now i want to read many articles from dataBase's tables then i have puting that datas inside grid's columns.{like a 'pinterest style' page } a pic for more explain , please see it
You can create pairs in controller:
$scope.users = [
{name:"jack"},
{name:"joe"},
{name:"alen"},
{name:"mina"},
{name:"mari"},
{name:"karen"}
];
$scope.pairs = [];
for (var i = 0; i < $scope.users.length; i+=2) {
$scope.users[i].index = i+1;
if ($scope.users[i+1]) {
$scope.users[i+1].index = i+2;
$scope.pairs.push([$scope.users[i], $scope.users[i+1]]);
} else {
$scope.pairs.push([$scope.users[i]]);
}
}
and iterate over pairs:
<table ng-controller="fillTable" border=1>
<tbody>
<tr ng-repeat="pair in pairs">
<td ng-repeat="user in pair">user {{user.index}}:{{user.name}}</td>
</tr>
</tbody>
</table>
There is no other workaround than to make a special array containing user pairs :
$scope.$watch('users', function() {
$scope.userPairs = [];
for (var i=0;i<$scope.users.length;i=i+2) {
$scope.userPairs.push({
name1 : $scope.users[i].name,
name2 : $scope.users[i+1].name
})
}
})
also use ng-repeat properly (you want to iterate over <tr>'s not <tbody>'s :
<table border=1>
<tbody>
<tr ng-repeat="user in userPairs">
<td>user 1:{{user.name1 }}</td>
<td>user 2:{{user.name2 }}</td>
</tr>
</tbody>
</table>
demo -> http://plnkr.co/edit/yK3F9US4XuS6sPnVv0Dd?p=preview
<table ng-controller="fillTable" border=1>
<tbody ng-repeat="user in users track by $index">
<tr>
<td>user 1:{{users[$index].name}}</td>
<td>user 2:{{users[$index+1].name}}</td>
</tr>
<tr>
<td>user 3:{{users[$index+2].name}}</td>
<td>user 4:{{users[$index+3].name}}</td>
</tr>
<tr>
<td>user 5:{{users[$index+4].name}}</td>
<td>user 6:{{users[$index+5].name}}</td>
</tr>
</tbody>
</table>

Reversing first and last names using jquery

Trying to take this table and take the names, when I click one radio button it changes the names from something like: Tom Hanks to Hanks, Tom. Here is the html:
<h1>Address Book</h1>
Show Names as:
<input name="change_last_first" value="last" type="radio">First, Last
<input name="change_last_first" value="first" type="radio">Last, First
<div>
<table <thead="">
<tbody>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
</tbod
<tbody>
<tr>
<td>9001</td>
<td class="name">Tom Hanks</td>
<td>tomhanks#moviestars.com</td>
</tr>
<tr>
<td>9002</td>
<td class="name">Bruce Willis</td>
<td>brucewillis#moviestars.com</td>
</tr>
<tr>
<td>9003</td>
<td class="name">Jim Carrey</td>
<td>jimcarrey#moviestars.com</td>
</tr>
<tr>
<td>9004</td>
<td class="name">Tom Cruise</td>
<td>tomcruise#moviestars.com</td>
</tr>
<script>
</script>
</tbody>
</table>
</div>
<meta charset="utf-8">
<title>Interview Test</title>
<link rel="stylesheet" href="./webassets/style.css" media="screen" type="text/css">
<h1>Company Staff List</h1>
<div>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>9001</td>
<td>Tom Hanks</td>
</tr>
<tr>
<td>9002</td>
<td>Bruce Willis</td>
</tr>
<tr>
<td>9003</td>
<td>Jim Carrey</td>
</tr>
<tr>
<td>9004</td>
<td>Tom Cruise</td>
</tr>
</tbody>
</table>
</div>
Here is the jquery, its all I could come up with and does not work at all. :(
$(document).ready(function () {
$("input[name='change_last_first']").click(function () {
$(".name").text(function() {
$(this).split(" ").reverse();
});
});
});
});
You need to return the result. Also since you are using the function arg syntax of text use the second argument of the function for the current text.
$(".name").text(function(_, cur) {
return curText.split(/\s+|,/).reverse();
});
Fiddle
Another easy way to handle this assuming the general format of name is First Last or Last, First:
$("input[name='change_last_first']").change(function () {
var arr = [" ", ","],
sep = this.value === 'first' ? 0 : 1;
$(".name").text(function (_, curText) {
return curText.split(arr[sep % 2]).reverse().join(arr[(sep + 1) % 2]);
});
});
Demo
For this you need to split full name with space and than you can use reverse().
Note: because reverse() is a method of array instances. It won't directly work on a string. You should first split the characters of the string into an array, reverse the array and then join back into a string.
$("input[name='change_last_first']").click(function () {
$(".name").each(function() {
var revName = $(this).text().split(" ").reverse().join(" ");
$(this).text(revName);
});
});
Try This

Categories

Resources