Search code examples
javascriptjqueryajaxxmlhttprequestjquery-events

File Upload Progress Event not firing, although file uploads


I've seen a few posts on here with similar issues, but I can't seem to get this solved. Basically, I have an AJAX file uploader that doesn't seem to call the progress event. The other events fire just fine, and the file uploads exactly as I expect it, but the progress event isn't being called. The Javascript is shown below:

$('input[name=avatar_upload]').change(function(e) {
    // Get the Form
    var setupForm = $('#setup-member-form');

    // Get the File Array
    var file = document.getElementById('avatar-upload').files[0];

    // Show the File Upload Progress
    $('#avatar-upload-progress').show();

    // Create a new Form Data Object
    var formData = new FormData();

    // Add the File
    formData.append('avatar', file);

    // Create the AJAX Object
    var ajax = new XMLHttpRequest();

    // Add the Event Listeners
    ajax.addEventListener("loadstart", function(evt) {
         // Do something in here...
         $('#output').append("upload starting...\n");
    }, false);
    ajax.addEventListener("progress", function(evt) {
         var percentLoaded = (evt.loaded / evt.total) * 100;
         $('#output').append(percentLoaded + "% loaded\n");
         $('#avatar-upload-progress .ui-progress-bar-inner').animate({'width' : percentLoaded + '%'}, 400);
    }, false);
    ajax.addEventListener("load", function(evt) {
         // Do something in here when loaded...
         $('#output').append("upload complete!");
    }, false);

    // Open the Form
    ajax.open("POST", $('input[name=upload_handler]').val());
    ajax.send(formData);
});

At first I thought it might just be because the file was too small for the progress event to have a chance to fire, but I've tried it with larger files, and the load event fires, then there is a few seconds pause, then the complete event fires.

If anyone has any ideas, please let me know!


Solution

  • Just tested this, and for uploads you have to use XMLHttpRequest.upload, as attaching the events directly to XMLHttpRequest only fires once when uploading.

    It's also explained in the documentation on MDN

    $('#avatar-upload').on('change', function () {
        var file = document.getElementById('avatar-upload').files[0];
    
        $('#avatar-upload-progress').show();
        var formData = new FormData();
        formData.append('avatar', file);
    
        var ajax = new XMLHttpRequest();
    
        ajax.upload.addEventListener("loadstart", function (evt) {
            $('#output').append("upload starting...\n");
        }, false);
    
        ajax.upload.addEventListener("progress", function (evt) {
            var percentLoaded = (evt.loaded / evt.total) * 100;
            $('#output').append(percentLoaded + "% loaded\n");
            $('#avatar-upload-progress .ui-progress-bar-inner').animate({
                'width': percentLoaded + '%'
            }, 400);
        }, false);
    
        ajax.upload.addEventListener("load", function (evt) {
            $('#output').append("upload complete!");
        }, false);
    
        ajax.open("POST", $('input[name=upload_handler]').val());
        ajax.send(formData);
    });