Drupal 7 Javascript Ajax Framework example from a link

By shane
Fri, 2012-11-23 11:24
comments

Share with Others

Drupal 7 Ajax Framework Example

For a Daily Dose of Drupal episode that covers this blog post topic as well, take a look at Drupal 7 Ajax Framework Link Example.

After struggling to find documentation on how to take advantage of the Drupal Ajax Framework with just a simple HTML link I decided to provide an example to anyone else who might be struggling with the same problem. The documentation on drupal.org is very detailed, however most of the documentation centers around using the Drupal 7 Ajax Framework with forms. In this case I just want to use the Drupal 7 Ajax Framework with a simple link.

I am going to start by creating a simple module that will provide an example. First we create the ajax_link.info file:


name = "Ajax Link Test"
description = "A simple Ajax link example"
core = 7.x

The next step is to create the ajax_link.module file. In this module file we start with the hook_menu implementation. We will first just create the hook_menu implementation for a very simple page.

/**
 * Implements hook_menu().
 */
function ajax_link_menu() {
  $items = array();
 
  $items['ajax-test'] = array(
    'title' => 'Ajax Test',
    'type' => MENU_NORMAL_ITEM,
    'page callback' => 'ajax_link_page',
    'access arguments' => array('access content'),
  );
 
  return $items;
}

Next we create the page callback for our hook_menu implementation. This page just displays a simple link that will load additional HTML to the page using Ajax when clicked.

/**
 * Callback function that displays a simple Ajax powered link.
 */
function ajax_link_page() {
  return array(
    '#type' => 'link',
    '#title' => t('Ajax Link'),
    '#href' => 'my-ajax-test/nojs',
    '#prefix' => '<div id="ajax-link">',
    '#suffix' => '</div><div id="ajax-display"></div>',
    '#ajax' => array(
      'effect' => 'fade',
    ),
  );
}

Now we save everything, clear the cache and take a look at the page.

Drupal 7 Ajax Framework test page

It is not working yet, we need to create the hook_menu item for the Ajax callback. Our hook_menu implementation now looks like:

/**
 * Implements hook_menu().
 */
function ajax_link_menu() {
  $items = array();
 
  $items['ajax-test'] = array(
    'title' => 'Ajax Test',
    'type' => MENU_NORMAL_ITEM,
    'page callback' => 'ajax_link_page',
    'access arguments' => array('access content'),
  );
 
  $items['my-ajax-test/%'] = array(
    'title' => 'Ajax test callback',
    'type' => MENU_CALLBACK,
    'page callback' => 'ajax_link_callback',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
  );
 
  return $items;
}

We now create the Ajax callback. We build this out to handle both Ajax calls and requests with no Javascript. The Ajax framework will replace the "nojs" part of the path with "ajax" when the link is clicked.

/**
 * Ajax callback to display the current time.
 */
function ajax_link_callback($ajax) {
  // Do any database queries, processing, etc.
  $time = t('The current time is: !time', array('!time' => date('Y-m-d H:i:s')));
 
  if ($ajax == 'ajax') {
    $commands = array();
    // Ajax command to replace the #ajax-display element with the current time.
    $commands[] = ajax_command_replace('#ajax-display', "<div id='ajax-display'>" . $time . "</div>");
    // Add a visual "changed" marker to the '#ajax-display' element.
    $commands[] = ajax_command_changed('#ajax-display');
    // Menu 'page callback' and #ajax['callback'] functions are supposed to
    // return render arrays. If returning an Ajax commands array, it must be
    // encapsulated in a render array structure.
    ajax_deliver(array('#type' => 'ajax', '#commands' => $commands));
  }
  else {
    // No ajax, just display the time on a page using renderable array.
    return array(
      '#markup' => $time,
    );
  }
}

We now have everything we need for a simple example. The comments in the code examples should help explain what is going on. Lets look at a screenshot of what it looks like after the link is clicked.

Drupal 7 Ajax Framework response

The last step was one that took me awhile to figure out. What if you want to execute or trigger some extra JavaScript/Jquery after the Ajax call is complete. Perhaps you need to manipulate other things on the page, or need to modify the html that was just loaded through the Drupal 7 Ajax Framework. In this case the easiest way I found is to build a simple Jquery plugin and call that plugin using the ajax_command_invoke function.

The first step is to create the JavaScript file, we will call it ajax_link.js. In this example I simply hide the Ajax link, set a timeout to remove the loaded content after 5 seconds, and then re-display the Ajax link. You could of course do anything you needed to in the JavaScript file. Below is my jQuery plugin.

(function($) {
  $.fn.ajax_link = function() {
    $('#ajax-link').hide();
    setTimeout(function() {
      $('#ajax-display').fadeOut().html("").show();
      $('#ajax-link').fadeIn();
    }, 5000)
  }
})(jQuery);

We need to modify the info file to make sure this Javascript file is added on every page.


name = "Ajax Test"
description = "A simple Ajax link example"
core = 7.x
scripts[] = ajax_link.js

The last step is to add the ajax_command_invoke function call to our Ajax callback in our module file.

/**
 * Ajax callback to display the current time.
 */
function ajax_link_callback($ajax) {
  // Do any database queries, processing, etc.
  $time = t('The current time is: !time', array('!time' => date('Y-m-d H:i:s')));
 
  if ($ajax == 'ajax') {
    $commands = array();
    // Ajax command to replace the #ajax-display element with the current time.
    $commands[] = ajax_command_replace('#ajax-display', "<div id='ajax-display'>" . $time . "</div>");
    // Add a visual "changed" marker to the '#ajax-display' element.
    $commands[] = ajax_command_changed('#ajax-display');
    // Trigger our ajax_link jQuery plugin.
    $commands[] = ajax_command_invoke(NULL, "ajax_link");
 
    // Menu 'page callback' and #ajax['callback'] functions are supposed to
    // return render arrays. If returning an Ajax commands array, it must be
    // encapsulated in a render array structure.
    ajax_deliver(array('#type' => 'ajax', '#commands' => $commands));
  }
  else {
    // No ajax, just display the time on a page using renderable array.
    return array(
      '#markup' => $time,
    );
  }

That is it. You can now test out a working example of loading content through the Drupal 7 Ajax Framework using a link. After the link loads the Ajax content, you trigger additional JavaScript to be run on the page. Simple as that!

Let me know if you have other ways of doing something like this in the comments below.