Creating Drupal 8 AJAX Callback Commands

Mar 07, 2016

One of the biggest benefits of the AJAX framework introduced in Drupal 7 were callback commands, functions which return a json object of commands to run for any AJAX request. Callback commands, like many things in Drupal, are extensible meaning you can create and invoke your own.

Drupal 8 also comes with a version of the AJAX Framework (this time utilizing OOP practices) and callback commands. Let’s take a look at exactly what a callback command is and how it works by learning how to create and use a custom one in Drupal 8.

The following example code will revolve around a scenario of retrieving and displaying messages to a user using AJAX. A message is composed of an id, subject, and content.

Creating a Callback Command

All callback commands are composed of two parts, server side PHP code and client side Javascript. The PHP is what is called in an AJAX request, the the javascript is what is invoked from the AJAX response.

Where to create custom commands

Like many things in Drupal, custom commands can be defined by modules. To create custom callback commands you will need to create a custom module. To gain a better understanding of how to create and structure a Drupal 8 module, check out the documentation.

In the following code examples for creating and using a custom callback command, we will be using everyone’s favorite example module “mymodule”.

Server Side PHP

In Drupal 8 a callback commands is an object that implements the “CommandInterface” class. (Check out the documentation for interfaces if you need to brush up). “CommandInterface” requires a single method to be implemented by an object, the “render” method. This method is expected to return an associative array.

The only required key in the returned associative array is command, the value of which is the name of a javascript function to be invoked on the client side. All other elements returned to the array will be passed as part of the data argument sent to the javascript function.

<?php
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,
    );
  }
}

In the code example above, we are creating an object called “ReadMessageCommand” which is located in mymodule/src/Ajax/ReadMessageCommand.php. When the object is invoked it takes in a message object as an argument. The render method returns an associative array, which will call the javascript “readMessage” command and pass along information about the message to the client.

As callback commands go, the example is pretty basic. However it is easy to see how easily a command object could be extended to perform much more complex server side functionality before returning the associative array in the render method.

Client Side Javascript

On the javascript side, in Drupal 8 a callback command is just a javascript function attached to a global javascript object. The object which is provided by the AJAX framework is named Drupal.AjaxCommands.prototype. All functions attached to this object receive the same three parameters;

ajax – An object which contains information about the triggering element, the callback that was made, the method of the request, etc…
response – The object that was returned from the AJAX request. This object contains the data in the associative array returned from the PHP object.
status – The status code of the request, 200, 404, 500, etc…
(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('<li>' + response.subject + '</li>');
  }
})(jQuery, Drupal);
In the code example above, we are creating a javascript library in “mymdoule/js/command.js.” In this javascript library we are attaching the “readMessage” function to the global object. This command is just a wrapper for additional javascript functions to print the message data returned from the response. You will notice that the name of this function is the same as what was set as the value of the “command” key in the associative array returned by the “render” method of the PHP object.

Since a callback command is just a wrapper for additional javascript functionality, the complexity of what the command can change on the page, how it can change it, other javascript it can call is very versatile.

Using a Custom Callback Command

Using a custom callback command is just as easy as creating one. In Drupal 8 there are three steps you need to follow;

Tell Drupal about your javascript library.
Include your javascript library on the page.
Include custom command in an AJAX response.
Tell Drupal about your Javascript Library

In Drupal 7, to include custom javascript on a page you could just use the function drupal_add_js(). In Drupal 8 this is no longer the case, as that function has been removed. Instead everything is treated as an asset library. For information on how to define and include an asset library, checkout the documentation.

mymodule.commands:
  version: VERSION
  js:
    js/commands.js: {}
  dependencies:
     - core/drupal.ajax
In the example code, we are creating the “mymodule/mymodule.libraries.yml” file. In which, we are defining the “mymodule.commands” javascript library and telling Drupal where the javascript file is located and that it has a dependency on the Drupal AJAX library. Since we list the ajax library as a dependency in our libraries.yml file, Drupal will automatically include it on any page that has our javascript library.

Include Javascript on the Page

For Drupal to attach your custom command to the global commands object, you need to make sure your javascript is included on the page. Since the drupal_add_js() function is gone in Drupal 8, you need to add your library to the “#attached][library” section of a render array.

<?php
/**
 * @file
 * Contains \Drupal\mymodule\Controller\MyModuleController.
 */
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'][] = 'mymodule/mymodule.commands';
    return $page;
  }
  // ...
}
?>
In the example code, in our controller class we have a method which is rendering a page of messages using a render array. To this array we are attaching our custom library.

Include Custom Command in an AJAX Response

For your custom callback command to be used it has to be included in an AJAX response. In Drupal 8 a function that is being called from an AJAX request needs to return an AjaxResponse object. This object has the method “addCommand” which is used to invoke callback command objects and add them to the response. The AjaxResponse object will call the “render” method of each attached command to build an array of functions to call on the client.

<php
/**
 * @file
 * Contains \Drupal\mymodule\Controller\MyModuleController.
 */
namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;

class MyModuleController extends ControllerBase {
  // ...
// AJAX Callback to read a message.
  public function readMessageCallback($method, $mid) {
    $message = mymodule_load_message($mid);
    // Create AJAX Response object.
    $response = new AjaxResponse();
    // Call the readMessage javascript function.
    $response->addCommand( new ReadMessageCommand($message));
   );
   // Return ajax response.
   return $response;
  }
  // ...
}
?>
In this example code, we have a method in our Controller class that is being called from an AJAX request. In the method we are creating a new AjaxResonse object, and adding our custom ReadMessageCommand, passing to it a message object. We are then returning the AjaxResponse object.

Review

To create and use custom AJAX callback commands in Drupal 8, there are just a few simple steps you need to follow. When creating a custom callback command;

  • Create a PHP Object which implements the CommandInterface class. Making sure the object has a “render” method which returns an associative array with the key of “command.”
  • Attach a javascript function to the global “Drupal.AjaxCommands.prototype” object. Making sure it accepts the three arguments “ajax”, “response” and “status.”
When using a custom callback command;

  • Tell Drupal about you javascript library with a *.libraries.yml file. Be sure to list the Drupal Ajax library as a dependency.
  • Include your custom js library onto the page by attaching it to the “#attached][library” section of a render array.

Want to learn how Genuine can help you with your next digital, creative, tech or media project? Get in touch with us at contacts@wearegenuine.com.