Tập tành Creating custom ajax command In Drupal 9

23rd Jun 2022
Table of contents

I am writing this post to help drupal 8 developers for creating a custom Ajax Command to insert value in CKEditor in a node edit form, Like Body field of a node. Here are the steps:

Step 1:  create a custom :

for best practice create a folder named as "custom" in modules folder. Then create a folder named as your module in my case its my_custom. create following files structure.

I. my_custom.info.yml  with following code

name: my_custom
type: module
description: Custom module to handle Custom APIs and custom requirements
package: custom
core: 8.x

II. my_custom.module

with following code:

/**
* @file
* contains my_custom.module file
*/

use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;
use Drupal\Core\Render\Element\StatusMessages;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\my_custom\Ajax\InsertInCkeditor; // this my custom class

/**
* Implementing hook_form_alter()
* @param array $form, $form_state , $form_id
*/
function my_custom_form_alter(array &$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {  
  if ($form_id == 'node_job_listing_form') {
    // attaching custom js library to node edit form.
    $form['#attached']['library'][] = 'my_custom/my-custom';
    //adding a prefix wrapper of ajax callback.
    $form['#prefix'] = '<div id="nodeJobListingForm">';
    $form['#suffix'] = '</div>';  
    //adding a prefix to body field for creating  proper selector.
    $form['body']['widget']['#prefix'] =  '<div id="job_body">';
    $form['body']['widget']['#suffix'] =  '</div>'; //job_requirements

    //select list on which change I am going to fire js event
    $jobs_list = ['india', 'US', 'Uk', 'France'];
    $form['field_job_title']['widget']['#options'] = array('_none' => '- Select -') + $jobs_list;
    $form['field_job_title']['widget']['#ajax'] = array(
      'callback' => 'updateFormValuesCallback',
      'event' => 'change',
      'wrapper' => 'nodeJobListingForm',
      'progress' => array(
        'type' => 'throbber',
        'message' => NULL,
      ),
    );

  }
}

/**
* Custom Ajax callback form change on node edit/submit form
*
**/
function updateFormValuesCallback(array $form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $job_description = '<p>Hi this is test message.</p>';
  $response->addCommand(new InsertInCkeditor('#job_body textarea', 'val', [$job_description]));
  return $response;
}

III. my_custom.libraries.yml

In this file I will define my custom js library add following code to this file

my-custom:
  js:
    js/my-custom.js: {}
  dependencies:
    - core/drupal.ajax
    - core/jquery
    - core/ jquery.once
    - core/ drupal
    - ckeditor/drupal.ckeditor

I have added CKeditor Library as dependency for my js library, so that I will be included on page before my Library and I can use CKEditor Library to insert data.

Now Need to define Drupal\my_custom\Ajax\InsertInCkeditor class by creating new file in

my_module/src/Ajax folder

file name: will be same as class name InsertInCkeditor.php with following code:

<?php
/**
* InsertInCkeditor.php contains InsertInCkeditor class
* Defines custom ajax command for set value in CKEditor by ajax
**/
namespace Drupal\my_custom\Ajax;
use Drupal\Core\Ajax\CommandInterface;
use Drupal\Core\Asset\AttachedAssets;

/**
 * Class ExtendCommand.
 */
class InsertInCkeditor implements CommandInterface {
   /**
   * A CSS selector string.
   *
   * If the command is a response to a request from an #ajax form element then
   * this value can be NULL.
   *
   * @var string
   */
  protected $selector;

  /**
   * A jQuery method to invoke.
   *
   * @var string
   */
  protected $method;

  /**
   * An optional list of arguments to pass to the method.
   *
   * @var array
   */
  protected $arguments;

  /**
   * Constructs an InvokeCommand object.
   *
   * @param string $selector
   *   A jQuery selector.
   * @param string $method
   *   The name of a jQuery method to invoke.
   * @param array $arguments
   *   An optional array of arguments to pass to the method.
   */
  public function __construct($selector, $method, array $arguments = []) {
    $this->selector = $selector;
    $this->method = $method;
    $this->arguments = $arguments;
  }

  public function render() {
      return [
        'command' => 'InsertInCkeditor',
        'selector' => $this->selector,
        'args' => $this->arguments,
      ];  
    }
}

?>

3. Calling CKeditor Instance to put data in CKeditor my-custom.js file.  Here I am defining my custom ajax command InsertInCkeditor. Because CKEDITOR instance is not found ready at the time of firing this ajax so I have set value of command in a localStorage. So I can use them on ajaxStop() event. Here is the code.

(function ($, Drupal, CKEDITOR) {
/**
 * Add new custom command.
 */
 
 //var CKEDITOR = CKEDITOR;
  Drupal.AjaxCommands.prototype.InsertInCkeditor = function (ajax, response, status ) {     
    var textareaInstance = jQuery(response.selector).attr('id');
    var textData = response.args;  
    localStorage.setItem(textareaInstance, textData);
    //localStorage.setItem("textData", textData);        
  }

})(jQuery, Drupal, CKEDITOR);

jQuery( document ).ajaxStop(function() {
  var instance1 = 'edit-body-0-value';
  var instance2 = 'edit-field-job-requirements-0-value';
  var instance1Data = localStorage.getItem(instance1);
  var instance2Data = localStorage.getItem(instance2);
   
  /*console.log('instance1: '+ instance1);
  console.log('instance2: '+ instance2);
  console.log('instance1Data: '+ instance1Data);
  console.log('instance2Data: '+ instance2Data);*/
  if(instance1 !== undefined && instance1 != '' ) {
      CKEDITOR.instances[instance1].setData(instance1Data, {
      callback: function() {
          this.checkDirty(); // true
          localStorage.setItem(instance1, "");
        }
    } );
  }
  if(instance2 !== undefined && instance2 != "" ) {
    CKEDITOR.instances[instance2].setData(instance2Data, {
      callback: function() {
          this.checkDirty(); // true
          localStorage.setItem(instance2, "");
        }
    } );
  }
  /*for(var instanceName in CKEDITOR.instances) {  
    if(instanceName == instance) {    
      CKEDITOR.instances[instance].setData(descData, {
          callback: function() {
          this.checkDirty(); // true
          localStorage.setItem("instance", "");
          localStorage.setItem("textData", "");
        }
      } );   
    }
  }
   */
     
});

Here is the code which will let enable you to insert value in CkEditor using ajax commands programatically. if you face any bug please let know in comment I will try my best to help you.

Thanks for the tutorial, without I wouldn't manage to make it work. I changed javascript a bit to make it more universal, maybe someone will find it helpful.

(function ($, Drupal, CKEDITOR) {
  /**
   * Add new custom command.
   */
  Drupal.AjaxCommands.prototype.InsertInCkeditor = function (ajax, response, status ) {
    var selector = jQuery(response.selector).attr('id');
    var data = response.args;
    localStorage.setItem(selector, data);
  }
})(jQuery, Drupal, CKEDITOR);

jQuery( document ).ajaxStop(function() {
  for(var selector in CKEDITOR.instances) {               // Array of Ckeditor selectors on page
    if(localStorage.hasOwnProperty(selector)) {           // Do you have any data for given selector?
      var selectorData = localStorage.getItem(selector);  // Load data
      localStorage.removeItem(selector);                  // Remove data from localStorage
      CKEDITOR.instances[selector].setData(selectorData, { callback: this.checkDirty });
    }
  }
});
Bạn thấy bài viết này như thế nào?
0 reactions

Add new comment

Image CAPTCHA
Enter the characters shown in the image.
Câu nói tâm đắc: “Điều tuyệt với nhất trong cuộc sống là làm được những việc mà người khác tin là không thể!”

Related Articles

Master list (in progress) of how to get parts of fields for use in Twig templates. I’m always having to look these up, so I thought I’d hash them out and write them down.

Litespeed Cache là plugin WordPress dùng để kết hợp với Web Server LiteSpeed nhằm tăng tốc website WordPress của bạn gấp nhiều lần

In this article, we are going to see how some tools & libraries will make people's lives easier during the development & code review process.

In this tutorial, you will learn how to improve the custom code, theme and module, and general code development by using the pre-commit hook on git

Trước khi tìm hiểu xem PHP Code Sniffer là gì thì các bạn cần phải nắm được coding convention là gì đã.