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();
                });

            })
  • 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 Dec 14 '13 at 7:02
  • Just after the async jobs. – Daniel Hoechst Dec 14 '13 at 14:22
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;" />
  • 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. – Daniel Hoechst Dec 14 '13 at 16:51
  • Never mind. Copy paste error. All is working! Thanks for the great answer and explanations. – Daniel Hoechst Dec 14 '13 at 17:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.