SlideShare a Scribd company logo
Demystifying Ajax
Callback Commands
(in Drupal 8)
events.drupal.org/node/8466
DrupalconΒ 2016
Mike Miles
GenuineΒ ( )wearegenuine.com
AllΒ theΒ internetΒ places:Β mikemiles86
Defining Callback Commands
InstructionsΒ builtΒ byΒ theΒ ServerΒ andΒ 
executedΒ byΒ theΒ ClientΒ inΒ anΒ AjaxΒ event.
Callback Command: JavaScript
AttachedΒ toΒ 'Drupal.AjaxCommands.prototype'
DefinedΒ inΒ 'misc/ajax.js'
AcceptsΒ 3Β arguments:
ajax
response
status
WrapperΒ forΒ additionalΒ JavaScript
Callback Structure: JavaScript
01 (function ($, window, Drupal, drupalSettings) {
02 'use strict';
03 /**
04 * [commandName description]
05 *
06 * @param {Drupal.Ajax} [ajax]
07 * @param {object} response
08 * @param {number} [status]
09 */
10 Drupal.AjaxCommands.prototype.[commandName] = function(ajax, response, status){
11
12 // Custom javascript goes here ...
13
14 }
15
16 })(jQuery, this, Drupal, drupalSettings);
[module]/js/[javascript].js
ExampleΒ ofΒ theΒ structureΒ forΒ theΒ JavaScriptΒ halfΒ ofΒ aΒ callbackΒ commandΒ asΒ definedΒ inΒ aΒ module.
Callback Command: PHP
ClassΒ thatΒ implementsΒ CommandInterface
DefinesΒ aΒ methodΒ calledΒ 'render'
ReturnsΒ anΒ associativeΒ array:
MustΒ haveΒ elementΒ withΒ keyΒ ofΒ 'command'
ValueΒ mustΒ beΒ nameΒ ofΒ JavaScriptΒ function
OtherΒ elementsΒ passedΒ asΒ responseΒ data
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.
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.
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.
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.
Callback Commands
UsedΒ inΒ allΒ AjaxΒ requests
ComposedΒ ofΒ twoΒ parts:Β JavaScriptΒ function,Β PHPΒ Class
ProvidedΒ byΒ coreΒ andΒ modules
Creating Callback Commands
Example Scenario
CreateΒ aΒ callbackΒ commandΒ forΒ theΒ jQueryΒ 'SlideDown'Β animation
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.
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.
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.
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.
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'
Using Callback Commands
Example Scenario
LoadΒ watchdogΒ logΒ messageΒ detailsΒ ontoΒ theΒ overviewΒ pageΒ using
AjaxΒ commands.
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.
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.
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Β 'useΒ­ajax'Β (lineΒ #18),Β whichΒ theΒ AjaxΒ FrameworkΒ willΒ lookΒ for.
PageΒ stillΒ rendersΒ theΒ same.Β HoweverΒ nowΒ includesΒ AjaxΒ FrameworkΒ includingΒ theΒ customΒ SlideDown
command.Β TheΒ messageΒ titleΒ linksΒ willΒ nowΒ triggerΒ anΒ ajaxΒ request.
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.
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).
WhenΒ aΒ messageΒ titleΒ isΒ clicked,Β theΒ AjaxΒ requestΒ isΒ made.Β TheΒ endpointΒ buildsΒ anΒ AjaxResponseΒ of
commandsΒ andΒ DrupalΒ returnsΒ aΒ JSONΒ string.
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.
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'
Resources
DrupalΒ 8Β AjaxΒ Framework:Β bit.ly/Drupal8Ajax
ThisΒ Presentation:Β bit.ly/Con16Ajax
PresentationΒ Slides:Β bit.ly/Con16AjaxSlides
ExampleΒ Code:Β bit.ly/Con16AjaxCode
CreatingΒ CommandsΒ inΒ D8:Β bit.ly/D8AjaxCmds
MyΒ Blog:Β mikeΒ­miles.com
Feedback
@mikemiles86
Β #DrupalCon Β @WeAreGenuine D8Β AjaxΒ CommandsΒ /Β Β MichaelΒ Miles
Thank You!

More Related Content

PDF
Demystifying Drupal AJAX Callback Commands
PDF
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
PDF
MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8
PDF
ΠœΠΈΡ…Π°ΠΈΠ» ΠšΡ€Π°ΠΉΠ½ΡŽΠΊ - Form API + Drupal 8: Form and AJAX
PDF
NYCCAMP 2015 Demystifying Drupal AJAX Callback Commands
PDF
#36.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_μž¬μ§μžν™˜κΈ‰κ΅μœ‘,μ‹€μ—…μžκ΅μœ‘,κ΅­λΉ„μ§€μ›κ΅μœ‘, μžλ°”κ΅μœ‘,ꡬ...
PDF
#18.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_ꡭ비지원IT학원/μ‹€μ—…μž/μž¬μ§μžν™˜κΈ‰κ΅μœ‘/μžλ°”/μŠ€ν”„λ§/...
PPTX
Magento 2 | Declarative schema
Demystifying Drupal AJAX Callback Commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8
ΠœΠΈΡ…Π°ΠΈΠ» ΠšΡ€Π°ΠΉΠ½ΡŽΠΊ - Form API + Drupal 8: Form and AJAX
NYCCAMP 2015 Demystifying Drupal AJAX Callback Commands
#36.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_μž¬μ§μžν™˜κΈ‰κ΅μœ‘,μ‹€μ—…μžκ΅μœ‘,κ΅­λΉ„μ§€μ›κ΅μœ‘, μžλ°”κ΅μœ‘,ꡬ...
#18.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_ꡭ비지원IT학원/μ‹€μ—…μž/μž¬μ§μžν™˜κΈ‰κ΅μœ‘/μžλ°”/μŠ€ν”„λ§/...
Magento 2 | Declarative schema

What's hot (19)

PDF
#31.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ κ°•μ’Œ, μž¬μ§μžν™˜κΈ‰κ΅μœ‘,μ‹€μ—…μžκ΅­λΉ„μ§€μ›...
PDF
Alfredo-PUMEX
PDF
Catalyst patterns-yapc-eu-2016
PDF
td_mxc_rubyrails_shin
ZIP
First Steps in Drupal Code Driven Development
Β 
PDF
PDF
RicoLiveGrid
PPTX
IndexedDB - Querying and Performance
PPTX
Planbox Backbone MVC
PDF
Upgrade your javascript to drupal 8
PPTX
Анатолий Поляков - Drupal.ajax framework from a to z
KEY
Zend framework service
PDF
Drupal 8: Fields reborn
PDF
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
PDF
Sane Async Patterns
PPTX
An ADF Special Report
KEY
Php Unit With Zend Framework Zendcon09
PPTX
Using the Features API
PDF
11-DWR-and-JQuery
#31.μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ & λ§ˆμ΄λ°”ν‹°μŠ€ (Spring Framework, MyBatis)_μŠ€ν”„λ§ν”„λ ˆμž„μ›Œν¬ κ°•μ’Œ, μž¬μ§μžν™˜κΈ‰κ΅μœ‘,μ‹€μ—…μžκ΅­λΉ„μ§€μ›...
Alfredo-PUMEX
Catalyst patterns-yapc-eu-2016
td_mxc_rubyrails_shin
First Steps in Drupal Code Driven Development
Β 
RicoLiveGrid
IndexedDB - Querying and Performance
Planbox Backbone MVC
Upgrade your javascript to drupal 8
Анатолий Поляков - Drupal.ajax framework from a to z
Zend framework service
Drupal 8: Fields reborn
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
Sane Async Patterns
An ADF Special Report
Php Unit With Zend Framework Zendcon09
Using the Features API
11-DWR-and-JQuery
Ad

Similar to Demystifying AJAX Callback Commands in Drupal 8 (20)

PDF
Patterns Are Good For Managers
PDF
11-DWR-and-JQuery
PDF
Ajax on drupal the right way - DrupalCamp Campinas, SΓ£o Paulo, Brazil 2016
PDF
Drupal & javascript
PPTX
Serverless archtiectures
PDF
jQuery and Rails: Best Friends Forever
PDF
Intro to Laravel 4
PDF
Introduction to Backbone.js for Rails developers
PPTX
Soa development using javascript
PDF
Dependency Management with RequireJS
ODP
Javascript frameworks: Backbone.js
PDF
JQuery In Drupal
PPTX
React, Flux and a little bit of Redux
PPT
Sqlapi0.1
PDF
Andy Postnikov - Drupal 7 vs Drupal 8: ΠΎΡ‚ бутстрапа Π΄ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€Π°
PDF
Lviv 2013 d7 vs d8
PDF
Symfony2 - from the trenches
PDF
Lviv 2013 d7 vs d8
Β 
PDF
Rails is not just Ruby
PPT
Backbone js
Patterns Are Good For Managers
11-DWR-and-JQuery
Ajax on drupal the right way - DrupalCamp Campinas, SΓ£o Paulo, Brazil 2016
Drupal & javascript
Serverless archtiectures
jQuery and Rails: Best Friends Forever
Intro to Laravel 4
Introduction to Backbone.js for Rails developers
Soa development using javascript
Dependency Management with RequireJS
Javascript frameworks: Backbone.js
JQuery In Drupal
React, Flux and a little bit of Redux
Sqlapi0.1
Andy Postnikov - Drupal 7 vs Drupal 8: ΠΎΡ‚ бутстрапа Π΄ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€Π°
Lviv 2013 d7 vs d8
Symfony2 - from the trenches
Lviv 2013 d7 vs d8
Β 
Rails is not just Ruby
Backbone js
Ad

More from Michael Miles (17)

PDF
Inclusive Design: Thinking beyond accessibility
PDF
How to Foster Team Success
PDF
How to Foster Team Success | Drupalcon 2017
PDF
Inclusive Design: Thinking Beyond Accessibility | NERDSummit 2017
PDF
Inclusive Design: Thinking Beyond Accessibility | DCNL 2017
PDF
The Flexibility of Drupal 8 | DCNLights 2017
PDF
INCLUSIVE DESIGN: Going beyond Accessibility
PDF
Inclusive Design
PDF
The Flexibility of Drupal 8
PDF
The Flexibility of Drupal
PDF
Badcamp 2015 - R.E.A.D: Four Steps for Selecting The Right Modules
PDF
The Flexibility of Drupal
PDF
The Flexibility of Drupal
PDF
Flcamp2015 - R.E.A.D: Four steps for selecting the right modules
PDF
R.E.A.D: Four steps for selecting the right modules Midcamp 2015
PDF
How to R.E.A.D: Steps for how to select the correct module @NEWDCamp 2014
PDF
To Patch or Custom: How to decide when to patch a contrib module or go custom...
Inclusive Design: Thinking beyond accessibility
How to Foster Team Success
How to Foster Team Success | Drupalcon 2017
Inclusive Design: Thinking Beyond Accessibility | NERDSummit 2017
Inclusive Design: Thinking Beyond Accessibility | DCNL 2017
The Flexibility of Drupal 8 | DCNLights 2017
INCLUSIVE DESIGN: Going beyond Accessibility
Inclusive Design
The Flexibility of Drupal 8
The Flexibility of Drupal
Badcamp 2015 - R.E.A.D: Four Steps for Selecting The Right Modules
The Flexibility of Drupal
The Flexibility of Drupal
Flcamp2015 - R.E.A.D: Four steps for selecting the right modules
R.E.A.D: Four steps for selecting the right modules Midcamp 2015
How to R.E.A.D: Steps for how to select the correct module @NEWDCamp 2014
To Patch or Custom: How to decide when to patch a contrib module or go custom...

Recently uploaded (20)

PDF
πŸ’° π”πŠπ“πˆ πŠπ„πŒπ„ππ€ππ†π€π πŠπˆππ„π‘πŸ’πƒ π‡π€π‘πˆ 𝐈𝐍𝐈 πŸπŸŽπŸπŸ“ πŸ’°
Β 
PDF
SASE Traffic Flow - ZTNA Connector-1.pdf
PDF
RPKI Status Update, presented by Makito Lay at IDNOG 10
Β 
PDF
APNIC Update, presented at PHNOG 2025 by Shane Hermoso
Β 
PPTX
international classification of diseases ICD-10 review PPT.pptx
PPTX
CHE NAA, , b,mn,mblblblbljb jb jlb ,j , ,C PPT.pptx
PPTX
Introuction about ICD -10 and ICD-11 PPT.pptx
PDF
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf
PPTX
Introuction about WHO-FIC in ICD-10.pptx
PPTX
PptxGenJS_Demo_Chart_20250317130215833.pptx
PPTX
Internet___Basics___Styled_ presentation
PDF
The Internet -By the Numbers, Sri Lanka Edition
Β 
PDF
Triggering QUIC, presented by Geoff Huston at IETF 123
Β 
PPTX
522797556-Unit-2-Temperature-measurement-1-1.pptx
PDF
An introduction to the IFRS (ISSB) Stndards.pdf
PDF
Slides PDF The World Game (s) Eco Economic Epochs.pdf
PPTX
innovation process that make everything different.pptx
PDF
WebRTC in SignalWire - troubleshooting media negotiation
PPTX
Funds Management Learning Material for Beg
PDF
Tenda Login Guide: Access Your Router in 5 Easy Steps
πŸ’° π”πŠπ“πˆ πŠπ„πŒπ„ππ€ππ†π€π πŠπˆππ„π‘πŸ’πƒ π‡π€π‘πˆ 𝐈𝐍𝐈 πŸπŸŽπŸπŸ“ πŸ’°
Β 
SASE Traffic Flow - ZTNA Connector-1.pdf
RPKI Status Update, presented by Makito Lay at IDNOG 10
Β 
APNIC Update, presented at PHNOG 2025 by Shane Hermoso
Β 
international classification of diseases ICD-10 review PPT.pptx
CHE NAA, , b,mn,mblblblbljb jb jlb ,j , ,C PPT.pptx
Introuction about ICD -10 and ICD-11 PPT.pptx
Automated vs Manual WooCommerce to Shopify Migration_ Pros & Cons.pdf
Introuction about WHO-FIC in ICD-10.pptx
PptxGenJS_Demo_Chart_20250317130215833.pptx
Internet___Basics___Styled_ presentation
The Internet -By the Numbers, Sri Lanka Edition
Β 
Triggering QUIC, presented by Geoff Huston at IETF 123
Β 
522797556-Unit-2-Temperature-measurement-1-1.pptx
An introduction to the IFRS (ISSB) Stndards.pdf
Slides PDF The World Game (s) Eco Economic Epochs.pdf
innovation process that make everything different.pptx
WebRTC in SignalWire - troubleshooting media negotiation
Funds Management Learning Material for Beg
Tenda Login Guide: Access Your Router in 5 Easy Steps

Demystifying AJAX Callback Commands in Drupal 8

  • 1. Demystifying Ajax Callback Commands (in Drupal 8) events.drupal.org/node/8466 DrupalconΒ 2016
  • 6. Callback Structure: JavaScript 01 (function ($, window, Drupal, drupalSettings) { 02 'use strict'; 03 /** 04 * [commandName description] 05 * 06 * @param {Drupal.Ajax} [ajax] 07 * @param {object} response 08 * @param {number} [status] 09 */ 10 Drupal.AjaxCommands.prototype.[commandName] = function(ajax, response, status){ 11 12 // Custom javascript goes here ... 13 14 } 15 16 })(jQuery, this, Drupal, drupalSettings); [module]/js/[javascript].js ExampleΒ ofΒ theΒ structureΒ forΒ theΒ JavaScriptΒ halfΒ ofΒ aΒ callbackΒ commandΒ asΒ definedΒ inΒ aΒ module.
  • 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Β 'useΒ­ajax'Β (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'