3

Below is the code I am using which basically passes multiple files to be uploaded. In the loop each file is resized client side and then uploaded.

I want to execute an ajax call after the loop is finished uploading the photos. The ajax call basically reloads a specific div and refreshes the photos.

How do I prevent the ajax call from executing until the loop has finished.

if (window.File && window.FileReader && window.FileList && window.Blob)
    {       
        var files = document.getElementById('filesToUpload').files;    
        for(var i = 0; i < files.length; i++) 
        {
            resizeAndUpload(files[i]);


        }

        // when loop finished, execute ajax call
            $.ajax
            ({
                type: "POST",
                url: "photos.php",
                data: dataString,
                success: function(html)
                {
                    $("#photo-body").html(html);
                }       
            });
        }       
    }

function resizeAndUpload(file)
{
    var reader = new FileReader();
    reader.onloadend = function() 
    {
        var tempImg = new Image();
        tempImg.src = reader.result;
        tempImg.onload = function()
        {
            var MAX_WIDTH = 382.25;
            var MAX_HEIGHT = 258.5;
            var tempW = tempImg.width;
            var tempH = tempImg.height;

            if (tempW > tempH) 
            {
                if (tempW > MAX_WIDTH)
                {
                    tempH *= MAX_WIDTH / tempW;
                    tempW = MAX_WIDTH;
                }
            } 
            else
            {
                if (tempH > MAX_HEIGHT)
                {
                    tempW *= MAX_HEIGHT / tempH;
                    tempH = MAX_HEIGHT;
                }
            }

            var canvas = document.createElement('canvas');
            canvas.width = tempW;
            canvas.height = tempH;
            var ctx = canvas.getContext("2d");
            ctx.drawImage(this, 0, 0, tempW, tempH);
            var dataURL = canvas.toDataURL("image/jpeg");

            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(ev)
            {
                document.getElementById('filesInfo').innerHTML = 'Upload Complete';

            };
            xhr.open('POST', 'upload-resized-photos.php', true);
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            var data = 'image=' + dataURL;
            xhr.send(data); 


        }
    }
    reader.readAsDataURL(file);
}

var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"];    
function Validate(oForm)
{
    var arrInputs = oForm.getElementsByTagName("input");
    for (var i = 0; i < arrInputs.length; i++) 
    {
        var oInput = arrInputs[i];
        if (oInput.type == "file")
        {
            var sFileName = oInput.value;
            if (sFileName.length > 0)
            {
                var blnValid = false;
                for (var j = 0; j < _validFileExtensions.length; j++) 
                {
                    var sCurExtension = _validFileExtensions[j];
                    if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) 
                    {
                        blnValid = true;
                        break;
                    }
                }

                if (!blnValid) 
                {
                    alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
                    return false;
                }   
            }
        }
    }
    return true;
}

3 Answers3

1

You can wrap the $ajax call in a function, and call the function at the end of the final loop.

(just the top part of your script)

if (window.File && window.FileReader && window.FileList && window.Blob) {       

    function loopFinished(){
        $.ajax
        ({
            type: "POST",
            url: "photos.php",
            data: dataString,
            success: function(html)
            {
                $("#photo-body").html(html);
            }       
        });
    }

    var files = document.getElementById('filesToUpload').files;    
    for(var i = 0; i < files.length; i++) 
    {
        resizeAndUpload(files[i]);
        if (files.length+1 == [i]){
            loopFinished();
        }
    }
} 
Bradley4
  • 510
  • 1
  • 6
  • 13
1

You can use any promise library to do this. Here is example of using jQuery promise

     (function ($) {
        var files = [1, 2, 3, 4],
            allPromises = [];
        for (var i = 0; i < files.length; i++) {
            var promise = resizeAndUpload(files[i]);
            allPromises.push(promise);

        }

        $.when.apply($, allPromises).done(function () {
            makeAjaxCall();
        });

        function makeAjaxCall() {
            console.log('Put Ajax call here');
        }

        function resizeAndUpload(file) {
            var defer = $.Deferred();
//Set timeout simulates your long running process of processing file
            setTimeout(function () {
                console.log('processing file ' + file);
                defer.resolve();

            }, 2000);
            return defer.promise();
        }
    })(jQuery);

Here is a jSFiddle http://jsfiddle.net/x6oh471f/2/

0

One or more of the methods in your resizeAndUpload() function must be happening asynchronously. Which means they'll do their thing in the background while the rest of your javascript is run and they should fire an event when they are complete. You will want to call the ajax method once the last one of these methods has complete and event fired. For example, the fileReader methods are asychronous. Which means you will probably need to do something like:

FileReader.onloadend = function(){
   totalFilesLoaded = totalFilesLoaded + 1;
   if (totalFilesLoaded == files.length){
      //all files have been uploaded, run $ajax
   }
}

EDIT: now you have uploaded the rest of your code, try something like this:

window.totalFilesLoaded = 0;
var files = document.getElementById('filesToUpload').files;
window.totalFilesToLoad = files;

if (window.File && window.FileReader && window.FileList && window.Blob)
    {       

        for(var i = 0; i < files.length; i++) 
        {
            resizeAndUpload(files[i]);
        }

    }

Separate ajax function:

window.runAjax = function(){
           $.ajax
            ({
                type: "POST",
                url: "photos.php",
                data: dataString,
                success: function(html)
                {
                    $("#photo-body").html(html);
                }       
            });
}

function resizeAndUpload(file)
{
    var reader = new FileReader();
    reader.onloadend = function() 
    {

    ...

            xhr.onreadystatechange = function(ev)
            {
                document.getElementById('filesInfo').innerHTML = 'Upload Complete';


                window.totalFilesLoaded++;
                if (window.totalFilesLoaded == window.totalFilesToLoad.length){
                    window.runAjax()
                }


            };

    ...

    }
    reader.readAsDataURL(file);
}
Clearnoi
  • 3
  • 2
  • Where would i add that code. I tried adding it after the for loop. The files upload but the ajax does get called. I am setting totalFilesLoaded = 0 before entering loop aswell. – Carl Faulkner Jun 26 '15 at 23:05
  • runAjax is never executed. If i add an alert(files.length), I get undefined. – Carl Faulkner Jun 26 '15 at 23:48
  • Apologies, files also needs to be global, put the `var files = document.getElementById('filesToUpload').files;` declaration at the top, outside the if statement with totalFilesLoaded - I have edited my response again - sorry I don't have time to test it myself – Clearnoi Jun 26 '15 at 23:54
  • something weird is happening. I have everything as above. If i put an alert(totalFilesLoaded) underneath totalFilesLoaded nothing is alerted. Also for some reason runAjax is never called. Im lost. – Carl Faulkner Jun 27 '15 at 00:01
  • That is odd, you mean you alert it straight underneatheath `var totalFilesLoaded = 0;` ? And no alert box is appearing at all? You may want to put this on [jsfiddle](http://jsfiddle.net/) or similar. – Clearnoi Jun 27 '15 at 00:12
  • I was doing an alert after the totalFilesLoaded = totalFilesLoaded + 1 to see what was hapening but nothing is happening. The file does upload but the ajax doesnt get called. Which means the div never refreshes automatically. – Carl Faulkner Jun 27 '15 at 00:20
  • .. also are you familar with the [console](https://developer.chrome.com/devtools/docs/console)? It will flag if any uncaught errors are thrown in your js – Clearnoi Jun 27 '15 at 00:21
  • hmm! ok I have made the relevent vars a property of the window object to ensure they are global. Try copying the changes I've made at the top and inside the xhr.onreadystatechange function. I must go for now but I hope you get to the bottom of it! – Clearnoi Jun 27 '15 at 00:34
  • .. oh and would need to be the same for the ajax function actually so now its window.runAjax – Clearnoi Jun 27 '15 at 00:45
  • Just checked with debugger in console and was getting an error in validating the file type. I remove it and it's now working. 1 slight issue is that sometimes the last photo doesn't show. It's still uploaded though. – Carl Faulkner Jun 27 '15 at 00:52
  • Thanks for all the help. I managed to get that working. It works well until I tried to upload a photo using the ipad. Works on my Samsung mobile as you can only upload 1 photo at a time on samsung devices. Works well on the laptop as well, but the ipad doesnt upload. Do you know any reason why this would happen. Is it something to so with the client side javascript resizing etc. – Carl Faulkner Jun 28 '15 at 22:22
  • It may be because IOS doesn't fully support the window.file methods? http://caniuse.com/#feat=fileapi – Clearnoi Jun 29 '15 at 08:25
  • Do you know of a way round this at all – Carl Faulkner Jun 29 '15 at 11:07
  • Not off the top of my head, but you can use js to [check if you are on ios](http://stackoverflow.com/questions/9038625/detect-if-device-is-ios), then use an alternative method, do a bit more googling to find out alternative options for ios: http://stackoverflow.com/questions/6978778/what-are-the-alternatives-for-file-upload-on-ios-safari – Clearnoi Jun 29 '15 at 13:34