2

Trying to make a progress bar for a form upload (old HTML4 form upload, not new HTML5 API). The progress actually tracks additional work being done after the file has moved. The way it has been designed is that the stream stays opened until after the additional work is done, and then the server-side method finally returns, which closes the stream.

I'm having some issues that may be specific to Chrome. I do also have a working implementation, but I'm hoping to get something "better".

For anybody who is likely to ask for code: it's intentionally not here. The scenario explains the problem; the code itself wasn't "at fault" and will just be more clutter.

Failed attempt #1 in a nutshell

  1. Initiate form upload
  2. Set interval on an Ajax call that grabs the progress in some JSON
  3. Render the data to a progress bar

Reason for failure: the upload stream blocks other activity on the page, and you cannot make additional Ajax calls during the transfer.

Failed attempt #2 in a nutshell

  1. Create an iFrame which contains the same Ajax calls
  2. Render the data to an element within the iFrame (everything needed is self-contained and does not reference the "top" document in the least)

Result:

  • before initiating the form upload, I could render "status: waiting" from the JSON. The rendering function also incremented a counter so I would see "attempt #X". The # of attempts would increment while status is waiting.

  • after transfer initiated, the Ajax calls were successfully getting 200 and I could inspect the responses to see that the JSON was in fact there.

  • HOWEVER, I could not update the "shadow DOM" (is that the correct term?) in the iFrame. Attempts to access nodes within the iFrame and modify them failed. Even the counter did not increment.

  • When the transfer completed, it would then successfully render "status: complete" and the counter would jump ahead (the counter was incrementing, but rendering it to the iFrame just wasn't working)

GRR!

Successful Attempt

The iFrame does not request Ajax anymore. The iframe's src attribute is set to a URL that returns a pre-rendered progress bar. The document being loaded into the iframe is set to reload itself. So at the prescribed interval, it re-renders a new progress bar which has "moved along".

The result is a "working" progress bar, although sometimes the lag in the request causes the iframe to be blank for a split second, which isn't my preference.


Can anybody think of a better way to do this? Is it possible that I could have the form itself in the iFrame and the Ajax work in the "top" document instead?

I mainly want to divide the presentation layer from the data layer, but as long as I have to return a rendered progress bar, that isn't going to work. As a bonus, if I can find a way to update the progress bar via Ajax, I won't have those "blank" blips.

Greg Pettit
  • 10,749
  • 5
  • 53
  • 72
  • Have you tried submitting the file upload to an iFrame which blocks nothing on the page but allows server requests to happen? Alos - depending on your restrictions - if you have access to HTML5 browsers there is a progress event on XHR objects now. But it's only supported by Chrome and Firefox (maybe Opera). Definitely not IE. – Brandon Buck Apr 24 '13 at 19:22
  • Thanks, isuriel. I think that'll be something to try. I have not done so yet. The HTML5 progress event will give me access to the "move" portion, but I will still need to access the "post-move" progress from the server. But reversing the role of the iFrame might be a way to go. – Greg Pettit Apr 24 '13 at 19:28
  • this one seem to have everything you require, in case you're using jQuery http://stackoverflow.com/questions/15410265/file-upload-progress-bar-with-jquery – Oleg Mikheev Apr 24 '13 at 19:37
  • Oleg, if I'm reading the code correctly, it's not going to handle the "after the file move" portion. It will just sit at 100% while the "extra" work is being done; this will work for the first leg of the transfer (moving the file) but it doesn't provide a mechanism for capturing the progress of the second leg (the extra work being done). – Greg Pettit Apr 24 '13 at 19:43

4 Answers4

3

To expand on my comment and offer guidance, to perform the "hidden iframe file upload" you need to have a hidden frame (so obvious isn't it?) with a name.

<html>
  <body>
    <iframe name="file-upload" src="" style="border: none; visibility: hidden; width: 0; height: 0; position: absolute; top: 0; left: 0;"></iframe>
    The iframe shouldn't be visible, just pretend I didn't use inline styles though.
    <form id="uploadForm" action="anaction.php" enctype="whatever-you-need-here" method="post">
      File: <input type="file" /><br />
      <input type="submit" value="Upload" />
    </form>
  </body>
</html>

All pretty standard stuff so far. Next up comes the Javascript:

var form = document.getElementById("uploadForm");
form.onsubmit = function() { 
  console.log("The form has been submitted, start progress!"); 
}
form.target = "file-upload"; // the name of the iframe
// Go about your business, when "Upload" is pressed the file will be submitted
// to the iframe so you'd start your progress requests on form submit.

Ignore the poor practices, it's a simple example.

Brandon Buck
  • 7,177
  • 2
  • 30
  • 51
  • Doesn't seem to be working. My enctype is "multipart/form-data"; the upload works, but in Chrome there's still a blocking condition. I'm not sure how to tell if it's actually sending the file from the iFrame, though; it LOOKS like it's still sending it from the top document. – Greg Pettit Apr 24 '13 at 21:19
  • note: it seems to work in Firefox, sort of: the code is fine, but the form upload keeps crashing the browser. ;) Buggy implementation of form upload lately, I guess. – Greg Pettit Apr 24 '13 at 21:29
  • I left off the action on the form (if you left it off as well doubtful) and the IFrame may need an empty `src` attribute to begin with - I'm not sure. Other than that, I've used this method before with no issues. – Brandon Buck Apr 24 '13 at 21:45
  • Yeah, I have an empty src attribute and included an action. The upload does fire up; it's just not allowing the Ajax calls for progress (in Chrome). – Greg Pettit Apr 24 '13 at 21:47
  • Nix that... I don't know if I was viewing a cached version or what, but it is now working! Thanks for your help; the recommended libraries are still on my list to research, but this is really the solution I was after. – Greg Pettit Apr 24 '13 at 21:50
  • 1
    @Azd325 If using a new enough version of jQuery (I think 1.9) then: `$(formSelector).prop("target", "file-upload");` otherwise: `$(formSelector)[0].target = "file-upload";` – Brandon Buck May 16 '13 at 14:52
  • Really nice is works but how I can step out of the form to do a redirect. – Azd325 May 17 '13 at 09:45
1

honestly I do all the front end dev for an app and I was looking for the same thing. First i tried just using our socket.io to send back a number which i then turned into a percentage. I'd then apply that to the twitter bootstrap prog bar.

What i ended up doing and sticking with was using fine uploader http://fineuploader.com/ The documentation kinda sucks and you'll have to toy with it a little bit but it has a built in event that fires over and over while uploading something that will actually return you the progress.

btm1
  • 3,866
  • 2
  • 23
  • 26
  • Please open up [a support ticket](https://github.com/Widen/fine-uploader/issues/new) in the Fine Uploader Github project if you have any suggestions for improving the documentation. I've gone to great lengths to make the documentation complete, but I'd like to know if it can be improved further. – Ray Nicholus Apr 24 '13 at 19:28
  • I will look into the Fine Uploader; I just wonder how it will handle the unconventional use case I have (the server doesn't return and close the stream until some "extra" work is done). – Greg Pettit Apr 24 '13 at 19:29
  • @GregPettit The depends on what your expectations are. Your use case, as described here, doesn't sound unconventional to me (unless I am missing something). – Ray Nicholus Apr 24 '13 at 19:31
1

I decided to use: http://blueimp.github.io/jQuery-File-Upload/ because it is free and gives you nice progress bar.

Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116
1

The last time I did it I just submitted the form with data to some invisible iframe, then I could just forget about it.

Next I started polling some URL/REST API for progress.

Once the submit is done - an event will fire, its handler will stop progress polling.

I don't see any problem with this approach, but for some reason neither of yours seem to match what I'm describing, so I'm putting it as an answer.


If you use jQuery the best approach would be to "ajaxify" your form using jQuery Form plugin. You can refer to this question for the example: File upload progress bar with jQuery.

Community
  • 1
  • 1
Oleg Mikheev
  • 17,186
  • 14
  • 73
  • 95
  • This seems to be what izuriel suggested in the comments. I haven't tried it yet, but the idea is sound. I'll report back! – Greg Pettit Apr 24 '13 at 19:31