In this article we will show a solution to add an ajax call to populate multiple information in a Drupal 8 form textarea element.
In this example, the script will autocomplete users list in the form for a custom module called MyModule. The user will enter first 2 letters of a name or email.
1) create a library
In MyModule.libraries.yml add the necessary javascript reference that will be used to populate the users in the form:
MyModule_lib:
version: VERSION
js:
js/autocomplete.js: {}
dependencies:
- core/jquery
- core/jquery.ui.autocomplete
The autocomplete function as dependencies which are based on jQuery library.
2) JS script
The jQuery autocomplete.js file that we use is copied below. It is implemented as Drupal behaviors You need to add this file in MyModule/js/ folder.
JS script:
(function ($, Drupal, drupalSettings) {
Drupal.behaviors.MyModule_autocomplete = {
attach: function (context, settings) {
jQuery(function() {
function split( val ) {
return val.split( /,\s*/
);
}
function extractLast( term ) {
return split( term ).pop();
}
jQuery( "#edit-users" )
.bind( "keydown", function( event ) {
if ( event.keyCode === jQuery.ui.keyCode.TAB &&
jQuery( this ).data( "ui-autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
source: function( request, response ) {
jQuery.getJSON("mypath/autocomplete", {
term: extractLast( request.term )
}, response );
},
search: function() {
// custom minLength
var term = extractLast( this.value );
if ( term.length 2 ) {
return false;
}
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end - used for multi select
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
});
}
};
})(jQuery, Drupal, drupalSettings);
3) Route
In the script above, the "path/autocomplete" is the path to the controller function that will handle and return the queries.
In your file "MyModule.routing.yml", you need to have a route to the function like:
form_autocomplete:
path: '/mypath/autocomplete'
defaults:
_controller: '\Drupal\MyModule\Controller\MyController::autocomplete'
4) Controller
In MyController class, the autocomplete function will return the list of names that will be populated in the form textbox:
public function autocomplete(Request $request) {
$text = $request->query->get('term');
$query = "SELECT distinct name from {users_field_data} WHERE mail like :t1 or name like :t2 ";
$a = array(':t1' => "$text%", ':t2' => "$text%");
$name = db_query($query, $a)->fetchCol();
return new JsonResponse($name);
}
In the function above the 'term' is the user input. The script will query the database for users names or users emails that match the input and will return it as a Json array.
5) The form
In the custom module form, add the textarea element:
$form['users'] = array(
'#type' => 'textarea',
'#rows' => 2,
'#attributes' => array('placeholder' => t('enter recipients name separated by comma.')),
'#required' => TRUE,
'#default_value' => NULL,
6) the result
The result will show as below. When the user type first 2 letters of the name he is looking for, a list of matches will be displayed below the box and added to the list in the textarea when clicked. The values of the list are separated by a comma (see the terms.join( ", " ) function in autocomplete.js).
Add new comment