Can onprogress functionality be added to jQuery.ajax() by using xhrFields?

dcorsello picture dcorsello · Mar 27, 2013 · Viewed 45.6k times · Source

As suggested here: https://gist.github.com/HenrikJoreteg/2502497, I'm trying to add onprogress functionality to my jQuery.ajax() file upload. The upload works fine, and the onprogress event is firing, but not as I expected--instead of firing repeatedly at some time interval, it's firing only once, when the upload has completed. Is there a way to specify the frequency of onprogress refreshes? Or, am I trying to do something that can't be done? Here's my code:

$.ajax(
{
    async: true,
    contentType: file.type,
    data: file,
    dataType: 'xml',
    processData: false,
    success: function(xml)
    {
        // Do stuff with the returned xml
    },
    type: 'post',
    url: '/fileuploader/' + file.name,
    xhrFields:
    {
        onprogress: function(progress)
        {
            var percentage = Math.floor((progress.total / progress.totalSize) * 100);
            console.log('progress', percentage);
            if (percentage === 100)
            {
                console.log('DONE!');
            }
        }
    }
});

Answer

GetFree picture GetFree · Jan 8, 2014

Short answer:
No, you can't do what you want using xhrFields.

Long answer:

There are two progress events in a XmlHttpRequest object:

  • The response progress (XmlHttpRequest.onprogress)
    This is when the browser is downloading the data from the server.

  • The request progress (XmlHttpRequest.upload.onprogress)
    This is when the browser is sending the data to the server (including POST parameters, cookies, and files)

In your code you are using the response progress event, but what you need is the request progress event. This is how you do it:

$.ajax({
    async: true,
    contentType: file.type,
    data: file,
    dataType: 'xml',
    processData: false,
    success: function(xml){
        // Do stuff with the returned xml
    },
    type: 'post',
    url: '/fileuploader/' + file.name,
    xhr: function(){
        // get the native XmlHttpRequest object
        var xhr = $.ajaxSettings.xhr() ;
        // set the onprogress event handler
        xhr.upload.onprogress = function(evt){ console.log('progress', evt.loaded/evt.total*100) } ;
        // set the onload event handler
        xhr.upload.onload = function(){ console.log('DONE!') } ;
        // return the customized object
        return xhr ;
    }
});

The xhr option parameter must be a function that returns a native XmlHttpRequest object for jQuery to use.