How can i use XmlHttpRequest or FileAPI in Internet Explorer? - javascript

Below code is from the html5uploader and it works well on all browsers except IE 10.
I have tried my best to include a function where IE is detected and the dropped file read but was unable to get this working in IE.
How do i modify code in the function below to include Internet Explorer 10?
Full Javascript code here.
Link to uploader here.
// Firefox 3.6, Chrome 6, WebKit
if(window.FileReader) {
// Once the process of reading file
this.loadEnd = function() {
bin = reader.result;
xhr = new XMLHttpRequest();
xhr.open('POST', targetPHP+'?up=true', true);
var boundary = 'xxxxxxxxx';
var body = '--' + boundary + "\r\n";
body += "Content-Disposition: form-data; name='upload'; filename='" + file.name + "'\r\n";
body += "Content-Type: application/octet-stream\r\n\r\n";
body += bin + "\r\n";
body += '--' + boundary + '--';
xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary);
// Firefox 3.6 provides a feature sendAsBinary ()
if(xhr.sendAsBinary != null) {
xhr.sendAsBinary(body);
// Chrome 7 sends data but you must use the base64_decode on the PHP side
} else {
xhr.open('POST', targetPHP+'?up=true&base64=true', true);
xhr.setRequestHeader('UP-FILENAME', file.name);
xhr.setRequestHeader('UP-SIZE', file.size);
xhr.setRequestHeader('UP-TYPE', file.type);
xhr.send(window.btoa(bin));
}
if (show) {
var newFile = document.createElement('div');
newFile.innerHTML = 'Loaded : '+file.name+' size '+file.size+' B';
document.getElementById(show).appendChild(newFile);
}
if (status) {
document.getElementById(status).innerHTML = 'Loaded : 100%<br/>Next file ...';
}
}

perhaps this can help other people, even if the problem is resolved for you:
1) be sure you force your browser to IE10 : <meta http-equiv="X-UA-Compatible" content="IE=edge">
2) don't use reader.readAsBinaryString(file); but reader.readAsDataURL(file); for IE
3) send the XHR object with xhr.send and do not use btoa (just do xhr.send((bin));)
4) Generally, in order your code to be comptatible with all browser, use if (navigator.appName === "Microsoft Internet Explorer") { ... } and open your XHR object with a different target for each browser (like this: xhr.open('POST', targetPHP+'?up=true&browser=IE', true); ), because if will be handled differently by PHP.
Everything is explained here : How can i change the XmlHttpRequest or FileAPI used in html5uploader to support IE

Related

AJAX File Upload with XMLHttpRequest that support i.e 9

I am trying to upload a file using ajax. The code below works perfectly on all browsers except i.e 9 and previous versions. Unfortunately I am forced to support these browsers so I am wondering how I could modify this code so it will work on i.e.
I have seen some posts suggest using an iframe but i fail to see how this fixes my problem.
I have tried using fileInput.name since it seems that i.e doesn't allow me to have an array of files, this meant that I could actually get to the line where it sends but I wasn't sure what that line should be. xhr.send(fileInput); didn't seem to work.
Also attempted using formdata but then also fould that ie9 didn't support that.
Your help would be greatly appreciated.
<script>
function uploadFile(fileInput, label1, label2, filename) {
var fileInput = document.getElementById(fileInput);
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.open('POST', 'Create/Upload');
xhr.setRequestHeader('Content-type', 'multipart/form-data');
//Appending file information in Http headers
//xhr.setRequestHeader('X-File-Name', filename);
xhr.setRequestHeader('X-File-Type', fileInput.files[0].name);
xhr.setRequestHeader('X-File-Type', fileInput.files[0].type);
xhr.setRequestHeader('X-File-Size', fileInput.files[0].size);
xhr.setRequestHeader('X-Type', label1);
//Sending file in XMLHttpRequest
xhr.send(fileInput.files[0]);
//xhr.send(fileInput);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
$('#' + label1).text(xhr.responseText.replace(/\"/g, ""));
document.getElementById(label1).style.color = "green";
document.getElementById(label2).style.display = 'none';
}
else {
$('#' + label1).text("File upload failed");
document.getElementById(label1).style.color = "red";
}
}
}
document.getElementById('uploaderAuto').onsubmit = function () {
myfile = $('#fileInputAuto').val();
var ext = myfile.split('.').pop();
ext = ext.toLowerCase();
if (ext == "pdf" || ext == "docx" || ext == "doc" || ext == "odf" || ext == "rtf") {
uploadFile('fileInputAuto', 'Auto', "AutoView", myfile);
} else {
alert("The following is a list of accepted file types:\n\n - Word Document (*.doc)\n - Word Document (*.docx)\n - Portable Document Format (*.pdf)\n - Open Document Format (*.odf)\n - Rich Text Format (*.rtf)\n\nPlease choose a file with one of these file types.");
}
return false;
}
document.getElementById('uploaderOther1').onsubmit = function () {
myfile = $('#fileInputOther1').val();
uploadFile('fileInputOther1', 'Other1', 'Other1View', myfile);
return false;
}
document.getElementById('uploaderOther2').onsubmit = function () {
myfile = $('#fileInputOther2').val();
uploadFile('fileInputOther2', 'Other2', 'Other2View', myfile);
return false;
}
</script>
I ended up using the script from here: http://www.phpletter.com/Our-Projects/AjaxFileUpload/ and it works very well.
I was using asp.net server side so this tutorial helped: http://totalpict.com/b/asp.net%20generic/5/34396

Origin file:// is not allowed by Access-Control-Allow-Origin with WebWorker

I´m developing a mobile app with PhoneGap and jQuery Mobile.
I´m connecting to REST web service in my Web Worker using XMLHttpRequest.
var url = "http://myurl.dyndns.org:9018/WebService/webresources/UsersWS/getUser";
var params = '{"id":"' + 5 + '"}';
var xhr;
try {
xhr = new XMLHttpRequest();
xhr.open('POST', url, false);
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var result = JSON.parse(xhr.responseText);
self.postMessage("PRUEBA: "+result.d);
}
};
xhr.send(JSON.stringify(params));
} catch (e) {
self.postMessage('Error occured in XMLHttpRequest: ' + xhr.statusText + ' ReadyState: ' + xhr.readyState + ' Status:' + xhr.status + ' E: ' +e+' Msg:'+e.message);
}
In Samsung Galaxy 3 with Android Version 4.3, it works, but in Nexus 7 Tablet with Android Version 4.4.2 is not working.
I get this message:
"XMLHttpRequest cannot load http://myurl.dyndns.org:9018/WebService/webresources/UsersWS/getUser. Origin file:// is not allowed by Access-Control-Allow-Origin.", source: (0)
I have read that Nexus has Chrome Browser and this has some problems (Ref: Origin null is not allowed by Access-Control-Allow-Origin) but I don´t know what can I do, I use xhr.setRequestHeader("Access-Control-Allow-Origin", "*"); but I doesn´t work...
Can you help me, please?
Thanks in advance.
I started to use a very simple webserver to serve the files following this documentation and it worked. The reason is that some webbrowsers(e.g. Safari) handle local files differently than data from a server.
http://4pcbr.com/topic/staticme_simplest_web_server_for_serving_static_files

download file using an ajax request

I want to send an "ajax download request" when I click on a button, so I tried in this way:
javascript:
var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();
download.php:
<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");
readfile("file.txt");
?>
but doesn't work as expected, how can I do ? Thank you in advance
Update April 27, 2015
Up and coming to the HTML5 scene is the download attribute. It's supported in Firefox and Chrome, and soon to come to IE11. Depending on your needs, you could use it instead of an AJAX request (or using window.location) so long as the file you want to download is on the same origin as your site.
You could always make the AJAX request/window.location a fallback by using some JavaScript to test if download is supported and if not, switching it to call window.location.
Original answer
You can't have an AJAX request open the download prompt since you physically have to navigate to the file to prompt for download. Instead, you could use a success function to navigate to download.php. This will open the download prompt but won't change the current page.
$.ajax({
url: 'download.php',
type: 'POST',
success: function() {
window.location = 'download.php';
}
});
Even though this answers the question, it's better to just use window.location and avoid the AJAX request entirely.
To make the browser downloads a file you need to make the request like that:
function downloadFile(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download=fileName;
link.click();
};
req.send();
}
You actually don't need ajax at all for this. If you just set "download.php" as the href on the button, or, if it's not a link use:
window.location = 'download.php';
The browser should recognise the binary download and not load the actual page but just serve the file as a download.
Cross browser solution, tested on Chrome, Firefox, Edge, IE11.
In the DOM, add an hidden link tag:
<a id="target" style="display: none"></a>
Then:
var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";
req.setRequestHeader('my-custom-header', 'custom-value'); // adding some headers (if needed)
req.onload = function (event) {
var blob = req.response;
var fileName = null;
var contentType = req.getResponseHeader("content-type");
// IE/EDGE seems not returning some response header
if (req.getResponseHeader("content-disposition")) {
var contentDisposition = req.getResponseHeader("content-disposition");
fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
} else {
fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
}
if (window.navigator.msSaveOrOpenBlob) {
// Internet Explorer
window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
} else {
var el = document.getElementById("target");
el.href = window.URL.createObjectURL(blob);
el.download = fileName;
el.click();
}
};
req.send();
It is possible. You can have the download started from inside an ajax function, for example, just after the .csv file is created.
I have an ajax function that exports a database of contacts to a .csv file, and just after it finishes, it automatically starts the .csv file download. So, after I get the responseText and everything is Ok, I redirect browser like this:
window.location="download.php?filename=export.csv";
My download.php file looks like this:
<?php
$file = $_GET['filename'];
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=".$file."");
header("Content-Transfer-Encoding: binary");
header("Content-Type: binary/octet-stream");
readfile($file);
?>
There is no page refresh whatsoever and the file automatically starts downloading.
NOTE - Tested in the following browsers:
Chrome v37.0.2062.120
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
I prefer location.assign(url);
Complete syntax example:
document.location.assign('https://www.urltodocument.com/document.pdf');
developer.mozilla.org/en-US/docs/Web/API/Location.assign
For those looking a more modern approach, you can use the fetch API. The following example shows how to download a spreadsheet file. It is easily done with the following code.
fetch(url, {
body: JSON.stringify(data),
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
})
.then(response => response.blob())
.then(response => {
const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "file.xlsx";
document.body.appendChild(a);
a.click();
})
I believe this approach to be much easier to understand than other XMLHttpRequest solutions. Also, it has a similar syntax to the jQuery approach, without the need to add any additional libraries.
Of course, I would advise checking to which browser you are developing, since this new approach won't work on IE. You can find the full browser compatibility list on the following link.
Important: In this example I am sending a JSON request to a server listening on the given url. This url must be set, on my example I am assuming you know this part. Also, consider the headers needed for your request to work. Since I am sending a JSON, I must add the Content-Type header and set it to application/json; charset=utf-8, as to let the server know the type of request it will receive.
#Joao Marcos solution works for me but I had to modify the code to make it work on IE, below if what the code looks like
downloadFile(url,filename) {
var that = this;
const extension = url.split('/').pop().split('?')[0].split('.').pop();
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "blob";
req.onload = function (event) {
const fileName = `${filename}.${extension}`;
const blob = req.response;
if (window.navigator.msSaveBlob) { // IE
window.navigator.msSaveOrOpenBlob(blob, fileName);
}
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
URL.revokeObjectURL(link.href);
};
req.send();
},
Decoding a filename from the header is a little bit more complex...
var filename = "default.pdf";
var disposition = req.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, '');
}
This solution is not very different from those above, but for me it works very well and i think it's clean.
I suggest to base64 encode the file server side (base64_encode(), if you are using PHP) and send the base64 encoded data to the client
On the client you do this:
let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
let uri = URL.createObjectURL(blob);
let link = document.createElement("a");
link.download = THE_FILE_NAME,
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
This code puts the encoded data in a link and simulates a click on the link, then it removes it.
Your needs are covered by
window.location('download.php');
But I think that you need to pass the file to be downloaded, not always download the same file, and that's why you are using a request, one option is to create a php file as simple as showfile.php and do a request like
var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);
showfile.php
<?php
$file = $_GET["file"]
echo $file;
where file is the file name passed via Get or Post in the request and then catch the response in a function simply
if(ajaxRequest.readyState == 4){
var file = ajaxRequest.responseText;
window.location = 'downfile.php?file=' + file;
}
}
there is another solution to download a web page in ajax. But I am referring to a page that must first be processed and then downloaded.
First you need to separate the page processing from the results download.
1) Only the page calculations are made in the ajax call.
$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },
function(data, status)
{
if (status == "success")
{
/* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
window.location.href = DownloadPage.php+"?ID="+29;
}
}
);
// For example: in the CalculusPage.php
if ( !empty($_POST["calculusFunction"]) )
{
$ID = $_POST["ID"];
$query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
...
}
// For example: in the DownloadPage.php
$ID = $_GET["ID"];
$sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
...
$filename="Export_Data.xls";
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: inline; filename=$filename");
...
I hope this solution can be useful for many, as it was for me.
this works for me
var dataObj = {
somekey:"someValue"
}
$.ajax({
method: "POST",
url: "/someController/someMethod",
data: dataObj,
success: function (response) {
const blob = new Blob([response], { type: 'text/csv' });
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "file.csv";
document.body.appendChild(a);
a.click();
}
});

Javascript: set filename to be downloaded

I'm using a plugin to generate a csv file from a table, the file is being downloaded with a "download" filename, how can I change the filename e.g. as dowload.csv
var csv = $("#table").table2CSV({delivery:'download'});
window.location.href = 'data:text/csv;charset=UTF-8,'+ encodeURIComponent(csv);
i wrote a tool you can use to save a file to the downloads folder of the local machine with a custom filename, if that's possible on the client's machine.
as of this writing, you need chrome, firefox, or IE10 for that specific capability, but this tool falls-back to an un-named download if that's all that's available, since something is better than nothing...
for your use:
download(csv, "dowload.csv", "text/csv");
and the magic code:
function download(strData, strFileName, strMimeType) {
var D = document,
a = D.createElement("a");
strMimeType= strMimeType || "application/octet-stream";
if (navigator.msSaveBlob) { // IE10
return navigator.msSaveBlob(new Blob([strData], {type: strMimeType}), strFileName);
} /* end if(navigator.msSaveBlob) */
if ('download' in a) { //html5 A[download]
a.href = "data:" + strMimeType + "," + encodeURIComponent(strData);
a.setAttribute("download", strFileName);
a.innerHTML = "downloading...";
D.body.appendChild(a);
setTimeout(function() {
a.click();
D.body.removeChild(a);
}, 66);
return true;
} /* end if('download' in a) */
//do iframe dataURL download (old ch+FF):
var f = D.createElement("iframe");
D.body.appendChild(f);
f.src = "data:" + strMimeType + "," + encodeURIComponent(strData);
setTimeout(function() {
D.body.removeChild(f);
}, 333);
return true;
} /* end download() */
update: added future-resistant IE routine
update2: checkout the evolved version on GitHub that includes dataURL and Blob support.

Ajax Request Always Throws an Error

function loaded() {
var xmldoc,
currenttime = new Date().getTime(),
req,
address = 'http://webservices.foo.com/eSignalQuotes/eSignalQuotes.asmx/GetDelayedQuotes?',
symbols = 'symbols=' + '+c,s,ct,zw,kw,adm+',
cusip = '&cusip=',
fields = '&fields=' + 'desc,month,year,recent,netchg,-decimal',
type = '&type=' + 'future,stock,index',
dispfullname = '&dispfullname=' + 'true',
datefmt = '&datefmt=',
timefmt = '&timefmt=',
timestamp = '&' + Math.floor(currenttime/3600000),
query = address + symbols + cusip + fields + type + dispfullname + datefmt + timefmt + timestamp;
;
if(window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.addEventListener('error', function(e) {alert('Error');}, false);
req.addEventListener('load', function(e) {xmldoc = req.responseText;}, false);
req.open('GET', query, true);
req.send();
}
That's what my code looks like, and it always throws an error in Safari and Firefox. The crazy thing is if I remove the event listeners, and change the response type to responseText, Internet Explorer gives me output. I tried overrideMimetype, but that didn't seem to help. If I check the response in Firefox or Safari, I get null. I'm at a loss, and any help would be appreciated.
I should mention that I'd prefer to avoid any 3rd party libraries for this.
Update:
The error occurs during the progress event, and if I check .lengthComputable I get false
Update 2:
Safari sheds more light on the issue:
XMLHttpRequest cannot load Origin is not allowed by Access-Control-Allow-Origin.
I can't be 100% sure, but it seems to me that the issue involved cross-site communication. What I ended up doing was having a PHP script download the file then I used javascript to get it locally.
<?php
$mark = $_GET['mark'];
$xmldoc = new DOMDocument();
$xmldoc -> preserveWhiteSpace = false;
$xmldoc -> formatOutput = true;
$xmldoc -> load($mark);
unlink('fenced.xml');
echo $xmldoc -> save('fenced.xml');
?>
Javascript:
localreq.open('GET', 'fenced.xml', true);
localreq.addEventListener('load', function(e) {xmldoc = localreq.responseXML;}, false);
localreq.send();

Categories