6

I have a page that prompts the user for information and may need to do multiple web service callouts. Each callout needs to do DML when complete, so I'm using Visualforce Remoting to perform those actions first. Once the actions are complete, I need to execute an Apex method to do some more work. This may be more of a JavaScript question, but hopefully someone has the answer.

Right now, the page doesn't wait for all the remoting calls to finish before invoking the action. How can I get it to wait?

My Button:

<apex:commandButton action="{!buildFax}" onclick="checkForCharts(function(){return true});" value="Build Fax" />

My JS (somewhat simplified):

function getChart(client, accession, callback) { 
        PatientCharts.getPatientChartToSObjectRemote(
        '{!theCase.Id}',
        client,
        accession,
        function(result, event){
            callback(event);
        });
    }

    function checkForCharts(docallback) {
        // Async worker counters
        var workers = 0;

        function tickWorkers() {
            workers--;
            if ( workers === 0 ) {
                if (docallback)
                    docallback();
            }
        }

        j$('[id$="patTab"]')
            .find('input[type="checkbox"][name$="chart"]:checked').closest('tr')
            .each(function() {
                var client = j$(this).find('[id$="client"]').text();
                var accession = j$(this).find('[id$="accn"]').text();
                workers++;
                getChart(client, accession, function(eventres) {
                    tickWorkers();
                });

            })
2
  • Do the actions and callbacks need to be chained in a particular order or is it just at the very end after a bunch of parallel async calls that the apex needs to run?
    – Mark Pond
    Commented Dec 14, 2013 at 7:02
  • Just after the async jobs. Commented Dec 14, 2013 at 14:22

1 Answer 1

8

The answer is apex:actionFunction to generate a JavaScript function bound to an APEX method that can be passed as a JavaScript callback.

Let's try to understand, what happens when pressing your button:

<apex:commandButton action="{!buildFax}" onclick="checkForCharts(function(){return true});" value="Build Fax" />

Of course, the onclick code is executed first. It means invoking checkForCharts, that correctly starts the asynchronous workers and returns no value. Then the returned value (in our case nothing, or rather the undefined constant) is checked:

  • if it's identical to false, no further actions are executed,
  • otherwise the action method is called normally.

Thus the method buildFax is called immediately after setting up workers, not waiting for evaluation of the callback.

After this long introduction, the fix is easy:

<apex:actionFunction action="{!buildFax}" name="doBuildFax" />
<apex:commandButton value="Build Fax" onclick="checkForCharts(doBuildFax); return false;" />
2
  • Thanks! I think that is going to work, but there must be something wrong with my async worker logic. The callback is coming too early still. Commented Dec 14, 2013 at 16:51
  • Never mind. Copy paste error. All is working! Thanks for the great answer and explanations. Commented Dec 14, 2013 at 17:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .