Creating a Custom Ajax Command in Drupal 8

Table of contents

Drupal 8 provides the option to include an Ajax Callback within our applications using the Ajax Framework. There are some existing functions which can be used: Methods to hide/show elements in the html document, attach content to an element, redirect a page after a submit, and so on. Sometimes we need to implement something particular, or a custom JS code. In that case, those out-of-the-box functions are not enough. Fortunately, we can also create our own custom responses. So, let’s start creating a new ajax callback for a custom form submission.

Since now we are using Drupal 8, we can take advantage of the Drupal Console to easily generate the necessary boilerplate code. That said, before continue make sure you have the latest console version (1.6.0) if you do not have it yet, you can follow instructions at the official docs page.

Generating the custom Module

The first step is to define the module where code will be generated. If you don’t have a custom module, you can create a new one executing the following Drupal Console command:

drupal generate:module 
--module="example" 
--machine-name="example" 
--module-path="modules/custom" 
--description="My Awesome Module" 
--core="8.x" 
--package="Custom" 
--module-file 
--no-interaction

Creating AJAX Command

Now that we have a home for our new AJAX command, we can create the command itself. Starting in Drupal Console 1.6.0, the drupal generate:ajax:command generates a custom AJAX command.

After entering the command, you will be prompted for several pieces of information to generate the boilerplate code for the command:

We can also specify all the options up front:

drupal generate:ajax:command  
--module="example" 
--class="ExampleCommand" 
--method="example" 
--js-name="example" 
--no-interaction

Once complete, we can inspect what was generated.

The AJAX Command Class

The generated Ajax Command class implements CommandInterface, and the mandatory method to implement the render function:

 <?php

namespace DrupalexampleAjax;

use DrupalCoreAjaxCommandInterface;

 /**
 * Class ExampleCommand.
 */
 class ExampleCommand implements CommandInterface {

 /**
 * Render custom ajax command.
 *
 * @return ajax command function
 */
 public function render() {
     return [
         'command' => 'example',
         'message' => 'My Awesome Message'
     ];
 }

}

The render() method must return a render array. In this case, ‘example’ will be the javascript command which we will invoke later inside the *.js file. We can define other properties on this response, for example a custom message.

The JavaScript file

Now let’s take a look to the second generated file, example.js, which is located inside your custom module. Here, we are reading the message property from the response object and displaying the result in the browser’s console. This is a really basic example, but you can implement a more robust actions depending on your requirements in fact we could reuse AJAX functions from core to interact with our response.

 (function ($, Drupal) {
/**
 * Add new custom command.
 */
Drupal.AjaxCommands.prototype.example = function (ajax, response, status) {
  console.log(response.message);
}
})(jQuery, Drupal);

While our example is pretty simple — it just writes to the browser’s console — you can make any command you like!

The library definition file

In addition to the above boilerplate, Drupal Console also generated a library definition file:

example-library:
 js:
   js/example.js: {}
 dependencies:
   - core/drupal.ajax

The library definition tells Drupal what javascript file(s) need to be loaded, and where and where to find them relative to the module’s directory. We can also define any required dependencies — such as core/drupal.ajax above — by defining the dependencies key.

Invoking our custom command

First we need to attach the library to the rendered page. There are lots of ways to do this. For this post, we want to attach it to a specific form. So, we’ll define a form alter:

function custom_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  /**
   * Apply the form_alter to a specific form #id
   * the form #id can be found through inspecting the markup
   */

  if ($form['#id'] == 'custom-form') {
    /**
     * Include a js, which was defined in example.libraries.yml
     */
    $form['#attached']['library'][] = "example/example-library";
  }

}

We alter the $form array by adding a new item under #attached. Since we’re attaching a library, we also use the library key. Finally, we specify our module name (example) and then our library name (example-library).

The above only attaches all the necessary Javascript. Now we need to put it to use! To do that, we need to modify the submit callback of the form to add our custom AJAX command:

/**
     * {@inheritdoc}
     */
    public function exampleSubmitForm(array &$form, FormStateInterface $form_state) {

        if ($form_state->hasAnyErrors() || !empty($form_state->getErrors())) {
            $ajax_response = new AjaxResponse();
            $ajax_response->addCommand(new AjaxCommand());

            return $ajax_response;
        }

    }

To add our command, we need to tell Drupal to only return AJAX content, rather than a full web page. In the form submit function we create a new AjaxResponse and call the addCommand() method to add our custom command.

Put together, our custom ajax command will be triggered every time the exampleSubmitForm() method is called, and our custom message will appear in the browser’s console.

Wrap up

While Drupal Console makes creating a new AJAX command easy, you can also do it manually:

  1. Create a custom command class extending AjaxInterface.
  2. Invoke the Drupal.AjaxCommands.prototype object and define there your custom actions.
  3. Create a library definition specify the location of your custom Javascript.
  4. Include core/drupal.ajax as part of the library dependencies.
  5. Add your ajax custom command by using addCommand() on the ajax response object.

Creating a custom AJAX command isn’t complex in Drupal 8. Once you add the command to the AJAX response, you can create all kinds of amazing user experiences!