download excel file using post request - javascript

I've an API endpoint that takes in a JSON and returns a excel file. The endpoint directly sends the file, not the link to the file. How do I download the file using JQuery AJAX.
Backend Code:
public function postExcel() {
// Parse request body
$reqBody = json_decode(file_get_contents('php://input'));
// On Valid Request
if(isset($reqBody, $reqBody->regno, $reqBody->offset) && $reqBody->offset < 100 && $reqBody->offset >= 0) {
// Create and add metadata to the workbook
$workbook = new \PHPExcel();
$workbook->getProperties()
->setCreator('AUScraper')
->setTitle('AU Results')
->setLastModifiedBy('AUScraper')
->setDescription('generated by AUScraper')
->setSubject('generated by AUScraper')
->setKeywords('anna university unofficial semester result API')
->setCategory('semester results');
$worksheet = $workbook->getSheet(0);
$worksheet->setTitle('results');
// Get the results
$results = $this->requestAU($reqBody->regno, $reqBody->offset);
// Update worksheet
//Output the file
ob_clean();
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=\"results.xlsx\"");
header("Cache-Control: max-age=0");
header("Expires: 0");
$workbookWriter = new \PHPExcel_Writer_Excel2007($workbook);
$workbookWriter->save("php://output");
}
// On Invalid Request
header('Content-Type: application/json');
http_response_code(400);
return json_encode(['error' => 'invalid request']);
}
Frontend Code:
import $ from 'jquery';
import 'materialize';
$(() => {
$('#reg_form').submit(() => {
// format data to send
let form_data = {};
form_data.regno = $('#reg_no').val();
form_data.offset = $('#offset').val();
// Send the request
$.ajax({
url: 'http://localhost/git_repo/AUScraper/app/public/api/excel',
data: JSON.stringify(form_data),
type: 'POST',
contentType: 'application/json',
success: function(data) {
var blob=new Blob([data], {type : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="result_"+new Date()+".xlsx";
link.click();
},
error: (xhr,status,error) => {
let errorMessage = JSON.parse(xhr.responseText);
Materialize.toast(errorMessage.error, 2000);
}
});
return false;
});
});
I don't want to save the file in server beforehand, but just download it. Thanks in advance.

The problem in the above question was, I was able to download the file but it was corrupted. I fixed it by setting responseType of xhr to blob.
New AJAX code for reference:
let xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost/git_repo/AUScraper/app/public/api/excel');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
let link=document.createElement('a');
link.href=window.URL.createObjectURL(this.response);
link.download="results.xlsx";
link.click();
}
else {
Materialize.toast('Invalid data!', 2000);
}
}
xhr.send(form_data);

Related

using POST in ajax in vanilla js

I am trying to send the post request to my PHP file but it is saying undefined index.
my js code -
document.getElementById("btn1").addEventListener('click', xh );
function xh(){
xhr = new XMLHttpRequest();
//xhr.open('GET', 'req.php?msg=hello bro', true);
xhr.open('POST', 'req.php');
xhr.getResponseHeader('Content-type', 'application/w-xxx-form-urlencoded');
xhr.onprogress = function () {
// document.getElementById("loading").classList.remove("dis");
}
xhr.onload = function () {
console.log(this.responseText);
}
xhr.send("msg=hello");
}
my PHP code -
<?php
if(isset($_POST['msg'])){
echo "set";
}
else{
echo "not set";
}
?>
I also tried the server request method but it didn't work
it is showing not set, and if I try to echo the $_POST['msg']; it says undefined index 'msg'
Instead of
xhr.getResponseHeader('Content-type', 'application/w-xxx-form-urlencoded');
you want to set the request header
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
Read more about XHR. The present approach it to use fetch() though.
fetch("req.php", {
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: "msg=hello"
}).then(response => response.text())
.then(console.log)

Can't upload a file in TinyMCE...?

Having an issue with uploading images on Tiny. I want to upload the images to folder /images/owner/ I don't want a blob, but rather to upload full files.
I can upload to file_upload.php no problem from test.html. Containing a text input and a file input only. file_upload.php looks like this ...
<?php
/***************************************************
* Only these origins are allowed to upload images *
***************************************************/
$accepted_origins = array("http://localhost", "http://192.168.1.1", "https://example.com/");
/*********************************************
* Change this line to set the upload folder *
*********************************************/
$owner_id=$_POST["owner"];
//$owner_id='15601a2cc3d5b2';
$imageFolder = "images/". $owner_id . "/";
// Don't attempt to process the upload on an OPTIONS request
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("Access-Control-Allow-Methods: POST, OPTIONS");
return;
}
reset($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])){
// Sanitize input
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
header("HTTP/1.1 400 Invalid file name.");
return;
}
// Verify extension
if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
header("HTTP/1.1 400 Invalid extension.");
return;
}
// Accept upload if there was no origin, or if it is an accepted origin
$filetowrite = $imageFolder . $temp['name'];
move_uploaded_file($temp['tmp_name'], $filetowrite);
// Determine the base URL
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https://" : "http://";
$baseurl = $protocol . $_SERVER["HTTP_HOST"] . rtrim(dirname($_SERVER['REQUEST_URI']), "/") . "/";
// Respond to the successful upload with JSON.
// Use a location key to specify the path to the saved image resource.
// { location : '/your/uploaded/image/file'}
echo json_encode(array('location' => $baseurl . $filetowrite));
} else {
// Notify editor that the upload failed
header("HTTP/1.1 500 Server Error");
}
?>
This Tiny JS code is on my editor.php page. I don't want a blob that can't be linked to. I want to send an email newsletter and only proper files/images on the server will render...
<script>
tinymce.init({
selector: '#mytextarea',
images_upload_handler: images_upload_handler,
plugins: 'image code',
toolbar: 'undo redo | link image',
/* enable title field in the Image dialog*/
image_title: true,
/* enable automatic uploads of images represented by blob or data URIs*/
automatic_uploads: true,
/*
URL of our upload handler (for more details check: https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_url)
images_upload_url: './js/tinymce/postAcceptor.php',
here we add custom filepicker only to Image dialog
*/
file_picker_types: 'image',
/* and here's our custom image picker*/
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
/*
Note: In modern browsers input[type=\"file\"] is functional without
even adding it to the DOM, but that might not be the case in some older
or quirky browsers like IE, so you might want to add it to the DOM
just in case, and visually hide it. And do not forget do remove it
once you do not need it anymore.
*/
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
/*
Note: Now we need to register the blob in TinyMCEs image blob
registry. In the next release this part hopefully won't be
necessary, as we are looking to handle it internally.
*/
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
/* call the callback and populate the Title field with the file name */
cb(blobInfo.blobUri(), { title: file.name });
};
reader.readAsDataURL(file);
};
input.click();
},
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
});
function images_upload_handler (blobInfo, success, failure, progress) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST','https://example.com/myfolder/file-upload.php');
xhr.upload.onprogress = function (e) {
progress(e.loaded / e.total * 100);
};
xhr.onload = function() {
var json;
if (xhr.status === 403) {
failure('HTTP Error: ' + xhr.status, { remove: true });
return;
}
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
xhr.onerror = function () {
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
};
formData = new FormData();
formData.append('owner','" . $owner_id . "');
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
};
When i do this from chrome web dev ...
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST','https://example.com/myfolder/file-upload.php');
formData = new FormData();
formData.append('owner','ddddddddd');
formData.append('file', '/home/me/Desktop/image/mail.png');
xhr.send(formData);
I get array(0) {}
I can't send both values, owner and file. I've stacked them in the correct order.
Also have to click upload on the Tiny editor image popup, when i use General it gives me a blob.
No luck. Sorry if this post is kinda verbose. Thought you'd need all the code to help...

Corrupted .xlsx file from Flask web app and ajax POST request

I have a Flask web app with a URL route that receives a post request with some json, parses it to an .xlsx file, then returns the file with send_file().
Server side, I can see that the .xlsx file that is generated is correct but, once downloaded on the client side, the file is corrupted and can't be opened and is much larger than expected (201KB vs. 112KB).
I suspect it's some sort of encoding issue, but I've tried a whole bunch of stuff and can't make any headway. Can anyone help, please?
Flask route:
#app.route('/request/export_XLSX',methods=['POST'])
def request_export_XLSX():
json_model = json_util.loads(request.data.decode('ascii', 'ignore'))
xlsx_model = detox.xlsxFromJSONModel(json_model) # Returns file path
result = send_file(xlsx_model, as_attachment=True, attachment_filename=json_model['id']+'.xlsx', mimetype='application/vnd.ms-excel')
return result
JavaScript:
var exportModelExcel = function(){
var model = detox.fba.model
d3.selectAll('*').style("cursor","wait")
var modelJson = JSON.stringify(model)
$.ajax({
type: "POST",
url: "/request/export_XLSX",
data: modelJson,
success: function(d){
d3.selectAll('*').style("cursor","")
var blob = new Blob([d], {type: 'application/vnd.ms-excel'})
var link=document.createElement("a");
link.href=window.URL.createObjectURL(blob);
link.download=model.id+".xlsx";
link.click();
},
error: function(jqxhr,textStatus,errorThrown){
console.log("Error: " ,textStatus,errorThrown)
d3.selectAll('*').style("cursor","")
alert("There was an error exporting the model")
},
contentType: 'application/json',
responseType: 'blob',
processData: false,
});
}
Here's a link where you can see the good and bad .xlsx files: https://gofile.io/d/xywI1D
Well, I ended up ripping out the ajax and using an XMLHTTPRequest instead.
It works nicely and results in an uncorrupted .xlsx file. 🙂
var exportModelExcel = function(){
var model = detox.fba.model;
var modelJson = JSON.stringify(model);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var downloadUrl = URL.createObjectURL(xhttp.response);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = downloadUrl;
a.download = model.id+".xlsx";
a.click();
}
};
xhttp.open("POST", "/request/export_XLSX", true);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.responseType = "blob";
xhttp.send(modelJson);
}

RecordRTC in Laravel

I'm trying to use an example PHP-and-FFmpeg from the technology RecordRTC (https://github.com/muaz-khan/RecordRTC) in Laravel project.
There is an js function:
function xhr(url, data, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
callback(request.responseText);
}
};
request.open('POST', url);
request.send(data);
}
Calls for the following function:
function PostBlob(audioBlob, videoBlob, fileName) {
var formData = new FormData();
formData.append('filename', fileName);
formData.append('audio-blob', audioBlob);
formData.append('video-blob', videoBlob);
xhr('/upload/store', formData, function(ffmpeg_output) {
document.querySelector('h1').innerHTML = ffmpeg_output.replace(/\\n/g, '<br />');
preview.src = 'uploads/' + fileName + '-merged.webm';
preview.play();
preview.muted = false;
});
}
where data sends to save.php for downloading video to server.
Instead of the file i used the 'store' way, added to web.php:
Route::post('/upload/store', 'UploadController#store')->name('store');
in a controller i tenprorary made the following:
public function store(Request $request)
{
dd($request);
}
but in console firefox writes:
Invalid URI. Load of media resource failed
Please tell me where did i make a mistake?
The problem is in the PostBlob function in this line, which uses a wrong URI:
xhr('save.php', formData, function(ffmpeg_output) {
Change the save.php to /upload/store.

Download and open PDF file using Ajax

I have an action class that generates a PDF. The contentType is set appropriately.
public class MyAction extends ActionSupport
{
public String execute() {
...
...
File report = signedPdfExporter.generateReport(xyzData, props);
inputStream = new FileInputStream(report);
contentDisposition = "attachment=\"" + report.getName() + "\"";
contentType = "application/pdf";
return SUCCESS;
}
}
I call this action through an Ajax call. I don't know the way to deliver this stream to browser. I tried a few things but nothing worked.
$.ajax({
type: "POST",
url: url,
data: wireIdList,
cache: false,
success: function(response)
{
alert('got response');
window.open(response);
},
error: function (XMLHttpRequest, textStatus, errorThrown)
{
alert('Error occurred while opening fax template'
+ getAjaxErrorString(textStatus, errorThrown));
}
});
The above gives the error:
Your browser sent a request that this server could not understand.
Here is how I got this working
$.ajax({
url: '<URL_TO_FILE>',
success: function(data) {
var blob=new Blob([data]);
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
link.click();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated answer using download.js
$.ajax({
url: '<URL_TO_FILE>',
success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});
You don't necessarily need Ajax for this. Just an <a> link is enough if you set the content-disposition to attachment in the server side code. This way the parent page will just stay open, if that was your major concern (why would you unnecessarily have chosen Ajax for this otherwise?). Besides, there is no way to handle this nicely acynchronously. PDF is not character data. It's binary data. You can't do stuff like $(element).load(). You want to use completely new request for this. For that pdf is perfectly suitable.
To assist you more with the server side code, you'll need to tell more about the language used and post an excerpt of the code attempts.
I don't really think that any of the past answers spotted out the problem of the original poster. They all presume a GET request while the poster was trying to POST data and get a download in response.
In the course of searching for any better answer we found this jQuery Plugin for Requesting Ajax-like File Downloads (if link is broken sometime in the future, see the internet archive).
In its "heart" it creates a "temporary" HTML form containing the given data as input fields. This form is appended to the document and posted to the desired URL. Right after that the form is removed again:
jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
.appendTo('body').submit().remove()
Update Mayur's answer looks pretty promising and very simple in comparison to the jQuery plug-in I referred to.
This is how i solve this issue.
The answer of Jonathan Amend on this post helped me a lot.
The example below is simplified.
For more details, the above source code is able to download a file using a JQuery Ajax request (GET, POST, PUT etc). It, also, helps to upload parameters as JSON and to change the content type to application/json (my default).
The html source:
<form method="POST">
<input type="text" name="startDate"/>
<input type="text" name="endDate"/>
<input type="text" name="startDate"/>
<select name="reportTimeDetail">
<option value="1">1</option>
</select>
<button type="submit"> Submit</button>
</form>
A simple form with two input text, one select and a button element.
The javascript page source:
<script type="text/javascript" src="JQuery 1.11.0 link"></script>
<script type="text/javascript">
// File Download on form submition.
$(document).on("ready", function(){
$("form button").on("click", function (event) {
event.stopPropagation(); // Do not propagate the event.
// Create an object that will manage to download the file.
new AjaxDownloadFile({
url: "url that returns a file",
data: JSON.stringify($("form").serializeObject())
});
return false; // Do not submit the form.
});
});
</script>
A simple event on button click. It creates an AjaxDownloadFile object. The AjaxDownloadFile class source is below.
The AjaxDownloadFile class source:
var AjaxDownloadFile = function (configurationSettings) {
// Standard settings.
this.settings = {
// JQuery AJAX default attributes.
url: "",
type: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8"
},
data: {},
// Custom events.
onSuccessStart: function (response, status, xhr, self) {
},
onSuccessFinish: function (response, status, xhr, self, filename) {
},
onErrorOccured: function (response, status, xhr, self) {
}
};
this.download = function () {
var self = this;
$.ajax({
type: this.settings.type,
url: this.settings.url,
headers: this.settings.headers,
data: this.settings.data,
success: function (response, status, xhr) {
// Start custom event.
self.settings.onSuccessStart(response, status, xhr, self);
// Check if a filename is existing on the response headers.
var filename = "";
var disposition = xhr.getResponseHeader("Content-Disposition");
if (disposition && disposition.indexOf("attachment") !== -1) {
var filenameRegex = /filename[^;=\n]*=(([""]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1])
filename = matches[1].replace(/[""]/g, "");
}
var type = xhr.getResponseHeader("Content-Type");
var blob = new Blob([response], {type: type});
if (typeof window.navigator.msSaveBlob !== "undefined") {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// Use HTML5 a[download] attribute to specify filename.
var a = document.createElement("a");
// Safari doesn"t support this yet.
if (typeof a.download === "undefined") {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () {
URL.revokeObjectURL(downloadUrl);
}, 100); // Cleanup
}
// Final custom event.
self.settings.onSuccessFinish(response, status, xhr, self, filename);
},
error: function (response, status, xhr) {
// Custom event to handle the error.
self.settings.onErrorOccured(response, status, xhr, self);
}
});
};
// Constructor.
{
// Merge settings.
$.extend(this.settings, configurationSettings);
// Make the request.
this.download();
}
};
I created this class to added to my JS library. It is reusable. Hope that helps.
What worked for me is the following code, as the server function is retrieving File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:
$http.get( fullUrl, { responseType: 'arraybuffer' })
.success(function (response) {
var blob = new Blob([response], { type: 'application/pdf' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob); // for IE
}
else {
var fileURL = URL.createObjectURL(blob);
var newWin = window.open(fileURL);
newWin.focus();
newWin.reload();
}
});
To fix the blank PDF issue in post request to get stream data like PDF, we need to add response type as 'arraybuffer' or 'blob' in request
$.ajax({
url: '<URL>',
type: "POST",
dataType: 'arraybuffer',
success: function(data) {
let blob = new Blob([data], {type: 'arraybuffer'});
let link = document.createElement('a');
let objectURL = window.URL.createObjectURL(blob);
link.href = objectURL;
link.target = '_self';
link.download = "fileName.pdf";
(document.body || document.documentElement).appendChild(link);
link.click();
setTimeout(()=>{
window.URL.revokeObjectURL(objectURL);
link.remove();
}, 100);
}
});
You could use this plugin which creates a form, and submits it, then removes it from the page.
jQuery.download = function(url, data, method) {
//url and data options required
if (url && data) {
//data can be string of parameters or array/object
data = typeof data == 'string' ? data : jQuery.param(data);
//split params into form inputs
var inputs = '';
jQuery.each(data.split('&'), function() {
var pair = this.split('=');
inputs += '<input type="hidden" name="' + pair[0] +
'" value="' + pair[1] + '" />';
});
//send request
jQuery('<form action="' + url +
'" method="' + (method || 'post') + '">' + inputs + '</form>')
.appendTo('body').submit().remove();
};
};
$.download(
'/export.php',
'filename=mySpreadsheet&format=xls&content=' + spreadsheetData
);
This worked for me. Found this plugin here
Concerning the answer given by Mayur Padshala this is the correct logic to download a pdf file via ajax but as others report in the comments this solution is indeed downloads a blank pdf.
The reason for this is explained in the accepted answer of this question: jQuery has some issues loading binary data using AJAX requests, as it does not yet implement some HTML5 XHR v2 capabilities, see this enhancement request and this discussion.
So using HTMLHTTPRequest the code should look like this:
var req = new XMLHttpRequest();
req.open("POST", "URL", true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="name_for_the_file_to_save_with_extention";
link.click();
}
The following code worked for me
//Parameter to be passed
var data = 'reportid=R3823&isSQL=1&filter=[]';
var xhr = new XMLHttpRequest();
xhr.open("POST", "Reporting.jsp"); //url.It can pdf file path
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status === 200) {
var blob = new Blob([xhr.response]);
const url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'myFile.pdf';
a.click();
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data)
, 100
})
}
};
xhr.send(data);
Hope this will save you a few hours and spare you from a headache.
It took me a while to figure this out, but doing regular $.ajax() request ruined my PDF file, while requesting it through address bar worked perfectly.
Solution was this:
Include download.js: http://danml.com/download.html
Then use XMLHttpRequest instead of $.ajax() request.
var ajax = new XMLHttpRequest();
ajax.open("GET", '/Admin/GetPdf' + id, true);
ajax.onreadystatechange = function(data) {
if (this.readyState == 4)
{
if (this.status == 200)
{
download(this.response, "report.pdf", "application/pdf");
}
else if (this.responseText != "")
{
alert(this.responseText);
}
}
else if (this.readyState == 2)
{
if (this.status == 200)
{
this.responseType = "blob";
}
else
{
this.responseType = "text";
}
}
};
ajax.send(null);
create a hidden iframe, then in your ajax code above:
url: document.getElementById('myiframeid').src = your_server_side_url,
and remove the window.open(response);
This snippet is for angular js users which will face the same problem, Note that the response file is downloaded using a programmed click event.
In this case , the headers were sent by server containing filename and content/type.
$http({
method: 'POST',
url: 'DownloadAttachment_URL',
data: { 'fileRef': 'filename.pdf' }, //I'm sending filename as a param
headers: { 'Authorization': $localStorage.jwt === undefined ? jwt : $localStorage.jwt },
responseType: 'arraybuffer',
}).success(function (data, status, headers, config) {
headers = headers();
var filename = headers['x-filename'];
var contentType = headers['content-type'];
var linkElement = document.createElement('a');
try {
var blob = new Blob([data], { type: contentType });
var url = window.URL.createObjectURL(blob);
linkElement.setAttribute('href', url);
linkElement.setAttribute("download", filename);
var clickEvent = new MouseEvent("click", {
"view": window,
"bubbles": true,
"cancelable": false
});
linkElement.dispatchEvent(clickEvent);
} catch (ex) {
console.log(ex);
}
}).error(function (data, status, headers, config) {
}).finally(function () {
});
I have found a solution that solved this problem for me (blank pdf when using jquery ajax). I've found this magical solution here: https://www.py4u.net/discuss/904599 (Answer 2) and it involves adding xhrFields to your ajax call:
xhrFields: {
responseType: 'blob'
}
My working example:
$.ajax({
url: "myUrl",
type: 'GET',
headers: {"token": mySecurityToken},
xhrFields: {
responseType: 'blob'
},
data: {id: myId}
}).done(function( data, statusText, xhr ) {
var filename = "";
var disposition = xhr.getResponseHeader("Content-Disposition");
if (disposition && (disposition.indexOf("attachment") !== -1) || disposition.indexOf("filename") !== -1) {
var filenameRegex = /filename[^;=\n]*=(([""]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1])
filename = matches[1].replace(/[""]/g, "");
}
var type = xhr.getResponseHeader("Content-Type");
var blob = new Blob([data], {type: type});
if (typeof window.navigator.msSaveBlob !== "undefined") {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// Use HTML5 a[download] attribute to specify filename.
var a = document.createElement("a");
// Safari doesn"t support this yet.
if (typeof a.download === "undefined") {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () {
URL.revokeObjectURL(downloadUrl);
}, 100); // Cleanup
}
})
I hope this will solve this nasty issue for many of you.
var xhr;
var beforeSend = function(){
$('#pleasewaitDL').modal('show');
}
$(function () {
$('#print_brochure_link').click(function(){
beforeSend();
xhr = new XMLHttpRequest();
xhr.open("GET",$('#preparedPrintModalForm').attr('action'), true);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status === 200) {
var file = window.URL.createObjectURL(this.response);
var a = document.createElement("a");
a.href = file;
a.download = this.response.name || "Property Brochure";
console.log(file);
document.body.appendChild(a);
a.click();
window.onfocus = function () {
document.body.removeChild(a)
}
$('#pleasewaitDL').modal('hide');
};
};
xhr.send($('#preparedPrintModalForm').serialize());
});
$('#pleasewaitDLCancel').click(function() {
xhr.abort();
});
});
If you have to work with file-stream (so no physically saved PDF) like we do and you want to download the PDF without page-reload, the following function works for us:
HTML
<div id="download-helper-hidden-container" style="display:none">
<form id="download-helper-form" target="pdf-download-output" method="post">
<input type="hidden" name="downloadHelperTransferData" id="downloadHelperTransferData" />
</form>
<iframe id="pdf-helper-output" name="pdf-download-output"></iframe>
</div>
Javascript
var form = document.getElementById('download-helper-form');
$("#downloadHelperTransferData").val(transferData);
form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse";
form.submit();
Due to the target="pdf-download-output", the response is written into the iframe and therefore no page reload is executed, but the pdf-response-stream is output in the browser as a download.
100% OK for all file types
// download the file
var link = document.createElement('a'),
filename = fname;
link.href = URL.createObjectURL(data);
link.download = filename;
link.click();
Do you have to do it with Ajax? Couldn't it be a possibility to load it in an iframe?
The best usage is to do an anchor or a form with the provided link, but it you need to do a validation or in other cases using jquery the best usage is to add a form and submit it using jquery (don't forget to set your request disposition as attachement on server side).
<form id="pdf-form" action="/link_to/download_your.pdf" accept-charset="UTF-8" method="get">
<input type="hidden" name="data" id="data" value="your data"></form>
and
Download my Pdf
then in jquery
$('#pdf').click(function () {
// your data if it json do it like this JSON.stringify(your_data_as_json)
$('#data').val(data);
$('#pdf-form').submit();
})

Categories