Phonegap change image src with jquery not working on Android - javascript

I try to change the src of a img tag with jquery. In firefox it is working fine, but in the phonegap developer app on android, nothing happens.
What I'm doing:
I'm getting an image as base64 with a ajax request. If the request is complete, I'm making an URL Object from the image, and change the src of the img tag to the url Object. Here my code:
$.ajax({
type: 'GET',
dataType: 'json',
url: MySecretPHPFunctionOnAServerThatReturnsABase64Image...,
complete: function(data) {
var base64Image = data.responseText;
var image = makeUrlObject(base64Image, "image/jpeg");
// ERROR!!! :-)
// Only working in Browser, not on android...
$("#scanPreview").prop("src", image + '?' + genTimestamp());
},
error: function() {}
});
I think the makeUrlObject Function is not the reason for the error, but if you want to see it, for making sure, or if I'm overlooking something ;-)
function makeUrlObject(dataURL, typeURL) {
var binStr = atob(dataURL);
var buf = new ArrayBuffer(binStr.length);
var view = new Uint8Array(buf);
for(var i = 0; i < view.length; i++)
view[i] = binStr.charCodeAt(i);
var blob = new Blob([view], {type: typeURL});
binStr=null;
buf = null;
view = null;
URL = window.URL || window.webkitURL;
return URL.createObjectURL(blob);
};

Instead of .prop("src"
try
var elem = document.getElementById('myimg');
myimg.src="theimage.jpg";
also case sensitive

Related

HTML Chrome doesn't open base64 pdf without right click->open [duplicate]

After updating Google Chrome, the report jsPDF in a new Window does not work any more.
The console shows the message:
Not allowed to navigate top frame to data URL:
data:application/pdf;base64,JVBERi0xLjMKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1....
Can you help-me?
Thanks.
This works well now that chrome has removed top frame navigation. Only downloading the pdf in chrome gives problem. Download works in well in firefox tho.
var string = doc.output('datauristring');
var iframe = "<iframe width='100%' height='100%' src='" + string + "'></iframe>"
var x = window.open();
x.document.open();
x.document.write(iframe);
x.document.close();
Apparently Google Chrome has removed support for top-frame navigation, you can see more informations here: https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/GbVcuwg_QjM
You may try to render the jsPDF to an iFrame
I recently had the same problem using FileReader object to read content and show my JSReport.
var reader = new FileReader();
reader.onload = function (e) {
window.open(reader.result, "_blank");
}
reader.readAsDataURL(blob);
Unfortunatly after chrome update all my report stopped working.
I tried to fix this by using Blob object and it's still working but if you have a popup blocker it will not work.
var file = new Blob([blob], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
I finally find a way to avoid this problem by creating the iFrame dynamically after reading this topic and i decided to share the solution.
var file = new Blob([blob], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
var win = window.open();
win.document.write('<iframe src="' + fileURL + '" frameborder="0" style="border:0; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%;" allowfullscreen></iframe>')
Maybe can help, create a function to export with the download attribute html5:
var docPdf = doc.output();
exportToFile(docPdf,defaults.type);
function exportToFile(data,type){
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/'+type+';filename='+'exportar.'+type+';'+'charset=utf-8,' + encodeURI(data);
hiddenElement.target = '_blank';
hiddenElement.download = 'exportar.'+type;
hiddenElement.click();
}
the download property of the a element has to contain a file name.
function window_download( datauri )
{
const match = datauri.match(/(filename=)([^;]+)/);
const fileName = match ? match[2] : '' ;
if ( fileName )
{
const downloadLink = document.createElement("a");
downloadLink.download = fileName;
downloadLink.innerHTML = "Download File";
downloadLink.href = datauri ;
downloadLink.click();
}
else
{
throw 'missing download file name' ;
}
// get contents of pdf from jsPDF as a data uri.
const uri = pdf.output('datauristring', 'packing-list.pdf' );
window_download( uri ) ;
<iframe id="ManualFrame"
frameborder="0"
style="border:0"
allowfullscreen>
</iframe>
<script>
$(function () {
setManualFrame();
});
function setManualFrame() {
$("#ManualFrame").attr("height", screen.height);
$("#ManualFrame").attr("width", screen.width);
$("#ManualFrame").attr("src", "data:application/pdf;base64," + Your_PDF_Data);
}
</script>
var pdfUrl = doc.output('datauri').substring(doc.output('datauri').indexOf(',')+1);
var binary = atob(pdfUrl.replace(/\s/g, ''));
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);
for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i);
}
var blob = new Blob( [view], { type: "application/pdf" });
var url = URL.createObjectURL(blob);
function openPDF(){
window.open(url);
}
As chrome removed its support for - Top-frame navigation. Luckily jsPDF has an API - "save()", which offers the same functionality as doc.output('datauri')
Below is the example implementation of save()
var doc = new jsPDF();
doc.addImage(imgData, 'JPEG', 0, 0, 300, 160);
doc.save('fileName.pdf');
save(filename, options) → {jsPDF|Promise}
Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf'). Uses FileSaver.js-method saveAs.
Refer JSPDF documentation for more information -
Add attrbute download
Based on Joyston's answer, but without reparsing and therefore without additional need to escape something:
x=window.open();
iframe=x.document.createElement('iframe')
iframe.width='100%'
iframe.height='100%'
iframe.frameBorder=0
iframe.style="border: 0"
iframe.src='data:text/html........' //data-uri content here
x.document.body.appendChild(iframe);
Not related to jspdf, but did help me here (and this question is the top hit at google): If specifying a download="..." attribute to the anchor tag, the download prompt will properly open up.
#kuldeep-choudhary
Hi, in fact, to solve i'm using object tag with angularJS 1.5.xx
<object ng-attr-data="{{data}}" type="application/pdf"></object>
and in script:
$scope.doc.data = $sce.trustAsResourceUrl(doc.output("datauristring"));
In pure javascript, maybe like this works:
html:
<object id="obj" type="application/pdf" ></object>
js:
document.elementById('obj').data = doc.output("datauristring");
please, try and correct-me if I wrong.
Using download="" made me able to download the file
/**
* Creates an anchor element `<a></a>` with
* the base64 pdf source and a filename with the
* HTML5 `download` attribute then clicks on it.
* #param {string} pdf
* #return {void}
*/
function downloadPDF(pdf) {
const linkSource = `data:application/pdf;base64,${pdf}`;
const downloadLink = document.createElement("a");
const fileName = "vct_illustration.pdf";
downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();
}
Source from: https://medium.com/octopus-labs-london/downloading-a-base-64-pdf-from-an-api-request-in-javascript-6b4c603515eb
In angular2+ -
app.component.html -
<object id="obj" [attr.data] type="application/pdf"> </object>
app.component.ts
document.getElementById('obj').dataset.data = doc.output("datauristring");
var blob = doc.output("blob");
window.open(URL.createObjectURL(blob));

How to display PDF (Blob) on iOS sent from my angularjs app

My Angular 1.5 application connect to a Java/Tomcat/Spring backend server via REST.
One REST service generates PDF and send it to the client. It works fine on DEsktop browsers (FF, Chrome at least) but I cannot see the PDF content on iOS (ipad for instance) whatever the browser I am using (Chrome, Safari..)
Here is the Angular Code :
$http.get("/displayPdf", {responseType: 'arraybuffer', params: {id: 1}}).
success(function(data) {
var blob = new Blob([data], {type 'application/pdf'});
var objectUrl = window.URL.createObjectURL(blob);
window.open(objectUrl);
}
);
The Spring/Jax-RS code is :
#GET
#Path("displayPdf")
#Produces("application/pdf")
Response displayPdf(#QueryParam("id") Long id) {
byte[] bytes = service.generatePdf();
return javax.ws.rs.core.Response.ok().
entity(bytes).
header("Content-Type", "pdf").
header("Content-Disposition", "attachment; filename='test.pdf'").
build();
}
I have done my research here for instance(AngularJS: Display blob (.pdf) in an angular app) but could not find an appropriate solution.
So please, do you know what should I do to display the generated PDF to my iPad/iPhone end-users ?
Thanks a lot
None of the solutions proposed above did work for me.
The main issue comes from URL that wasn't retrieved correctly in iOS. The following code do the correct work :
window.URL = window.URL || window.webkitURL;
Also even with this, it did not work on Chrome iOS, neither Opera iOS...so after digging the internet and inspired with the following questions :
Blob createObjectURL download not working in Firefox (but works when debugging)
How to open Blob URL on Chrome iOS
Display blob (.pdf) in an angular app
... I finally ended up with the following code (working on all iOS browsers except FF on iOS) :
if (window.navigator.msSaveOrOpenBlob) { //IE 11+
window.navigator.msSaveOrOpenBlob(blob, "my.pdf");
} else if (userAgent.match('FxiOS')) { //FF iOS
alert("Cannot display on FF iOS");
}
} else if (userAgent.match('CriOS')) { //Chrome iOS
var reader = new FileReader();
reader.onloadend = function () { $window.open(reader.result);};
reader.readAsDataURL(blob);
} else if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)) { //Safari & Opera iOS
var url = $window.URL.createObjectURL(blob);
window.location.href = url;
}
Just add the below code as your $http call.I've handled for other browsers as well.
$http.get("/displayPdf", {responseType: 'arraybuffer', params: {id: 1}}).success(function(data) {
var blob = new Blob([data], {type 'application/pdf'});
var anchor = document.createElement("a");
if(navigator.userAgent.indexOf("Chrome") != -1||navigator.userAgent.indexOf("Opera") != -1){
$window.open(URL.createObjectURL(file,{oneTimeOnly:true}));
}else if(navigator.userAgent.indexOf("iPad") != -1){
var fileURL = URL.createObjectURL(file);
//var anchor = document.createElement("a");
anchor.download="myPDF.pdf";
anchor.href = fileURL;
anchor.click();
}else if(navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("Safari") != -1){
var url = window.URL.createObjectURL(file);
anchor.href = url;
anchor.download = "myPDF.pdf";
document.body.appendChild(anchor);
anchor.click();
setTimeout(function(){
document.body.removeChild(anchor);
window.URL.revokeObjectURL(url);
}, 1000);
}
});
i use basically your same setup but i build my pdf differently using, unable to test with iOS but i hope this helps some
$http({ url: $scope.url,
method: "GET",
headers: { 'Accept': 'application/pdf' },
responseType: 'arraybuffer' })
.then(function (response) {
var file = new Blob([response.data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
$scope.pdfContent = $sce.trustAsResourceUrl(fileURL);
});//end http

Permission denied for clicking link in Internet Explorer 11

I modified an existing AngularJS-App, which lists customers, by adding a button, that allows to download the customer information as a vcard. I create the vcard in Javascript directly on click. The download-button calls the following function on click with the customer-item as argument:
function transcodeToAnsi(content){
var encoding = "windows-1252";
var nonstandard = {NONSTANDARD_allowLegacyEncoding: true};
return new TextEncoder(encoding, nonstandard).encode(content);
}
$scope.download = function(item) {
var filename = 'contact.vcf';
var aId = "vcard";
var content = createVCard(item);
var encoded = transcodeToAnsi(content);
var blob = new Blob([ encoded ], { type : 'vcf' });
var url = (window.URL || window.webkitURL).createObjectURL(blob);
$("body").append('<a id="' + aId + '" href="' + url + '" download=' + filename + ' class="hidden"></a>');
$timeout(function(){
document.getElementById(aId).click();
$("#" + aId).remove();
})
return false;
}
In the createVCard-function I just create the file content as a String, so it should not enter into the problem. The transcoding is done by this library: https://github.com/inexorabletash/text-encoding
The function works without problem in Firefox and Chrome, but not in IE11. The following error is given in the console:
Error: Permission denied
at Anonymous function (http://***/Contacts2015/js/contacts.js:169:9)
at Anonymous function (http://***/static/9bojdXAkdR8XdVMdSTxZAgzEwGWhHMwgpuONdU2Y8F4.js:14305:11)
at completeOutstandingRequest (http://***/static/9bojdXAkdR8XdVMdSTxZAgzEwGWhHMwgpuONdU2Y8F4.js:4397:7)
at Anonymous function (http://***/static/9bojdXAkdR8XdVMdSTxZAgzEwGWhHMwgpuONdU2Y8F4.js:4705:7) undefined
Line 169 is this instruction of the function above:
document.getElementById(aId).click();
The same error is displayed, when this statement is input in the console manually.
I would appreciate every hint about the reason and even more a good workaround.
EDIT
Corrected error-line and typo.
You cannot directly open blobs in Microsoft IE. You must use window.navigator.msSaveOrOpenBlob. There's also msSaveBlob if that's what you need.
$scope.download = function() {
//etc... logic...
var blob = new Blob([encoded], {type: 'vcf'});
//for microsoft IE
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else { //other browsers
var a = document.createElement('a');
a.style = "display:none";
a.href = URL.createObjectURL(blob);
a.download = "filename.jpg";
a.click();
}
}
One last thing: the previous code won't work on firefox because firefox doesn't support click(). You can prototype its behavior using this snippet:
HTMLElement.prototype.click = function() {
var evt = this.ownerDocument.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, this.ownerDocument.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
this.dispatchEvent(evt);
}

Chrome extension/jQuery works on one site but not others? Trying to fire an event on clicking a link

I have three different js files for three different sites. Let me preface by saying the manifest does have the proper settings to have these these on the proper sites, and only one function of the extension (the most important one) does not work.
The first, which works, is for pages like these: http://hearthstonetopdeck.com/deck.php?d=1613
var decklist = [];
$('.cardname').each(function(i, el) {
var values = $(this).text().split(' ');
var count = parseInt(values.shift(), 10);
for (var i = 0; i < count; i++) {
decklist.push(values.join(' '));
}
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
var html = $('#deckname').html() + '';
fileName = $('#deckname').text() + '.txt';
html = html.replace(/<h1>#/, '<h1><a class="download" href="#download">DOWNLOAD</a> - #');
$('#deckname').html(html);
});
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
Running this in the console will work just as it does with the extension. I have tested all 3 of these js files both using the chrome extension method and pasting in the console. Results are identical.
The second site (http://www.hearthhead.com/deck=300/spell-power-on-a-budget), for which it USED to work, no longer does. I can't seem to remember change any code either, and it should fire identically. The issue here is that, while the download link appears, either the event doesn't fire or it simply doesn't work. Here is the code for site #2:
var decklist = [];
$('.deckguide-cards-type li').each(function(i, el) {
var values = $(this).text().substring(1).split(' ');
if ($.inArray("x2", values) != "-1") {
values.pop();
decklist.push(values.join(' '));
}
decklist.push(values.join(' '));
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
$(document).ready(function(){
var html = $('.text h1').html() + ' hearthstonedeckdl';
fileName = $('.text h1').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '- <a class="download" href="#download">DOWNLOAD</a>');
$('.text h1').html(html);
});
Firing the function saveData on load DOES work exactly as expected, and a .txt file is downloaded with the proper data. This is the intended function on clicking the download link, and it works in the first example.
This final example has not worked period, but as before, firing on load works, properly. It's simply the link I'm having issues with. The site is here: http://www.hearthpwn.com/decks/46364-d3managements-legend-hunter
The code is below:
var decklist = [];
$('.col-name').each(function(i, el) {
var values = $(this).text().substring(2).substring(0, $(this).text().length - 10).replace(/[^a-zA-Z0-9\.\s']+/g ,"").split(' ');
if ($.inArray("", values) != "-1") {
return;
} else if ($(this).text().substr($(this).text().length - 3, 1) == "2") {
decklist.push(values.join(' '));
decklist.push(values.join(' '));
} else {
decklist.push(values.join(' '));
}
});
var data = decklist.join("\r\n");
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob([data], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
$(document).ready(function(){
var html = $('.t-deck-title').html() + ' hearthstonedeckdl';
fileName = $('.t-deck-title').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '</br><a class="download" href="#download">DOWNLOAD</a>');
$('.t-deck-title').html(html);
});
I'm fairly new to jQuery, but consulting with a friend of mine that has more experience than me can't seem to find the issue, and it's driving me absolutely mad.
Thanks!
You declare a click event on an anchor before it is created.
Replace this:
$(document).ready(function(){
$('a[href="#download"]').click(function(){
saveData(data, fileName);
});
});
With this:
$(document).ready(function(){
$(document).on('click', 'a[href="#download"]', function(){
saveData(data, fileName);
});
});
Or keep your code and make sure you call this:
var html = $('.t-deck-title').html() + ' hearthstonedeckdl';
fileName = $('.t-deck-title').text() + '.txt';
html = html.replace(/hearthstonedeckdl/, '</br><a class="download" href="#download">DOWNLOAD</a>');
$('.t-deck-title').html(html);
before attaching the click event.
Have you tried giving jquery another namespace? I noticed on the site you provided does not run jquery which might mean on the other sites it may be conflicting.
try
var $jg = jQuery.noConflict();
at the top of your document.
Then instead of
$('.t-deck-title')
try
$jg('.t-deck-title')

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