Demystifying Drupal AJAX Callback Commands http://nerdsummit.org/node/2068 NERDsummit 2015 #NERDsummit
A presentation at NERDSummit in September 2015 in Amherst, MA, USA by Michael Miles
Demystifying Drupal AJAX Callback Commands http://nerdsummit.org/node/2068 NERDsummit 2015 #NERDsummit
Goals of this Session Explain what AJAX callback commands are Demonstrate how to use AJAX callback commands Outline how to create AJAX callback commands
Michael Miles From: Boston, MA USA Work: Genuine @WeAreGenuine(.com) (I have stickers!) Exp: Working with Drupal since 2008. Acquia Grand Master. 2014 Acquia MVP. Twitter: @mikemiles86 Drupal.org: mikemiles86 All the Places: mikemiles86
Warning About Example Code There is example code Some coding standards ignored for presentation purposes Drupal 8 code still subject to change
What Commands Are
From a High Level The response of AJAX request PHP code to instruct JavaScript functions A JavaScript function attached to an object Defined by Drupal core or modules 17 AJAX callback commands in Drupal 7
Example: The “Remove” Command Using the “examples” module (available on Drupal.org), showing using the ‘remove’ AJAX Callback command. The checkbox is checked, which makes an AJAX request, which returns the command to remove the element with the sample text.
On the Client Side [D7] A function on the ‘Drupal.ajax.prototype.commands’ object Receives ‘ajax’, ‘response’ and ‘status’ arguments A wrapper for additional javascript // 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
On the Server Side [D7] A PHP function which returns an associative array Array must have an element with key of ‘command’ The value is the name of a JavaScript function Additional array elements set as response data /** * Creates a Drupal Ajax ‘remove’ command. */ function ajax_command_remove($selector) { return array( ‘command’ => ‘remove’, ‘selector’ => $selector, ); } includes/ajax.inc
How to Use Commands
Example Scenario 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
Example Scenario. Have a page that lists messages to read. When a message subject is clicked, an AJAX request is made to retrieve the message. The server returns an array of commands to run, which updates the page with the selected message.
To Use Commands… 1. Include Drupal AJAX JavaScript library 2. Attach AJAX to page elements 3. Define a callback path and function Returns a render array of commands [D7]
3.a Define a callback path // 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 Creating two menu items for callback functions. The first is for handling graceful degredation when reached outside an AJAX Request. The second is the AJAX callback, which add a delivery callback of “ajax_callback” so Drupal know to return an AJAX Response object.
3.b Return array of commands using a render array [D7] // 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’, ‘<li>’ . $message->subject . ‘</li>’), ); // Return an AJAX render array. return array( ‘#type’ => ‘ajax’, ‘#commands’ => $commands, ); } mymodule/mymodule.module Lines #5 thru #14, building an array of Core AJAX Callback commands. Each mapps to a javascript function. Line #16 building a render array of type ‘ajax’. Drupal will package into JSON and send back to the client.
Creating Custom Commands
To Create a Command… 1. Add a function to the Drupal ajax command JavaScript object 2. Write PHP code that returns an associative array. Must have an element with key of ‘command’ Value is name of the JavaScript function Additional elements for response data
That’s it.
A Custom Command in Drupal 7 1. Add a function to ‘Drupal.ajax.prototype.commands’ 2. Define a PHP function to return an array
Using a custom command… 1. Tell Drupal to include custom JavaScript 2. Return custom command in callback function
Again…that’s it.
Using a Custom Command in Drupal 7 1. Use drupal_add_js() to include custom JavaScript on page 2. Add command to render array returned by callback
AJAX Commands in Drupal 8
Changes to AJAX Commands 22 AJAX callback commands in Drupal 8 JavaScript attatches to ‘Drupal.AjaxCommands.prototype’ object A PHP object that implements CommandInterface Must implement ‘render’ method
Example: The “Remove” Command Using the “examples” module (available on Drupal.org), showing using the ‘remove’ AJAX Callback command. The checkbox is checked, which makes an AJAX request, which returns the command to remove the element with the sample text.
A function on the ‘Drupal.AjaxCommands.prototype’ object /** * 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
An object that implements CommandInterface 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
To Use Commands in Drupal 8 1. Include Drupal AJAX JavaScript library Must attach to a render array 2. Attach AJAX to page elements 3. Define a callback path and function Returns an AjaxResponse object
Example Scenario. Have a page that lists messages to read. When a message subject is clicked, an AJAX request is made to retrieve the message. The server returns an array of commands to run, which updates the page with the selected message.
Attach library to a render array namespace Drupal\mymodule\Controller; use Drupal\Core\Controller\ControllerBase; class MyModuleController extends ControllerBase { // … // Render a page of my messages public function messagesPage() { // … build $content // Create render array. $page[] = array( ‘#type’ => ‘markup’, ‘#markup’ => $content, ); // Attach JavaScript library. $page[‘#attached’][‘library’][] = ‘core/drupal.ajax’; return $page; } // … } mymodule/src/Controller/MyModuleController.php Function for building messages page is now using a render array. to the ‘#attached’, ‘library’ array of that render array, declaring the drupal.ajax library to be included.
Callback returns commands using an AJAXResponse() [D8] namespace Drupal\mymodule\Controller; use Drupal\Core\Controller\ControllerBase; class MyModuleController extends ControllerBase { // … // AJAX Callback to read a message. public function readMessageCallback($method, $mid) { $msg = mymodule_load_message($mid); // Create AJAX Response object. $response = new AjaxResponse(); // Replace content of current message subject. $response->addCommand(new HtmlCommand(‘#current-msg h2’, $msg->subject)); // Replace content of current message body. $response->addCommand(new HtmlCommand(‘#current-msg p’, $msg->content)); // Remove message from unread list. $response->addCommand(new RemoveCommand(‘#msg-’ . $mid)); // Add message to read list. $item = ‘<li>’ . $msg->subject . ‘</li>’; $response->addCommand(new AppendCommand(‘#read-msgs’, $item)); // Return ajax response. return $response; } mymodule/src/Controller/MyModuleController.php Returning an AjaxResponse object instead of a render array like in Drupal 7. AjaxResponse has an ‘addCommand’ method, which takes the argument of a command object.
Custom Commands in Drupal 8 1. Add function to ‘Drupal.AjaxCommands.prototype’ 2. Define a command object that implements CommandInterface
Using a Custom Command in Drupal 8 1. Tell Drupal about custom JavaScript library 2. Attach library to a render array 3. Add command to AjaxResponse object in callback
Let’s Review
AJAX Callback Commands Are… Returned by all AJAX Framework requests PHP abstraction for JavaScript functions Defined by core and modules
To Use AJAX Callback Commands… Include Drupal AJAX JavaScript library Attach AJAX to page elements Have server side callback return array of commands
To Create AJAX Callback Commands… Add function to Drupal ajax command JavaScript object. Write PHP code to return associative array with a ‘command’ key
To Use Custom AJAX Callback Commands… Include custom JavaScript Include custom command in callback function
Resources Drupal AJAX Framework: bit.ly/DrupalAJAX This Presentation: bit.ly/NERD15ajax Presentation Slides: bit.ly/NERD15ajaxSlides Example Code for Drupal 7: bit.ly/NERD15ajaxEx Creating Commands in D8: bit.ly/D8AjaxCmds
Send me feedback! @mikemiles86 #NERDsummit
Thank You! Questions? #NERDsummit @WeAreGenuine AJAX Callback Commands / @mikemiles86