fbpx Create a Drupal ajax link in Drupal 7 (it's easy) | ComputerMinds Skip to main content

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

14th Feb 2012

James Silver

Senior Developer

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.