7

I'm exporting my DHTMLX grid to csv and have successfully been able to create the .CSV file. The problem I'm having is that it isn't prompting the user to save/open the file. I'm using a $.post call from javascript to send the CSV string to PHP, then writing that string to csv. For some reason it isn't creating a prompt for the user, but it is successfully writing the file and saving on the server. Below is the relevant code:

JS:

myGrid.csvParser = myGrid.csvExtParser;
myGrid.setCSVDelimiter('|');
myGrid.csv.row = "endOfRow";           
var gridCsvData = myGrid.serializeToCSV();

    $.post(
        "data/export.php", 
        { 
           csvdata: gridCsvData
        }
    );

PHP (export.php):

$csvData = $_REQUEST['csvdata'];

$csv = explode('endOfRow',$csvData);

$myfile = "grid.csv";

$fh = fopen($myfile, 'w') or die("can't open file");

foreach($csv as $line) {
    fputcsv($fh, explode('|',$line),',','"');
}

fclose($fh);

//Redirect output to a client's web browser (csv)
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=grid.csv");
header("Pragma: no-cache");
header("Expires: 0");

This code works perfectly in the sense that it exports the Grid exactly how I want it and saves it to 'grid.csv'. The problem is that it isn't prompting the user to save the file. Is this a problem with my PHP headers or do I need to put something in the $.post to prompt on success? Thanks for any help!

ad2387
  • 551
  • 2
  • 11
  • 21

2 Answers2

14

You can't prompt the user to download a file from an AJAX call. One thing you can do is, make an iFrame, put a form in it, then POST it. That way, it'll look like an AJAX call, but the user will be prompted to download the file.

// Create iFrame
var iframe = document.createElement('iframe');
iframe.style.display = "none";
document.body.appendChild(iframe);

// Get the iframe's document
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

// Make a form
var form = document.createElement('form');
form.action = 'data/export.php'; // Your URL
form.method = 'POST';

// Add form element, to post your value
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'csvdata';
input.value = gridCsvData;  // Your POST data

// Add input to form
form.appendChild(input);

// Add form to iFrame
// IE doesn't have the "body" property
(iframeDoc.body || iframeDoc).appendChild(form);

// Post the form :-)
form.submit();

P.S. Your PHP code doesn't actually echo the CSV to the screen, it just saves it to a file.

After the header calls, make sure you have:

readfile($myfile);
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • Looks promising. Current working through the error: 'body' is null or not an object on the line 'iframeDoc.body.appendChild(form);'. Any ideas? Thanks! – ad2387 Aug 23 '12 at 19:22
  • @adaher23: What browser are you using? – gen_Eric Aug 23 '12 at 19:25
  • Just tried it in Firefox..works perfectly. Need it to work with IE8/9 though – ad2387 Aug 23 '12 at 19:29
  • @adaher23: I updated the answer, give that a try. IE doesn't support the `.body` property. If you can use jQuery, I'd suggest it. It would fix these silly cross-browser issues. – gen_Eric Aug 23 '12 at 19:41
  • 2
    You could also do the same thing (add a form element) with the current document, rather than an iframe, with the same effect. – Heretic Monkey Aug 23 '12 at 19:44
  • @MikeMcCaughan: Hmm, didn't think of that. Since file downloads don't count as the page loading, that would work too. I just prefer iframes, just in case. – gen_Eric Aug 23 '12 at 19:48
  • Wow, thanks so much man. Works great, if I could accept it twice I would – ad2387 Aug 23 '12 at 19:51
2

The right way to do this in HTML5 is to use the File API. See this for details: http://hackworthy.blogspot.com/2012/05/savedownload-data-generated-in.html.

If HTML5 is not an option, then take this approach.

After you do a POST, generate a GET request for the file using:

document.location = "file.csv";

Depending on the browser, the file will either be saved (Chrome) or user will be prompted to choose a file name to save as. Of course, the POST handler has to save the file somewhere.

$.ajax({
    type: "POST",
    url: "post.php",
    success: function() {
        console.log("Worked!");
        document.location = "test.csv";
    },
    error: function() {
        console.log("Failed!");
    }
});
RajV
  • 6,860
  • 8
  • 44
  • 62