0

I'm working with HTML5 multiple file uploader. For some purpose I'm queuing the requests into a JavaScript array and I'm trying with two approaches here, one is, sending all the requests by a loop using a for loop and the next approach is like starting the next request after the previous request got finished. Here is the code,

    function processUploads(i)
{
    if(typeof(i)=="undefined")
        return;

    if(i==0)
    {
        for(i=0;i<4;i++)
        {
            xhrQ[i].open("POST",FUurl,true);
            xhrQ[i].send(fdQ[i]);
            xhrQ[i].onreadystatechange = function() {
                if (xhrQ[i].readyState == 4 && xhrQ[i].status == 200) {                
                    uploadComplete(xhrQ[i],i);
                }
            }
        }
    }
    else
    {
        xhrQ[i].open("POST",FUurl,true);
        xhrQ[i].send(fdQ[i]);
        xhrQ[i].onreadystatechange = function() {
            if (xhrQ[i].readyState == 4 && xhrQ[i].status == 200) {                
                uploadComplete(xhrQ[i],i);
            }
        }
    }
}

function uploadComplete(xhr,i)
{
    //processUploads(i+1);
    var responseJSON = eval('(' + xhr.responseText + ')');
    var upldrID = responseJSON.data.queueId;

    var fileProgElem = $("#file_content").find("div[file-count="+upldrID+"]");
    fileProgElem.attr("upload","finished");
    fileProgElem.find("input[id=asset_id]").val(responseJSON.data.asset_id);

    if(typeof(responseJSON)=="undefined") {
        return;
    }

    $("#bar"+upldrID).css("width: 100%");
    $("#progress_text"+upldrID).addClass("hide");
    $("#progress_bar"+upldrID).html("Upload Complete!");

    var pagename = $("#pagename").attr('value');

    var cover_art = "<img src='"+responseJSON.data.thumb_location+"' alt='"+$.trim($("#file_name"+upldrID).html())+"' />";
    $("#cover_art"+upldrID).html(cover_art);

    //Hide the cross icon and enable the save 
    var action_divs = '<div id="done'+upldrID+'" class="hide enable">'
            +'<a id="delete_file_'+upldrID+'" onclick="saveWorkspaceFileDetails(\''+responseJSON.data.project_id+'\',\''+responseJSON.data.asset_id+'\',\''+upldrID+'\',\''+responseJSON.data.file_name+'\',\''+responseJSON.data.size+'\',\'delete\',\''+pagename+'\')">'
            +'<i class="tl-icon-20-close-gray"></i>'
            +'</a>'
            +'</div>';

    $("#cancel_upload"+upldrID).append(action_divs);

    $("#progress_cancel"+upldrID).addClass("hide").removeClass("show");
    $("#done"+upldrID).addClass("show").removeClass("hide");        

    //To show the post and cancel button
    $("#submitFileUpload").removeClass("hide").addClass("show");

    //Updating the title with the default value of file_name
    var file_title =  $.trim($("#file[file-count='"+upldrID+"']").find("#file_title").val());
    if (file_title == "" && file_title != undefined){
        $("#file[file-count='"+upldrID+"']").find("#file_title").val(responseJSON.data.file_name);
    }

    //For other category we need to enable the dropdown     
    if(responseJSON.data.category_id=='999')
    {
        $("#select_category"+upldrID).removeClass("hide").addClass("show");
    }

            //totSelFiles is a number of selected files that i sets as a global variable
    if(i<(totSelFiles-1))
    {
        processUploads(i+1);
    }
    else
        return;
}

But the problem is i'm getting the readyState and status as 0 in the if loop. But the file is getting uploaded to the server and the else condition is also working well if i only enable that block. So what could be the problem. I'm greatly confused. Any help would be greatly appreciate.

Stranger
  • 10,332
  • 18
  • 78
  • 115

1 Answers1

1

The problem is related to the closure you create with the anonymous function you use for onreadystatechange. It will have access to the value of i, but not from the time of creation of the closure but rather from the time of its execution. At that point of time i is always 4 and xhrQ[i] will not refer to the correct object. Use this instead

xhrQ[i].onreadystatechange = function() {
   if(this.readyState == 4 && this.status == 200) {

   }
}

The problem is that you want to continue with the index i inside the uploadComplete() function. For this you might need to create another inner closure with an immediately executing function that will create a local copy of the current index.

xhrQ[i].onreadystatechange = (function(_innerI) {
   var that = this;
   return function() {
      if(that.readyState == 4 && that.status == 200) {
         uploadComplete(that, _innerI);
      }
   }
})(i);
devnull69
  • 16,402
  • 8
  • 50
  • 61