|
|
|
@ -8,223 +8,155 @@
|
|
|
|
|
use Drupal\Core\Form\FormStateInterface;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @defgroup ajax Ajax framework
|
|
|
|
|
* @defgroup ajax Ajax API
|
|
|
|
|
* @{
|
|
|
|
|
* Functions for Drupal's Ajax framework.
|
|
|
|
|
* Overview for Drupal's Ajax API.
|
|
|
|
|
*
|
|
|
|
|
* Drupal's Ajax framework is used to dynamically update parts of a page's HTML
|
|
|
|
|
* based on data from the server. Upon a specified event, such as a button
|
|
|
|
|
* click, a callback function is triggered which performs server-side logic and
|
|
|
|
|
* may return updated markup, which is then replaced on-the-fly with no page
|
|
|
|
|
* refresh necessary.
|
|
|
|
|
* @section sec_overview Overview of Ajax
|
|
|
|
|
* Ajax is the process of dynamically updating parts of a page's HTML based on
|
|
|
|
|
* data from the server. When a specified event takes place, a PHP callback is
|
|
|
|
|
* triggered, which performs server-side logic and may return updated markup or
|
|
|
|
|
* JavaScript commands to run. After the return, the browser runs the JavaScript
|
|
|
|
|
* or updates the markup on the fly, with no full page refresh necessary.
|
|
|
|
|
*
|
|
|
|
|
* This framework creates a PHP macro language that allows the server to
|
|
|
|
|
* instruct JavaScript to perform actions on the client browser. When using
|
|
|
|
|
* forms, it can be used with the #ajax property.
|
|
|
|
|
* The #ajax property can be used to bind events to the Ajax framework. By
|
|
|
|
|
* default, #ajax uses 'system/ajax' as its path for submission and thus calls
|
|
|
|
|
* \Drupal\system\FormAjaxController::content() and a defined #ajax['callback']
|
|
|
|
|
* function. However, you may optionally specify a different path to request or
|
|
|
|
|
* a different callback function to invoke, which can return updated HTML or can
|
|
|
|
|
* also return a richer set of
|
|
|
|
|
* @link ajax_commands Ajax framework commands @endlink.
|
|
|
|
|
* Many different events can trigger Ajax responses, including:
|
|
|
|
|
* - Clicking a button
|
|
|
|
|
* - Pressing a key
|
|
|
|
|
* - Moving the mouse
|
|
|
|
|
*
|
|
|
|
|
* Standard form handling is as follows:
|
|
|
|
|
* - A form element has a #ajax property that includes #ajax['callback'] and
|
|
|
|
|
* omits #ajax['path']. See below about using #ajax['path'] to implement
|
|
|
|
|
* advanced use-cases that require something other than standard form
|
|
|
|
|
* handling.
|
|
|
|
|
* - On the specified element, Ajax processing is triggered by a change to
|
|
|
|
|
* that element.
|
|
|
|
|
* - The browser submits an HTTP POST request to the 'system/ajax' Drupal
|
|
|
|
|
* path.
|
|
|
|
|
* - The controller for the route '/system/ajax',
|
|
|
|
|
* \Drupal\system\FormAjaxController::content(), calls drupal_process_form()
|
|
|
|
|
* to process the form submission and rebuild the form if necessary. The
|
|
|
|
|
* form is processed in much the same way as if it were submitted without
|
|
|
|
|
* Ajax, with the same #process functions and validation and submission
|
|
|
|
|
* handlers called in either case, making it easy to create Ajax-enabled
|
|
|
|
|
* forms that degrade gracefully when JavaScript is disabled.
|
|
|
|
|
* - After form processing is complete,
|
|
|
|
|
* \Drupal\system\FormAjaxController::content() calls the function named by
|
|
|
|
|
* #ajax['callback'], which returns the form element that has been updated
|
|
|
|
|
* and needs to be returned to the browser, or alternatively, an array of
|
|
|
|
|
* custom Ajax commands.
|
|
|
|
|
* - The array is serialized using
|
|
|
|
|
* \Drupal\Core\Ajax\AjaxResponse::ajaxRender() and sent to the browser.
|
|
|
|
|
* - The browser unserializes the returned JSON string into an array of
|
|
|
|
|
* command objects and executes each command, resulting in the old page
|
|
|
|
|
* content within and including the HTML element specified by
|
|
|
|
|
* #ajax['wrapper'] being replaced by the new content returned by
|
|
|
|
|
* #ajax['callback'], using a JavaScript animation effect specified by
|
|
|
|
|
* #ajax['effect'].
|
|
|
|
|
* @section sec_framework Ajax responses in forms
|
|
|
|
|
* Forms that use the Drupal Form API (see the
|
|
|
|
|
* @link form_api Form API topic @endlink for more information about forms) can
|
|
|
|
|
* trigger AJAX responses. Here is an outline of the steps:
|
|
|
|
|
* - Add property '#ajax' to a form element in your form array, to trigger an
|
|
|
|
|
* Ajax response.
|
|
|
|
|
* - Write an Ajax callback to process the input and respond.
|
|
|
|
|
* See sections below for details on these two steps.
|
|
|
|
|
*
|
|
|
|
|
* A simple example of basic Ajax use from the
|
|
|
|
|
* @link http://drupal.org/project/examples Examples module @endlink follows:
|
|
|
|
|
* @subsection sub_form Adding Ajax triggers to a form
|
|
|
|
|
* As an example of adding Ajax triggers to a form, consider editing a date
|
|
|
|
|
* format, where the user is provided with a sample of the generated date output
|
|
|
|
|
* as they type. To accomplish this, typing in the text field should trigger an
|
|
|
|
|
* Ajax response. This is done in the text field form array element
|
|
|
|
|
* in \Drupal\config_translation\FormElement\DateFormat::getFormElement():
|
|
|
|
|
* @code
|
|
|
|
|
* function main_page() {
|
|
|
|
|
* return \Drupal::formBuilder()->getForm('ajax_example_simplest');
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* function ajax_example_simplest($form, FormStateInterface $form_state) {
|
|
|
|
|
* $form = array();
|
|
|
|
|
* $form['changethis'] = array(
|
|
|
|
|
* '#type' => 'select',
|
|
|
|
|
* '#options' => array(
|
|
|
|
|
* 'one' => 'one',
|
|
|
|
|
* 'two' => 'two',
|
|
|
|
|
* 'three' => 'three',
|
|
|
|
|
* ),
|
|
|
|
|
* '#ajax' => array(
|
|
|
|
|
* 'callback' => 'ajax_example_simplest_callback',
|
|
|
|
|
* 'wrapper' => 'replace_textfield_div',
|
|
|
|
|
* ),
|
|
|
|
|
* );
|
|
|
|
|
*
|
|
|
|
|
* // This entire form element will be replaced with an updated value.
|
|
|
|
|
* $form['replace_textfield'] = array(
|
|
|
|
|
* '#type' => 'textfield',
|
|
|
|
|
* '#title' => t("The default value will be changed"),
|
|
|
|
|
* '#description' => t("Say something about why you chose") . "'" .
|
|
|
|
|
* (!empty($form_state['values']['changethis'])
|
|
|
|
|
* ? $form_state['values']['changethis'] : t("Not changed yet")) . "'",
|
|
|
|
|
* '#prefix' => '<div id="replace_textfield_div">',
|
|
|
|
|
* '#suffix' => '</div>',
|
|
|
|
|
* );
|
|
|
|
|
* return $form;
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* function ajax_example_simplest_callback($form, FormStateInterface $form_state) {
|
|
|
|
|
* // The form has already been submitted and updated. We can return the replaced
|
|
|
|
|
* // item as it is.
|
|
|
|
|
* return $form['replace_textfield'];
|
|
|
|
|
* }
|
|
|
|
|
* '#ajax' => array(
|
|
|
|
|
* 'callback' => 'Drupal\config_translation\FormElement\DateFormat::ajaxSample',
|
|
|
|
|
* 'event' => 'keyup',
|
|
|
|
|
* 'progress' => array(
|
|
|
|
|
* 'type' => 'throbber',
|
|
|
|
|
* 'message' => NULL,
|
|
|
|
|
* ),
|
|
|
|
|
* ),
|
|
|
|
|
* @endcode
|
|
|
|
|
*
|
|
|
|
|
* In the above example, the 'changethis' element is Ajax-enabled. The default
|
|
|
|
|
* #ajax['event'] is 'change', so when the 'changethis' element changes,
|
|
|
|
|
* an Ajax call is made. The form is submitted and reprocessed, and then the
|
|
|
|
|
* callback is called. In this case, the form has been automatically
|
|
|
|
|
* built changing $form['replace_textfield']['#description'], so the callback
|
|
|
|
|
* just returns that part of the form.
|
|
|
|
|
* As you can see from this example, the #ajax property for a form element is
|
|
|
|
|
* an array. Here are the details of its elements, all of which are optional:
|
|
|
|
|
* - callback: The callback to invoke to handle the server side of the
|
|
|
|
|
* Ajax event. More information on callbacks is below in @ref sub_callback.
|
|
|
|
|
* - path: The URL path to use for the request. If omitted, defaults to
|
|
|
|
|
* 'system/ajax', which invokes the default Drupal Ajax processing (this will
|
|
|
|
|
* call the callback supplied in the 'callback' element). If you supply a
|
|
|
|
|
* path, you must set up a routing entry to handle the request yourself and
|
|
|
|
|
* return output described in @ref sub_callback below. See the
|
|
|
|
|
* @link menu Routing topic @endlink for more information on routing.
|
|
|
|
|
* - wrapper: The HTML 'id' attribute of the area where the content returned by
|
|
|
|
|
* the callback should be placed. Note that callbacks have a choice of
|
|
|
|
|
* returning content or JavaScript commands; 'wrapper' is used for content
|
|
|
|
|
* returns.
|
|
|
|
|
* - method: The jQuery method for placing the new content (used with
|
|
|
|
|
* 'wrapper'). Valid options are 'replaceWith' (default), 'append', 'prepend',
|
|
|
|
|
* 'before', 'after', or 'html'. See
|
|
|
|
|
* http://api.jquery.com/category/manipulation/ for more information on these
|
|
|
|
|
* methods.
|
|
|
|
|
* - effect: The jQuery effect to use when placing the new HTML (used with
|
|
|
|
|
* 'wrapper'). Valid options are 'none' (default), 'slide', or 'fade'.
|
|
|
|
|
* - speed: The effect speed to use (used with 'effect' and 'wrapper'). Valid
|
|
|
|
|
* options are 'slow' (default), 'fast', or the number of milliseconds the
|
|
|
|
|
* effect should run.
|
|
|
|
|
* - event: The JavaScript event to respond to. This is selected automatically
|
|
|
|
|
* for the type of form element; provide a value to override the default.
|
|
|
|
|
* - prevent: A JavaScript event to prevent when the event is triggered. For
|
|
|
|
|
* example, if you use event 'mousedown' on a button, you might want to
|
|
|
|
|
* prevent 'click' events from also being triggered.
|
|
|
|
|
* - progress: An array indicating how to show Ajax processing progress. Can
|
|
|
|
|
* contain one or more of these elements:
|
|
|
|
|
* - type: Type of indicator: 'throbber' (default) or 'bar'.
|
|
|
|
|
* - message: Translated message to display.
|
|
|
|
|
* - url: For a bar progress indicator, URL path for determining progress.
|
|
|
|
|
* - interval: For a bar progress indicator, how often to update it.
|
|
|
|
|
*
|
|
|
|
|
* To implement Ajax handling in a form, add '#ajax' to the form
|
|
|
|
|
* definition of a field. That field will trigger an Ajax event when it is
|
|
|
|
|
* clicked (or changed, depending on the kind of field). #ajax supports
|
|
|
|
|
* the following parameters (either 'path' or 'callback' is required at least):
|
|
|
|
|
* - #ajax['callback']: The callback to invoke to handle the server side of the
|
|
|
|
|
* Ajax event, which will receive a $form and $form_state as arguments, and
|
|
|
|
|
* returns a renderable array (most often a form or form fragment), an HTML
|
|
|
|
|
* string, or an array of Ajax commands. If returning a renderable array or
|
|
|
|
|
* a string, the value will replace the original element named in
|
|
|
|
|
* #ajax['wrapper'], and
|
|
|
|
|
* theme_status_messages()
|
|
|
|
|
* will be prepended to that
|
|
|
|
|
* element. (If the status messages are not wanted, return an array
|
|
|
|
|
* of Ajax commands instead.)
|
|
|
|
|
* #ajax['wrapper']. If an array of Ajax commands is returned, it will be
|
|
|
|
|
* executed by the calling code.
|
|
|
|
|
* - #ajax['path']: The menu path to use for the request. This is often omitted
|
|
|
|
|
* and the default is used. This path should map
|
|
|
|
|
* to a controller that returns data using
|
|
|
|
|
* \Drupal\Core\Ajax\AjaxResponse::ajaxRender(). Defaults to 'system/ajax',
|
|
|
|
|
* which invokes \Drupal\system\FormAjaxController::content(), eventually
|
|
|
|
|
* calling the function named in #ajax['callback']. If you use a custom path,
|
|
|
|
|
* you must set up the menu entry and handle the entire callback in your own
|
|
|
|
|
* code.
|
|
|
|
|
* - #ajax['wrapper']: The CSS ID of the area to be replaced by the content
|
|
|
|
|
* returned by the #ajax['callback'] function. The content returned from
|
|
|
|
|
* the callback will replace the entire element named by #ajax['wrapper'].
|
|
|
|
|
* The wrapper is usually created using #prefix and #suffix properties in the
|
|
|
|
|
* form. Note that this is the wrapper ID, not a CSS selector. So to replace
|
|
|
|
|
* the element referred to by the CSS selector #some-selector on the page,
|
|
|
|
|
* use #ajax['wrapper'] = 'some-selector', not '#some-selector'.
|
|
|
|
|
* - #ajax['effect']: The jQuery effect to use when placing the new HTML.
|
|
|
|
|
* Defaults to no effect. Valid options are 'none', 'slide', or 'fade'.
|
|
|
|
|
* - #ajax['speed']: The effect speed to use. Defaults to 'slow'. May be
|
|
|
|
|
* 'slow', 'fast' or a number in milliseconds which represents the length
|
|
|
|
|
* of time the effect should run.
|
|
|
|
|
* - #ajax['event']: The JavaScript event to respond to. This is normally
|
|
|
|
|
* selected automatically for the type of form widget being used, and
|
|
|
|
|
* is only needed if you need to override the default behavior.
|
|
|
|
|
* - #ajax['prevent']: A JavaScript event to prevent when 'event' is triggered.
|
|
|
|
|
* Defaults to 'click' for #ajax on #type 'submit', 'button', and
|
|
|
|
|
* 'image_button'. Multiple events may be specified separated by spaces.
|
|
|
|
|
* For example, when binding #ajax behaviors to form buttons, pressing the
|
|
|
|
|
* ENTER key within a textfield triggers the 'click' event of the form's first
|
|
|
|
|
* submit button. Triggering Ajax in this situation leads to problems, like
|
|
|
|
|
* breaking autocomplete textfields. Because of that, Ajax behaviors are bound
|
|
|
|
|
* to the 'mousedown' event on form buttons by default. However, binding to
|
|
|
|
|
* 'mousedown' rather than 'click' means that it is possible to trigger a
|
|
|
|
|
* click by pressing the mouse, holding the mouse button down until the Ajax
|
|
|
|
|
* request is complete and the button is re-enabled, and then releasing the
|
|
|
|
|
* mouse button. For this case, 'prevent' can be set to 'click', so an
|
|
|
|
|
* additional event handler is bound to prevent such a click from triggering a
|
|
|
|
|
* non-Ajax form submission. This also prevents a textfield's ENTER press
|
|
|
|
|
* triggering a button's non-Ajax form submission behavior.
|
|
|
|
|
* - #ajax['method']: The jQuery method to use to place the new HTML.
|
|
|
|
|
* Defaults to 'replaceWith'. May be: 'replaceWith', 'append', 'prepend',
|
|
|
|
|
* 'before', 'after', or 'html'. See the
|
|
|
|
|
* @link http://api.jquery.com/category/manipulation/ jQuery manipulators documentation @endlink
|
|
|
|
|
* for more information on these methods.
|
|
|
|
|
* - #ajax['progress']: Choose either a throbber or progress bar that is
|
|
|
|
|
* displayed while awaiting a response from the callback, and add an optional
|
|
|
|
|
* message. Possible keys: 'type', 'message', 'url', 'interval'.
|
|
|
|
|
* More information is available in the
|
|
|
|
|
* @link forms_api_reference.html Form API Reference @endlink
|
|
|
|
|
*
|
|
|
|
|
* In addition to using Form API for doing in-form modification, Ajax may be
|
|
|
|
|
* enabled by adding classes to buttons and links. By adding the 'use-ajax'
|
|
|
|
|
* class to a link, the link will be loaded via an Ajax call. When using this
|
|
|
|
|
* method, the href of the link can contain '/nojs/' as part of the path. When
|
|
|
|
|
* the Ajax framework makes the request, it will convert this to '/ajax/'.
|
|
|
|
|
* The server is then able to easily tell if this request was made through an
|
|
|
|
|
* actual Ajax request or in a degraded state, and respond appropriately.
|
|
|
|
|
*
|
|
|
|
|
* Similarly, submit buttons can be given the class 'use-ajax-submit'. The
|
|
|
|
|
* form will then be submitted via Ajax to the path specified in the #action.
|
|
|
|
|
* Like the ajax-submit class above, this path will have '/nojs/' replaced with
|
|
|
|
|
* '/ajax/' so that the submit handler can tell if the form was submitted
|
|
|
|
|
* in a degraded state or not.
|
|
|
|
|
*
|
|
|
|
|
* As a developer you basically create a \Drupal\Core\Ajax\AjaxResponse and add
|
|
|
|
|
* a couple of \Drupal\Core\Ajax\CommandInterface onto it, which will be
|
|
|
|
|
* converted to a commands array automatically. This commands array will be
|
|
|
|
|
* converted to a JSON object and returned to the client, which will then
|
|
|
|
|
* iterate over the array and process it like a macro language.
|
|
|
|
|
*
|
|
|
|
|
* Each command item is an associative array which will be converted to a
|
|
|
|
|
* command object on the JavaScript side. $command_item['command'] is the type
|
|
|
|
|
* of command, e.g. 'alert' or 'replace', and will correspond to a method in the
|
|
|
|
|
* Drupal.ajax[command] space. The command array may contain any other data that
|
|
|
|
|
* the command needs to process, e.g. 'method', 'selector', 'settings', etc.
|
|
|
|
|
*
|
|
|
|
|
* Commands are usually created with a couple of helper functions, so they
|
|
|
|
|
* look like this:
|
|
|
|
|
* @subsection sub_callback Setting up a callback to process Ajax
|
|
|
|
|
* Once you have set up your form to trigger an Ajax response (see @ref sub_form
|
|
|
|
|
* above), you need to write some PHP code to process the response. If you use
|
|
|
|
|
* 'path' in your Ajax set-up, your route controller will be triggered with only
|
|
|
|
|
* the information you provide in the URL. If you use 'callback', your callback
|
|
|
|
|
* method is a function, which will receive the $form and $form_state from the
|
|
|
|
|
* triggering form. You can use $form_state to get information about the
|
|
|
|
|
* data the user has entered into the form. For instance, in the above example
|
|
|
|
|
* for the date format preview,
|
|
|
|
|
* \Drupal\config_translation\FormElement\DateFormat\ajaxSample() does this to
|
|
|
|
|
* get the format string entered by the user:
|
|
|
|
|
* @code
|
|
|
|
|
* $commands = array();
|
|
|
|
|
* // Replace the content of '#object-1' on the page with 'some html here'.
|
|
|
|
|
* $commands[] = ajax_command_replace('#object-1', 'some html here');
|
|
|
|
|
* // Add a visual "changed" marker to the '#object-1' element.
|
|
|
|
|
* $commands[] = ajax_command_changed('#object-1');
|
|
|
|
|
* // #ajax['callback'] functions are supposed to return render arrays. If
|
|
|
|
|
* // returning an Ajax commands array, it must be encapsulated in a render
|
|
|
|
|
* // array structure.
|
|
|
|
|
* return array('#type' => 'ajax', '#commands' => $commands);
|
|
|
|
|
* $format_value = \Drupal\Component\Utility\NestedArray::getValue(
|
|
|
|
|
* $form_state['values'],
|
|
|
|
|
* $form_state['triggering_element']['#array_parents']);
|
|
|
|
|
* @endcode
|
|
|
|
|
*
|
|
|
|
|
* When returning an Ajax command array, it is often useful to have
|
|
|
|
|
* status messages rendered along with other tasks in the command array.
|
|
|
|
|
* In that case the the Ajax commands array may be constructed like this:
|
|
|
|
|
* Once you have processed the input, you have your choice of returning HTML
|
|
|
|
|
* markup or a set of Ajax commands. If you choose to return HTML markup, you
|
|
|
|
|
* can return it as a string or a renderable array, and it will be placed in
|
|
|
|
|
* the defined 'wrapper' element (see documentation above in @ref sub_form).
|
|
|
|
|
* In addition, any messages returned by drupal_get_messages(), themed as in
|
|
|
|
|
* status-messages.html.twig, will be prepended.
|
|
|
|
|
*
|
|
|
|
|
* To return commands, you need to set up an object of class
|
|
|
|
|
* \Drupal\Core\Ajax\AjaxResponse, and then use its addCommand() method to add
|
|
|
|
|
* individual commands to it. In the date format preview example, the format
|
|
|
|
|
* output is calculated, and then it is returned as replacement markup for a div
|
|
|
|
|
* like this:
|
|
|
|
|
* @code
|
|
|
|
|
* $commands = array();
|
|
|
|
|
* $commands[] = ajax_command_replace(NULL, $output);
|
|
|
|
|
* $status_messages = array('#theme' => 'status_messages');
|
|
|
|
|
* $commands[] = ajax_command_prepend(NULL, drupal_render($status_messages));
|
|
|
|
|
* return array('#type' => 'ajax', '#commands' => $commands);
|
|
|
|
|
* $response = new AjaxResponse();
|
|
|
|
|
* $response->addCommand(new ReplaceCommand(
|
|
|
|
|
* '#edit-date-format-suffix',
|
|
|
|
|
* '<small id="edit-date-format-suffix">' . $format . '</small>'));
|
|
|
|
|
* return $response;
|
|
|
|
|
* @endcode
|
|
|
|
|
*
|
|
|
|
|
* See @link ajax_commands Ajax framework commands @endlink
|
|
|
|
|
* The individual commands that you can return implement interface
|
|
|
|
|
* \Drupal\Core\Ajax\CommandInterface. Available commands provide the ability
|
|
|
|
|
* to pop up alerts, manipulate text and markup in various ways, redirect
|
|
|
|
|
* to a new URL, and the generic \Drupal\Core\Ajax\InvokeCommand, which
|
|
|
|
|
* invokes an arbitrary jQuery commnd.
|
|
|
|
|
*
|
|
|
|
|
* As noted above, status messages are prepended automatically if you use the
|
|
|
|
|
* 'wrapper' method and return HTML markup. This is not the case if you return
|
|
|
|
|
* commands, but if you would like to show status messages, you can add
|
|
|
|
|
* @code
|
|
|
|
|
* array('#theme' => 'status_messages')
|
|
|
|
|
* @endcode
|
|
|
|
|
* to a render array, use drupal_render() to render it, and add a command to
|
|
|
|
|
* place the messages in an appropriate location.
|
|
|
|
|
*
|
|
|
|
|
* @section sec_other Other methods for triggering Ajax
|
|
|
|
|
* Here are some additional methods you can use to trigger Ajax responses in
|
|
|
|
|
* Drupal:
|
|
|
|
|
* - Add class 'use-ajax' to a link. The link will be loaded using an Ajax
|
|
|
|
|
* call. When using this method, the href of the link can contain '/nojs/' as
|
|
|
|
|
* part of the path. When the Ajax JavaScript processes the page, it will
|
|
|
|
|
* convert this to '/ajax/'. The server is then able to easily tell if this
|
|
|
|
|
* request was made through an actual Ajax request or in a degraded state, and
|
|
|
|
|
* respond appropriately.
|
|
|
|
|
* - Add class 'use-ajax-submit' to a submit button in a form. The form will
|
|
|
|
|
* then be submitted via Ajax to the path specified in the #action. Like the
|
|
|
|
|
* ajax-submit class on links, this path will have '/nojs/' replaced with
|
|
|
|
|
* '/ajax/' so that the submit handler can tell if the form was submitted in a
|
|
|
|
|
* degraded state or not.
|
|
|
|
|
* - Add property '#autocomplete_route_name' to a text field in a form. The
|
|
|
|
|
* route controller for this route must return an array of options for
|
|
|
|
|
* autocomplete, as a \Symfony\Component\HttpFoundation\JsonResponse object.
|
|
|
|
|
* See the @link menu Routing topic @endlink for more information about
|
|
|
|
|
* routing.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|