This session outlines and explains Drupal 8 AJAX callback commands and how to use them. AJAX callback commands are the sets of PHP and JavaScript functions that control all AJAX functionality on a Drupal site. You will be surprised about how simple and straight forward they are. Mastering these commands will allow your AJAX calls to do so much more then just return rendered HTML. Allowing you to provide the visitors of your Drupal 8 site a more dynamic, richer experience.
8. Callback Structure: PHP
01 namespace Drupal[module]Ajax
02 use DrupalCoreAjaxCommandInterface;
03
04 // An Ajax command for calling [commandName]() JavaScript method.
05 class [CommandName]Command implements CommandInterface {
06
07 // Implements DrupalCoreAjaxCommandInterface:render().
08 public function render() {
09 return array(
10 'command' => '[commandName]', // Name of JavaScript Method.
11 // other response arguments...
12 );
13 }
14 }
[module]/src/Ajax/[CommandName]Command.php
Example of the structure for the PHP half of a callback command as defined in a module.
9. Core Example: Remove
01 Drupal.AjaxCommands.prototype = {
02 // ...
03 /**
04 * Command to remove a chunk from the page.
05 *
06 * @param {Drupal.Ajax} [ajax]
07 * @param {object} response
08 * @param {string} response.selector
09 * @param {object} [response.settings]
10 * @param {number} [status]
11 */
12 remove: function (ajax, response, status) {
13 var settings = response.settings || ajax.settings || drupalSettings;
14 $(response.selector).each(function () {
15 Drupal.detachBehaviors(this, settings);
16 })
17 .remove();
18 },
19 //...
misc/ajax.js
The JavaScript function for the core 'remove' callback command. It is basically a wrapper for the jQuery
'remove' method.
10. Core Example: RemoveCommand
01 namespace DrupalCoreAjax;
02 use DrupalCoreAjaxCommandInterface;
03 /**
04 * Ajax command for calling the jQuery remove() method.
05 * ...
06 */
07 class RemoveCommand Implements CommandInterface {
08 // ...
09 /**
10 * Implements DrupalCoreAjaxCommandInterface:render().
11 */
12 public function render() {
13 return array(
14 'command' => 'remove',
15 'selector' => $this->selector,
16 );
17 }
18 }
core/lib/Drupal/Core/Ajax/RemoveCommand.php
The PHP class for the core 'remove' callback command. Implements CommandInterface, so it must
define the method 'render' that returns an associative array.
11. PHP
01 //...
02 public function render() {
03 return array(
04 'command' => 'remove',
05 'selector' => $this->selector,
06 );
07 }
core/lib/Drupal/Core/Ajax/RemoveCommand.php
JavaScript
01 //...
02 remove: function (ajax, response, status) {
03 var settings = response.settings || ajax.settings || drupalSettings;
04 $(response.selector).each(function () {
05 Drupal.detachBehaviors(this, settings);
06 })
07 .remove();
08 },
misc/ajax.js
Can see how the two halfs are tied together. Value on line #4 of PHP matches JavaScript function name
defined on line #2 in JavaScript. Passed CSS selector on line #5 in PHP is used on line #4 in JavaScript.
15. Create a Module
01 name: 'Slide Down Command'
02 type: module
03 description: Provides an Ajax Callback command for the jQuery SlideDown method.
04 package: other
05 core: 8.x
slide_down/slide_down.info.yml
Custom Ajax callback commands must be defined in a module.
16. Create JavaScript Function
01 (function ($, window, Drupal, drupalSettings) {
02
03 'use strict';
04
05 // Command to Slide Down page elements.
06 Drupal.AjaxCommands.prototype.slideDown = function(ajax, response, status){
07 // Get duration if sent, else use default of slow.
08 var duration = response.duration ? response.duration : "slow";
09 // slide down the selected element(s).
10 $(response.selector).slideDown(duration);
11 }
12 })(jQuery, this, Drupal, drupalSettings);
slide_down/js/slidedown-command.js
Attach a JavaScript function to the AjaxCommands object provided by the Ajax Framework. Accepts the
three arguments and is a wrapper for the jQuery method.
17. Create Asset Library
01 slidedown:
02 version: VERSION
03 js:
04 js/slidedown-command.js; {}
05 dependencies:
06 - core/drupal.ajax
slide_down/slide_down.libraries.yml
In Drupal 8 custom JavaScript files must be added to an asset library to be able to be included on a
page.
18. Create PHP Class
01 namespace Drupalslide_downAjax;
02 use DrupalCoreAjaxCommandInterface;
03
04 class SlideDownCommand implements CommandInterface {
05 // ...
06 // Constructs an SlideDownCommand object.
07 public function __construct($selector, $duration = NULL) {
08 $this->selector = $selector;
09 $this->duration = $duration;
10 }
11
12 // Implements DrupalCoreAjaxCommandInterface:render().
13 public function render() {
14 return array(
15 'command' => 'slideDown',
16 'method' => NULL,
17 'selector' => $this->selector,
18 'duration' => $this->duration,
19 );
20 }
21 }
slide_down/src/Ajax/SlideDownCommand.php
Create a PHP class that implements CommandInterface. Must define a 'render' method and return an
associative array. In the array, pass the element with key of 'command' and value being the name of the
JavaScript function and any repsonse data.
19. To Create a Callback Command:
Create a module
Attach JavaScript function to 'Drupal.AjaxCommands.prototype'
Define an asset library
Create PHP class that implements 'CommandInterface'
22. Add Ajax Library to Page
01 use DrupaldblogControllerDbLogController as ControllerBase;
02
03 class DbLogController extends ControllerBase {
04 // Override overview() method.
05 public function overview() {
06 $build = parent::overview();
07 // ...
08 // Add custom library.
09 $build['#attached']['library'][] = 'ajax_dblog/ajax-dblog';
10 return $build;
11 }
12 // ...
13 }
ajax_dblog/src/Controller/DbLogController.php
Need to attach custom library onto page so that custom JavaScript and Ajax Framework is included.
23. 01 ajax-dblog:
02 version: VERSION
03 css:
04 component:
05 css/ajax_dblog.module.css: {}
06 js:
07 js/behaviors.js: {}
08 dependencies:
09 - slide_down/slidedown
ajax_dblog/ajax_dblog.libraries.yml
01 slidedown:
02 version: VERSION
03 js:
04 js/slidedown-command.js: {}
05 dependencies:
06 - core/drupal.ajax
slide_down/slide_down.libraries.yml
Defining a dependency in the library on another library. The other library depends on the Ajax
Framework. Drupal will follow chain to include all depended JavaScript files.
24. Add Ajax to Elements
01 namespace Drupalajax_dblogController;
02 use DrupaldblogControllerDbLogController as ControllerBase;
03
04 class DbLogController extends ControllerBase {
05 // Override overview() method.
06 public function overview() {
07 $build = parent::overview();
08 // Alter the links for each log message.
09 foreach ($build['dblog_table']['#rows'] as &$row) {
10 // ...
11 // Build route parameters.
12 $params = array(
13 'method' => 'nojs',
14 //...
15 );
16 // Build link options.
17 $ops = array( 'attributes' => array(
18 'class' => array('use-ajax', 'dblog-event-link'),
19 ));
20 // Replace with a new link.
21 $row['data'][3] = Link::createFromRoute($txt,'ajax_dblog.event',$params,$ops);
22 }
23 return $build; ajax_dblogs/src/Controller/DbLogController.php
Need to have elements that will trigger an Ajax request. Rebuilding links on page to point to new route
(line #21). Links will have the class 'useajax' (line #18), which the Ajax Framework will look for.
26. Create Ajax Request Endpoint
01 ajax_dblog.event:
02 path: '/admin/reports/dblog/{method}/event/{event_id}'
03 defaults:
04 _controller: 'Drupalajax_dblogControllerDbLogController::ajaxEventDetails'
05 requirements:
06 _permission: 'access site reports'
07 method: 'nojs|ajax'
ajax_dblog/ajax_dblog.routing.yml
/admin/reports/dblog/nojs/event/123
/admin/reports/dblog/ajax/event/123
Create an endpoint that will handle Ajax Requests. The ajax framework will replace 'nojs' with 'ajax' on
all request. Can use as a check to handle graceful degradation.
27. Return an AjaxResponse of Callback Commands
01 use DrupalCoreAjaxAjaxResponse;
02 use DrupalCoreAjaxAfterCommand;
03 use DrupalCoreAjaxRemoveCommand;
04 use Drupalslide_downAjaxSlideDownCommand;
05
06 class DbLogController extends ControllerBase {
07 // ...
08 public function ajaxEventDetails($method, $event_id) {
09 //...
10 if ($method == 'ajax') {
11 $event = parent::eventDetails($event_id);
12 $event_details = [ ... ];
13 // Create an AjaxResponse.
14 $response = new AjaxResponse();
15 // Remove old event details.
16 $response->addCommand(new RemoveCommand('.dblog-event-row'));
17 // Insert event details after event.
18 $response->addCommand(new AfterCommand('#dblog-event-' . $event_id, $event_details
19 // SlideDown event details.
20 $response->addCommand(new SlideDownCommand('#dblog-event-details-' . $event_id
21 }
22 // ...
23 } ajax_dblog/src/Controller/DbLogController.php
Have a method that is the endpoint for the Ajax request (line #8). Need to build an AjaxReponse object
(line #14). Will add commands to this response using the 'addCommand' method and creating a new
instance of the relevant Callback Command class (lines #16, #18, #20).
29. Ajax Response
01 [
02 {
03 "command":"remove",
04 "selector":".dblog-event-row"
05 },
06 {
07 "command":"insert",
08 "method":"after",
09 "selector":"#dblog-event-32",
10 "data":"...",
11 "settings":null
12 },
13 {
14 "command":"slideDown",
15 "method":null,
16 "selector":"#dblog-event-details-32",
17 "duration":null
18 }
19 ]
The returned JSON array is parsed by Ajax Framework. Finds JavaScript function to execute and the
passes the object as the data for the response argument of the function.
30. To Use Callback Commands
Include the Ajax library and commands on the page.
Have endpoint that returns an AjaxResponse
Add commands to response using 'addCommand'