views:

455

answers:

5

I have an operation on my Page that then requires 3 long (few seconds each) operations to be performed in series. After each operation is performed though, I would like the controller to return a partial view and have the page update with a status (keeps the user informed, I find that if people know that stuff is happening they worry less). Is there a MVC 'way' of doing this, or should I just use jQuery to do it?

Thanks.

A: 

You will want to use jQuery to issue three separate calls to three separate control methods and update the three areas of the page upon return separately.

The only way to "bunch" up calls would be to combine it all into one, but you can't get return values fired back to the client upon return of more than one call (almost like streaming, there's nothing listening on the client end after you return your first result set, that connection is closed).

casperOne
I sort of came to this conclusion after running in circles for a bit, however now that causes a different problem for me. IE is silly in that it does not update the UI (or give you the option to force update) while you are running a Javascript. So when I try to do 3 synchronous JQuery.ajax calls, my UI is frozen until all of them complete. Now other posts on this site say the solution is to make the operation asynchronous, but um... I wouldn't be using synchronous if order didn't matter... any ideas?
BitFiddler
@BitFiddler: Calls to the ajax method on jQuery are asycnrhonus (you are providing a callback, right?). If you are seeing the screen freeze up then I'm guessing that the UI update is blocking, and not the async call.
casperOne
No the calls are not async. I need them to happen in a specific order (the systems I am working with are separate but depend on one another... don't get me started). So apperently IE doesn't update it's DOM until all scripts are done running, this is my problem :-(
BitFiddler
A: 

So I have created a slight hack, that seems to work:

On the client side I have:

function onClickHandler() {
    updateUI("Beginning Batch...");
    setTimeout(klugeyClick, 0);
}

function klugeyClick() {
    $.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action1", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action1 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
    setTimeout(klugeyClick2, 0);
}

function klugeyClick2() {
    $.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action2", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action2 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
    setTimeout(klugeyClick3, 0);
}

function klugeyClick3() {
    $.ajax({ type: "GET", dataType: "json", url: "/ControllerName/Action3", success: function(msg) { updateUI(msg) }, async: false, error: function(XMLHttpRequest, textStatus, errorThrown) { updateUI("Action3 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); } });
}

function updateUI(result) {
    $("#UIelement").text(result);
}

On the server side I have:

Function Action1() As JsonResult
    System.Threading.Thread.Sleep(3000)
    Return Json("Operation One Complete...")
End Function

Function Action2() As JsonResult
    System.Threading.Thread.Sleep(3000)
    Return Json("Operation Two Complete...")
End Function

Function Action3() As JsonResult
    System.Threading.Thread.Sleep(3000)
    Return Json("Operation Three Complete...")
End Function

Now I have two problems. First, I would like to have a follow up message that displays "Batch Complete" but following the same pattern and just adding another 'klugeyClick' with a call to UpdateUI (with or without a seTimeout) causes the last operation message not to be displayed. I think the callback within the jQuery.ajax method makes this kluge work somehow but without an ajax call, I can't put any follow-up messages.

The next problem is that although all my calls are getting to my webservice and are returning json results just fine, I always get an error coming back from the jQuery callback. Any ideas why this might be?

Thanks.

BitFiddler
A: 

The reason your "kludgy" solution works is because the setTimeout() method creates an event. Thus your logic is:

  1. Update UI
  2. Setup event for step 1:
    1. Start "ajax" call
    2. Wait for "ajax" to finish
    3. Setup event for step 2
      1. Start "ajax" call
      2. Wait for "ajax" to finish
      3. Setup event for step 3
        1. Start "ajax" call

This is precisely what the callback feature of ajax() is for.

function Step1() {
    $.ajax({ 
        type: "GET", 
        dataType: "json", 
        url: "/ControllerName/Action1", 
        success: function(msg) { 
            updateUI(msg);
            Step2(); // call step 2 here!
        }, 
        async: true, // don't block the UI
        error: function(XMLHttpRequest, textStatus, errorThrown) { 
            updateUI("Action1 Error: " + XMLHttpRequest + " -- " + textStatus + " ---- " + errorThrown); 
        } 
    });
}
function Step2() {
    // similar to step one
}
Joel Potter
But if I string 3 of these Async ajax calls together, will the always come back in order?
BitFiddler
I just tested it, if I were to use your solution it would not work as desired. They will arrive out of order with Async set to true, in my solution they will not arrive out of order. Essentially, I am unblocking the interface while I wait for the response so that I can update it... which is what I want. However, without doing another Ajax call at the end to some dummy webservice method, I can't pull this trick again to say that the whole batch is finished. Also, the result still isn't coming back successfully for some reason.
BitFiddler
I think I might have misread your post... re-testing your solution again...
BitFiddler
They will always fire in the correct order and one after the other since Step2 does not get called until after Step1 has finished successfully. I wouldn't make another call just to get the "Batch Complete" message. Just tag it on to the end of your third message in some manner. i.e. "Operation three complete... Batch Complete"
Joel Potter
Joel, you are right. So that simplifies my code, but does not help with displaying a message at the end saying "batch complete" I tried adding a: setTimeout(updateUI("FINISHED"), 3000); On the last step, but that causes the results from the last service call to be skipped. Also, any idea why the json call is always coming back as an "unknown error"?
BitFiddler
javascript doesn't have threads. That the first mistake with setTimeout. You have events and you, but there is only one thread of code running at a given time.
graffic
@graffic: Technically that is true, however, it helps to think of code started with `setTimeout` as threaded since it lives separately from the initializing code. The apparent effect is that of a threaded program.
Joel Potter
@Joel: then people ask themselves why the browser is frozen. "I just left the code running in a thread". HTML5 will bring "workers" that are pure threads.
graffic
@graffic: I'll be careful in future to differentiate threads and events. Pre HTML5 it was a useful analogy in my mind, but you are right that it can cause confusion.
Joel Potter
A: 

So as far as I can tell, the only way to get a Follow up message to appear the way I want it do (i.e. a few seconds after my last operation) is to have a dummy webservice method that I call that returns the last message after a delay... crumby.

Now my last problem is that all of my calls to my jsonResult actions come back with a textStatus of 'error' to the client. Now according to the docs this means an http error, but how could there be an http error if the method was called on the server side correctly and a Json result was produced (verified by setting a breakpoint on the server)?

BitFiddler
Last problem ended up being something related to json and 'get' operations. Apparently some setting somewhere needs to be set to allow this (it doesn't appear to be supported out of the box). I just switched to using Post and everything worked like a charm.
BitFiddler
A: 

For our site we have a big action that requires some time. That action is composed by subactions, we aggregate the results and we build a nice view.

One year ago:

  • We were doing that in a sequence: action1, then action2, etc.
  • We had that typical page of: please wait.

Tricks that can help you:

  • We do parallel requests on the server side.
  • We wait for results in a results page. The javascript there needs some time to load, so while the server searches, we load the page.
  • We ask the server every second: have you finished? And we get partial results as the different actions complete.

I don't know if you can apply all of these things to your problem but some of then can be really nice.

We don't use MVC, we use some asmx services with jQuery and ajax.

graffic