Create a Drupal ajax link in Drupal 7 (it's easy)
James Silver
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:
-
Make the link be requested with ajax.
-
Identify on the server-side when the link has been requested by ajax.
-
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.