How to Generate and download PDF in Ionic 5 apps
Tags: ionic, javascript, mobile, angular
Published: 2021-08-24 16:50:37

<main role="main"><article class=" u-minHeight100vhOffset65 u-overflowHidden postArticle postArticle--full is-supplementalPostContentLoaded is-withAccentColors" lang="en" ><div class="postArticle-content js-postField js-notesSource editable" id="editor_7" g_editable="true" role="textbox" contenteditable="false" data-default-value="Title
Tell your story…"><section name="966b" class="section section--body section--first"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><p name="814b" class="graf graf--p graf-after--figure">In this tutorial we will learn how we can generate PDF in an Ionic app, and download it to the device. You might have ordered food or any item from some e-commerce application and after ordering you must have downloaded the invoice/bill for it as a proof. Similarly there are several other scenarios where your app might need a PDF generation and download facility.</p><p name="6c87" class="graf graf--p graf-after--p">We will understand this feature through Enappd’s <a href="https://store.enappd.com/product/grocery-complete-platform-user-delivery-and-admin-app/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Grocery Application</a> workflow, where <strong class="markup--strong markup--p-strong">we order some items, then generate an invoice/bill and download it in the form of PDF. </strong>You can follow the same steps to create the PDF generation feature in your own Ionic app.</p><p name="853c" class="graf graf--p graf-after--p">To know more about Grocery Shopping Platform you can read Enappd’s <a href="https://enappd.com/blog/ionic-5-grocery-shopping-user-delivery-and-admin-apps/171"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank"><strong class="markup--strong markup--p-strong">Grocery Shopping Platform Blog</strong></a><strong class="markup--strong markup--p-strong"> </strong>or check the <a href="https://www.youtube.com/watch?v=OC0crxN_31M"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">feature video</a>. Before moving on, we will understand ordering flow of Grocery Application, so it will be easy for us to implement our Invoice task.</p><h3 name="e39e" class="graf graf--h3 graf-after--p">Ionic —&hairsp;Introduction</h3><p name="e01f" class="graf graf--p graf-after--h3">If you are reading this blog, you are probably already aware of <a href="https://ionicframework.com/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener"    target="_blank">Ionic</a>, <a href="https://cordova.apache.org/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener"    target="_blank">Cordova</a> and <a href="https://capacitorjs.com/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener noopener"    target="_blank">Capacitor</a> frameworks. While Ionic is the front-end wrapper framework for mobile UI, Cordova is the build framework that converts Ionic code into a device (Android /iOS) compatible code.</p><p name="b426" class="graf graf--p graf-after--p"><a href="https://capacitorjs.com/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener"    target="_blank">Capacitor</a> is another option in place of Cordova to build apps using Ionic. While Capacitor is born couple of years ago, Cordova has been around for a decade. That’s the reason Cordova has more community made plugins for various unique features, but Capacitor is quickly catching up as well.</p><h3 name="eea7" class="graf graf--h3 graf-after--p">Item Ordering Flow&hairsp;—&hairsp;Grocery&nbsp;Platform</h3><p name="b458" class="graf graf--p graf-after--h3">The flow is same as what you might have encountered while ordering items in any other app. We simply add items to the Cart and Checkout with selected Address (<a href="https://www.youtube.com/watch?v=OC0crxN_31M"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Here’s a video</a> of the flow). In the <a href="https://store.enappd.com/product/grocery-complete-platform-user-delivery-and-admin-app/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Grocery Platform</a>, the items are then automatically added to the ‘My orders’ tab and from there you can download the Invoice/Bill for our ordered Items, as shown below.</p><figure tabindex="0" contenteditable="false" name="56be" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 661px; max-height: 500px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 75.6%;"></div><img class="graf-image" data-image-id="1*yMp7wlBoXmYbYh6GZ5e7jg.jpeg" data-width="661" data-height="500" alt="Enappd’s Grocery shopping platform PDF generation" src="https://cdn-images-1.medium.com/max/800/1*yMp7wlBoXmYbYh6GZ5e7jg.jpeg"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Enappd’s Grocery shopping platform PDF generation</figcaption><br></figure><p name="a0de" class="graf graf--p graf-after--figure">In above screens you can see items in <strong class="markup--strong markup--p-strong">My Order</strong> Tab which we have ordered. From this we can generate Invoice and later download it as PDF, as shown below.</p><figure tabindex="0" contenteditable="false" name="a522" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 320px; max-height: 500px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 156.29999999999998%;"></div><img class="graf-image" data-image-id="1*YbbSzGwbWmm6azpIu3icuw.jpeg" data-width="320" data-height="500" alt="Downloaded PDF in Enappd’s Grocery shopping platform" src="https://cdn-images-1.medium.com/max/800/1*YbbSzGwbWmm6azpIu3icuw.jpeg"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Downloaded PDF in Enappd’s Grocery shopping&nbsp;platform</figcaption><br></figure><p name="a9fe" class="graf graf--p graf-after--figure">You can see the Invoice contains the delivery address, ordered products with price, grand total and many other information. The information in the PDF corresponds to the logged in user, and can be easily changed as you wish.</p><p name="9e9a" class="graf graf--p graf-after--p">Now let’s start the flow to implement PDF generation in our Application. <strong class="markup--strong markup--p-strong">We will create a blank Ionic app with dummy item list and related item details, and ‘My Order’ page UI from where we’ll download the invoice.</strong></p><h3 name="b730" class="graf graf--h3 graf-after--p">Structure of the&nbsp;post</h3><p name="f4b1" class="graf graf--p graf-after--h3">We’ll follow these steps to implement the feature</p><ol class="postList"><li name="cb4c" class="graf graf--li graf-after--p">Create a blank Ionic app</li><li name="83a7" class="graf graf--li graf-after--li">Create the required UI and dummy data for demo purpose</li><li name="03aa" class="graf graf--li graf-after--li">Setup PDF generation plugin</li><li name="f1e7" class="graf graf--li graf-after--li">Setup PDF content and styling</li><li name="b7cc" class="graf graf--li graf-after--li">Test on device</li></ol><h3 name="dc03" class="graf graf--h3 graf-after--li">Step 1&hairsp;—&hairsp;Create a blank Ionic&nbsp;app</h3><p name="60b6" class="graf graf--p graf-after--h3">Generally in all our blogs, we start with creating blank Ionic app, so a new comer or beginner can also try the feature. To create an <strong class="markup--strong markup--p-strong">Ionic Angular</strong> Project you just have to run one command and that’s it&nbsp;! Rest of the things are handled by the Ionic-CLI. Run the below command in you terminal.</p><pre name="648a" class="graf graf--pre graf-after--p">$ ionic start pdfgen blank --type=angular --cordova</pre><p name="348b" class="graf graf--p graf-after--pre">The <code class="markup--code markup--p-code">--type=angular</code> told the CLI to create an <strong class="markup--strong markup--p-strong">Angular</strong> app. And <code class="markup--code markup--p-code">--cordova</code> tells the CLI to integrate Cordova support.</p><p name="b74e" class="graf graf--p graf-after--p">( My environment for this blog is&hairsp;—&hairsp;Node 14.x, Ionic 5.5, Angular 11.x, NPM 7.x, Cordova 10.0 )</p><p name="324d" class="graf graf--p graf-after--p">This will create an empty ionic project in the working directory of your pc. For more details on creating a new Ionic app from scratch, check out our blog on Ionic Apps<a href="https://enappd.com/blog/how-to-create-an-ionic-app-for-beginners/144/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener"    target="_blank"> here</a>.</p><h3 name="77a3" class="graf graf--h3 graf-after--p">Step 2&hairsp;—&hairsp;Create the required UI and dummy&nbsp;data</h3><p name="b2c5" class="graf graf--p graf-after--h3">You can create the required UI as shown in the images for Enappd’ <a href="https://store.enappd.com/product/grocery-complete-platform-user-delivery-and-admin-app/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Grocery Platform</a>, though it’s not mandatory. For demo, you can implement the PDF generation feature just on a simple button, using the dummy data same as a genuine full scale Grocery app.</p><p name="c8be" class="graf graf--p graf-after--p">We’ll use a JSON of dummy order data, which will populate our HTML like the actual app. This JSON can be added and accessed from <code class="markup--code markup--p-code">environment.ts</code>&nbsp;, but in the actual app you’ll have this data coming from server anyway.</p><figure tabindex="0" contenteditable="false" name="d1f0" class="graf graf--figure graf--iframe graf-after--p"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 113.857%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/2f842ed83b7e43c92b2127e49561dee1.js %}</div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for embed (optional)">Dummy order data for PDF generation</figcaption><br></figure><p name="2841" class="graf graf--p graf-after--figure">With this dummy data populated in our UI, here’s how my UI looks</p><figure tabindex="0" contenteditable="false" name="7c4f" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 386px; max-height: 676px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 175.1%;"></div><img class="graf-image" data-image-id="1*18YEoqCDjNc4sxheWnlF3A.png" data-width="386" data-height="676" alt="UI for My Orders page- PDF generation in Ionic apps" src="https://cdn-images-1.medium.com/max/800/1*18YEoqCDjNc4sxheWnlF3A.png"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">UI for My Orders page— PDF generation in Ionic&nbsp;apps</figcaption><br></figure><p name="71fb" class="graf graf--p graf-after--figure">Here’s the HTML and CSS for the UI if you want</p><figure tabindex="0" contenteditable="false" name="83a8" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 266.714%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/f9e28d64e4bbb56a17347ef54fb12571.js %}</div></div></figure><p name="8e41" class="graf graf--p graf-after--figure">We can see in above html code we have mapped through array of products using <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">*ngFor=”let product of order.products”</strong></code>. Note, the dummy data is coming from <code class="markup--code markup--p-code">environment.ts</code> for this demo, but for your actual app it should come from the server.</p><h3 name="a4c7" class="graf graf--h3 graf-after--p">Step 3&hairsp;—&hairsp;Setup PDF generation plugin</h3><p name="d62a" class="graf graf--p graf-after--h3">Let’s install the PDF generation plugin and the npm packages in our application. <strong class="markup--strong markup--p-strong">We will use Cordova PDFGenerator Plugin to implement this feature</strong></p><pre name="16fb" class="graf graf--pre graf-after--p">$ ionic cordova plugin add cordova-pdf-generator<br>$ npm install @ionic-native/pdf-generator</pre><p name="da17" class="graf graf--p graf-after--pre">This above command will add the PDFGenerator to the plugins folder. Once the plugins are installed, add the PDFGenerator Module to <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">app.module.ts</strong></code> like below</p><pre name="2004" class="graf graf--pre graf-after--p">...<br><strong class="markup--strong markup--pre-strong">import { PDFGenerator } from '@ionic-native/pdf-generator/ngx';</strong></pre><pre name="06e5" class="graf graf--pre graf-after--pre">@NgModule({<br>... ,</pre><pre name="74ec" class="graf graf--pre graf-after--pre">providers: [<strong class="markup--strong markup--pre-strong">PDFGenerator</strong>, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],</pre><pre name="691a" class="graf graf--pre graf-after--pre">...<br>})<br>export class AppModule { }</pre><p name="fa9f" class="graf graf--p graf-after--pre">This will provide the PDFGenerator instance available to the complete application and we can use the Plugin in any of the app pages.</p><h3 name="5bea" class="graf graf--h3 graf-after--p">Step 4&hairsp;—&hairsp;Setup PDF content and&nbsp;styling</h3><p name="c600" class="graf graf--p graf-after--h3">Generating a PDF starts from a properly styled HTML. You can either</p><ol class="postList"><li name="9e69" class="graf graf--li graf-after--p">Have same HTML show in the app’s page, AND be printed as PDF, or</li><li name="1942" class="graf graf--li graf-after--li">Use a different HTML to show in app, and different to print in PDF</li></ol><p name="1aaa" class="graf graf--p graf-after--li">Here’s how we’ll generate PDF (Method 1) —</p><p name="59bd" class="graf graf--p graf-after--p">Click on <code class="markup--code markup--p-code">INVOICE</code> button in <strong class="markup--strong markup--p-strong">My Orders</strong> page → Opens a Modal where the order invoice will show up → If you see the details are correct, you can download the invoice using<code class="markup--code markup--p-code">DOWNLOAD</code> button</p><h4 name="5a19" class="graf graf--h4 graf-after--p">Create PDF Download&nbsp;Modal</h4><p name="f654" class="graf graf--p graf-after--h4">To create the Modal Component, you can run the below command&nbsp;:-</p><pre name="469a" class="graf graf--pre graf-after--p">$ ionic generate component components/invoice</pre><p name="ead7" class="graf graf--p graf-after--pre">This above command will add a component in path “components/invoice” like in below folder structure&nbsp;:-</p><figure tabindex="0" contenteditable="false" name="13fb" class="graf graf--figure graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 280px; max-height: 179px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 63.9%;"></div><img class="graf-image" data-image-id="1*IGE7PGNsOia97DZBj4N6BA.png" data-width="280" data-height="179" src="https://cdn-images-1.medium.com/max/800/1*IGE7PGNsOia97DZBj4N6BA.png"><div class="crosshair u-ignoreBlock"></div></div></figure><p name="624c" class="graf graf--p graf-after--figure">Add the Modal component to <code class="markup--code markup--p-code">app.module.ts</code></p><pre name="ca71" class="graf graf--pre graf-after--p">...<br><strong class="markup--strong markup--pre-strong">import { InvoiceComponent } from './components/invoice/invoice.component';</strong></pre><pre name="e4cd" class="graf graf--pre graf-after--pre">@NgModule({</pre><pre name="d4cf" class="graf graf--pre graf-after--pre">declarations: [AppComponent, <strong class="markup--strong markup--pre-strong">InvoiceComponent</strong>],</pre><pre name="7594" class="graf graf--pre graf-after--pre">...<br>})<br>export class AppModule { }</pre><p name="271e" class="graf graf--p graf-after--pre">We will open this modal from <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">openInvoice</strong></code> function of<code class="markup--code markup--p-code">home.page.ts</code>&nbsp;, here’s how the code will look, including the dummy data inclusion from <code class="markup--code markup--p-code">environment.ts</code></p><figure tabindex="0" contenteditable="false" name="ec89" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 103.429%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/0db15ace9e0af73a41f6d173cbec6a14.js %}</div></div></figure><h4 name="e736" class="graf graf--h4 graf-after--figure">PDF Download Modal&nbsp;UI</h4><p name="aa1c" class="graf graf--p graf-after--h4">For PDFs, we have to work with traditional <code class="markup--code markup--p-code">table</code>&nbsp;, <code class="markup--code markup--p-code">&lt;tr&gt;</code>&nbsp;, <code class="markup--code markup--p-code">&lt;td&gt;</code> etc elements. So we design our Invoice page with these tags, while using our Angular <code class="markup--code markup--p-code">*ngIf</code> etc.</p><blockquote name="c900" class="graf graf--blockquote graf-after--p"><strong class="markup--strong markup--blockquote-strong">IMPORTANT: You need to add all CSS inline for PDF styling to work.</strong></blockquote><p name="0ece" class="graf graf--p graf-after--blockquote">Here’s how the HTML code looks for the modal + PDF</p><figure tabindex="0" contenteditable="false" name="9c87" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 358%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/50c4d573f3ab9e7628c07c08f66a701c.js %}</div></div></figure><p name="ea59" class="graf graf--p graf-after--figure">In above snippet, we have the id named <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">PrintInvoice</strong></code><strong class="markup--strong markup--p-strong"> </strong>from where our PDF content will start (means complete element/div is content for PDF). We will click on Download Invoice button to run the <code class="markup--code markup--p-code">downloadInvoice()</code> method defined in <code class="markup--code markup--p-code">invoice.component.ts</code></p><p name="7d64" class="graf graf--p graf-after--p">Here’s how the Modal will look like with the order details</p><figure tabindex="0" contenteditable="false" name="d540" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 386px; max-height: 678px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 175.6%;"></div><img class="graf-image" data-image-id="1*pBMmeBZ4LowmCIP-PmPuSw.png" data-width="386" data-height="678" alt="Download PDF modal&hairsp;—&hairsp;PDF generation in Ionic apps" src="https://cdn-images-1.medium.com/max/800/1*pBMmeBZ4LowmCIP-PmPuSw.png"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Download PDF modal&hairsp;—&hairsp;PDF generation in Ionic&nbsp;apps</figcaption><br></figure><h4 name="a66e" class="graf graf--h4 graf-after--figure">Download Logic</h4><p name="aa0f" class="graf graf--p graf-after--h4">In <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">openInvoice</strong></code><strong class="markup--strong markup--p-strong"> </strong>method of <code class="markup--code markup--p-code">home.page.ts</code>, we passed the <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">order</strong></code> object through Modal Controller. We receive this value in <code class="markup--code markup--p-code">invoice.component.ts</code> using <strong class="markup--strong markup--p-strong">@Input() order; </strong>and we used this order object to show the complete Information in modal. Here’s the logic for <code class="markup--code markup--p-code">invoice.component.ts</code></p><figure tabindex="0" contenteditable="false" name="862a" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 125.429%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/36b5878c3b9dc0647740695cba2f0a7a.js %}</div></div></figure><p name="8a8a" class="graf graf--p graf-after--figure">The <code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">downloadInvoice</strong></code><strong class="markup--strong markup--p-strong"> </strong>method will be called once you click on the download Invoice button. The method contains the&nbsp;:-</p><pre name="1e06" class="graf graf--pre graf-after--p">this.content = document.getElementById('PrintInvoice').innerHTML;</pre><p name="f66b" class="graf graf--p graf-after--pre">This will capture the whole content of the Invoice/bill which have the Id of <code class="markup--code markup--p-code">PrintInvoice</code> in our html page and save it to the content class variable. And further we can also specify the options for generating PDF like below</p><pre name="f6dc" class="graf graf--pre graf-after--p"><em class="markup--em markup--pre-em">let</em> options = {<br>  documentSize: 'A4',<br>  type: 'share',<br>  fileName: 'Order-Invoice.pdf'<br>};</pre><p name="836a" class="graf graf--p graf-after--pre">Here we can specify the file name by which it will be saved in your system/Mobile and specify the file size like ‘A4’ or ‘A3’ etc. After this the main code that generates PDF out of the HTML is&nbsp;:-</p><pre name="9fd9" class="graf graf--pre graf-after--p">this.pdfGenerator.fromData(this.content, options).then((<em class="markup--em markup--pre-em">base64</em>) <em class="markup--em markup--pre-em">=&gt;</em> {<br>   <em class="markup--em markup--pre-em">console</em>.log('OK', base64);<br>}).catch((<em class="markup--em markup--pre-em">error</em>) <em class="markup--em markup--pre-em">=&gt;</em> {<br>   <em class="markup--em markup--pre-em">console</em>.log('error', error);<br>});</pre><p name="f5cd" class="graf graf--p graf-after--pre"><code class="markup--code markup--p-code"><strong class="markup--strong markup--p-strong">fromData</strong></code><strong class="markup--strong markup--p-strong"> </strong>is the method defined under PDFGenerator Plugin which will convert the HTML =&gt; PDF, This method takes the HTML content and options as the argument and returns the base64 URL.</p><h3 name="7c6e" class="graf graf--h3 graf-after--p">Step 5&hairsp;—&hairsp;Test on&nbsp;device</h3><p name="3ee8" class="graf graf--p graf-after--h3">If you haven’t added any platform you can run below command to add Android platform and build app</p><pre name="0617" class="graf graf--pre graf-after--p">$ ionic cordova platform add android<br>$ ionic cordova build android<br>$ ionic cordova run android // device should be attached</pre><p name="d5c9" class="graf graf--p graf-after--pre">This will add the android platform and required plugin in project like below&nbsp;:-</p><figure tabindex="0" contenteditable="false" name="dbf9" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 374px; max-height: 170px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 45.5%;"></div><img class="graf-image" data-image-id="1*Gx--_KRxZ8Ap3rphgHSPbg.jpeg" data-width="374" data-height="170" src="https://cdn-images-1.medium.com/max/800/1*Gx--_KRxZ8Ap3rphgHSPbg.jpeg"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Added Android Platform and&nbsp;Plugin</figcaption><br></figure><p name="efa8" class="graf graf--p graf-after--figure">Clicking on <code class="markup--code markup--p-code">DOWNLOAD INVOICE</code>button will lead to the following OS PDF handler, where you can download the PDF using that highlighted button.</p><figure tabindex="0" contenteditable="false" name="50a7" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 320px; max-height: 500px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 156.29999999999998%;"></div><img class="graf-image" data-image-id="1*ME7VCJHj34afywlozKUqyw.jpeg" data-width="320" data-height="500" alt="OS PDF Handler&hairsp;—&hairsp;PDF generation in Ionic apps" src="https://cdn-images-1.medium.com/max/800/1*ME7VCJHj34afywlozKUqyw.jpeg"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">OS PDF Handler&hairsp;—&hairsp;PDF generation in Ionic&nbsp;apps</figcaption><br></figure><p name="fdc5" class="graf graf--p graf-after--figure">Here’s the full flow of downloading your invoice in your own Grocery Shopping App in Ionic</p><figure tabindex="0" contenteditable="false" name="b8dd" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 365px; max-height: 650px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 178.1%;"></div><img class="graf-image" data-image-id="1*hdEt-s1mtyzifJpdt2nJsA.gif" data-width="365" data-height="650" alt="PDF generation in Ionic apps" src="https://cdn-images-1.medium.com/max/800/1*hdEt-s1mtyzifJpdt2nJsA.gif"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">PDF generation in Ionic&nbsp;apps</figcaption><br></figure><h3 name="e6ab" class="graf graf--h3 graf-after--figure">Conclusion</h3><p name="e5ec" class="graf graf--p graf-after--h3">In this tutorial we saw how we can generate a PDF for dynamic data, in Ionic apps. Also we learnt how we can design our own PDF and then download it. You can do a lot of designing to make your PDF look cool-er. The limitation being it has to stick to standard HTML tags like <code class="markup--code markup--p-code">&lt;table&gt;</code>&nbsp;, <code class="markup--code markup--p-code">&lt;tr&gt;</code> etc. and the CSS needs to be written inline.</p><p name="44b1" class="graf graf--p graf-after--p">You can now add this amazing PDF generation feature to your Ionic e-commerce or shopping apps, wherever you need to generate invoices.</p><p name="d890" class="graf graf--p graf-after--p graf--trailing is-selected">Stay tuned for more awesome tutorials&nbsp;! And get complete code for the tutorial by signing up below.</p></div></div></section><section name="269c" class="section section--body"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="1712" class="graf graf--h3 graf--leading">Next Steps</h3><p name="ee74" class="graf graf--p graf-after--h3">If you liked this blog, you will also find the following blogs interesting and helpful. Feel free to ask any questions in the comment section</p><h3 name="bdf7" class="graf graf--h3 graf-after--p">Ionic Capacitor</h3><ul class="postList"><li name="5f8e" class="graf graf--li graf-after--h3"><strong class="markup--strong markup--li-strong">Basic</strong>&hairsp;—&hairsp;<a href="https://enappd.com/blog/use-geolocation-geocoding-and-reverse-geocoding-in-ionic-capacitor/131"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Geolocation</a> | <a href="https://enappd.com/blog/qr-code-and-barcode-scanning-with-ionic-capacitor/127"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Barcode &amp; QR code</a> | <a href="https://enappd.com/blog/facebook-login-in-capacitor-apps-with-ionic-angular/128"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Facebook Login</a> (Angular) | <a href="https://enappd.com/blog/facebook-login-in-ionic-react-capacitor-apps/118"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Facebook Login (React)</a> | <a href="https://enappd.com/blog/icon-splash-in-ionic-react-capacitor-apps/114"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Icon and Splash</a> | <a href="https://enappd.com/blog/camera-and-gallery-in-ionic-react-app-using-capacitor/110"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Camera &amp; Photo Gallery</a> | <a href="https://enappd.com/blog/debugging-ionic-apps-using-chrome-and-safari-developers-tools/167"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Debugging with browser</a>|Theming in Ionic apps</li><li name="0f51" class="graf graf--li graf-after--li"><strong class="markup--strong markup--li-strong">Advanced</strong>&hairsp;—&hairsp;<a href="https://enappd.com/blog/implement-admob-in-ionic-react-capacitor-apps/135"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">AdMob</a> | <a href="https://enappd.com/blog/local-notifications-in-ionic-5-capacitor/132"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Local Notifications</a> | <a href="https://enappd.com/blog/google-login-in-ionic-react-capacitor-apps/122"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Google Login</a> | <a href="https://enappd.com/blog/twitter-login-in-ionic-react-capacitor-app/121"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Twitter Login</a> | <a href="https://enappd.com/blog/html5-games-in-ionic-capacitor-using-phaser/115"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Games using Phaser</a> | <a href="https://enappd.com/blog/play-music-in-ionic-capacitor-apps/112"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Play music</a> | <a href="https://enappd.com/blog/firebase-push-notification-in-ionic-react-capacitor/111"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Push Notifications</a></li></ul><h3 name="da78" class="graf graf--h3 graf-after--li">Ionic Cordova</h3><ul class="postList"><li name="23b7" class="graf graf--li graf-after--h3"><a href="https://enappd.com/blog/ionic-app-with-nodejs-express-mysql-sequelize-taxi-app/160"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Taxi Booking App example with Ionic, Node, Express and MySQL</a></li><li name="e3ed" class="graf graf--li graf-after--li">Ionic Payment Gateways&hairsp;—&hairsp;<a href="https://enappd.com/blog/integrate-stripe-payment-gateway-in-ionic-5-apps-and-pwa-using-firebase/158"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Stripe with Firebase</a> | <a href="https://enappd.com/blog/ionic-5-stripe-payment-integration-firebase-cloud-functions-vs-node-express-based-server/159"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Stripe with NodeJS</a> | <a href="https://enappd.com/blog/paypal-integration-in-ionic-apps-and-pwa/142"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">PayPal</a> | <a href="https://enappd.com/blog/how-to-integrate-apple-pay-in-ionic-4-apps/21"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Apple Pay</a> | <a href="https://enappd.com/blog/how-to-integrate-razorpay-in-ionic-4-apps-and-pwa/20"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">RazorPay</a></li><li name="4ecb" class="graf graf--li graf-after--li">Ionic Charts with&hairsp;—&hairsp;<a href="https://enappd.com/blog/ionic-4-charts-using-google-charts/66"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Google Charts </a>| <a href="https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-3/60"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">HighCharts</a> | <a href="https://enappd.com/blog/adding-charts-in-ionic-4-apps-and-pwa-part-2/54"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">d3.js</a> | <a href="https://enappd.com/blog/charts-in-ionic-4-apps-and-pwa-part-1/52"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Chart.js</a></li><li name="7dc9" class="graf graf--li graf-after--li">Ionic Authentications&hairsp;—&hairsp;<a href="https://enappd.com/blog/firebase-email-authentication-in-ionic-apps/153"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Via Email</a> | <a href="https://enappd.com/blog/implement-anonymous-login-in-ionic-apps-with-firebase/154"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Anonymous</a> | <a href="https://enappd.com/blog/facebook-login-in-ionic-apps-using-firebase/150"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Facebook</a> | <a href="https://enappd.com/blog/implement-google-login-in-ionic-apps-using-firebase/147"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Google</a> | <a href="https://enappd.com/blog/twitter-login-in-ionic-4-apps-using-firebase/24"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Twitter</a> | <a href="https://enappd.com/blog/firebase-phone-authentication-in-ionic-5-apps/169"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Via Phone</a></li><li name="1310" class="graf graf--li graf-after--li">Ionic Features&hairsp;—&hairsp;<a href="https://enappd.com/blog/ionic-5-complete-guide-on-geolocation/141"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Geolocation</a>| <a href="https://enappd.com/blog/ionic-complete-guide-barcode-qrcode-scan/140"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">QR Code reader</a> | <a href="https://enappd.com/blog/best-fitness-plugins-for-ionic-4-how-to-use-pedometer/15"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Pedometer</a>| <a href="https://enappd.com/blog/implement-signature-pad-in-ionic-apps/145"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Signature</a> <a href="https://enappd.com/blog/implement-signature-pad-in-ionic-apps/145"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Pad</a> | <a href="https://enappd.com/blog/using-background-geolocation-in-ionic-angular-apps/165"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Background Geolocation</a></li><li name="5a5f" class="graf graf--li graf-after--li">Media in Ionic&hairsp;—&hairsp;<a href="https://enappd.com/blog/spotify-like-music-in-ionic-4-apps/48"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Audio</a> | <a href="https://enappd.com/blog/adding-video-player-in-ionic-4-app/64"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Video</a> | <a href="https://enappd.com/blog/camera-and-image-picker-in-ionic-apps/148"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Image Picker</a> | <a href="https://enappd.com/blog/how-to-add-image-cropper-in-ionic-apps/149"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Image Cropper</a></li><li name="71f9" class="graf graf--li graf-after--li">Ionic Essentials&hairsp;—&hairsp;<a href="https://enappd.com/blog/debugging-ionic-apps-using-chrome-and-safari-developers-tools/167"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Debugging with browser</a>| <a href="https://enappd.com/blog/ionic-4-save-and-retrieve-data-locally-on-device/59"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Native Storage</a> | <a href="https://enappd.com/blog/how-to-translate-in-ionic-internationalization-and-localization/143"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Translations</a> | <a href="https://enappd.com/blog/how-to-use-rtl-right-to-left-in-ionic-apps-pwa/152"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">RTL</a> | <a href="https://enappd.com/blog/using-sentry-error-monitoring-with-ionic-angular-applications/164"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Sentry Error Monitoring</a> | <a href="https://enappd.com/blog/social-sharing-component-in-ionic-5-mobile-web-apps/168"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Social sharing</a></li><li name="58ce" class="graf graf--li graf-after--li">Ionic messaging&hairsp;—&hairsp;<a href="https://enappd.com/blog/how-to-implement-firebase-push-notifications-in-ionic-apps/157"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Firebase Push</a> | <a href="https://enappd.com/blog/automatically-read-sms-in-ionic-4-apps/42"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Reading SMS</a> | <a href="https://enappd.com/blog/local-notifications-in-ionic-5-capacitor/132"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Local Notifications</a></li><li name="0b6b" class="graf graf--li graf-after--li">Ionic with Firebase&hairsp;—&hairsp;<a href="https://enappd.com/blog/how-to-integrate-firebase-in-ionic-4-apps/23"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Basics</a> | <a href="https://enappd.com/blog/firebase-with-ionic-4-hosting-auth-and-db-connection/58"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Hosting and DB</a> | <a href="https://enappd.com/blog/firebase-cloud-functions-in-ionic-5-complete-guide/166"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Cloud functions</a> | <a href="https://enappd.com/blog/github-actions-deploying-ionic-angular-app-to-firebase-hosting/146"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Deploy App to Firebase</a> | <a href="https://enappd.com/blog/how-to-use-firebase-emulators-with-ionic-angular-applications/163"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Firebase simulator</a></li><li name="eaef" class="graf graf--li graf-after--li graf--trailing">Unit Testing in Ionic&hairsp;—&hairsp;<a href="https://enappd.com/blog/beginners-guide-to-ionic-angular-unit-testing-part-1/151"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Part 1</a> | <a href="https://enappd.com/blog/beginners-guide-to-ionic-angular-unit-testing-part-2-mocks-and-spies/155"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Mocks &amp; Spies</a>| <a href="https://enappd.com/blog/beginners-guide-to-ionic-angular-unit-testing-async-testing/156"  class="markup--anchor markup--li-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Async Testing</a></li></ul></div></div></section><section name="5071" class="section section--body section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><h3 name="ad14" class="graf graf--h3 graf--leading">Ionic React Full App with Capacitor</h3><p name="4fa5" class="graf graf--p graf-after--h3">If you need a base to start your next Ionic 5 React Capacitor app, you can make your next awesome app using <a href="https://store.enappd.com/product/ionic-react-full-app-capacitor/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Ionic 5 React Full App in Capacitor</a></p><figure tabindex="0" contenteditable="false" name="0d2d" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 441px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 63%;"></div><img class="graf-image" data-image-id="1*G3yOFVX4oABx9MhUy-3kng.png" data-width="760" data-height="479" alt="Ionic 5 React Full App in Capacitor from Enappd" src="https://cdn-images-1.medium.com/max/800/1*G3yOFVX4oABx9MhUy-3kng.png"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Ionic 5 React Full App in Capacitor from&nbsp;Enappd</figcaption><br></figure><h3 name="30ba" class="graf graf--h3 graf-after--figure">Ionic Capacitor Full App (Angular)</h3><p name="9a60" class="graf graf--p graf-after--h3">If you need a base to start your next Angular <strong class="markup--strong markup--p-strong">Capacitor app</strong>, you can make your next awesome app using <a href="https://store.enappd.com/product/capacitor-full-app-with-ionic-angular/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener noopener noopener"    target="_blank">Capacitor Full App</a></p><figure tabindex="0" contenteditable="false" name="c219" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 761px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 108.7%;"></div><img class="graf-image" data-image-id="0*UwSHcofTMStMnzAX.png" data-width="736" data-height="800" alt="Capacitor Full App with huge number of layouts and features" src="https://cdn-images-1.medium.com/max/800/0*UwSHcofTMStMnzAX.png"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Capacitor Full App with huge number of layouts and&nbsp;features</figcaption><br></figure><h3 name="2f1c" class="graf graf--h3 graf-after--figure">Ionic Full App (Angular and&nbsp;Cordova)</h3><p name="1008" class="graf graf--p graf-after--h3">If you need a base to start your next Ionic 5 app, you can make your next awesome app using <a href="https://store.enappd.com/product/ionic-full-app"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">Ionic 5 Full App</a></p><figure tabindex="0" contenteditable="false" name="16d6" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 442px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 63.1%;"></div><img class="graf-image" data-image-id="0*1ArpKyhiDHZnevwB.jpeg" data-width="700" data-height="442" alt="Ionic Full App with huge number of layouts and features" src="https://cdn-images-1.medium.com/max/800/0*1ArpKyhiDHZnevwB.jpeg"><div class="crosshair u-ignoreBlock"></div></div><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Ionic Full App in Cordova, with huge number of layouts and&nbsp;features</figcaption><br></figure><p name="4fee" class="graf graf--p graf--empty graf-after--figure graf--trailing"><br></p></div></div></section></div></article></main>