Click here to Skip to main content
15,885,546 members
Articles / Web Development / HTML

Show an animation while waiting for a download to start

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
23 Apr 2016CPOL3 min read 42.7K   825   12   4
This article shows a cool trick to display a loading animation while waiting for a download to start. If the download starts, the animation is automatically hidden.

Introduction

In a web application you often want to download a file that is created on the fly on the server. If this takes more than a few seconds you want to show some kind of feedback to the user, like a "Please wait..." message and a nice loading animation:

It is easy to show such an animation using JavaScript when a download link or button is clicked and the request is sent back to the server. However when the server answers directly with the file to download, there is no way to hook into that event and hide the animation.

I will show you a nice trick to hide the animation as soon as the download is ready and the browser shows the download dialog.

Background

The trick I use makes use of a cookie: Just before the server starts writing the generated file into the response stream, it sets a cookie. The cookie is sent to the browser as part of the HTTP header of the response and is immediately available as soon as the first bytes of the response are received by the browser.

Cookies can also be read from JavaScript. So what we do is starting a timer that polls for the existence of this cookie when the download link/button is pressed. This timer continues to work while the request is running. As soon as we have found our cookie, we know that the download is ready and can hide the animation.

Using the code

Let's take a look at the client code first. This is the MVC view:

C#
@using (Html.BeginForm("Download", "Home"))
{
    @Html.Hidden("cookieValue")
    <input type="submit" id="btnDownload" value="Download!" />
}

We have a form that will issue an HTTP POST and call an action "Download" in a controller named "Home". Within the form we have a hidden field and a button that starts our download.

JavaScript
<script>
    var _tmr;
    $(function () {
        $('#btnDownload').click(function () {
            // save timestamp in hidden field
            $('#cookieValue').val(Date.now().toString());

            // show animation
            $('body').addClass("loading");

            // start timer to wait for cookie
            _tmr = window.setInterval(function () {
                var _str = 'dlc=' + $('#cookieValue').val();
                if (document.cookie.indexOf(_str) !== -1) {
                    // hide animation
                    $('body').removeClass("loading");
                }
            }, 100);
        });
    });
</script>

Using jQuery, we attach a click event to the download button. If this button is clicked, we generate a unique key from the current time and store this key into our hidden field.

Then we show the loading animation by adding the CSS class "loading" to the HTML body (this is out of scope of this article as there are 100 ways to show a loading animation).

Next we start a timer which fires an event every 100ms. In that event we read all cookies of the current URL. "document.cookie" returns a string with all cookie names and values, separated with a semicolon character. We check if this string contains a cookie with the name "dlc" and a values that matches the unique key that we stored in our hidden field before.

If we have found such a cookie, the loading animation is hidden again.

Now let's look at the server side code. This is the Download method of our HomeController class:

C#
[HttpPost]
public FileResult Download(string cookieValue)
{
    // wait 10 seconds to simulate a long running operation
    System.Threading.Thread.Sleep(10000);

    // create a dummy text file to download
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("This is a demo file that has been generated on the server.");
    sb.AppendLine();
    for (int i = 1; i <= 1000; i++)
    {
        sb.AppendLine("Line " + i.ToString() + "  " + DateTime.Now.ToString());
    }

    // add a cookie with the name 'dlc' and the value from the postback
    ControllerContext.HttpContext.Response.Cookies.Add(new HttpCookie("dlc", cookieValue));

    return File(Encoding.ASCII.GetBytes(sb.ToString()), "text/plain", "data.txt");
}

The value of the hidden field is automatically passed in the cookieValue parameter of the method.

To simulate a time consuming file generation I use a Thread.Sleep to add a delay of 10 seconds. Also I generate a dummy text-file that contains 1'000 lines of text.

The most important part is adding a cookie to the response. I used "dlc" as the name of the cookie, but any name will be ok as long as you use the same name in the JavaScript code. The cookie value will be set to the cookieValue parameter.

After setting the cookie, the dummy file is returned as a FileResult.

Points of Interest

It is important to use another unique value for the cookie each time we start a download. Otherwise it would not work if someone starts the same download again because the cookie is already existing!

Although my example is using ASP.NET MVC, the principle can easily be transferred to any other programming language.

History

  • 2016-04-23 - first release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Sevitec Informatik AG
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionElement doesnt go away Pin
Member 1414103419-Feb-19 9:13
Member 1414103419-Feb-19 9:13 
SuggestionTimer left running after download? Pin
drwebmonkey30-Mar-17 11:02
drwebmonkey30-Mar-17 11:02 
Questionproject file missing Pin
Vishnu Rana25-Apr-16 22:51
Vishnu Rana25-Apr-16 22:51 
AnswerRe: project file missing Pin
Simon B.28-Apr-16 8:29
Simon B.28-Apr-16 8:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.