Drupal - How can I trigger a javascript function when a Drupal ajax call is complete?

I ended up adding some additions commands to the page that is being returned by the ajax handler like this:

$commands = array();
$commands[] = ajax_command_invoke(NULL, 'grid_content_loading', array('argument1', 'argument2'));
$commands[] = ajax_command_append('#grid-content-target', $html);
$commands[] = ajax_command_invoke(NULL, 'grid_content_loaded', array('argument1', 'argument2'));
$page = array('#type' => 'ajax', '#commands' => $commands);
ajax_deliver($page);

And on the client side I created 2 javascript funtions through jQuery:

(function($) {
$.fn.grid_content_loading = function($argument1, $argument2) {
   ...
};

$.fn.grid_content_loaded = function($argument1, $argument2) {
   ...
};
})(jQuery);

In my project, I had already written well-defined JavaScript code that updated the page stats after an AJAX call.

Since I wanted to reuse the functions without going to the extent of "extending jQuery", I ended up with the following solution, using an existing jQuery function, instead of defining a new one. This was inspired by what the 'flags' module does -- it simply triggers an event, and allows many Javascript event listeners to act in response, as opposed to having just a single hard-coded, custom jQuery plugin/extension as in the solution explored in the previous answers.

In a Drupal Module:

// in_some_ajax_function()

$commands[] = ajax_command_invoke('html', 'trigger', array('MY_EVENT'));

In Javascript:

// Added an event binding to my $(document).ready();

$(document).ready(function(){

  $(document).bind('MY_EVENT', function() {
    alert('MY_EVENT');
  });

});

I had to note that the first parameter for ajax_command_invoke is NEVER any native JavaScript objects, so the following never works, because it translates into a 'document' (element) selector:

// This tries to select $('document')
// ... which is nothing, since there are no 'document' elements.

$commands[] = ajax_command_invoke('document', 'trigger', array('MY_EVENT'));

Curiously, binding on $(document) and triggering on $('html') are compatible. I suppose you can get very creative, and bind/trigger on more specific, deeper-level elements. If you can think of a scenario where doing so makes more sense than a top-level event trigger, please comment!


Code sample:

$commands = array();
$commands[] = array(
    'command' => 'your_js_callback', // the name of your javascript callback
    'value1'  => 'My first value',
    'value2'  => 'My second value',
);
ajax_render($commands);

JS Code:

(function($, Drupal) {
    Drupal.ajax.prototype.commands.your_js_callback = function(ajax, response, status) {
        alert(response.value1);
        alert(response.value2);
    }
})(jQuery, Drupal);

Tags:

Javascript

Ajax

7