This question is not totally answered, please fell free to contribute !
I'm trying to display a simple progress bar
while a large form is submitted.
The form contains a dozen of fields, plus some file upload fields, where the user can select a picture. Then, when he clicks on a Create
button, the form with data and pictures are submitted and the entity is created in DB. (only one click to submit the form AND the pictures).
Everything works fine, but I'd like to display a progress bar during the submit process.
I have found a lot of tutorials explaining how to display a progress bar, but I don't find anyone explaining how to display a progress bar indicating the percentage of work accomplished by a method, ie, I'd like to see 10%, 25%, etc... during the submit process.
So, basically, this is what I've done : (this is an ASP.NET MVC3 project)
@model MyModel
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "target-form", enctype = "multipart/form-data" }))
{
//some Html.TextBoxFor() and other @Html.DropDownListFor
@Html.TextBoxFor(m => m.File, new { type = "file"})
<input type="submit" value="Create" class="submitButton" />
<div id="progressBar"></div>
}
And a basic controller
[HttpPost]
public ActionResult Create(MyModel model)
{
if (ModelState.IsValid)
{
DALLayer dal = new DALLayer()
dal.AddEntity(model);
return RedirectToAction("Index", "Home");
}
return null;
}
Is it possible to transform my last <div>
in a progressBar
displaying the state of upload progress ?
Here are my requirements :
Thank you very much !
UPDATE 1
Here is a JSFIDDLE, where I'm trying to adapt this link but without success... If you think you can help, you're welcome !
UPDATE 2
Ok, I used acarlon's answer to submit my form with XMLHttpRequest
and the datas are correcty posted to the controller. However, the ProgressBar still doesn't appear !
I just replace the data passed to the controller by :
formData = new FormData(document.getElementById("target-form") );
xhr.open("POST", "@Url.Action("MyMethod", "MyController")", true );
and try some different headers, like :
xhr.setRequestHeader("X-File-Name", $('#Files_0__File')[0].files[0].name);
xhr.setRequestHeader("X-File-Size", $('#Files_0__File')[0].files[0].size);
xhr.setRequestHeader("X-File-Type", $('#Files_0__File')[0].files[0].type);
//Also tried with "Content-Length" but it doesn't care about it.
(It was hardcoded here to be sure it has good values. I'll do it in a loop when I'll be more at ease with it.)
And when I submit my form, the XMLHttpRequest
send has these fields :
readyState: 4
status: 0 <= should be 200, right ?
And in the error handler
, I have these values :
loaded: 0
total: 883526
type: "error"
So the data are submitted to my controller, but I'm unable to display this damned progressbar...
In this example, modeless progress is shown in the address bar. Otherwise, if the window has a status bar, display the modeless progress in the status bar. Put any corresponding text to its left in the status bar. In this example, modeless progress is shown in the status bar.
You can use XMLHttpRequest
to receive updates when uploading files. There are also various jquery-type wrappers to achieve the same. I will describe a solution using XMLHttpRequest
.
First intercept the form submit.
$("#target-form").submit(function () {
Then create XHR request:
xhr = new XMLHttpRequest();
Then register to be notified about progress events:
xhr.upload.addEventListener( "progress", function ( evt )
{
if( evt.lengthComputable )
{
var progressPercent = ( evt.loaded / evt.total ) * 100;
showProgress( value );//your function.
}
}, false );
//Some other events you will probably want to subscribe to
xhr.addEventListener( "load", function ()
{
fileUploadComplete( this.responseText );
}, false );
xhr.addEventListener( "error", function ( first, second, third )
{
fileUploadComplete( "Error: Image format not supported." );
}, false );
xhr.addEventListener( "abort", function ()
{
fileUploadComplete( "Error: Upload was cancelled. Please try again." );
}, false );
Open XHR passing in any arguments (id
is shown as an example)
xhr.open( "post", '@Html.Raw( @Url.Action( "UploadImage", new { someId = id } ) )', true );
// Set appropriate headers
xhr.setRequestHeader( "Content-Type", "multipart/form-data" );
xhr.setRequestHeader( "X-File-Name", name );
// Send the file
xhr.send( file );
Then in the controller:
public ActionResult UploadImage( int someId, HttpPostedFileBase userFile )
{
...
}
You will receive the updates in the update handler.
Extension for long running server task
If there is some long running task on the server (such as writing the data to the database), then you need to chunk the operations (so that you can give updates on completion of each chunk) on the server and implement code to handle a long running service that you can query from javascript. See here. The basic idea is to start the task on the server side and periodically check the progress from Javascript. You may want to have two separate progress bars, one for uploading and one for the server side operation. This provides more information to the user - they will know that the file upload is complete and now some server-side operation is happening.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With