1

We have a form with five <input type="file"/> elements that is in production and working great. We get request timeouts and MaxRequestLength exceeded errors on occasion. To prevent these errors, I planned to write some Javascript to upload the files one-at-a-time instead of all at once. Here is how I planned on doing this...

  1. On document.ready, inject a hidden iframe into page
  2. Change the <form> to target the iframe
  3. Disable all elements on the form (which prevents them from being POSTed)
  4. Enable one file-upload at a time and submit the form
  5. Wait for the response from the server
  6. When server response is printed into iframe, start the next upload
  7. When all uploads are done, refresh the page, which will invoke some server-side logic that populates a grid.

My problem is with number 5. Normally I think I could figure this out no problem, but I am just having one of those days where my brain is on strike. Here is my code thus far...

$(function() {
  $("<iframe/>").attr("src", "test.htm").attr("name", "postMe").hide().appendTo("body");
  $("form").attr("target", "postMe").submit(function(e) {
    e.preventDefault();
    $("#btnSubmit").attr("disabled", "disabled").val("Please Wait, Files are Uploading");

    for(var i = 1; i < 6; i++) {
      $("input[type=file]").attr("disabled", "disabled");
      $("#FileUpload" + i).removeAttr("disabled");
      $("form")[0].submit();
      // HELP!!!
      // How do I wait for server before next iteration?
    }

    location.reload(true);
  });
});

What kind of construct do I need here in order to "wait" for the server response before kicking off the next upload?

6
  • I should note that I want to write this code myself, not use some fancy plugin with a bunch of dependencies. Commented Dec 2, 2009 at 15:09
  • If this become too much of a pain, I might just try to use use five iframes! That's the last thing I want to do, but it might be what I have to do. Commented Dec 2, 2009 at 15:19
  • 1
    @Stodola Nobody wants anything to do with flash' is really subjective. What is your problem with Flash? I was trying to give you more information regarding Uploadify. ' I dont understand why you want to reinvent something that already works perfectly if you just look around for other solutions that exist. Commented Dec 23, 2009 at 15:25
  • @jmein Flash is third-party. It does not work on 64-bits. It has a dependency. It's annoying. It's inaccessible. It has security problems. Call it subjective all you want; nobody I know would ever use it in a production scenario. It's a toy for children. Commented Dec 23, 2009 at 15:30
  • @JoshStdolla Then why does Hulu work on my 64 bit machine? Hulu uses flash. Commented Dec 23, 2009 at 15:36

5 Answers 5

2

I've had a lot of success lately using Uploadify--it's very configurable, free, and allows for multiple-uploads. It also provides the option for callback functions allowing you to really configure it any way you want.

http://www.uploadify.com/

Sign up to request clarification or add additional context in comments.

4 Comments

Are you serious? It requires Flash. No way in hell would I ever use that.
Why not? SWFUpload and consorts work great, and they open a lot of possibilities for file uploads that vanilla HTML/JS don't have.
I don't care what you are saying about Flash. I'm never goin to use it. Read the first comment I left on the question.
There is UploadFive by Uploadify which using HTML5 instead of Flash. Cost about 5$.
1

I think you should listen for iframe's load event and perform input's switching in the handler. I completed with my own uploader today and this solution worked for me.

11 Comments

Interesting approach!! Thank you very much, I am going to try this.
+1 I don't think that you're going to find a way to actually block and wait until the iframe loads; you'll want to make your code asynchronous, and get a callback when the iframe is ready for the next iteration.
Any chance you could show me some code Alex? I am struggling.
In short, my onload event handler on the frame is not getting fired. I assign the handler right after the form is submitted. Should I be doing this elsewhere?
You could find a working sample here: liveui.net/demo-bugtracker/Tasks/… The script currently working is a bit outdated (it is already two weeks old :) ) but you can find newest version that is much better in our download archive. Pay attention to 'jquery.uploadfield.js' file. You must pay attention to "this.iframe.bind('load', this.iframe, ..." line.
|
1

Just FYI: jquery.forms plugin is all about making ajax form submitions. I use this plugin to submit a form (such as a file upload) in a separate iframe which the plugin takes care of automatically, and gives you a nice callback when completing.

This way most work for you is done.

http://jquery.malsup.com/form/

3 Comments

Nice! I like the callback, I am going to dig into this code and see how it works, but I probably will not be using the plugin.
There's nothing there that will do the uploads one at a time, which is ultimately what I am after.
Step 1: Create a file upload mechanism using the plugin. Step 2: Use the success handler to trigger step 1 again. And so on. Remember it has all the jquery ajax events callbacks.
1

It can be done with the help of jQuery's queue method and load event.

<!DOCTYPE HTML>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script>
//here's an upload script
(function($){
    //make 'em accessible within the scope
    var $iframe, $form;

    $(document).ready(function(){
        //create 'em only once, but use 'em many times
        $iframe = $('<iframe name="iframe" id="iframe" style="display:none"></iframe>').appendTo('body');       
        $form = $('<form method="post" enctype="multipart/form-data" target="iframe" style="display:none"></form>').appendTo('body');   
    });

    var iframeUpload = $({});

    $.iframeUpload = function(s){   
        iframeUpload.queue(function(next){
            //as we only wanna this new event
            $iframe.load(function(){
                //we must unbind the old one
                $iframe.unbind('load');

                //success or error, the question is up to you
                s.success();

                //but remember to remove or replace the old stuff
                $form.find('input').remove();

                next();
            });

            $form.attr('action', s.url).append(s.file).submit();
        });
    };
})(jQuery); 
//and this is how to use the script
(function($){$(document).ready(function(){
    $('input[type="submit"]').click(function(){
        $('input[type="file"]').each(function(){
            $.iframeUpload({
                url: 'http://example.com/upload.php',
                file: this,
                success: function(){
                    console.log('uploaded');
                }
            });
       });
    }); 
})})(jQuery);   
</script>
</head>
<body>   
    <!-- here are multiple files -->
    <input type="file" name="file" />
    <input type="file" name="file" />
    <input type="file" name="file" /> 
    <!-- to upload -->
    <input type="submit" />
</body>
</html>

Comments

0

I was able to do this, by starting with the code at A Strategy for Handling Multiple File Uploads Using Javascript. That code uses an XMLHttpRequest for each file, but actually doesn't check the result from the server. I modified it to wait for the result from the server, sequentially, as follows:

var fileNumber = 0
var fileList = []    // see the code linked above for how to handle the fileList
var resultPane = document.getElementById('resultpane')   // a textarea box

sendNext = function() {
  if (fileNumber >= fileList.length) {
    resultPane.value += 'Done uploading '+fileNumber+' files\n'
    return 0
  }
  var formData = new FormData()
  var request = new XMLHttpRequest()
  request.onreadystatechange = function() {
    if (request.readystate == XMLHttpRequest.DONE) {
      resultPane.value += request.responseText    // show whatever the server said about each file
      sendNext()                                  // and send the next file
    }
  }
  formData.set('file', fileList[fileNumber])
  request.open('POST', 'https://example.com/upload-receiver')
  request.send(formData)
  resultPane.value += 'Sending file number '+fileNumber+'\n'
  fileNumber++
}

Comments

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.