Block UI and show message until sforce.connection.remoteFunction() call completes

My question is along the same lines as this post How to show wait message that is used by actions.

I am trying to accomplish the same using the Action Framework.  See screenshot below:




My issue is that the first Show Message and block UI is never shown (or is happening so fast that it is not perceptible).  The async remote call is executed and falls through to the next action w/o waiting until the promise is invoked.

What are my options?  Any guidance is appreciated.

Best,
Irvin

Irvin, what does your Snippet look like? What you’ll probably need to do is to re-write your Snippet to make it return a jQuery Deferred’s Promise, which you can resolve in the onSuccess of your call to sforce.connection.remoteFunction(), for instance. By having your Snippet return a jQuery Promise, the Action Framework knows that you are doing an asynchronous operation, and waits until the Promise is resolved to carry on with additional steps.

So for instance, you could rewrite your Snippet to look something like this:

// Create a jQuery Deferred<br>var dfd = $.Deferred(); <br>var url = '/some/remotesite';<br>var sessionId = skuid.utils.userInfo.sessionId; <br>sforce.connection.remoteFunction({<br>&nbsp; &nbsp;url : url,&nbsp;<br>&nbsp; &nbsp;requestHeaders: {<br>&nbsp; &nbsp; &nbsp; "Authorization":"Bearer "+sessionId,&nbsp;<br>&nbsp; &nbsp; &nbsp; "Content-Type":"application/json",&nbsp;<br>&nbsp; &nbsp; &nbsp; "Connection":"Keep-Alive"&nbsp;<br>&nbsp; &nbsp;},&nbsp;<br>&nbsp; &nbsp;method: "GET",&nbsp;<br>&nbsp; &nbsp;onSuccess : function(response) {&nbsp;<br>&nbsp; &nbsp; &nbsp; dfd.resolve(response);&nbsp;<br>&nbsp; &nbsp;},&nbsp;<br>&nbsp; &nbsp;onFailure : function(response) {&nbsp;<br>&nbsp; &nbsp; &nbsp; dfd.reject(response);<br>&nbsp; &nbsp;}&nbsp;<br>}); <br>// Return the Deferred's Promise<br>return dfd.promise();



Notice how we create a Deferred, then in the onSuccess function we call dfd.resolve() to indicate that our asynchronous operation completed successfully, and in the onFailure function we call dfd.reject() to indicate that something went wrong. The Snippet then returns the Deferred’s Promise, telling Skuid to delay further Actions until the Deferred is either resolved — in which case the Action sequence continues — or rejected, in which case any On-Error Actions defined for this action will be executed.

Hi Zach,

Simply returning the promise did the trick.  

Is this documented anywhere?  If not, this would be a great FAQ.  

As always, thanks for the guidance and timely reply.

Best,
Irvin

Not currently documented anywhere, we definitely need to add an article about this.

Agreed! This post is super-helpful. It would be great to have some documentation on this.

I am having a similar problem.

Can this Deferred Promise technique be used with sforce.apex.execute?

Or do I have to rewrite my code to use sforce.connection.remoteFunction?

Here’s my code snippet:

var params = arguments[0], $ = skuid.$; $.blockUI({ message: 'Waiting...', timeout: 5000 }); var MtgModel = skuid.model.getModel(Items); var eventModel = skuid.model.getModel('Event'); var eventRow = eventModel.getFirstRow() var mtgIds = ''; $.each(MtgModel.getRows(),function(i,row){ if (myIds !== '') myIds = myIds + ','; myIds = myIds + row.Id; }); var result = sforce.apex.execute( 'MyWebservice','MyFunction',{inputString:myIds ,eventId:eventRow.Id} ); $.unblockUI(); $.blockUI({ message: 'Done<br>' + result, timeout: 5000 }); 

Suggestions on how to adapt this to properly block the UI are appreciated.

Thanks,
Tony

Tony,

From what I’ve seen, sforce.apex.execute() is synchronous, meaning that JavaScript’s execution should be blocked until your call finishes, so I would expect that the sequence here would work fine, although you don’t need the $.unblockUI() call at the end — the subsequent $.blockUI() call with a timeout will unblock the UI after 5000 milliseconds. If you’re seeing the UI get unblocked before sforce.apex.execute finishes, then that would be surprising.

Thanks Zach.

I tried removing the unblockUI call. Still a problem.

The behavior I am seeing is this:

– First Block UI message never shows
– A couple seconds go by as the apex code runs
– the Second Block UI message shows once the apex is done

Can’t think of any reason why the sforce.apex.execute would unblock the UI but that seems to be what is happening.

Thoughts?

Tony



Can you put some console.logs in place so we can get an idea of what’s happening? Try this:

var params = arguments[0],
$ = skuid.$;
console.log(‘before show waiting message’);
$.blockUI({ message: ‘Waiting…’, timeout: 5000 });
console.log(‘after show waiting message’); 
var MtgModel = skuid.model.getModel(Items);
 var eventModel = skuid.model.getModel(‘Event’);
 var eventRow = eventModel.getFirstRow();
 var mtgIds = ‘’;
$.each(MtgModel.getRows(),function(i,row){
    if (myIds !== ‘’) myIds = myIds + ‘,’;
    myIds = myIds + row.Id;
 });
console.log(‘before execute apex’); 
var result = sforce.apex.execute( ‘MyWebservice’,‘MyFunction’,{inputString:myIds ,eventId:eventRow.Id} );
console.log(‘after execute apex’); 
console.log(‘before block ui with done message’); 
$.blockUI({
 message: 'Done ’ + result,
 timeout: 5000
});
console.log(‘after block ui with done message’); 

Sure thing. Here’s what I got from my Firefox Console

before show waiting message Test:333:1
after show waiting message Test:339:1
before execute apex Test:355:1
POST XHR https://c.cs11.visual.force.com/services/Soap/package/MyWebservice [HTTP/1.1 200 OK 6747ms]
after execute apex Test:359:5
before block ui with done message Test:360:5
after block ui with done message Test:367:1
POST XHR https://c.cs11.visual.force.com/apexremote


Note that it waits for 6.7 seconds while it makes the Apex call.




Do the messages all show up at once, or does the “after execute” message show up only once the Apex call finishes?

There is a long delay while the apex executes before the “after execute apex” message appears.

Hey Zach - Any thoughts on this?

Would still love to resolve this issue.  What’s my next step here?

Tony, are you running this Snippet as part of an Action Framework sequence? If so, can you post a screenshot of your action sequence?

It’s a pretty simple Action Framework

I tried blocking and unblocking the UI in the action framework rather than in the snippet but that also did not work properly:

In this case the first Show message does not appear until after the Snippet has run. Then the first message appears, then when the second message appears immediately after.

If I comment out the “sforce.apex.execute” call it works as you would expect with the first message showing immediately upon clicking the navigation item.

I could send you a video or give you access to my org if you would like.

Can you try removing the Query 2 Models action and see if that makes the initial Block UI take effect?

When I remove the Query 2 Models it goes:

1. click
2. wait a second or so while snippet runs
3. second block UI message appears

First block UI message never appears.

Wow, this is quite confusing. My recommendation at this point would be to follow the typical debugging path of removing code until you get it to work, then code back in until it stops. So I’d start by just having the code to run your first blockUI message, comment out everything after that. Once you (hopefully) get this to show as expected, start adding in additional code till the first blockUI message stops showing, then we’ll at least have a better idea of which piece of code is the culprit, or if it’s even related to this code at all.

I finally got it to work. The secret was putting my remote call in the “onBlock” parameter to the blockUI call. That way the remote call does not happen until after the onBlock has truly blocked the UI. I have no idea why this is necessary, but it seems to work.

This was key: http://malsup.com/jquery/block/#options

var params = arguments[0], $ = skuid&#46;$; $&#46;blockUI({ message: 'Before Remote Message', onBlock:function(){ &#47;&#47;do stuff var result = sforce&#46;apex&#46;execute( 'MyWebservice','MyFunction',{inputString:ids} ); skuid&#46;model&#46;updateData([Model1,Model2,Model3],function(){ $&#46;blockUI({ message: 'After Remote Message' + result, timeout: 2000 }); }); } });