Add Multiple Elements to PDF via jsPDF's addHT

2019-08-17 16:56发布

问题:

I am using an angular-ui tabset to display several separate bits of information. Because the actual content of the tabs that aren't active is hidden, it does not print if I just add the entire body of the page. The only tab content that you see after printing is the currently active tab. I'm attempting to print everything inside of these tabs along with another single element from the page using the addHTML method to preserve the way that it looks.

Printing any of these individually works well, but I can't seem to find a way to print all of the items at once.

For example, this is the code used to print a single element.

var pdf = new jsPDF('p', 'pt', 'a4');
pdf.addHTML($('#foo').first(), function() {
    pdf.save();
});

That works (although the output is all black, but I suppose that's a separate issue). Now, I would like to have several addHTML statements to finish adding the content I need and then save. Something like

var pdf = new jsPDF('p', 'pt', 'a4');
pdf.addHTML($('#foo').first());
_.each( $('.bar').first().children(), function(e) {
    pdf.addHTML(e);
});
pdf.save();

However, taking the second approach when the pdf is saved, it is just completely blank.

It's worth noting that this works, but it doesn't have the formatting that I would like to keep and has more content than I'd like:

  var doc = new jsPDF();

  doc.fromHTML($('body').get(0), 15, 15, {
    'width': 170,
  }, function() {
    doc.save();
  });

Attempting to force it to select just #foo and .bar ends up coming out to the same problem that I have above.

Any suggestoins on the correct way to do this would be greatly appreciated.

回答1:

Adam's answer never quite worked for me, for one reason or another. Instead, I went with the approach of creating a new div, appending all of my stuff to it, printing it, and then destroying it. That can be accomplished via something along these lines:

      var pdf = new jsPDF('p','pt','letter');

      $("#printing-holder").append("<div id='printingDiv' style='background-color: white;'></div>");
      ($('#foo')).clone().appendTo("#printingDiv");
      _.each( $('.bar').children(), function(e) {
        $("#printingDiv").append('<br/>');
        $(e).clone().appendTo("#printingDiv");
        $("#printingDiv").append('<br/>');
      });
      pdf.addHTML(($("#printingDiv")[0]), {pagesplit: true}, function() {
        console.log("THING");
        pdf.save();
        $("#printingDiv").remove();
      });

Note that the pagesplit option splits the image up if it is larger than one page, but (as of the date of this answer) seems to vastly lower the quality of the PDF generated.



回答2:

Calling pdf.save() outside of the addHTML callback will most likely create the pdf before the addHTML method had a chance to add the html. Try something like this:

Not tested

var pdf = new jsPDF('p', 'pt', 'a4');
var elements = $(".bar");
var i = 0;
var recursiveAddHtml = function () {
    if (i < elements.length) {
        var x = 0, y = i * 20; 
        pdf.addHTML(elements.get(i), x, y, function () {
            i++;
            recursiveAddHtml();
        });
    } else {
        pdf.save();
    }
}

recursiveAddHtml();

This should call recursiveAddHtml for each element, one at a time, then call save when it reaches the end.

Update

I just tried this out and it seems to work, except that it positions all elements on top of each other. I'm not sure how to detect the height of the content currently in the pdf yet, so I added x and y coordinates to the example so you can at least see the different elements in the PDF.

Also, make sure you set the background-color to something otherwise it defaults to black.