Skip to main content

Create a Drupal ajax link in Drupal 7 (it's easy)

An article from ComputerMinds - Building with Drupal in the UK since 2005
14th Feb 2012

James Silver

Developer
Hey, you seem to look at this article a lot! Why not Bookmark this article so you can find it easily in the future?

Part 1: Make the link work without javascript

In this example we have a table listing log entries of some kind. We want to put a delete link against each log entry allowing the administrator to delete the log entry:

The following code is responsible for printing out each link onto the page:


$query = array(
  'tok' => drupal_get_token('delete_log_item' . $flid),
) + drupal_get_destination();
$output[] = l(t('Delete'), 'admin/my-custom-log/delete/' . $flid, array('query' => $query));

The callback of which is defined by the following hook_menu item:


  $items['admin/my-custom-log/delete/%'] = array(
    'page callback' => 'my_custom_log_entry_delete',
    'page arguments' => array(3),
    'access arguments' => array('permission name'),
    'type' => MENU_CALLBACK,
  );

And the callback code is:


function my_custom_log_entry_delete($flid) {
  
  if (empty($_GET['tok']) || !drupal_valid_token($_GET['tok'], 'delete_log_item' . $flid)) {
    return MENU_ACCESS_DENIED;
  }
  
  db_delete('my_custom_log')
    ->condition('flid', $flid)
    ->execute();

    drupal_set_message(t('Deleted 1 message'));
    drupal_goto();
}

Part 2: Ajaxify it

Three simple steps:

  1. Make the link be requested with ajax.

  2. Identify on the server-side when the link has been requested by ajax.

  3. Decide what we want to do with the page when responding to an ajax request.

One Simply add the class 'use-ajax' to the link and it will ajax. Also add in 'nojs' into the url. This will be rewritten automatically by Drupal JS as 'ajax' when it is being requested using ajax:


// Make sure Drupal Ajax framework javascript is around
drupal_add_library('system', 'drupal.ajax');

$query = array(
  'tok' => drupal_get_token('delete_log_item' . $flid),
) + drupal_get_destination();
$output[] = l(t('Delete'), 'admin/my-custom-log/delete/nojs/' . $flid, array('attributes' => array('class' => 'use-ajax'), 'query' => $query));

Two Change our hook_menu item to include a 'nojs' and 'ajax' version of the path. We can use the same callback:


  $items['admin/my-custom-log/delete/nojs/%'] = array(
    'page callback' => 'my_custom_log_entry_delete',
    'page arguments' => array(3, 4),
    'access arguments' => array('permission name'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/my-custom-log/delete/ajax/%'] = array(
    'delivery callback' => 'ajax_deliver',
  ) + $items['admin/my-custom-log/delete/nojs/%'];

Three Make our callback respond with something sensible when on an ajax request:


function my_custom_log_entry_delete($ajax, $flid) {
  
  $is_ajax = $ajax === 'ajax';
  
  // Since clicking this link updates the database, we used drupal_get_token() for security.
  if (empty($_GET['tok']) || !drupal_valid_token($_GET['tok'], 'delete_log_item' . $flid)) {
    return MENU_ACCESS_DENIED;
  }
  
  db_delete('my_custom_log')
    ->condition('flid', $flid)
    ->execute();
  
  if ($is_ajax) {
    $commands = array();
    
    // Perhaps we could remove the table row we just deleted?
    $commands[] = ajax_command_remove('.my-custom-log tr.flid-' . $flid);
    
    return array(
      '#type' => 'ajax',
      '#commands' => $commands,
    );
  }
  else {
    drupal_set_message(t('Deleted 1 message'));
    drupal_goto();
  }
}

Easy peasy. And for that last bit you can return any number of Drupal ajax commands you want.

Hi, thanks for reading

ComputerMinds are the UK’s Drupal specialists with offices in Bristol and Coventry. We offer a range of Drupal services including Consultancy, Development, Training and Support. Whatever your Drupal problem, we can help.