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;
}
4
  • 1
    You need to return promises from resizeAndUpload. Then use $.when() to wait for all the promises to complete. Commented Jun 26, 2015 at 22:27
  • Would you be able to show me how to do this within the above code. Many thanks Commented Jun 26, 2015 at 22:30
  • Can you add the code for resizeAndUpload? Commented Jun 26, 2015 at 22:35
  • Amended the above post to include function Commented Jun 26, 2015 at 22:41

3 Answers 3

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();
        }
    }
} 
Sign up to request clarification or add additional context in comments.

Comments

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/

Comments

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);
}

14 Comments

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.
runAjax is never executed. If i add an alert(files.length), I get undefined.
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
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.
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 or similar.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.