Drupal 7 Javascript Ajax Framework example from a link

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

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.

5 Secrets to Becoming a Drupal 7 Ninja

Comments

Kindly change the name of the module its name is same as core module which test the ajax system.

Good catch. I changed the name of the module to prevent using the same namespace.

Thanks for the comment.

Heya i'm for the first time here. I found this board and I find It really useful & it helped me out much. I hope to give something back and aid others like you aided me.

Drupal 7 frame work is not easy for new users but these type of post with a perfect example helps them immensely. I am looking for broader picture. Anyway this helps! Thanks for providing author

Thank you for the help!
Keep up the good work!

This article and your video were a big help, thank you!

I'm facing an issue trying to use this with an existing named node/page
call it "http://my_drupal_site/test-toc-page"

when I add the $items['test-ajax-page'] = array(
and all the other code that works with the 'fake' pages (they only exist as paths in the module items array), it never gets called for the test-toc-page that's actually in the Drupal site.

Is another step required for pages that already actually exist?

i have created the ajax enabled link . but i am not able to update view after deteting some of the item .how can i achieve it .

Thanks for this help.

I have been using the link for generating pdf using itext.I am using apache-wicket as front end .I need to generate pdf based on the check box selection in the grid.Once the pdf is generated i need to disable the check boxes in the grid.

Thanks for the future suggestions inadvance

Hi
I have used this example to work on ajax operation. it worked very fine, but when i am trying to do same ajax functionality suing button click i was unable to call the ajax can u please help me out... Here is the code i have used for ajax button markup..

$form['my_form_submit'] = array(

'#type' => 'submit',
'#value' => t('On click'),
'#weight' => 1,
'#ajax' => array(
'callback' => 'events_ajax_pager_content',
'wrapper' => 'ajax-display',
),
'#prefix' => '',
'#suffix' => '',
);

return $form;

Thanks.....

very well explained, thanks for taking the time.

Very clear and useful, thank you. So much Drupal stuff on the web is over-complicated. This is clean and easy to understand.

Post new comment