📜 ⬆️ ⬇️

Correct ajax requests in Drupal 7

Many send ajax requests in the old manner with hands using $ .ajax (), while in Drupal there is a fairly flexible mechanism for this that allows you to reuse ready-made code from the kernel, and reduce the number of JS code.
In order to start using it, you need to deal with such things as delivery callback, Drupal.ajax and JS-commands.

Delivery callback


I will describe briefly, because this question deserves a separate topic.
In D6, your menu callback had to return the finished html, which then turned around in theme ('page', $ content), and you got the page.
To return, for example, json-data bypassing page.tpl, you had to call drupal_json ($ result), and at the end of the callback function, you would call exit ().
D7 introduced a new concept - 'delivery callback'. Its essence is that the callback menu returns the answer in an intermediate form - as an array in a specific format (see the description of render arrays on Drupal.org ), and the function specified in the corresponding hook_menu element as the delivery callback will determine how to respond to the client - then as a page or convert to json.

Drupal.ajax


In Drupal, there is a standard way to send ajax requests.
Based on the implementation, he thought to work with forms (in the Form API itself, it is used everywhere), but nothing prevents us from using it anywhere.
The simplest example looks like this:
var settings = {url : myUrl}; var ajax = new Drupal.ajax(false, false, settings); ajax.eventResponse(ajax, {}); 

The third line is needed to immediately send a request. If you skip it, the request will be sent when the JS event settings.event (by default 'mousedown') occurs over the DOM / jQuery element passed as the second argument to Drupal.ajax ().
In our case, I just want to immediately send a request, so all this is omitted.
It should be noted that Drupal.ajax is declared in the file misc / ajax.js, so do not forget to enable it.

If you need to somehow influence the behavior of the request, you simply need to inherit from Drupal.ajax, override the desired method (for example, success callback), and then create an object of your own class.
There is another way to influence the handler of some event - simply override a function with the same name below the code (in the script that is connected later ajax.js), although I do not recommend this approach, sometimes it still has to be implemented, for example affect all places where new Drupal.ajax is already being used, and you won’t be able to go there (script from another module).
I also note that Drupal.ajax will send POST, and the dataType will be json. If this does not suit you, then you need to override / inherit.
')

JS-commands


JS commands are a set of JS functions, especially in that the fact of their calling and arguments can be defined on the server side when generating an ajax response.
This can be done by forming, as the return value of the callback menu for an ajax request, an array of the form:
 function your_module_ajax_menu_callback() { // ... $result = array( '#type' => 'ajax', '#commands' => array( array( 'command' => $command_name, ), ), ); return $result; } 

Where $ command_name is the name of the property / JS function from the Drupal.ajax.prototype.com commands object.
In this case, $ result is one of the render array options, and in order for it to be correctly converted to json-data, with the necessary headers, the hook_menu element corresponding to the callback must be set as 'delivery callback' - 'ajax_deliver':
 function your_module_menu() { // ... $items['ajax/your-module/path'] = array( 'title' => 'Get content by AJAX', 'page callback' => 'your_module_ajax_menu_callback', 'page arguments' => array(), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, 'delivery callback' => 'ajax_deliver', ); return $items; } 

The answer was formed, but who will call our teams? And here comes the third component - Drupal.ajax.
Sending an ajax request with its help means that the success event handler has already been declared, it will iterate over all installed commands from the response, and call the appropriate functions.

Consider an example - getting content using an ajax request and inserting it into some container on the page when you click on an item.
Usually we would write:
 $('#somen-link').click(function () { $.ajax({ type: 'GET', url: myUrl, dataType: 'html', success: function (data) { // Set up new content. $('div.container').html(data); } }); }); 

With our approach, we will replace it like this:
 var ajax = new Drupal.ajax(false, '#somen-link', {url : myUrl}); ajax.eventResponse(ajax, {}); 

And such code in the callback menu (do not forget about ajax_deliver as a delivery callback):
 $result = array('#type' => 'ajax'); $result['#commands'][] = ajax_command_insert('div.container', $html); return $result; 

Thus, with our ajax request, we formed an array of commands, which in ajax_deliver () will be converted to json, and then all commands will be called in Drupal.ajax.prototype.success as soon as the browser receives a response.

The point of the ajax_command_insert () function is to simply form an array with the name and parameters of the JS command.
In this case, to insert content from the 'data' key into the container on the page with the $ selector selector:
 array( 'command' => 'insert', 'method' => NULL, 'selector' => $selector, 'data' => $html, 'settings' => $settings, ); 

The kernel has a number of ajax_command_ * functions for quickly generating predefined commands from ajax.js.

You can freely define your commands by simply adding a function to the Drupal.ajax.prototype.commands prototype:
 /** * Ajax delivery command to switch among tabs by ID. */ Drupal.ajax.prototype.commands.gotoTab = function (ajax, response, status) { // response.data is a value setted in 'data' key of command on PHP side. if (response.data) { // ... } }; 

In order to invoke it, you just need to set the gotoTab name as the value of the 'command' key:
 $result['#commands'][] = array( 'command' => 'gotoTab', ); 

All additional keys of this array will be available in our JS function as response.YOUR_KEY, for example response.selector in the case of the insert command. Thus, we can pass any arguments.

What gives us all this?
First, there is a ready-made set of commands, and we can generally avoid manual processing of a success event.
The list of commands provided by the kernel can be found in ajax.js, where Drupal.ajax.prototype.commands is declared.

Secondly, we can write the implementation of our commands once, and then on the server side manage the command set (or, for example, let someone change them via hook_alter) for each case without changing the script code.

Source: https://habr.com/ru/post/164443/


All Articles