4

I would like to add autocomplete functionality to a textarea form element in Drupal 8. I have a fully functioning custom textfield which has autocomplete working on the same form. I have confirmed that the Textarea element has the processAutocomplete function. Therefore, I'm uncertain as to why this wouldn't work.

I realize that adding an autocomplete to a textarea is a bit unorthodox, but that's not the question. I have seen this done in Drupal 8, so I know it's possible. I just don't know if they used a form to accomplish it.

I have added the appropriate code in the routing file:

my_module.autocomplete_name:
   path: '/my-module/test-autocomplete'
   defaults:
     _controller:'\Drupal\my_module\Controller\Controller::functionName'
     _format: json
   requirements:
     _access: 'TRUE'

I have also added the field appropriately on the form:

$form['text_area'] = [
  '#type' => 'textarea',
  '#title' => t('Test text area'),
  '#default_value' => $authentication_configuration->get('text_area'),
  '#autocomplete_route_name' => 'my_module.autocomplete_name',
];

Finally, I have the appropriate logic in the referenced controller:

public function testAutocomplete(request $request) {
  // Set up the array to be returned and get the user input
  $matches = array();
  $input = $request->query->get('q');
  // If there is user input
  if ($input) {
    $words = explode(' ', $input);
    foreach ($words as $word) {
      /*
       * Logic for generating an autocomplete list of matches
       */
    }
  }
  return new JsonResponse($matches);
}
5

Textareas don't support autocomplete out of the box, you have to get a bit creative to make it work.

First you'll need to override the attach method of the autocomplete behaviour; add a library with a JS file containing this:

(function ($) {
  Drupal.behaviors.autocomplete.attach = function attach(context) {
    var $autocomplete = $(context).find('input.form-autocomplete,textarea.form-autocomplete').once('autocomplete');
    if ($autocomplete.length) {
      var blacklist = $autocomplete.attr('data-autocomplete-first-character-blacklist');
      $.extend(Drupal.autocomplete.options, {
        firstCharacterBlacklist: blacklist || ''
      });

      $autocomplete.autocomplete(Drupal.autocomplete.options).each(function () {
        $(this).data('ui-autocomplete')._renderItem = Drupal.autocomplete.options.renderItem;
      });

      $autocomplete.on('compositionstart.autocomplete', function () {
        Drupal.autocomplete.options.isComposing = true;
      });
      $autocomplete.on('compositionend.autocomplete', function () {
        Drupal.autocomplete.options.isComposing = false;
      });
    }
  };
})(jQuery);

The function is a straight copy of the core attach method, with the textarea added to the selectors, and a few references altered.

Then you'll need to add the autocomplete process method to the form element (it's not there by default), and also reference your library:

use Drupal\Core\Render\Element\Textarea;

...

$form['text_area'] = [
  '#type' => 'textarea',
  '#title' => t('Test text area'),
  '#default_value' => $authentication_configuration->get('text_area'),
  '#autocomplete_route_name' => 'my_module.autocomplete_name',
  '#process' => [
    [Textarea::class, 'processAutocomplete'],
  ],
  '#attached' => [
    'library' => [
      'mymodule/autocomplete'
    ],
  ],
];

Clear the cache and you should see the results immediately.

  • It worked! For those who may want to do this, be sure to include the use statement above. If you don't, it will not render a textarea. – Travis Dec 11 '18 at 17:26

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.