javascriptc#asp.nettimer

Run script immediately for timer loading


I tried to do that when I clicked on a button, then before processing - to make a timer so the user knows something is loading. However, the timer executes only at the end, and I want it to execute immediately.

Here is my C# code:

protected void OnSearchClick(object sender, System.EventArgs e)
        {
// Starting of the code

// The script
ClientScript.RegisterStartupScript(this.GetType(), "startTimer", "startTimer();", true);

// Ending of the code
ClientScript.RegisterStartupScript(this.GetType(), "stopTimer", "stopTimer();", true);

Here is my script code:

<div id="loadingContainer" style="display: none;">Loading<span id="timerDisplay"></span></div>
<script type="text/javascript">
    var timerInterval;

    function startTimer() {
        var loadingContainer = document.getElementById('loadingContainer');
        var timerDisplay = document.getElementById('timerDisplay');
        var dotStates = ['.', '..', '...'];
        var currentDotState = 0;

        loadingContainer.style.display = 'block';

        timerInterval = setInterval(function () {
            timerDisplay.textContent = dotStates[currentDotState];
            currentDotState = (currentDotState + 1) % 3;
        }, 1000);
    }

    function stopTimer() {
        clearInterval(timerInterval);
        document.getElementById('timerDisplay').textContent = "Done! ";
    }
</script>

And all I see is Loading Done! after the process is completed, and I want before it's completed to see the startTimer() script.


Solution

  • Keep in mind how the post-back or so-called "round trip" of a page lifecycle works.

    The browser page is sitting on the user's desktop. When you click a button, then the WHOLE page is set up to the server for processing. Then a copy of the page class is created, code behind starts running. While that code runs, the end user does not see ANY of your code changes. You can run a loop (server code) that updates a text box from 1 to 10 (with some 1 second delay in that loop). The user only sees the browser spinner (wait) in the upper left corner, and NOT ANY changes to the browser page.

    After all the changes to the browser care complete, and ONLY AFTER all changes and code runs, then the whole page THEN makes the trip back down to the client side.

    And above includes any script injection by that server-side code. So, you can register FunScipt1, FunScript2 etc. But, your code behind is ONLY injecting that JavaScript - it not going to run just yet!

    So, all the code behind has to finish, and it don't matter if you inject 2 scripts, or 10 scripts, they will ONLY run AFTER all code is done, and only run AFTER the whole page travels back down to the client side.

    And keep in mind that after the code behind runs, after you inject the script, and then the page travels down to the client side. Then the web page re-loads, JavaScript engine is loaded, and THEN your scripts run, including the one's you injected while the page is up on the server.

    So, the page life cycle looks (a round trip) looks like this:

    You have thus this:

    enter image description here

    Note how your page class - code behind is NOT in memory on the server.

    YOU DO NOT have this:

    enter image description here

    And you do NOT even have this:

    enter image description here

    Note very carefully here - the web page is on the CLIENT computer - it is NOT existing at all on the web server side.

    So, when you click on a button, or do a post-back, then you get the start of the round trip.

    This:

    enter image description here

    Our web page is sent up to the server. You now have this:

    enter image description here

    NOW an instance of the page class is created, and your code behind starts running.

    Your code behind can modify controls (even controls to be visible or not), but the page is NOT interacting with the user - ONLY code can MODIFY the web page (user does not see one change, or many changes).

    One change, or MANY changes to the web page can occur, but AS YOU update things like a text box etc., the user does NOT see these changes just yet. So, if you run a loop 1 to 10, and update a text box, the text box WILL be updated 1 to 10. However, the end user sees nothing, since that web page (and code) is running up on the server.

    Changes to web page are occurring on the server - the client-side browser does not have the web page any more!

    Once ALL of your code is done running, then and ONLY then does the page make the trip back to the client-side browser.

    The server-side class instance and code (and variables) are TOSSED OUT - DOES NOT exist! Your server-side page class is disposed - removed from memory, and the web page code behind does NOT exist any more.

    So, page travels back to the client side, is re-displayed, JavaScript is loaded, and THEN JavaScript starts running. So even the client-side page now 100% re-loads.

    enter image description here

    So, now armed with the above knowledge of a post back and round type (the page life cycle)?

    OK, this means that to display changes to the web page, the page MUST do a round trip.

    And this means if you going to display a spinner?

    Well, if you try to user server-side code (and Script Injection with RegisterScript), then that is too late, since all of your code, and 100% of your code server side will have to 100% complete BEFORE that web page travels back down to the client side.

    Armed with above knowledge?

    Then to display some spinner or "wait" while the page is processed by the server?

    Simply before you post the page, you use client-side code and display the spinner.

    Say we want a button click, and it is to load a GridView, and it will take a few seconds, and hence during that page loading time, we want to display a process message.

    Turns out, standard ASP.NET buttons allow both a client side click event, and a server-side event (with post-back).

    So, then this code:

    Markup:

            <asp:Button ID="cmdLoadGrid" runat="server" Text="Load data" 
                CssClass="btn"
                OnClick="cmdLoadGrid_Click"
                OnClientClick="$('#MySpinner').show();return true;" />
    
            <div id="MySpinner" runat="server" style="display:none">
                <h4>Loading data - please wait...</h4>
                <img src="Content/wait2.gif" />
            </div>
    
    
            <div id="MyGrid" runat="server" style="width:50%">
                <asp:GridView ID="GridView1" runat="server" 
                    CssClass="table"></asp:GridView>
            </div>
    

    Note the hidden div. Whatever we place inside of that div is what our "wait" message will show.

    For server side, I introduced a 3 second delay, since the GridView loads so fast.

    Hence server-side button code is this:

    Protected Sub cmdLoadData_Click(sender As Object, e As EventArgs)
    
        Dim strSQL =
            "SELECT FirstName, LastName, City, HotelName, Description
            FROM tblHotelsA
            ORDER BY HotelName"
    
    
        GridView1.DataSource = MyRst(strSQL)
        GridView1.DataBind()
    
        ' fake a 3 second delay
    
        System.Threading.Thread.Sleep(3000)
    
    End Sub
    

    Note very closely that we do not need to un-hide the spinner and div message.

    This is because if the server-side code takes 2 seconds, or 20 seconds? The client-side browser will continue to display the spinner GIF + message, and when the server-side code is completed, then a WHOLE NEW fresh web page travels down to the client side, and that includes the re-set of the hidden div.

    Hence, the un-hiding of the spinner div does not require a timer, since when the whole new copy of the browser travels back to the client side, then the whole page is re-loaded, and that includes our hidden div.

    Hence, armed with a simple understanding of how the page round trip (page lifecycle) works, then we use this knowledge to display our message for as long as the server-side code is running, and thus no timers etc. are required.

    The result of above thus looks like this:

    enter image description here

    In above, I assume you have jQuery for the .show() of the div, but you could say use 100% JavaScript.

    With an understanding of the page lifecycle, note how no need exists to hide the div, since the server going to send a whole new copy of the browser back from the server, and thus the div will revert back to its original setting (hidden). And we don't need any script injection (which is too late), and and we don't need some kind of timer either.

    So any changes to the browser with server side code will not and does not appear until such time the WHOLE page travels back to the client side. And this includes using RegisterScript. You can inject 2 or 10 scripts, but they are not going to run until the page makes the trip back to the browser. Note close then then I am free to put my fake "sleep" delay before the gird load, or after, it does not matter, since the user does not see the grid load or the results of any changes to the browser with code behind (including script injection ) until the whole page travels back to the client side.

    Once you grasp the page lifecycle, then display of a delay not only becomes easy, but we don't have to know in advance how long the server side code going to take. And note how when all such code is done, then a fresh whole new browser page is sent back to the client side, and the whole client side page is over written when that whole new fresh copy of the browser is sent down from the server side.