1

In my controller I have an ActionResult which returns a File.

[HttpPost]
public ActionResult ExportCSV(ReportResultViewModel model)   
{     
    var content = "hello,world";
    return File(Encoding.UTF8.GetBytes(content),"text/csv","export.csv");
}

In my view, when I post to this ActionResult, I display a modal saying "please wait".

<!--modal-->
<div class="modal fade" id="pleaseWaitDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content" style="background: #EBF3EB;">
            <div class="modal-header">
                <h1>Please wait...</h1>
            </div>
            <div class="modal-body">
                <div id="loader"></div>
            </div>
       </div>
    </div>
</div>
@using (Html.BeginForm("ExportCSV", "Reporting", FormMethod.Post, new { name = "back", id = "back", style = "width:100%" }))
{
     @Html.HiddenFor(m => m.A)
     @Html.HiddenFor(m => m.LOT)
     @Html.HiddenFor(m => m.OF)
     @Html.HiddenFor(m => m.THINGS)

     <input type="submit" data-toggle="modal" data-target="#pleaseWaitDialog" value="Export CSV" style="width: 100%; background: #fff" class="btn btn-default"  />
}

I want to hide it when the file is finally returned to the page.

Is there a way to detect client side (with JavaScript maybe) when the file arrives so I can hide the modal?

2
  • Tell me please what is unclear. Commented Jul 3, 2014 at 7:41
  • first time when ur form will load then u want to check is file is available???? Commented Jul 3, 2014 at 7:52

2 Answers 2

1

I think what you are after is the jQuery File Download http://jqueryfiledownload.apphb.com/ in your view add a reference to the jquery ui library and file download library then add a script tag.

<script type="text/javascript">

$(function () {
    var $pleaseWaitDialog= $("#pleaseWaitDialog"); 

    $(document).on("submit", "#back", function (e) {

        $pleaseWaitDialog.dialog({ modal: true });

        $.fileDownload($(this).prop('action'), {
            httpMethod: 'POST',
            data: $(this).serialize,
            successCallback: function (url) {
                $pleaseWaitDialog.dialog('close');
            },
            failCallback: function (responseHtml, url) {
                $pleaseWaitDialog.dialog('close');
            }
        });
        e.preventDefault; //otherwise normal form submit will occur 
    });
});
</script>

What this will do is when the submit button is clicked for the #ExportCSV form it will show a modal dialog box for the #pleaseWaitDialog tag. Then using the fileDownload plugin it will fire a post to the action url of the form. The data submitted comes from the $(this).serialize call. When the file has successfully been downloaded or if the call failed it simply closes the dialog box.

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

Comments

0

If you want to capture the return event, you'll have to submit the original request yourself over AJAX. Which means JavaScript will have to be ultimately responsible for downloading the file, instead of the browser via the Content-Disposition: attachment header.

In your controller, instead of returning a FileActionResult, you can convert the file into a Base64String and return that like this:

Byte[] bytes = File.ReadAllBytes("path");

if (Request.IsAjaxRequest())
{
    var file64 = Convert.ToBase64String(bytes);
    return Json( new {File = file64, MimeType = mimeType, FileName = fileName});
}
else
{
    // return file - should just auto download
    return File(bytes, mimeType, fileName);
}

Then in your AJAX handler, you can use HTML5/Javascript to generate and save a file using base64 encoding like this:

$(":submit").on("click", function(e) {
    e.preventDefault();
    var $form = $(this).closest('form');

    // disable buttons
    var $btns = $(":submit").addClass("disabled");

    $.ajax({
        type: $form.attr("method"),
        url: $form.attr("action"),
        data: $form.serializeArray(),
        success: function (data) {

            var pom = document.createElement('a');
            pom.setAttribute('href', 'data:' + data.MimeType + ';base64,' + data.File);
            pom.setAttribute('download', data.FileName);

            if (document.createEvent) {
                var event = document.createEvent('MouseEvents');
                event.initEvent('click', true, true);
                pom.dispatchEvent(event);
            }
            else {
                pom.click();
            }

            // reset buttons
            $btns.removeClass("disabled");
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(jqXHR);
        }
    });
});

IE / Edge Support

For IE /Edge, you'll need to use window.navigator.msSaveBlob. If you're sending back a base64 string, you'll also need to Creating a Blob from a base64 string in JavaScript

Further Reading:

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.