I want to write a file upload script that works in IE but the two types of code that I'm writing have problems in IE.
Please help. How can you write a file upload script that works in IE?
Type 1
Problem Not Support File Api In IE (Is the trick not to use it?)
<!DOCTYPE html>
<html>
<head runat="server">
<title></title>
<script src="Scripts/jquery-1.6.2.js" type="text/javascript"></script>
<script type="text/javascript">
function updateSize() {
var nBytes = 0;
var nFiles=0;
oFiles = document.getElementById("uploadInput").files;
nFiles = oFiles.length;
for (var nFileId = 0; nFileId < nFiles; nFileId++) {
nBytes += oFiles[nFileId].size;
}
var sOutput = nBytes + " bytes";
// optional code for multiples approximation
for (var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) {
sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
}
document.getElementById("fileNum").innerHTML = nFiles;
document.getElementById("fileSize").innerHTML = sOutput;
}
// end of optional code
</script>
</head>
<body>
<form id="form1" runat="server">
<p><input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple /> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span></p>
<p><input type="submit" value="Send file"></p>
</form>
</body>
</html>
Type 2
Problem Not Support document.getElementById('fileToUpload').files[0](Is the trick not to Get Files[0]?)
<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script type="text/javascript">
function fileSelected() {
var file = document.getElementById('fileToUpload').files[0];
if (file) {
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
}
}
function uploadFile() {
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
$.post("UploadHandler.ashx");
//xhr.open("POST", "UploadHandler.ashx");
xhr.send(fd);
}
function uploadProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = Math.round(evt.loaded * 100 / evt.total);
document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
document.getElementById('prog').value = percentComplete;
}
else {
document.getElementById('progressNumber').innerHTML = 'unable to compute';
}
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText);
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.");
}
</script>
</head>
<body>
<form id="form1">
<div>
<label for="fileToUpload">
Select a File to Upload</label>
<input type="file" name="fileToUpload[]" id="fileToUpload" onchange="fileSelected();" />
</div>
<div id="fileName">
</div>
<div id="fileSize">
</div>
<div id="fileType">
</div>
<div>
<input type="button" onclick="uploadFile()" value="Upload" />
</div>
<div id="progressNumber">
</div>
<progress id="prog" value="0" max="100.0"></progress>
</form>
</body>
Please Help :(
The most popular way to publish files to the web is by using an FTP (file transfer protocol) program. These programs create a link between your computer and the server that hosts your account, allowing you to copy and paste (or click and drag) your website files to your HostPapa hosting space.
File upload is not possible through AJAX. You can upload file, without refreshing page by using IFrame .
You can't use these functions unless you're using IE10 or another modern browser. Workarounds are possible for earlier versions of Internet Explorer (and other browsers), but you'll need to adjust your back-end code too.
Internet Explorer up until version 10 doesn't support a number of these features, the key ones being the FormData and FileReader APIs. Both of your code snippets rely on the FileReader
API, and the second one also relies on FormData
to upload the file dynamically.
I recently wrote a file upload widget that detected these features and served different code depending on support. I used the feature detections from Modernizr, because it's tests are regularly put to the test by the open source community:
var support = {
// Are files exposed to JS?
// As used by Modernizr @
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/file/api.js
'fileReader' : (function testFileReader(){
// Test: look for global file class.
return !!(window.File && window.FileList && window.FileReader);
}()),
// AJAX file upload via formData?
'formData' : window.FormData !== void 0
};
For your fileSelected
function, you'll need support.fileReader
to evaluate true
; for uploadFile
, you need support.formData
.
Without these features it's impossible to read a file from the front-end or to send a file using AJAX. What you can do, though, is send your file via a hidden <iframe/>
inside your current page, and get UploadHandler.ashx
to respond differently to non-XHR requests.
This solution is technically synchronous (just happening in another, hidden page), so you won't get updates — the only feedback is when the upload is complete and the server has responded. So you will only be able to inform the user as to file name, size, and success once they have completely uploaded it — which might take a while!
Anyway, the HTML for this would look as follows:
<form
id="form1"
runat="server"
action="UploadHandler.ashx"
target="fileIframe">
<iframe
name="fileIframe"
style="display:none"
onload="parseIframeResponse"
tabindex="-1">
</iframe>
<p>
<input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple />
selected files:
<span id="fileNum">
0
</span>
; total size:
<span id="fileSize">
0
</span>
</p>
<p>
<input type="submit" value="Send file">
</p>
</form>
A few changes:
target
, which means that when it posts its content to the URI in action
, it will load the response in there, as opposed to on the current page.name
reference to an iframe we've included. It is hidden with display:none
, and given a negative tabindex
just to make sure the user doesn't stumble into it. It also has an onload
property specified. This is the only way of binding functions to the load event in older versions of IE.So when the form is submitted, we stay on the current page and the server response loads in our hidden iframe. When that happens, the browser will execute the function named in the onload
attribute. Sadly, this means that function needs to be in the global scope!
I don't know how your back-end works, but if the iframe is to load the response instead of downloading it, it will need to be HTML or plain text (and that will need to be specified in the mime-type). You can tell whether the form was posted via AJAX from the back-end by looking for the X-Requested-With
header, which should have a value of XMLHttpRequest
— if that isn't there, then the iframe is asking for the response and you need to send text or HTML. You may want to stringify a JSON response that exposes the values you wanted to feed back to the user like fileName
, fileSize
& fileType
. I'm hoping you can do this yourself or get a colleague to handle it.
As mentioned, the response handler function will need to be in the global scope for the onload
attribute to bind to, because of old IE being very quirky. I see you're using jQuery, so if you went down the route of stringifying the server response, you could write this function as follows:
function parseIframeResponse(){
var response = $('#fileIframe').contents().find('body').text();
var object = $.parseJSON(response);
}
Issues with the iframe
load
event bindingAs mentioned earlier, the iframe load event needs to be bound inline as an attribute of the iframe itself — this is because IE will simply fail to register it otherwise. But this is problematic in and of itself because even an empty iframe (an empty or non-present
src
will default toabout:blank
) fires a load event. To mitigate this you will need to discard anyresponse
that evaluates to an empty string as a false positive, and make sure your back-end responds with some content even if it encounters a fault.
Presumably, you would then want to use whatever information is in there to execute some of the code you've currently got in the functions fileSelected
, uploadProgress
, etc.
Hope this helps.
In hindsight, despite writing this off the back of having developed my own solution to the problem, it could be considered negligent not to mention Fine Uploader, a heavily tested (over 700 closed issues!) and well maintained stand-alone plugin that aims to achieve the best file upload experience possible for IE7 and up. There's also a good selection of back-end server components — including ASP.NET — to parse the upload. You might find it easier to tweak this than roll your own!
load
event. Amended answer in place.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With