Skip to main content
ComputerMinds

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

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:

James Silver · 2 min read

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:

<code class="language-php hljs">
$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));
</code>

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

<code class="language-php hljs">
  $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,
  );
</code>

And the callback code is:

<code class="language-php hljs">
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();
}
</code>

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:

<code class="language-php hljs">
// 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));
</code>

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

<code class="language-php hljs">
  $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/%'];
</code>

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

<code class="language-php hljs">
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();
  }
}
</code>

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

Written by

James Silver

Meet the team