Utilizing jsPDF and html2canvas in a Vue.js application (no webpack involved)

I've been working on a feature within a Vuejs project that allows users to export a PDF containing specific Vuejs components by clicking a button. Everything was going smoothly until I encountered an issue. After npm installing the jsPDF and html2canvas packages, I added jsPDF to the component as follows:

import jsPDF from 'jspdf'

The function triggered on button click looks like this:

exportpdf() {
    let pdf = new jsPDF('p', 'px', 'a4')
    pdf.addHTML(this.$refs.userinfo, function() {
         pdf.save('web.pdf')
    })
}

Upon triggering the function, I received the error message:

Uncaught (in promise) Error: You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js...

This led me to the following issue: Using jsPDF and html2canvas with es6, which explains that jsPDF requires html2canvas to be accessible globally. However, integrating it in this manner is not recommended in Vuejs, as discussed in this article:

Inspired by the article, I included the html2canvas package in main.js:

import html2canvas from 'html2canvas'
...
Vue.use(html2canvas)

Now when I trigger the function, I encounter the error:

Uncaught (in promise) Provided element is not within a Document

I also attempted using document.querySelector('#userinfo'), but faced the same issue. At this point, I'm at a standstill and would greatly appreciate any assistance.

Answer №1

html2canvas does not function as a Vue plugin, therefore the use(...) method cannot be called on it.

However, you have the ability to create your own plugin instead.

import html2canvas from 'html2canvas'

let MyPlugin = {
  install(Vue, options) {
    window.html2canvas = html2canvas
  }
}

// ...
Vue.use(MyPlugin)

I do not quite understand the reason for being against window.html2canvas = html2canvas if another library requires it.

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

Enhance your VueJS and Tailwind development with dynamic classes and variables

I'm attempting to incorporate dynamic variables (props) into a Tailwind CSS class, but I seem to be encountering an issue: :class="`w-${percent}/12: ${show}`" Upon running this code, the output is as follows: <div class="w-0 h-2 tra ...

Issue with VueJS: Method not displaying returned data

I am successfully able to retrieve data in the console. However, I am encountering an issue when trying to display this data on the webpage using double curly braces. The rest of the template displays fine without any issues. Template: <template> ...

What is the reason behind the inconsistent behavior of Javascript's Date.getDate() and .setDate() methods?

As a hobbyist coder, I'm facing a challenging problem with building a dynamic HTML/CSS calendar. My goal is to have cells filled in based on today's date. However, when I attempt to add days to fill in another 13 days by looping through HTML elem ...

Tips for showing a map in a concealed location: Embed the code in the appropriate location

I've come across solutions for displaying a map in a hidden div, but as a designer and not a programmer, I'm unsure of where to insert the code. The issue is detailed in this post: Click here to view. To resolve the problem, the suggestion is to ...

Using Vue.js: Load component only after user's button click

I need some help with my code setup. I want to make it so that the components "dataPart1' and "dataPart2" are not loaded by default, but only appear when a user presses a button to view the data. How can I achieve this functionality in Vue.js? var ap ...

Building nested routes in a protected path using react-router version 6

At the moment, I am utilizing react-router-dom version 6.1.1 and I have a private route in use. Typically, within this private route, I include other routes to maintain my Sidebar. This is how my code appears: // App.tsx const RequireAuth: React.FC<P ...

Optimizing rest service calls with $resource

I am currently learning about the $resource to utilize RESTful Web Services. For my first attempt, I created a factory like this : 'use strict'; angular.module('BalrogApp').factory('Req', ['$resource', function($r ...

HTML dynamic voting system

I'm new to coding in HTML and I have a specific challenge that I need help with. I want to display a value on my webpage that increases every time a user clicks a button. Below is the code I have written so far: <script type="text/javascript& ...

The input box refuses to accept any typed characters

I encountered a strange issue where the input box in the HTML was not allowing me to type anything. const para = document.createElement('p') const innerCard = document.getElementsByClassName('attach') for(let i = 0; i < innerCard.l ...

A guide on Implementing PastBack Functionality with AJAX Responses

When I make a GET request for an HTML page, I come across the following element: <a id="ctl00_cphRoblox_ClaimOwnershipButton" href="javascript:__doPostBack('ctl00$cphRoblox$ClaimOwnershipButton','')">Claim Ownership</a> My ...

I require the ability to access a reference parameter with a dynamically changing name within a Vue template

<div v-for="x in 4" :class="(images[x] === null) ? 'not-removable' : 'removable'" class="img-container"> <input style="display: none" type="file" ...

Ajax is updating the information stored in the Data variable

Recently, I reached out to tech support for help with an issue related to Ajax not executing properly due to Access-Control-Allow-Origin problems. Fortunately, the technician was able to resolve the issue by adding a file named .htaccess with the code Head ...

Form submission is not functioning as expected

I am having trouble with my form submission. When I try to submit the form, nothing happens. I have tried various solutions but have not been able to resolve the issue. I have reviewed all available resources but still cannot figure out why my code is not ...

Angular Material: Enhanced search input with a universal clear button

After searching for a cross-browser search control with a clear button similar to HTML5, I found the solution rendered by Chrome: <input type="search> The code that gave me the most relevant results can be found here. I used the standard sample w ...

What is the best way to make three divs that can be adjusted in size?

Desired Layout: | A | | B | | C | ^ ^ Adjustment Behavior: | A | | B | | C | Current Issue: | A | C | I attempted to enhance the functionality by modifying the provided JavaScript cod ...

What is the best way to set the v-model property to an object that is constantly changing

I'm in the process of creating a dynamic form that allows users to add additional fields by simply clicking on a button labeled "adicionar condição." The concept is similar to what can be seen in the screenshot below: https://i.stack.imgur.com/Mpmr6 ...

What is the best way to retrieve multiple image file names using JavaScript?

I attempted to use the code snippet below to retrieve the names of all the images I selected, however when I used 'alert', I only received one name even though I selected multiple. My goal is to have all the names of the selected photos saved in ...

What is the best way to preserve the status of a report when moving to a new component instance?

In my Vue application, I am using Vue version 3.1.31 and vue-router version 4.0.14. Within the application, there is a report consisting of multiple objects that can navigate to a new route where users can view or print a PDF of the information. However, ...

The date error from day.js in Firefox is not valid

My date is formatted as 2022-01-27 09:23:48 UTC and I am trying to parse it into MMMM-DD-YYYY format (Jan-27-2022) using day.js. The parsing works well in Chrome, but Firefox returns an 'Invalid' result. import dayjs from "dayjs" const ...

When using vue-property-decorator, changes in data do not automatically generate an `emit` event

I have created a selection field that showcases a variety of fruits. My goal is to update the parent component with the selected fruits from the SelectAll feature. To achieve this, I implemented a component event called @Emit("fruitsSelected") which should ...