3

I created an ERP like system using Node.JS as backend and AngularJS as frontend. I need to print an invoice. So I need to download invoice as PDF. I have designed the whole Invoice with nice formatting with bootstrap CSS. And I got a solution to print that. Here's that code.

$scope.downloadQuotation = function () {
        html2canvas(document.getElementById('printQuotation'), {
            onrendered: function (canvas) {
                var data = canvas.toDataURL();
                var docDefinition = {
                    content: [{
                        image: data,
                        width: 540
                    }]
                };
                pdfMake.createPdf(docDefinition).download("Quotation_'" + $scope.selectedQuotation.id + "'.pdf");
            }
        });
    };

I am using 'html2canvas' and also pdfMake to generate this PDF. And 'printQuotation' is the div name of that HTML Invoice. There's an item table loading with dynamic data and some other information. Just a normal invoice.

This solution works fine sometimes. But when display size changes, I only get a blank PDF. Problem is if the invoice is not fit to display on the user's machine(laptop), we get a blank PDF. So please help me with this.

I don't need this way actually. Any solution. Client side or server side. My server is NodeJs and I saw many solutions and tried. But not working for me. This is the HTML page I need to convert to PDF.

<div class="widgets">
<button class="btn btn-success" ng-click="printQuotation()">Print Quotation</button>
<button class="btn btn-info" ng-click="downloadQuotation()">Download Quotation</button>
<a class="btn btn-warning" href="#/quotation/add">Create New Quotation</a>
<a class="btn btn-primary" href="#/quotation/view">Back to View All</a>
<br><br>
<div class="row" ba-panel id="printQuotation">
    <div style="min-width: 871px;overflow-x: scroll">
        <div class="">
            <hr>
            <div class="row">
                <div class="col-lg-6">
                    <p style="font-size: 18px;"><b>Quotation No : {{selectedQuotation.id}}</b></p>
                </div>
                <div class="col-lg-6" style="text-align: right">
                    <p style="font-size: 18px;"><b>Date : {{selectedQuotation.date | date:'yyyy-MM-dd'}}</b></p>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6">
                    <p style="font-size: 18px;"><b>Mr / Messrs : {{selectedQuotation.customer_name}}</b></p>
                    <p style="font-size: 18px;">We have pleasure in submitting our offer for the following items
                        :</p>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6">
                    <p style="font-size: 18px;"><b>Pump No : : {{selectedQuotation.pump_no}}</b></p>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6">
                    <p style="font-size: 18px;"><b>Se No : {{selectedQuotation.se_no}}</b></p>
                </div>
                <div class="col-lg-6" style="text-align: right">
                    <p style="font-size: 18px;"><b>Type : {{selectedQuotation.type}}</b></p>
                </div>
            </div>
            <br><br>
            <table class="table table-hover">
                <thead>
                <tr class="black-muted-bg">
                    <th style="font-size: 18px;">ID</th>
                    <th style="font-size: 18px;">Description</th>
                    <th style="font-size: 18px;">Qty</th>
                    <th style="font-size: 18px;">Unit Rate (R.O)</th>
                    <th style="font-size: 18px;">Amount (R.O)</th>
                </tr>
                </thead>
                <tbody>
                <tr ng-repeat="item in selectedQuotationItems" class="no-top-border">
                    <td style="font-size: 18px;">{{item.item_id}}</td>
                    <td style="font-size: 18px;">{{item.item_name}}</td>
                    <td style="font-size: 18px;">{{item.qty}}</td>
                    <td style="font-size: 18px;">{{item.unit_rate | currency:"":2}}</td>
                    <td style="font-size: 18px;">{{item.qty * item.unit_rate | currency:"":2}}</td>
                </tr>
                </tbody>
            </table>
            <hr>
            <div class="row">
                <div class="col-lg-6">
                    <p style="font-size: 18px;"><b>Note : {{selectedQuotation.remark}}</b></p>
                </div>
                <div class="col-lg-6" style="text-align: right">
                    <p style="font-size: 18px;"><b>Total Amount : {{selectedQuotation.total_amount |
                        currency:"":2}}</b></p>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6">

                </div>
                <div class="col-lg-6" style="text-align: right">
                    <p style="font-size: 18px;"><b>Discount : {{selectedQuotation.discount | currency:"":2}}</b></p>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-6">

                </div>
                <div class="col-lg-6" style="text-align: right">
                    <p style="font-size: 18px;"><b>Net Amount : {{selectedQuotation.net_amount | currency:"":2}}</b>
                    </p>
                </div>
            </div>
            <hr>
            <div class="row">
                <div class="col-lg-6">
                    <h3>PATROL INJECTOR SERVICES</h3>
                    <P style="font-size: 18px;">Specialist in all kinds of Diesel lnjection Pump & lnjectors</P>
                    <br>
                    <p>Prepared by : ................................</p>
                </div>
                <div class="col-lg-6" style="text-align: right">
                    <h3>For MUSCAT DIESEL PUMP SERVICES</h3>
                    <br>
                    <p style="font-size: 18px;">Authorized by : ................................</p>
                </div>
            </div>
        </div>
    </div>
</div>
<button class="btn btn-success" ng-click="printQuotation()">Print Quotation</button>
<button class="btn btn-info" ng-click="downloadQuotation()">Download Quotation</button>
<a class="btn btn-warning" href="#/quotation/add">Create New Quotation</a>
<a class="btn btn-primary" href="#/quotation/view">Back to View All</a>

Check the div following. I need to convert all the content inside that div to PDF.

<div class="row" ba-panel id="printQuotation">

Any suggestions? Please provide a sample code or something like that. Really stuck in this for a while and no solution at all.

10
  • Have you tried PDFKit?? Dont depende upon client side for PDF generation. Do it from server side Commented Mar 3, 2017 at 16:58
  • I tried bro. No good. I just followed some example. Can you send me a better one plz. Commented Mar 3, 2017 at 17:13
  • @harish2704 And also is it possible to take data from server and display as a table in PDFKit ? I need to create/generate a full invoice. Is that possible ? Commented Mar 3, 2017 at 17:14
  • In my knowledge, PDFKit is best available option for this. If you can share the example you tried, I can check Commented Mar 4, 2017 at 5:40
  • @harish2704 Hi, I just want to create this. faceinfotech.com/ReportDemo.pdf Please check this and let me know a possible way to do this. At the top, we have to leave 3 inch for their letter head and logos. There are two formats. they have pre-printed papers. All the data is loading via MySQL database and also items table too Commented Mar 6, 2017 at 6:16

2 Answers 2

3

I've made a prototype on GitHub for you, which you can find here: https://github.com/Geexteam/proto-node-pdf

It uses packages: html-pdf and handlebars as a basis.
Good luck!

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks you very much :) I will try this and let you know. Very kind of you.
Your solutions works. I just needed to do some little changes. Loading items via for loop. Like that. :) Thanks you very much.
Anyway can we do this using Jade ? I mean create the template in Jade and populate all the fields and table ?
0

The following solution uses AWS lambda and serverless framework with NodeJS.

There is a github library called serverless-chrome that comes close to the functionality you are looking for.

It works with AWS lambda and nodejs. It uses serverless chrome to visit your website and take screenshot or save the whole website as a PDF file and displays the PDF file. The deployment is pretty simple and uses the serverless framework. I deployed the github library on a client's AWS account.

Here is how the demo link which you get after deployment.

https://1wphj1kzch.execute-api.ap-southeast-1.amazonaws.com/dev/pdf?url=http://www.gmail.com

Replace the http://www.gmail.com with the website link of your choice. It waits for the website to load completely and then takes the screenshot. You can deploy this and use the link like the one generated above to take screenshot and save them or you can use another lambda function and save the pdfs to your S3 bucket on AWS.

Best of all if you are new to AWS you get 400,000 lambda executions free every month.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.