Tập tành Creating custom ajax command In Drupal 9
23rd Jun 2022I 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 }); } } });
Add new comment