Uncaught (in Promise) error Error: Element is not Attached to a Document when trying to generate a PDF of an HTML page

Asked

Viewed 846 times

0

I am trying to generate a PDF of a page made in HTML. This page has a chart created with Chart Js. I would like to click on the button to generate a PDF of the chart. However, clicking the Button generates the Uncaught (in Promise) error Error: Element is not Attached to a Document. Do you know where I might be making some shortcoming for such a mistake ?

  • I’m using html2canvas (as I have been reading that it is necessary to first convert the file to PNG).

  • I’m also using the jspdf to convert the file to PDF.

  • Follow the code below that is presenting problems:

window.onload = function() {
  //Chamando função ao carregar a página.
  let pegar = pegarStatusAtividades(configuraDados);

  html2canvas(document.querySelector("#canvas_status_atividades")).then(canvas => {
    document.body.appendChild(canvas)
  });

  // Função que transforma canvas em imagem e exporta para PDF
  // Você pode usar $(.'elemento').click() do jQuery para disparar a função 
  $('#gerar-pdf').on('click', function() {
    html2canvas($('#canvas_status_atividades'), {
      onrendered: function(canvas) {
        var imgData = canvas.toDataURL('image/png');
        var pdf = new jsPDF('p', 'mm');
        pdf.addImage(imgData, 'PNG', 10, 10);
        pdf.save('test.pdf');
      }
    });
  });

}
<!DOCTYPE html>
<html lang="pt-BR">

<head>
  <!-- Required meta tags -->
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE-edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Aprendendo</title>


  <link href="_bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
  <!-- ARQUIVO CSS DO BOOTSTRAP -->

  <link href="_chart/dist/Chart.css" rel="stylesheet">
  <script src="_chart/dist/Chart.js"></script>

</head>

<body>

  <div class="row">
    <div class="col-lg-12">
      <h1 class="text-center">Gráficos de Status das Atividades</h1>
    </div>
  </div>

  <div class="container-fluid" id="container-canvas">

    <div class="row">
      <div class="col-lg-8 offset-lg-2">
        <canvas id="canvas_status_atividades" width="400" height="400"></canvas>
      </div>
    </div>

    <div class="row">
      <div class="col-lg-8 offset-lg-2">
        <button class="btn btn-primary" id="gerar-pdf">Gerar PDF</button>
      </div>
    </div>

  </div>

  <script src="_jquery/jquery-3.3.1.min.js"></script>
  <!-- ARQUIVO JQUERY -->
  <script src="_bootstrap/4.3.1/js/bootstrap.min.js"></script>
  <!-- ARQUIVO BOOTSTRAP -->
  <script src="_jsPDF/dist/jspdf.min.js"></script>
  <!-- ARQUIVO jspdf -->
  <script src="_html2canvas/html2canvas.js"></script>
  <!-- ARQUIVO html2canvas -->
  <script src="scripts/script.js"></script>

</body>

</html>

OBS: The Chart is generated without problems with the JS Chart:

inserir a descrição da imagem aqui

1 answer

2


I don’t understand, you’re not the first one doing this, I was a collaborator of the html2canvas project (it was only a 2 code modifications) and I don’t understand why people insist on using html2canvas to get the image of a real canvas.

If the element is already canvas:

<canvas id="canvas_status_atividades" width="400" height="400"></canvas>

Just use .toDataURL() to get the image, example:

$('#gerar-pdf').on('click', function() {
    var canvas_status_atividades = document.getElementById('canvas_status_atividades');
    var pdf = new jsPDF('p', 'mm');
    pdf.addImage(canvas_status_atividades.toDataURL(), 'PNG', 10, 10);
    pdf.save('test.pdf');
});

Already the mistake Element is not attached to a Document may be a bug in the HTML2CANVAS version you’re using, I don’t know what you’re using, but maybe you’re outdated, or it may be some script of yours that’s "detaching" the DOM body element, but it’s not something related to your code.

  • Very good, William. Thank you very much, man. Let me ask you one more question. If I want, instead of just picking up a chart, pick up the whole page (because the page has multiple graphics), as I would ?

  • Like, pick up all the same. Menu, footer and other html elements of the page.

  • @Jason-Theinternship. in this case you will have to use html2canvas itself, but take a look if you are using the latest version and if there is no other script getting in the way, I would personally replace the canvas at the time in the snapshot by the image made by toDataURL and then use HTML2CANVAS

  • I’m using the latest yes. I got it on https://html2canvas.hertzen.com/.

  • William, could you help me with that ? I’m a layman and it’s the first time I’m using html2canvas and jspdf.

  • @Jason-Theinternship.may be some script of yours that is affecting the canvas, tried to use html2canvas(document.body, { and the same error occurs?

  • When I do this, no error is generated, but also the PDF is not generated.

  • 1

    @Jason-Theinternship. but if nothing is generated is pq has another error, you made my suggestion, only at the time of snapshot change the canvas by the generated image and then apply html2canvas?

  • Snapshot occurs at the time of the pdf.addImage line ?

  • 1

    @Jason-Theinternship. take canvas_status_atividades.toDataURL() adds with var nova = new Image; nova.src = canvas_status_atividades.toDataURL();, then take the variable nova, being like this: canvas_status_atividades.parentNode.replaceChild(canvas_status_atividades, nova);, there inside the onrendered do the opposite to restore: onrendered: function () { nova.parentNode.replaceChild(nova, canvas_status_atividades); ... } and at least try to grab the screenshot and open in a window.open, the PDF part you do after.

  • Sorry, William. I couldn’t follow your reasoning. I’m going to google it. But thank you for your answer to my question. It has already been useful to me in the matter of printing the graphics. Thank you!

  • William, the script would look something like this at the beginning ? https://jsfiddle.net/28pycq4x/

  • @Jason-Theinternship. you pasted the onrendered loose, you do so: https://pastebin.com/raw/U0zSbAKR

  • William, gave an error in the line of replaceChild. Showed that one parameter of replace is not the son of the other. Uncaught Domexception: Failed to execute 'replaceChild' on 'Node': The Node to be replaced is not a Child of this Node.

  • And even in this case, it wouldn’t do the same thing as that code, which only shows the PDF, did ?

  • I’ll leave my complete code for you to see how it is. If you can help me solve this, I would appreciate it. I was trying to generate these PDF in PHP with Wkhtmltopdf, but I also found problems. The charts of the Charts do not appear with this lib. I am 4 days trying to do this, but I have not been succeeding. Follow the link. https://jsfiddle.net/97ub84aL/

  • @Jason-Theinternship. I’ll see when I get home and send you a gist or fiddle with a functional example ;)

  • Thank you, William.

Show 13 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.