#NYCcamp
@WeAreGenuine
AJAX Callback Commands /
@mikemiles86
From: Boston, MA USA
Work:
Genuine
@WeAreGenuine(.com)
(I have stickers!)
Exp: Working with Drupal since 2008.
Acquia Certified. 2014 Acquia MVP.
Twitter: @mikemiles86
Drupal.org: mikemiles86
All the Places: mikemiles86
// Provide a series of commands that the server can request the client perform.
Drupal.ajax.prototype.commands = {
//...
/**
* Command to remove a chunk from the page.
*/
remove: function (ajax, response, status) {
var settings = response.settings || ajax.settings || Drupal.settings;
Drupal.detachBehaviors($(response.selector), settings);
$(response.selector).remove();
},
//...
}
misc/ajax.js
/**
* Creates a Drupal Ajax 'remove' command.
*/
function ajax_command_remove($selector) {
return array(
'command' => 'remove',
'selector' => $selector,
);
}
includes/ajax.inc
As a user
When I navigate to the 'my-messages' page
Then I see a list of my unread messages
And I see a list of my read messages
When I click on an unread message
Then the full messaged is retrieved from the server
And I see the content of my message
And the message is removed from the unread messages list
And the message is added to the read messages list
// Render a page of messages.
function mymodule_messages_page() {
// Include AJAX library.
drupal_add_library('system', 'drupal.ajax');
// Create inital page content.
$content = theme_item_list(array(
'title' => t('Unread Messages'),
'type' => 'ul',
'attributes' => array( 'id' => 'unread-msgs'),
'items' => mymodule_messages_list(mymodule_get_unread_messages()),
));
$content .= '';
$content .= theme_item_list(array(
'title' => t('Read Messages'),
'type' => 'ul',
'attributes' => array('id' => 'read-msgs'),
'items' => mymodule_messages_list(mymodule_get_read_messages(), FALSE),
));
return $content;
}
mymodule/mymodule.module
// Return array of message titles for use in a list.
function mymodule_messages_list($messages, $display_link = TRUE) {
$list_items = array();
foreach ($messages as $mid => $msg) {
// Build link to AJAX callback to load message.
$link = l($msg->subject, 'read-message-callback/nojs/' . $mid, array(
// Add class to link so Drupal knows to use AJAX.
'attributes' => array('class' => array('use-ajax')),
));
// Create list item for message.
$list_items[] = array(
'id' => 'msg-' . $mid,
// Set data to read message link or just message subject.
'data' => $display_link ? $link : $msg->subject,
);
}
return $list_items;
}
mymodule/mymodule.module
// Implements hook_menu().
function mymodule_menu() {
$items = array();
//.. Other menu items.
// None JS callback, for graceful degredation.
$items['read-message-callback/nojs/%'] = array(
'title' => 'AJAX Callback to Read Message',
'access arguments' => array('access content'),
'page callback' => 'mymodule_read_message_callback',
'page arguments' => array(1,2),
'type' => MENU_CALLBACK,
);
// Create AJAX callback. Add ajax_delivery callback.
$items['read-message-callback/ajax/%'] = array(
'delivery callback' => 'ajax_deliver',
) + $items['read-message-callback/nojs/%'];
return $items;
}
mymodule/mymodule.module
// AJAX Callback to read a message.
function mymodule_read_message_callback($method, $mid) {
$message = mymodule_load_message($mid);
// @TODO: Graceful degredation if not from ajax method or if no message.
$commands = array(
// Replace content of current message subject.
ajax_command_html('#current-msg h2', $message->subject),
// Replace content of current message body.
ajax_command_html('#current-msg p', $message->content),
// Remove message from unread list.
ajax_command_remove('#msg-' . $mid),
// Add message to read list
ajax_command_append('#read-msgs', '' . $message->subject . ' '),
);
// Return an AJAX render array.
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
mymodule/mymodule.module
That's it.
(function($, Drupal) {
// Add new command for reading a message.
Drupal.ajax.prototype.commands.readMessage = function(ajax, response, status){
// Place content in current-msg div.
$('#current-msg h2').html(response.subject);
$('#current-msg p').html(response.content);
// Remove from unread list.
$('#msg-' + response.mid).remove();
// Add message to read list.
$('#read-msgs').append('' + response.subject + ' ');
}
})(jQuery, Drupal);
mymodule/js/commands.js
/**
* AJAX command to read a message.
*/
function mymodule_command_read_message($message) {
return array(
'command' => 'readMessage',
'mid' => $message->mid,
'subject' => $message->subject,
'content' => $message->content,
);
}
mymodule/mymodule.module
Again...that's it.
// Render a page of my messages
function mymodule_messages_page() {
// Include AJAX library.
drupal_add_library('system', 'drupal.ajax');
// Include custom JavaScript.
drupal_add_js(drupal_get_path('module', 'mymodule') . '/js/commands.js');
// .. Build $content.
return $content;
}
mymodule/mymodule.module
// AJAX Callback to read a message.
function mymodule_read_message_callback($method, $mid) {
$message = mymodule_load_message($mid);
// @TODO: Graceful degredation if not from ajax method or if no message.
$commands = array(
// Call the readMessage javascript function.
mymodule_command_read_message($message),
);
// Return an AJAX render array.
return array(
'#type' => 'ajax',
'#commands' => $commands,
);
}
mymodule/mymodule.module
/**
* Provide a series of commands that the client will perform.
*/
Drupal.AjaxCommands.prototype = {
//...
/**
* Command to remove a chunk from the page.
*/
remove: function (ajax, response, status) {
var settings = response.settings || ajax.settings || drupalSettings;
$(response.selector).each(function () {
Drupal.detachBehaviors(this, settings);
}).remove();
},
//...
}
misc/ajax.js
Must implement 'render' method
namespace Drupal\Core\Ajax;
use Drupal\Core\Ajax\CommandInterface;
// AJAX command for calling the jQuery remove() method.
class RemoveCommand Implements CommandInterface {
protected $selector;
// Constructs a RemoveCommand object.
public function __construct($selector) {
$this->selector = $selector;
}
// Implements Drupal\Core\Ajax\CommandInterface:render().
public function render() {
return array(
'command' => 'remove',
'selector' => $this->selector,
);
}
}
core/lib/Drupal/Core/Ajax/RemoveCommand.php
// Render a page of my messages
function mymodule_messages_page() {
// .. build $content
// Create render array.
$page[] = array(
'#type' => 'markup',
'#markup' => $content,
);
// Attach JavaScript library.
$page['#attached']['library'][] = 'core/drupal.ajax';
return $page;
}
mymodule/mymodule.module
// AJAX Callback to read a message.
function mymodule_read_message_callback($method, $mid) {
$message = mymodule_load_message($mid);
// @TODO: Graceful degredation if not from ajax method or if no message.
// Create AJAX Response object.
$response = new AjaxResponse();
// Replace content of current message subject.
$response->addCommand(new HtmlCommand('#current-msg h2', $message->subject));
// Replace content of current message body.
$response->addCommand(new HtmlCommand('#current-msg p', $message->content));
// Remove message from unread list.
$response->addCommand(new RemoveCommand('#msg-' . $mid));
// Add message to read list.
$item = '<li>' . $message->subject . '</li>';
$response->addCommand(new AppendCommand('#read-msgs', $item));
);
// Return ajax response.
return $response;
}
mymodule/mymodule.module
(function($, Drupal) {
/**
* Add new command for reading a message.
*/
Drupal.AjaxCommands.prototype.readMessage = function(ajax, response, status){
// Place content in current-msg div.
$('#current-msg h2').html(response.subject);
$('#current-msg p').html(response.content);
// Remove from unread list.
$('#msg-' + response.mid).remove();
// Add message to read list.
$('#read-msgs').append('' + response.subject + ' ');
}
})(jQuery, Drupal);
mymodule/js/commands.js
namespace Drupal\mymodule\Ajax;
use Drupal\Core\Ajax\CommandInterface;
class ReadMessageCommand implements CommandInterface {
protected $message;
// Constructs a ReadMessageCommand object.
public function __construct($message) {
$this->message = $message;
}
// Implements Drupal\Core\Ajax\CommandInterface:render().
public function render() {
return array(
'command' => 'readMessage',
'mid' => $this->message->mid,
'subject' => $this->message->subject,
'content' => $this->message->content,
);
}
}
mymodule/src/Ajax/ReadMessageCommand.php
mymodule.commands:
version: VERSION
js:
js/commands.js: {}
dependencies:
- core/drupal.ajax
mymodule/mymodule.libraries.yml
// Render a page of my messages
function mymodule_messages_page() {
// .. build $content
// Create render array.
$page[] = array(
'#type' => 'markup',
'#markup' => $content,
);
// Attach JavaScript library.
$page['#attached']['library'][] = 'mymodule/mymodule.commands';
return $page;
}
mymodule/mymodule.module
// AJAX Callback to read a message.
function mymodule_read_message_callback($method, $mid) {
$message = mymodule_load_message($mid);
// @TODO: Graceful degredation if not from ajax method or if no message.
// Create AJAX Response object.
$response = new AjaxResponse();
// Call the readMessage javascript function.
$response->addCommand( new ReadMessageCommand($message));
);
// Return ajax response.
return $response;
}
mymodule/mymodule.module
Drupal AJAX Framework: bit.ly/DrupalAJAX
Examples Module: bit.ly/DrupalExMod
Drupal 7 Commands: bit.ly/D7ajaxCMD
Drupal 8 Commands: bit.ly/D8ajaxCMD
This Presentation: bit.ly/NYCcampAJAX
Presentation Slides: bit.ly/NYCcampAJAXSlides
Example Code: bit.ly/NYCcampAJAXEx
Questions?