2

I sometimes have operation that takes a while to compute. I would like to be able to display something, like a kind of grey layer covering everything, or a loading screen, while the operation computes. But I frankly have no idea how to do it.

I'm building an MVC app using MVC4, I'm beginning with jQuery and opened to any suggestions. How might I do that?

EDIT

Here's a sample of page I've been building:

<h2>Load cards</h2>

<script type="text/javascript">
    $(document).ready(function () {
        $("form").submit(function (event) {
            event.preventDefault();

            alert("event prevented"); // Code goes here
            //display loading
            $("#loadingDialog").dialog("open");

            alert("dialog opened"); // Never reaches here.

            $.ajax({
                type: $('#myForm').attr('method'),
                url: $('#myForm').attr('action'),
                data: $('#myForm').serialize(),
                accept: 'application/json',
                dataType: "json",
                error: function (xhr, status, error) {
                    //handle error
                    $("#loadingDialog").dialog("close");
                },
                success: function (response) {
                    $("#loadingDialog").dialog("close");
                }
            });
            alert("ajax mode ended");
        });
    });
</script>

@using (Html.BeginForm())
{
    <div class="formStyle">
        <div class="defaultBaseStyle bigFontSize">
            <label>
                Select a Set to import from:
            </label>
        </div>
        <div class="defaultBaseStyle baseFontSize">
            Set: @Html.DropDownList("_setName", "--- Select a Set")<br/>    
        </div>
        <div id="buttonField" class="formStyle">
            <input type="submit" value="Create List" name="_submitButton" class="createList"/><br/>
        </div>
    </div>
}

Here's a snippet of code from my javascript file:

$(document).ready(function ()
{
    $(".createList").click(function() {
        return confirm("The process of creating all the cards takes some time. " +
            "Do you wish to proceed?");
    });
}

As a bonus (this is not mandatory), I'd like it to be displayed after the user has confirmed, if it is possible. else I do not mind replacing this code.

EDIT

Following Rob's suggestion below, here's my controller method:

[HttpPost]
public JsonResult LoadCards(string _submitButton, string _cardSetName)
{


    return Json(true);
}

And here's the "old" ActionResult method:

[HttpPost]
public ActionResult LoadCards(string _submitButton, string _setName)
{
    // Do Work

    PopulateCardSetDDL();
    return View();
}

As of now the code never reaches the Json method. It does enter the ajax method up there (see updated code), but I don't know how to make this work out.

hsim
  • 2,000
  • 6
  • 33
  • 69
  • 1
    check out http://stackoverflow.com/questions/1718951/jquery-how-can-i-create-a-simple-overlay – Matt Jul 17 '13 at 19:42
  • I like the [BlockUI](http://www.malsup.com/jquery/block/#overview) plugin for jQuery. "Blocking without a message" in the demos might work for you. – EFeit Jul 17 '13 at 19:45
  • How are you POSTing to the server? jQuery AJAX or just a normal form post? – Rob Jul 17 '13 at 19:47
  • I just need to display something to the user telling him "Hey, wait, it's loading" while the operation underneath performs. – hsim Jul 17 '13 at 19:49
  • The best way would be to use jQuery's $.ajax() method to post to the server. You can hook up a javascript function to be called before the post and after the post. That way you can display/hide a "loading" modal or message for status. I'll see if I can find a good example for you. – Rob Jul 17 '13 at 19:53
  • @Matt I will be trying the link you posted, however I have a question if you are familiar with jQuery. Say that I have this: `$(".createListCard").click(function() { return confirm("The process of creating all the cards takes some time. " + "Do you wish to proceed?"); });`, is there any way to make the code act on the confirmation of the return? – hsim Jul 17 '13 at 19:54
  • @Rob I'm interested, I would like to see this. – hsim Jul 17 '13 at 19:54
  • @HerveS It depends. It isn't clear to me how you are making your POST, since you are just showing us a click handler with a confirm. When do you invoke the post? With jQuery, you can hook a `success`, `complete`, or `error` callback to know what happened on the server side. It is in these callbacks you could then hide the overlay. – Matt Jul 17 '13 at 19:59
  • Ok, I'll paste a sample of code up here to demonstrate my meaning. – hsim Jul 17 '13 at 20:04

3 Answers3

0

You can try creating the view to load the barebones of the page, and then issue an AJAX request to load the page data. This will enable you to show a loading wheel, or alternatively let you render the page in grey, with the main data overwriting that grey page when it comes back.

This is how we do it in our application, however there is probably a better way out there... if not I'll post some code!

EDIT: Here's the code we use:

Controller Action Method:

[HttpGet]
public ActionResult Details()
{
    ViewBag.Title = "Cash Details";
    return View();            
}

[HttpGet]
public async Task<PartialViewResult> _GetCashDetails()
{
    CashClient srv = new CashClient();
    var response = await srv.GetCashDetails();
    return PartialView("_GetCashDetails", response);
}

Details View:

<div class="tabs">
<ul>
    <li>Cash Enquiry</li>
</ul>
<div id="About_CashEnquiryLoading" class="DataCell_Center PaddedTB" @CSS.Hidden>
    @Html.Image("ajax-loader.gif", "Loading Wheel", "loadingwheel")
</div>
<div id="About_CashEnquiryData"></div>
   <a class="AutoClick" @CSS.Hidden data-ajax="true" data-ajax-method="GET" 
      data-ajax-mode="replace" data-ajax-update="#About_CashEnquiryData" 
      data-ajax-loading="#About_CashEnquiryLoading" data-ajax-loading-duration="10"
      href="@Url.Action("_GetCashDetails", "Home")"></a>
</div>

Custom Javascript:

$(document).ready(function () {
    //  Fire any AutoClick items on the page
    $('.AutoClick').each(function () {
        $(this).click();
    });
});
Nick
  • 1,116
  • 2
  • 12
  • 24
  • I'm interested, this is about what I am trying to achieve. See updated code for what I've done so far. – hsim Jul 18 '13 at 14:45
0

First you want to have jQuery "intercept" the form post. You will then let jQuery take care of posting the form data using ajax:

$("form").submit(function (event) {
    event.preventDefault();

    //display loading
    $("#loadingDialog").dialog("open");

    $.ajax({
        type: $('#myForm').attr('method'),
        url: $('#myForm').attr('action'),
        data: $('#myForm').serialize(),
        accept: 'application/json',
        dataType: "json",
        error: function (xhr, status, error) {
            //handle error
            $("#loadingDialog").dialog("close");
        },
        success: function (response) {
            $("#loadingDialog").dialog("close");
        }
    });
});

More information on the $.ajax() method is here: http://api.jquery.com/jQuery.ajax/

You could use the jquery dialog to display your message: http://jqueryui.com/dialog/

There are other ways to display a loading message. It could be as simple as using a div with a loading image (http://www.ajaxload.info/) and some text, then using jQuery to .show() and .hide() the div.

Then, in your controller, just make sure you're returning JsonResult instead of a view. Be sure to mark the Controller action with the [HttpPost] attribute.

[HttpPost]
public JsonResult TestControllerMethod(MyViewModel viewModel)
{
    //do work
    return Json(true);//this can be an object if you need to return more data
}
Rob
  • 5,578
  • 3
  • 23
  • 28
  • @Herve In response to your update, i've changed the jquery selector. If you want to give your form a specific ID, then you can use #myFormId instead. Just make sure the form is the only one on your page. – Rob Jul 17 '13 at 20:13
  • Ok, I will try this and give you the results. – hsim Jul 18 '13 at 12:26
  • I have updated the post so that you may see what I have done so far. Things does not work yet. – hsim Jul 18 '13 at 13:50
  • When debugging do you see any javascript errors? Are you calling $("#loadingDialog").dialog(...) with the options to initialize the dialog before calling "open"? – Rob Jul 22 '13 at 19:50
0

We hide the main content, while displaying an indicator. Then we swap them out after everything is loaded. jsfiddle

HTML

<div>
    <div class="wilma">Actual content</div>
    <img class="fred" src="http://harpers.org/wp-content/themes/harpers/images/ajax_loader.gif" />
</div>

CSS

.fred {
    width:50px;
}
.wilma {
    display: none;
}

jQuery

$(document).ready(function () {
    $('.fred').fadeOut();
    $('.wilma').fadeIn();
});
MiniRagnarok
  • 959
  • 11
  • 23