I am uploading a file via ajax request, by simply splitting them in to chunks.
The problem is progress event, Firefox for some reason doesn't want to fire that event, here is my code (most of the unnecessary code is removed)
//slice file
if(file.mozSlice){
chunk = file.mozSlice(startByte, endByte);
}else if(file.slice){
chunk = file.slice(startByte, endByte);
}else{
chunk = file;
isLast = true;
}
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(e){
console.log('progress');
}, false);
xhr.upload.addEventListener('error', function(e){
console.log("upload error!");
});
xhr.onreadystatechange = function(e){
if(this.readyState == 4 && this.status == 200){
//this chunk has bee uploaded, proceed with the next one...
}
}
xhr.open('POST', "", true);
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');//header
xhr.setRequestHeader('Content-Type', 'application/octet-stream');//generic stream header
xhr.send(chunk);
I'm sure i haven't made any big mistakes since chrome works without any problems, so there must be some Firefox related issue.
for Chrome:
xhr.upload.addEventListener('progress', function(e) {
console.log('progress');
}, false);
for Firefox:
xhr.addEventListener('progress', function(e) {
console.log('progress');
}, false);
I checked my implementation I'm adding the progress event after I call xhr.open, maybe that fixes it?
Try the 2nd code sample here: https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress does that work?
Related
I have 2 elements on a page
an input type="file" and a button
when the button is clicked, I want to check if the file selected on the input element still exists or not. Let's just say the file gets deleted or renamed after after being selected and before the button was clicked.
Is there a way to do this? Even just a simple alert code whether it exists or not would be helpful.. thank you
You can use the URL.createObjectURL method which will create a direct pointer to your file on the disk.
Then to check whether it has been deleted/renamed or not, you can simply try to fetch it (either through the fetch API, or through XHR).
let url;
inp.onchange = e => {
url = URL.createObjectURL(inp.files[0]);
btn.disabled = false;
}
btn.onclick = e => {
fetch(url)
.then((r) => console.log("File still exists"))
.catch(e => console.log("File has been removed or renamed"));
}
<input type="file" id="inp">
<button disabled id="btn">check if deleted</button>
ES5 version : (with a lot of quirks to handle... only tested in FF Safari and chrome)
var url;
inp.onchange = function(e) {
url = URL.createObjectURL(inp.files[0]);
btn.disabled = false;
}
btn.onclick = function(e) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url); // cache trick for Safari
xhr.responseType = 'blob';
var headers = { // Safari uses the cache...
"Pragma": "no-cache",
"Cache-Control": "no-store, no-cache, must-revalidate, post-check=0, pre-check=0",
"Expires": 0,
"Last-Modified": new Date(0), // January 1, 1970
"If-Modified-Since": new Date(0)
};
for (var k in headers) {
xhr.setRequestHeader(k, headers[k]);
}
xhr.onload = function(e) {
if (xhr.response.size) {
console.log("File still exists\n");
} else { // chrome fires the load event
console.log("File has been removed or renamed (load event)\n");
}
};
xhr.onerror = function(e) { // sometimes it fires an error
console.log("File has been removed or renamed (error event)\n");
};
try {
xhr.send();
} catch (e) { // sometimes it throws in FF
console.log("File has been removed or renamed (caught)\n");
}
}
<input type="file" id="inp">
<button disabled id="btn">check if deleted</button>
And fiddles for Safari which doesn't fetch BlobURIs from stacksnippetĀ®'s null-origined iframes :
ES6, ES5
Extending on #Kaiido answer: loading from URL like that will load the entire file. If the file is huge it will take very long time and/or will cause the browser to consume a lot of RAM. Tested on chrome with 8GB file - browser used around 8GB memory when using fetch. When using XHR it seemed not to eat up memory but the request took very long to complete. One possible workaround - check onprogress event of the XHR:
xhr.onprogress = function (e) {
if (e.loaded > 0) {
xhr.abort();
console.log("File still exists");
}
}
For the last hour or so, I've been trying to solve a problem, which came up when I tried to change html of an element from XMLHttpRequest.
xhr.open('GET', url);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onload = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(document.getElementById('notifications-navbar').innerHTML);
document.getElementById('notifications-navbar').innerHTML = xhr.responseText;
console.log(xhr.responseText);
console.log(document.getElementById('notifications-navbar').innerHTML);
} else {
console.log('error');
}
};
xhr.send();
The output of the console logs were:
pastebin
So in the console.log we can see the change to the innerHTML was made, however there is no change whatsoever when I have a look on the elements via Chrome inspect and also there is no change in the browser. I even tried to remove every other JS scripts that were being loaded and just make a simple change of the innerHTML outside of XHLHttpRequest, but that didn't help too. Please if you could help I would be really happy.
Not sure what your EndPoint URL is , but I wrote this for you and it works just fine. Hope this can help you!
HTML
<div id = "notifications-navbar"></div>
Javascript
var xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://jsonplaceholder.typicode.com/posts";
xhr.open('GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onload = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(document.getElementById('notifications-navbar').innerHTML);
document.getElementById('notifications-navbar').innerHTML = xhr.responseText;
console.log(xhr.responseText);
console.log(document.getElementById('notifications-navbar').innerHTML);
} else {
console.log('error');
}
};
xhr.send();
Okay, sorry guys, I found my mistake, I had in my HTML two elements with ID notifications-navbar and only the first one was being changed. Thanks for your help anyway.
Below is the snippet of my code that I am using. Actually video that I am loading is of about 1GB, so incase user has medium internet connection, the ajax times out the request, before the video gets fully loaded.
Hence I want to reset ajax time out period to 1 day, so that it doesn't gets timed out.
$(window).load(function(){
console.log("Downloading video...hellip;Please wait...");
var xhr = new XMLHttpRequest();
xhr.open('GET', 'video/video.m4v', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
console.log("got it");
var myBlob = this.response;
var vid = (window.webkitURL ? webkitURL : URL).createObjectURL(myBlob);
// myBlob is now the blob that the objec8t URL pointed to.
var video = document.getElementById("video");
console.log("Loading video into element");
video.src = vid;
// not needed if autoplay is set for the video element
// video.play()
//alert(1);
windowLoad();
$('body').removeClass('loading');
}
}
xhr.send();
});
Thanks
You can set the XMLHttpRequest.timeout
xhr.timeout = 86400000; // 1 day in milliseconds
xhr.ontimeout = function (e) {
// XMLHttpRequest timed out. Do something here.
};
I'm trying to implement a upload progress bar the HTML5 way, by using the XMLHttpRequest level 2 support for progress events.
In every example you see, the method is to add an event listener to the progress event like so:
req.addEventListener("progress", function(event) {
if (event.lengthComputable) {
var percentComplete = Math.round(event.loaded * 100 / event.total);
console.log(percentComplete);
}
}, false);
Such examples always seem to assume that event.lengthComputable will be true. After all, the browser knows the length of the request it's sending, surely?
No matter what I do, event.lengthComputable is false. I've tested this in Safari 5.1.7 and Firefox 12, both on OSX.
My site is built using Django, and I get the same problem on my dev and production setups.
The full code I'm using to generate the form upload is shown below (using jQuery):
form.submit(function() {
// Compile the data.
var data = form.serializeArray();
data.splice(0, 0, {
name: "file",
value: form.find("#id_file").get(0).files[0]
});
// Create the form data.
var fd = new FormData();
$.each(data, function(_, item) {
fd.append(item.name, item.value);
});
// Submit the data.
var req = new XMLHttpRequest();
req.addEventListener("progress", function(event) {
if (event.lengthComputable) {
var percentComplete = Math.round(event.loaded * 100 / event.total);
console.log(percentComplete);
}
}, false);
req.addEventListener("load", function(event) {
if (req.status == 200) {
var data = $.parseJSON(event.target.responseText);
if (data.success) {
console.log("It worked!")
} else {
console.log("It failed!")
}
} else {
console.log("It went really wrong!")
}
}, false);
req.addEventListener("error", function() {
console.log("It went really really wrong!")
}, false);
req.open("POST", "/my-bar/media/add/");
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send(fd);
// Don't really submit!
return false;
});
I've been tearing my hair out for hours on this. Any help appreciated!
Hey I found the answer from #ComFreek:
I made the same mistake.
The line I wrote was:
xhr.onprogress = uploadProgress;
The correct one should be
xhr.upload.onprogress = uploadProgress;
take a look into this :
https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
xhr.upload.addEventListener('progress',function(e){}) will also work.
I also had problem with sending multiple big files using AJAX (xmlhttprequest).
Found a solution and here is whole script that I use.
All you need is to place next line in your HTML page:
<input type="file" multiple name="file" id="upload_file" onchange="handleFiles(this)">
and use next script:
<script type="text/javacript">
var filesArray;
function sendFile(file)
{
var uri = "<URL TO PHP FILE>";
var xhr = new XMLHttpRequest();
var fd = new FormData();
var self = this;
xhr.upload.onprogress = updateProgress;
xhr.addEventListener("load", transferComplete, false);
xhr.addEventListener("error", transferFailed, false);
xhr.addEventListener("abort", transferCanceled, false);
xhr.open("POST", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText); // handle response.
}
};
fd.append('myFile', file);
// Initiate a multipart/form-data upload
xhr.send(fd);
}
function updateProgress (oEvent)
{
if (oEvent.lengthComputable)
{
var percentComplete = oEvent.loaded / oEvent.total;
console.log(Math.round(percentComplete*100) + "%");
} else {
// Unable to compute progress information since the total size is unknown
console.log("Total size is unknown...");
}
}
function transferComplete(evt)
{
alert("The transfer is complete.");
}
function transferFailed(evt)
{
alert("An error occurred while transferring the file.");
}
function transferCanceled(evt)
{
alert("The transfer has been canceled by the user.");
}
function handleFiles(element)
{
filesArray = element.files;
if (filesArray.length > 0)
{
for (var i=0; i<filesArray.length; i++)
{
sendFile(filesArray[i]);
}
filesArray = '';
}
}
</script>
Your result will be in console
I'm using FormData to ajax a file upload. The upload works, but the problem is that the "error" callback is never invoked. Even when my HTTP response is a 500 internal server error (to test this I tweak server to respond with 500), the "load" callback is invoked.
function upload_image() {
var form = document.getElementById('upload_image_form');
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function(e) {
alert("Success callback");
}, false);
xhr.addEventListener("error", function(e) {
alert("Error callback");
}, false);
xhr.open("POST", "/upload_image");
xhr.send(formData);
}
Any ideas? I'm testing this on Chrome.
This setup should work better for your needs:
var req = new XMLHttpRequest();
req.open('POST', '/upload_image');
req.onreadystatechange = function (aEvt) {
if (req.readyState == 4) {
if(req.status == 200)
alert(req.responseText);
else
alert("Error loading page\n");
}
};
req.send(formData);
In your code error callback is never called because it is only triggered by network-level errors, it ignores HTTP return codes.
The load event is called whenever the server responds with a message. The semantics of the response don't matter; what's important is that the server responded (in this case with a 500 status). If you wish to apply error semantics to the event, you have to process the status yourself.
Expanding on #rich remer's answer, here's how you could access the status yourself:
function upload_image() {
var form = document.getElementById('upload_image_form');
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function(e) {
if(e.currentTarget.status < 400)
alert("Load callback - success!");
else
alert("Load callback - error!");
}, false);
xhr.addEventListener("error", function(e) {
alert("Error callback");
}, false);
xhr.open("POST", "/upload_image");
xhr.send(formData);
}
Please note accessing of the e.currentTarget.status property of the response event (e). Looks like the status is actually available via any of e.{currentTarget,target,srcElement}.status - I'm not sure which one should be used as the best practice, though.
function get(url) {
return new Promise(function(succeed, fail) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.addEventListener("load", function() {
if (req.status < 400)
succeed(req.responseText);
else
fail(new Error("Request failed: " + req.statusText));
});
req.addEventListener("error", function() {
fail(new Error("Network error"));
});
req.send(null);
});
}
code from EJS
by the example code
it is clear that network error has no response, it trigger error event.
response trigger load event
and you have to decide what to do with the response status