I'm using the following $.ajax command to upload a file from a PhoneGap application:
function updateProgress( evt ) {
if ( evt.lengthComputable ) {
var percentComplete = evt.loaded / evt.total * 100;
console.log( percentComplete + "%" );
}
}
$.ajax({
url: url,
type: "POST",
data: data,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: successCallback,
error: errorCallback,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.addEventListener( "progress", updateProgress, false);
return xhr;
}
});
The upload works fine. However the progress event only fires one time, once the upload has completed. It does not actually fire during uploading - so upload progress does not actually display. There is just a pause while it is uploading, and then it displays 100%.
Any ideas what I am doing wrong?
The upload progress events are fired on xhr.upload, so attach the listener to that rather than xhr. There are also progress events on the xhr object but this is for the response coming back from the server.
See the MDN article for more details.
xhr.upload.addEventListener('progress', updateProgress, false)
(Thanks to A. Wolff and his comment on the OP.)
Related
I have a button where i'm injecting an ajax request to a distant web service.
the traitment takes effects after checking a condition given from the success of another ajax request (thats why i am usung "ajaxSuccess")
My fonction looks like this :
$('body').on('click', '#btn', function (e) {
$(document).ajaxSuccess(function (event, xhr, settings) {
if (settings.url === window.annonce.route.testService) {
xhr = xhr.responseJSON;
var msg = {},
if (xhr == 1) { //case of traitement to be done
msg["attr1"] = attr1;
msg["attr2"] = attr2;
msg = JSON.stringify(msg);
console.log(msg);
$.ajax({
method: 'POST',
url: servicePostulation,
data: {msg: msg},
dataType: 'json',
success: function (data) {
console.log(data);
$("#btn").addClass("active");
},
error: function (data) {
console.log(data);
}
});
}
}
})
}
I my case , the "console.log(msg)" shows me a multiple sending of data msg , which means a multiple clicking events , and that's exactly the problem i wanna evitate,
i have tried many solutions with the " $('body').on('click') like :
e.stopImmediatePropagation();
e.preventDefault();
stopPropagation()
one()
off()
unbind()
but nothing works , so is there any further solution or explication ??
My suggest is to disable the button when user click and then enable the button when ajax complete.
**onClick:**
$('#btn').prop("disabled", true);
Ajax complete/success:
$('#btn').prop("disabled", false);
I have this ajax post function run when an upload button is clicked, the files get uploaded to the server, the server sees for any errors and if there are erros, it notifies the user with the req.end(); function. The problem is, since then, I've moved to XMLHttpRequest() (to use the onprogress functions that it provides) but I still need to use those success and error functions from ajax. Is there a way to use them somehow with XMLHttpRequest? Thank you!
This is the code I have so far:
var xhrVideo = new XMLHttpRequest();
xhrVideo.open('POST', '/uploadVideo', true);
xhrVideo.upload.onprogress = function(e) {
if (e.lengthComputable) {
$('.videoProgress').html(((e.loaded / e.total) * 100).toFixed(0)+'%');
}
};
var videoForm = new FormData($('.videoUploadForm')[0]);
xhrVideo.send(videoForm);
And the ajax code:
var videoData = new FormData($('.videoUploadForm')[0]);
$.ajax({
url: '/uploadVideo',
type: 'POST',
data: videoData,
cache: false,
contentType: false,
processData: false,
mimeType:"multipart/form-data",
success: function(data){
switch(data){
case '1':
alert('Wrong Video File Extension');
break;
case '2':
alert('Wrong Image File Type');
break;
}
},
error: function(data){
alert('Something went wrong! Please reload this page')
}
});
Use listeners for load and error events.
Example adding a listener for success event.
xhrVideo.addEventListener('load', function(e) {
NOTE: the listeners must be added before the send() function
Also, I advise you to read the entire article about using XMLHttpRequest().
Personally , I like to use jquery ajax instead of pure javascript .. so you can use xhr with ajax and catch the progress and load event as well
xhr (default: ActiveXObject when available (IE), the XMLHttpRequest
otherwise) Type: Function() Callback for creating the XMLHttpRequest
object. Defaults to the ActiveXObject when available (IE), the
XMLHttpRequest otherwise. Override to provide your own implementation
for XMLHttpRequest or enhancements to the factory.
in your code you can use it like this
$.ajax({
xhr: function(){
var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total) * 100;
//Do something with upload progress
$('.videoProgress').html(Math.round(percentComplete)+"% uploaded");
}
}
}, false);
xhr.upload.addEventListener("load", function(evt){
evt.preventDefault();
},false);
return xhr;
},
// reset of your ajax code
Some time ago, I wrote a script that looks something like this:
$("#file-upload-button").click(function(e) {
e.preventDefault();
var data = new FormData();
jQuery.each($('#file-upload')[0].files, function(i, file) {
data.append('file', file);
});
$.ajax({
type: "POST",
url: self.urlroot + '/file/upload',
data: data,
contentType: false,
processData: false,
xhr: function() {
var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete);
//more stuff
}
}, false);
//Download progress
xhr.addEventListener("progress", function(evt){
//something similar to above
}, false);
return xhr;
},
success: function( response ) {
//stuff
},
error: function() {
//stuff
}
});
});
And it worked just fine. Today I tried to reuse the code on another page, and I've determined that evt.loaded is no longer tracking how much has been sent to the server, but is instead tracking how much of the file has been loaded into memory to be sent to the server. So it goes to 100% almost immediately, because the file loads to memory very quickly, while not giving an accurate indication of how much has been sent to the server at all. I tried updating my code to something like the following, to no avail:
$("#file-upload-button").change(function(e) {
e.preventDefault();
$("button").attr("disabled", true).fadeTo("fast", 0.5);
var data = new FormData();
jQuery.each($('#file-upload')[0].files, function(i, file) {
data.append('file', file);
});
var xhr = new XMLHttpRequest;
xhr.upload.onprogress = function (evt) {
var percentComplete = evt.loaded / evt.total;
console.log(percentComplete, evt.loaded, evt.total);
//some stuff
};
xhr.upload.onload = function (e) {
//some stuff
};
xhr.upload.onerror = function (e) {
//some stuff
};
xhr.open("POST", "Owl/");
xhr.send(data);
});
In both instances, it shows evt.loaded to be the same as evt.total almost immediately, and then several seconds later based on the size of the file, the upload actually finishes and the response is processed. Any idea how I can fix this to actually show progress on the upload?
I have the following example which uses the progress events in XHR2 to display a progress bar to the user when performing an AJAX request:
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', function(evt){
if (evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total) * 100;
if(percentComplete >= 100){
$('#loading-bar').find('.bar').css({'width': percentComplete + '%'});
$('#loading-bar')
.find('.bar')
.on('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', function() {
$('#loading-bar').fadeOut(function(){
$('#loading-bar').find('.bar').css({'width': ''});
});
});
} else {
$('#loading-bar').find('.bar').css({'width': percentComplete + '%'});
}
}
}, false);
return xhr;
},
type: 'GET',
url: 'Test.html',
success: function (response) {
},
error: function (jqXHR, textStatus, errorThrown) {
}
});
However for browsers that don't support XHR2, the bar won't animate nor will the loading-bar element be faded out from the DOM.
How can I implement a fallback? As I don't want to just fade the loading bar out on success as that will then conflict with the progress events for browsers that DO support it.
Or even better is it possible to get the progress by alternate means?
If it's download progress, we can do it when xhr.readyState >= 3. Just read the xhr.responseText.length, and then divide it by parseInt(xhr.getResponseHeader('Content-Length')) (assuming the server provides this header and it's same origin or with correct CORS header).
If it's upload progress, I don't know any method to polyfill it purely within the client-side. We can create an id for every upload session, and use another xhr to pull the upload receiving progress from the server. However that requires complicated implementation on the server-side. There are many such implementations in common languages, for example for PHP or .NET. You can look into them and implement your own.
Try using .onreadystatechange() with .readyState:
getter.onreadystatechange = function() {
if (loading) { //If the loading element has been loaded...
if (this.status === 200) { //If this.status is already 200...
loading.style.width = this.readyState*25+"%"; //This sets the width of loading according to this.readyState
if (this.readyState === 4) {
//We hide loadingBar and do stuff when we're done.
loadingBar.style.display = "none";
[do stuff]
}
}
}
};
If you're accepting 100 Continue statuses, you might also want to account for that into your loading bar. The way this is now, it's at a standstill for a while, but then zooms to 100% when it gets to the status 200 OK and the readyState property goes from 2 to 4.
Here's the fiddle: http://jsfiddle.net/NobleMushtak/QRuU6/
Look at this code please - how could I kill / update or restart an ajax call (not content that Ajax calls) after the content has already been called?
I mean the $('#posting_main') is called onclick and animated - how to stop ajax and make it another $('#posting_main') on another click?
$(document).ready(function() {
$("#img_x_ok").click(function(e){
e.preventDefault();
var post_text = $.trim($("#main_text_area").val());
var data_text = 'post_text='+ post_text;
if (post_text === "") return;
var xhr = $.ajax({
type: "POST",
url: "comm_main_post.php",
data: data_text,
cache: false,
success: function (data){
//content
$("#posting_main").fadeIn();
$("#posting_main").load("pull_comm.php");
$("#main_text_area").attr("value", "");
$("#posting_main").animate({
marginTop: "+=130px",
}, 1000 );
}
}); //ajax close
}); }); //both functions close
You can abort the current request with:
xhr.abort();
After having done that, you can run another $.ajax(...) to make a second request.
You could implement it like the following. Note that indenting code makes it a lot more readable!
$(document).ready(function() {
var xhr; // by placing it outside the click handler, you don't create
// a new xhr each time. Rather, you can access the previous xhr
// and overwrite it this way
$("#img_x_ok").click(function(e){
e.preventDefault();
var post_text = $.trim($("#main_text_area").val());
var data_text = 'post_text='+ post_text;
if (post_text === "") return;
if(xhr) xhr.abort(); // abort current xhr if there is one
xhr = $.ajax({
type: "POST",
url: "comm_main_post.php",
data: data_text,
cache: false,
success: function (data){
//content
$("#posting_main").fadeIn();
$("#posting_main").load("pull_comm.php");
$("#main_text_area").attr("value", "");
$("#posting_main").animate({
marginTop: "+=130px",
}, 1000 );
}
});
});
});
I am not sure I fully understand your question, however:
xhr.abort() will kill the AJAX request. After calling abort(), you could modify and resend the request, if desired.
$("#posting_main").stop() will stop the fadeIn animation. (And I think you might need to follow that with $("#posting_main").hide() to be sure it isn't left partially visible.)