0

My code works fine when I run the php script without ajax as a GET request. I get prompted to download the rendered pdf and all is well. However, I need to use ajax because I need to send more info from an html page to the php script than can be handled in a GET request.

What do I need to put into my ajax to make this work?

Thanks

js

function makePDF()
{
var x;
if(window.event) // IE8 and earlier
    {
    x=event.keyCode;
    }
else if(event.which) // IE9/Firefox/Chrome/Opera/Safari
    {
    x=event.which;
    }
keychar=String.fromCharCode(x);

alert(keychar);

if (keychar == 'p' || keychar == 'P')
{
    var charSheetHTML = characterSheet.innerHTML;

    $.ajax({ 
     url: 'pdf.php',
     data: {'charactersheet': charSheetHTML,},
     type: 'post',
     success: function (data) {**WHAT_DO_I_PUT_HERE??**},
     error: function (data) { alert("error\n" + data.toString()); }
    });
}
}

pdf.php

<?php
include_once( "bxcharacter/PDFChar.php.inc" );
PDFChar();  
?>

PDFChar.hph.inc

<?php

require_once('./tcpdf/tcpdf.php');

function PDFChar(){


 $pdf = new TCPDF();


 $pdf->AddPage('P');
 $pdf->writeHTML($_POST['charactersheet']);


 $pdf->Output("character.pdf", 'D');


}

?>
barna10
  • 177
  • 1
  • 9
  • ajax isn't really indended for downloads (or uploads). You should use a `document.location`-type redirect to point at the download URL, which allows the browser's own download mechanisms to kick in. – Marc B Feb 28 '14 at 18:18
  • If you need to send more data using ajax, then send the data with ajax, write to a temp file and on success redirect to the file. – Jonathan Kuhn Feb 28 '14 at 18:19
  • Ok, how do I write to a temp file? Thanks – barna10 Feb 28 '14 at 18:32
  • I worked out a working version that uses a form submission instead, but I'd still like an ajax solution. – barna10 Feb 28 '14 at 20:35
  • @barna10: pass your ajax data as an array to PDFChar(), and then try to fetch it. Hope it may help! – Emma Mar 10 '14 at 13:47
  • Saving to a file on the server seems to be the way to go. Now to automate file deletion... – barna10 Mar 13 '14 at 20:09

2 Answers2

2

This is not an ajax solution, but you can send your data with this way and if no error occurs, your page will not change.

Create a form element with inputs hidden which contains your data you want to send:

example format:

<form id="myForm" method="GET" action="pdf.php">
   <input type="hidden" name="data1" type="hidden" value="your JSON.stringify() data">
</form>

js code (call these where your ajax request is):

var myForm =  '<form id="myForm" method="GET" action="pdf.php">';
    myForm += '<input type="hidden" name="data1" type="hidden" value="JSON.stringify() data">';
    myForm += '</form>';

$("body").append(myForm);   // temporarily appending 
$("#myData-form").submit(); // submitting form with data
$("#myData-form").remove(); // remove form after submit

And as you said, force download will force file to download and page will remain same. However, if an error occurs, your page will change of course.

I don't know whether this is an effective way or not but in my case, this does the trick.

alpakyol
  • 2,402
  • 2
  • 29
  • 35
  • This somewhat works, but the data still seems to truncated. Is there a maximum amount of data you can submit with a form? – barna10 Mar 13 '14 at 17:33
  • According to my researches on internet, amount is related with the values predefined in server, so data limit can even be unlimited(this is my thought according to comments). See http://stackoverflow.com/questions/2341149/limit-of-post-arguments-in-html-or-php – alpakyol Mar 13 '14 at 19:29
  • Interesting, thanks for the info. I was able to get this working by saving it as a file on the server then downloading it. – barna10 Mar 14 '14 at 12:49
  • You might have already figured this out but, the GET method typically accepts a smaller payload by default, most of the time using the POST method will allow you a larger payload. – Mark Carpenter Jr Jan 14 '19 at 16:03
0

Old question, but I was trying to do something similar with Laravel PDF extension, and stumbled across this question. I did successfully do this asynchronously with the help of a nice blog post

https://nehalist.io/downloading-files-from-post-requests/

https://github.com/nehalist/download-post-requests

The using the form method, like the previous answer works fine too, but maybe this will help anyone else trying to achieve this with AJAX. The author's XMLHttpRequest method worked great for me!

The code that worked for me (almost verbatim from the blog post) ->

document.getElementById('exportpdf').addEventListener('click', function () {
  var request = new XMLHttpRequest();
  request.open('POST', '/your/post/endpoint/here', true);
  request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
  request.responseType = 'blob';

  request.onload = function() {

  if(request.status === 200) {
    var disposition = request.getResponseHeader('content-disposition');
    var matches = /"([^"]*)"/.exec(disposition);
    var filename = (matches != null && matches[1] ? matches[1] : 'file.pdf');

    var blob = new Blob([request.response], { type: 'application/pdf' });
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = filename;

    document.body.appendChild(link);

    link.click();

    document.body.removeChild(link);
  } 
};

I tried to get it to work with jQuery AJAX but failed, so I went with XMLHttpRequest. With jQuery, The download would work, but the content was always empty. I tried to do something like in this post -

https://keyangxiang.com/2017/09/01/HTML5-XHR-download-binary-content-as-Blob/

$.ajax does not support either arraybuffer or blob as its dataType. Thus we need write a beforeSend handler:

//setup ajax
$.ajaxSetup({
  beforeSend:function(jqXHR,settings){
    if (settings.dataType === 'binary'){
      settings.xhr().responseType='arraybuffer';
      settings.processData=false;
    }
  }
})

//use ajax now
$.ajax({
  url:url,
  dataType:"binary",
  success:function(data){
    console.log(data); //ArrayBuffer
    console.log(new Blob([data])) // Blob
  }
})

But never got it to work. Maybe someone smarter can figure out the jQuery method :)

40four
  • 1
  • 2