jQuery File Upload with custom Progress event and Ajax GC - javascript

I've built into an app a File Upload with Progress bar using jQuery.ajax .
But I'm concerned that I don't understand how garbage collection will handle it and therefore how memory efficient it will be.
For the progress bar, I had to add a custom xhr in order to add a "progress" event.
When will that custom xhr function and 'progress' event handler be cleaned up?
myApp.prototype.uploadFile = function () {
$.ajax({
type : "POST",
url : posturl,
xhr : function () { // custom xhr
var myXhr = $.ajaxSettings.xhr();
this.onSaveProgress(myXhr, file);
return myXhr;
}.bind(this),
contentType: false,
processData: false,
data : postdata,
beforeSend : this.onBeforeSend,
success : this.onSaveSuccess,
error : this.onSaveError
});
},
myApp.prototype.onSaveProgress = function (xhr, file) {
if (!xhr.upload)
return;
xhr.upload.addEventListener("progress", function (e) {
if (e.lengthComputable) {
var percent = Math.floor((e.loaded / e.total)*100) + "%";
$("#progress" + file.id).css("width", percent).text(percent);
}
}, false); // add new progress event handler
}
As you can see, I needed access to the file Object in the 'progress' event handler so I can update the correct progress bar.

Related

JS measuring the ajax completion time

I have a simple ajax request for js and php (fetching data from mysql)
function ajax_function(a,b) {
$.ajax({
type : 'POST',
url : mine.ajax_url,
dataType : 'json',
data : {
action : a,
},
success : b
});
};
How would I detect the time that it takes from the initial request to the completion? (I am trying to show progress bar).
Thanks!
If you want progress status:
xhr: function () {
var xhr = $.ajaxSettings.xhr(); // call the original function
xhr.addEventListener('progress', function (e) {
if (e.lengthComputable) {
var percentComplete = e.loaded / e.total;
// Do something with download progress
}
}, false);
return xhr;
}

Close fancybox at the end of file upload progress

I have a script to show a progress bar for when a user is uploading images. This upload form is within an open fancybox that I want to have closed once the images are finished uploading.
If I use a onclick event for when the user clicks the submit button to close the fancybox, it will not complete the image upload process.
Here is what I have for the progress bar. I'm wondering if there is a way to close fancybox once the progress bar gives the done message?
<script>
$(document).on('submit', 'form[profile-picture-data-remote]', function(e) {
e.preventDefault();
var fd = new FormData(this);
$.ajax({
url: $(this).attr('action'),
xhr: function() {
var xhr = new XMLHttpRequest();
var total = 0;
$.each(document.getElementById('profile-image-upload').files, function(i, file) {
total += file.size;
});
xhr.upload.addEventListener("progress", function(evt) {
var loaded = (evt.loaded / total).toFixed(2)*100;
$('#progress-container').css({
'display': 'block'
});
$('#progress').text('Uploading... ' + loaded + '%');
$('#progress').css({
'width': loaded+'%'
});
}, false);
return xhr;
},
type: 'post',
processData: false,
contentType: false,
data: fd,
success: function(data) {
var div = $('<div id="progress" class="uk-progress-bar" style="width: 100%;">Done!</div>')
$('#progress').replaceWith(div);
// ** IS THERE SOMETHING I CAN DO HERE TO CLOSE FANCYBOX NOW THAT THE IMAGE UPLOAD IS COMPLETE? **
}
});
});
</script>
The command to close fancybox is $.fancybox.close()
If the progress bar is in an IFrame within the fancybox, you'll need to use parent.$.fancybox.close()
Replacing your comment in the success method with the appropriate command should work.

Jquery ajax equivalent Titanium

This is an example of how I currently make an api call using titanium:
var url = "http://www.appcelerator.com";
var client = Ti.Network.createHTTPClient({
// function called when the response data is available
onload : function(e) {
Ti.API.info("Received text: " + this.responseText);
alert('success');
},
// function called when an error occurs, including a timeout
onerror : function(e) {
Ti.API.debug(e.error);
alert('error');
},
timeout : 5000 // in milliseconds
});
// Prepare the connection.
client.open("GET", url);
// Send the request.
client.send();
The trouble is by doing it this way, I am only able to access the object in the onload call back function.
I can't for example do this:
//snippet
var someObject;
onerror : function(e) {
someObject = this.responseText;
},
//end
function useObject(someObject){
alert(someObject);
}
Using jquery AJAX I would be able to do this, like this:
$.ajax({
type: "POST",
url: 'someurl',
data: param = "",
contentType: "application/json; charset=utf-8",
success: self.useObject,
error: errorFunc
});
Once the response is received, pass it to the success object.
How can I do the equilent in Titanium, given that it does not use Jquery.
I don't fully understand what you are trying to achieve ,but try something like:
var onLoad = function(e) {
console.log(this.responseText);
};
var client = Ti.Network.createHTTPClient({
onload: onLoad
});

Upload Image Using AJAX with Progress Indicator

I am trying to upload an image using AJAX. I have the local URL of my image
and I want to pass that image as a file to the web service to upload.
Suppose i have the local file URL as : file:///accounts/1000/shared/camera/IMG_00000322.jpg
Now using AJAX I want to pass this to webservice,
What will be the best way to do this? I also want show the progress while uploading
Using php in server side.
uploadImage : function(myImageUrl,chatId){
var formData = new FormData();
formData.append("chatId", chatId);
formData.append("fileimage", myImageUrl);
$.ajax(
{
type:"POST",
url:"http://suresh.sp.in/butler/public/uploadimage/getimage",
contentType:"image/png",
dataType:"json",
data:formData,
success:function(uploaded){
console.info(uploaded.status);
},
error:function(error){
console.info(error);
}
});
}
I used that snippet on several of my websites, it handles Multiples files upload, drag and drop, and a progress bar.
HTML
You will need a container to drop your batch of files, in our case it will be #output, and a list of files.
JS
First we will push the dataTransfer to jQuery's event and bind the drop event.
$(document).ready(function(){
// We add the dataTransfer special property to our jQuery event
$.event.props.push("dataTransfer");
// We bind events for drag and drop
$('#output').bind({
"dragenter dragexit dragover" : do_nothing,
drop : drop
});
});
// stop event propagation
function do_nothing(evt){
evt.stopPropagation();
evt.preventDefault();
}
Then we build our update progress function
// Progress bar update function
function update_progress(evt,fic) {
var id_tmp=fic.size;
//id_tmp help us keep track of which file is uploaded
//right now it uses the filesize as an ID: script will break if 2 files have the
// same size
if (evt.lengthComputable) {
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
if (percentLoaded <= 100) {
$('#'+id_tmp+' .percent').css('width', percentLoaded + '%');
$('#'+id_tmp+' .percent').html(percentLoaded + '%');
}
}
}
Last but not least our drop function
function drop(evt){
do_nothing(evt);
var files = evt.dataTransfer.files;
// Checking if there are files
if(files.length>0){
for(var i in files){
// if its really a file
if(files[i].size!=undefined) {
var fic=files[i];
// We add a progress listener
xhr = jQuery.ajaxSettings.xhr();
if(xhr.upload){
xhr.upload.addEventListener('progress', function (e) {
update_progress(e,fic);
},false);
}
provider=function(){ return xhr; };
// We build our FormData object
var fd=new FormData;
fd.append('fic',fic);
// For each file we build and Ajax request
$.ajax({
url:'/path/to/save_fic.php',
type: 'POST',
data: fd,
xhr:provider,
processData:false,
contentType:false,
complete:function(data){
//on complete we set the progress to 100%
$('#'+data.responseText+' .percent').css('width', '100%');
$('#'+data.responseText+' .percent').html('100%');
}
});
// for each file we setup a progress bar
var id_tmp=fic.size;
$('#output').after('<div class="progress_bar loading" id="'+id_tmp+'"><div class="percent">0%</div></div>');
$('#output').addClass('output_on');
// We add our file to the list
$('#output-listing').append('<li>'+files[i].name+'</li>');
}
}
}
}
That method doesn't work in IE9 or below.
Hope it helped!
Source(in french)
Some infos on progress tracking using XMLHttpRequest
Some infos on the datatransfer prop
EDIT:
PHP
From the server side you can handle the files normally using $_FILES etc...
In order to set the progress to 100% in the complete function your php script must echo the filesize.

What is the cleanest way to get the progress of JQuery ajax request?

In plain javascript is very simple: need just to attach the callback to {XMLHTTPRequest}.onprogress
var xhr = new XMLHttpRequest();
xhr.onprogress = function(e){
if (e.lengthComputable)
var percent = (e.loaded / e.total) * 100;
};
xhr.open('GET', 'http://www...', true);
xhr.onreadystatechange = function() {
...
};
xhr.send(null);
but I'm doing an ajax site that download html data with JQuery ($.get() or $.ajax()) and I was wondering which is the best way to get the progress of a request in order to display it with a little progress bar but curiously, I'm not finding anything usefull in JQuery documentation...
Something like this for $.ajax (HTML5 only though):
$.ajax({
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with upload progress here
}
}, false);
xhr.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
}
}, false);
return xhr;
},
type: 'POST',
url: "/",
data: {},
success: function(data){
//Do something on success
}
});
jQuery has already implemented promises, so it's better to use this technology and not move events logic to options parameter. I made a jQuery plugin that adds progress promise and now it's easy to use just as other promises:
$.ajax(url)
.progress(function(){
/* do some actions */
})
.progressUpload(function(){
/* do something on uploading */
});
Check it out at github
I tried about three different ways of intercepting the construction of the Ajax object:
My first attempt used xhrFields, but that only allows for one listener, only attaches to download (not upload) progress, and requires what seems like unnecessary copy-and-paste.
My second attempt attached a progress function to the returned promise, but I had to maintain my own array of handlers. I could not find a good object to attach the handlers because one place I'd access to the XHR and another I'd have access to the jQuery XHR, but I never had access to the deferred object (only its promise).
My third attempt gave me direct access to the XHR for attaching handlers, but again required to much copy-and-paste code.
I wrapped up my third attempt and replaced jQuery's ajax with my own. The only potential shortcoming is you can no longer use your own xhr() setting. You can allow for that by checking to see whether options.xhr is a function.
I actually call my promise.progress function xhrProgress so I can easily find it later. You might want to name it something else to separate your upload and download listeners. I hope this helps someone even if the original poster already got what he needed.
(function extend_jQuery_ajax_with_progress( window, jQuery, undefined )
{
var $originalAjax = jQuery.ajax;
jQuery.ajax = function( url, options )
{
if( typeof( url ) === 'object' )
{options = url;url = undefined;}
options = options || {};
// Instantiate our own.
var xmlHttpReq = $.ajaxSettings.xhr();
// Make it use our own.
options.xhr = function()
{return( xmlHttpReq );};
var $newDeferred = $.Deferred();
var $oldPromise = $originalAjax( url, options )
.done( function done_wrapper( response, text_status, jqXHR )
{return( $newDeferred.resolveWith( this, arguments ));})
.fail( function fail_wrapper( jqXHR, text_status, error )
{return( $newDeferred.rejectWith( this, arguments ));})
.progress( function progress_wrapper()
{
window.console.warn( "Whoa, jQuery started actually using deferred progress to report Ajax progress!" );
return( $newDeferred.notifyWith( this, arguments ));
});
var $newPromise = $newDeferred.promise();
// Extend our own.
$newPromise.progress = function( handler )
{
xmlHttpReq.addEventListener( 'progress', function download_progress( evt )
{
//window.console.debug( "download_progress", evt );
handler.apply( this, [evt]);
}, false );
xmlHttpReq.upload.addEventListener( 'progress', function upload_progress( evt )
{
//window.console.debug( "upload_progress", evt );
handler.apply( this, [evt]);
}, false );
return( this );
};
return( $newPromise );
};
})( window, jQuery );
jQuery has an AjaxSetup() function that allows you to register global ajax handlers such as beforeSend and complete for all ajax calls as well as allow you to access the xhr object to do the progress that you are looking for
http://www.htmlgoodies.com/beyond/php/show-progress-report-for-long-running-php-scripts.html
I was searching for a similar solution and found this one use full.
var es;
function startTask() {
es = new EventSource('yourphpfile.php');
//a message is received
es.addEventListener('message', function(e) {
var result = JSON.parse( e.data );
console.log(result.message);
if(e.lastEventId == 'CLOSE') {
console.log('closed');
es.close();
var pBar = document.getElementById('progressor');
pBar.value = pBar.max; //max out the progress bar
}
else {
console.log(response); //your progress bar action
}
});
es.addEventListener('error', function(e) {
console.log('error');
es.close();
});
}
and your server outputs
header('Content-Type: text/event-stream');
// recommended to prevent caching of event data.
header('Cache-Control: no-cache');
function send_message($id, $message, $progress) {
$d = array('message' => $message , 'progress' => $progress); //prepare json
echo "id: $id" . PHP_EOL;
echo "data: " . json_encode($d) . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
//LONG RUNNING TASK
for($i = 1; $i <= 10; $i++) {
send_message($i, 'on iteration ' . $i . ' of 10' , $i*10);
sleep(1);
}
send_message('CLOSE', 'Process complete');
Follow the steps to display Progress of Ajax Request:
Create a Spinner using Html & CSS or use Bootstrap Spinner.
Display the Spinner when the end-user is requesting for the AJAX Data for infinite loop or for threshold limit time.
So, after a SUCCESS / ERROR result of AJAX Request, remove the Spinner which is currently displayed and show your results.
To make it easy I recommend you using JS Classes for dynamically Displaying & Hiding the spinner for this purpose.
I Hope this helps!

Categories

Resources