23rd February 2012

Trigger Drupal managed AJAX calls at any time with Drupal 7

John Ennew
Technical Director

In a previous article I described how to trigger a CTools AJAX callback at any time, not just on an onclick event or form submission. This will only work with Drupal 6.  In Drupal 7, much of this functionality has now been brought into Drupal Core, which is great. Unfortunately, it also appears to have been changed considerably.  In this article I give a demonstration on how to achieve the same functionality with Drupal 7.

In this example you will create your own custom module again, called 'mymodule'.

Here is the contents of the mymodule.info file:

name = mymodule description = My Module core = 7.x scripts[] = js/mymodule.js 

In your mymodule file, let's start by defining the hook_menu which will define the path the ajax request will be made to.


/**
 * Implements hook_menu().
 */
function mymodule_menu() {
  $items = array();

  $items['mymodule/refresh-elements'] = array(
    'title' => 'AJAX callback - refresh the elements on the page',
    'page callback' => 'mymodule_refresh',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );

  return $items;
}

If you are comparing this with the previous Drupal 6 tutorial with CTools you will see there is no need to define the %ctools_js item here.  Next, we define the actual callback function which will do the processing and send the page change requests back to the browser. Add the following to mymodule.module file.


/**
 * Menu callback.
 */
function mymodule_refresh($action, $type) {
  if ($type != 'ajax') {
    // This is js only.
    return 'Oh well';
  }

  $commands = array();
  $commands[] = ajax_command_replace('.some-class', date('G:i:s'));
  $page = array('#type' => 'ajax', '#commands' => $commands);
  ajax_deliver($page);
}

The arguments to this function are each path element past the first one.  If our site was stored at http://www.example.com then the hook_menu defines a path at http://www.example.com/mymodule/refresh-elements.  When the mymodule_refresh function is called, the $action variable will be the string 'refresh-elements'.  If a third element was added to the path, then the $type variable would get filled with this. http://www.example.com/mymodule/refresh-elements/ajax - $type will be the string 'ajax'.  This will be the actual url we will use.

We also need to make use of the drupal.ajax library which we will include in the hook_init for this tutorial. Put this in the mymodule.module file.


/**
 * Implements hook_init().
 */
function mymodule_init() {
  drupal_add_library('system', 'drupal.ajax');
}

Now make a js folder in your mymodule folder and create a file called mymodule.js in it. This will contain our custom javascript.  This file is going to be included on every page of the site when the module is enabled. We specified this in the info file by defining the javascript file with the scripts[].  The javascript file contents look like this:


(function($){

  /**
   * Add an extra function to the Drupal ajax object
   * which allows us to trigger an ajax response without
   * an element that triggers it.
   */
  Drupal.ajax.prototype.specifiedResponse = function() {
    var ajax = this;

    // Do not perform another ajax command if one is already in progress.
    if (ajax.ajaxing) {
      return false;
    }

    try {
      $.ajax(ajax.options);
    }
    catch (err) {
      alert('An error occurred while attempting to process ' + ajax.options.url);
      return false;
    }

    return false;
  };

  /**
   * Define a custom ajax action not associated with an element.
   */
  var custom_settings = {};
  custom_settings.url = '/mymodule/refresh-elements/ajax/';
  custom_settings.event = 'onload';
  custom_settings.keypress = false;
  custom_settings.prevent = false;
  Drupal.ajax['custom_ajax_action'] = new Drupal.ajax(null, $(document.body), custom_settings);

  /**
   * Define a point to trigger our custom actions. e.g. on page load.
   */
  $(document).ready(function() {
    Drupal.ajax['custom_ajax_action'].specifiedResponse();
  });

})(jQuery);                               

To make this work we define an ajax action and then execute the action.

In the definition, the items you will need to change for your own purposes will be the custom_settings.url for your own module and path. The other settings will be left alone.  If you want to do more than one ajax request, duplicate the bits from var custom_settings = {}; to Drupal.ajax['custom_ajax_action'] ... changing each url for each action and also changing 'custom_ajax_action' string so it is unique for each action.

To trigger the action you need to run Drupal.ajax['custom_ajax_action'].specifiedResponse(); at the right time in your own javascript code. Above I have run it at page load.

Now, to see this work, crete a node add add something with a class of some-class and watch it be replaced with the current time.

Initial text

For some general information about using javascript in Drupal 7, check out this page. For general tutorial on Drupal 7's ajax features then check out this page.