Currently, my goal is to create PDFs using Angular

<button class="print" (click)="generatePDF()">Generate PDF</button>

Code to Generate PDF

generatePDF(): void {
    const element = document.getElementById('mainPrint') as HTMLElement;
    const imgWidth = 210;
    const pageHeight = 295;

    html2canvas(element, { scale: 2 }).then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF();
        const imgHeight = (canvas.height * imgWidth) / canvas.width;
        let heightLeft = imgHeight;
        let position = 0;

        while (heightLeft >= 0) {
            position = heightLeft - pageHeight;
            pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
            heightLeft -= pageHeight;
            if (heightLeft > 0) {
                pdf.addPage();
            }
        }

        pdf.save('page.pdf');
    });
}

Upon clicking the "Generate PDF" button, a PDF is produced. However, the initial 4-5 pages are appearing blank, with content only showing from the subsequent pages but not fully displayed.

Answer №1

I have successfully removed the extra space, although it may not be flawless. Perhaps you can enhance it further from here!

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { ChildComponent } from './child/child.component';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, ChildComponent],
  template: `
  <div id="mainPrint">
  <app-child/>
  </div>
    <button class="print" (click)="generatePDF()">Generate PDF</button>
  `,
})
export class App {
  name = 'Angular';

  generatePDF(): void {
    const element = document.getElementById('mainPrint') as HTMLElement;

    html2canvas(element, { scale: 2 }).then((canvas: any) => {
      var imgData = canvas.toDataURL('image/png');

      var imgWidth = 210;
      var pageHeight = 295;
      var imgHeight = (canvas.height * imgWidth) / canvas.width;
      var heightLeft = imgHeight;
      var doc = new jsPDF('p', 'mm', 'a4'); // landscape
      var position = 0;

      /* addImage explained below:
          param 1 -> image in code format
          param 2 -> type of the image. SVG not supported. needs to be either PNG or JPEG.
          all params are specified in integer
          param 3 -> X axis margin from left
          param 4 -> Y axis margin from top
          param 5 -> width of the image
          param 6 -> height of the image
      */

      doc.addImage(imgData, 'JPEG', 0, 0, imgWidth, imgHeight);
      heightLeft -= pageHeight;

      while (heightLeft >= 0) {
        position = heightLeft - imgHeight;
        doc.addPage();
        doc.addImage(imgData, 'JPEG', 0, 0, imgWidth, imgHeight);
        heightLeft -= pageHeight;
      }

      doc.save('page.pdf');
    });
  }
}

bootstrapApplication(App);

Visit stackblitz demo for more details.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you explain the definition of "mount" in the context of Express?

Currently diving into the world of Express.js, I stumbled upon this definition: "An Express router offers a limited set of Express methods. To initialize one, we call the .Router() method on the main Express import. To utilize a router, we mount it a ...

Input field in AngularJS not showing initial value from ng-model

I am currently utilizing ng-repeat to iterate through an array of keys and showcase the scenario value linked with each individual key. Previously, when the key value was hardcoded, the view code functioned as expected. However, now that ng-repeat supplies ...

Universal loading screen across all components

I am currently implementing a loading screen for this component in conjunction with the fetch method. My concern is whether I will need to replicate the same loading logic used in the example for every component that utilizes the fetch() method, or if the ...

When a child component sends props to the parent's useState in React, it may result in the return value being undefined

Is there a way to avoid getting 'undefined' when trying to pass props from a child component to the parent component's useState value? Child component const FilterSelect = props => { const [filterUser, setFilterUser] = useState('a ...

how to change class on vue function result

I need a way to display the content stored in requestData as li elements. Each list item should have an onclick function that, when clicked (selected), adds a specific value from a reference to an array. If clicked again (unselected), it should remove the ...

What is the best way to adapt a wavetable for compatibility with the `OscillatorNode.setPeriodicWave` function?

I am exploring the use of a custom waveform with a WebAudio OscillatorNode. While I have basic programming skills, I am struggling with the mathematical aspects of audio synthesis. Waveforms are essentially functions, which means I can sample them. Howeve ...

Issue with loading controllers in route files [Node.js]

I've encountered an issue while trying to include a user controller into my routes for a node js app. Everything was working fine until suddenly it started throwing an error message. I've thoroughly checked the code for any potential issues but s ...

The function(result) is triggered when an http.get request is made

Can anyone help me figure out why my function is jumping after completing the request? It seems to be skipping over .then(function(result){ }. I suspect that the issue might be related to the <a> element with an onclick attribute containing an href ...

Issue with displaying error message and disabling button as Keyup event fails to trigger

Is there a way to assess the user's input in real-time on an on-screen form to ensure that the pageName they enter is not already in the navbarMenuOptions array? If it is, I want to switch the visibility of displayName and displaySaveButton. However, ...

The classification of a property is determined by the types of the other properties present

I am trying to figure out a way in Typescript to create a general component that takes a prop called component, with the remaining props being specific to that component. How can I achieve this? For example: <FormField component={Input} ... /> Thi ...

Changing the key of a nested item within an array of objects using JavaScript

My task in JavaScript is to change the names of canBook -> quantity, variationsEN -> variations, and nested keys valueEN -> value. var prod = [{ price: 10, canBook: 1 }, { price: 11, canBook: 2, variationsEN: [{ valueE ...

The behavior of the dynamically generated object array differs from that of a fixed test object array

I'm facing an issue while trying to convert JSON data into an Excel sheet using the 'xlsx' library. Everything works perfectly when I use test data: //outputs excel file correctly with data var excelData = [{ test: 'test', test2: ...

Detect keypress within a BrowserWindow even when multiple BrowserView components are present

In my Electron application, I have a main BrowserWindow that contains the main user interface index.html, along with multiple BrowserView elements: browserWindow = new BrowserWindow({ width: width, height: height, frame: false }); browserWindow.webContents ...

What is causing the error message "may require a suitable loader" to appear when I add my TypeScript Node module to my Next.js application?

After developing a TypeScript node module and integrating it into my Next.js app, I encountered an error when attempting to run the app. Are you aware of any reason why this issue may be occurring? Please refer to the information provided below. Details a ...

Creating a new page in a PDF with Reportlab in Python

Currently, I am utilizing the Reportlab open-source version with Python on a Windows platform. Within my code, I have implemented a loop that iterates through various PNG files and merges them to generate a single PDF file. Each PNG file is resized to fit ...

Issue with remove functionality in Vue js implementation causing erratic behavior in my script

Within my Vue.js code, I have a functionality that displays categories from an API. When a category is clicked, it is added to the AddCategory array and then posted to the API. I have also implemented a button called RemoveAll which successfully empties th ...

In Internet Explorer 9, the cursor unexpectedly moves up above the element

Within my MVC3 application, I have implemented a feature to change the cursor when hovering over an element. Below is the JavaScript code that accomplishes this: $('#print').hover(function () { var cursorUrl = 'url(@Url.Content("~/Cont ...

Encountering an error while trying to update an Angular application to version 10

I am currently running a demo app and I am new to Angular. Below is my category list component. import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; im ...

Organizing AngularJS Components: Finding the Right Spot for the "Model" within Your Directory Structure

When it comes to AngularJS, it adheres to the MVC pattern (or more accurately MV*). Typically, we create distinct directories for each layer. For instance, controller JS files are usually placed in a directory called "controllers", and views are commonly s ...

updating a value in a svelte writable store using cypress

Inside my Svelte application, I am working with a boolean variable. import { writable } from 'svelte/store' export const authorised = writable(false) This variable is imported into App.svelte and other Svelte files, where it can be accessed and ...