Profile picture for user admin
Daniel Sipos
29 Apr 2019

In this short article I will show you something that amazed me when I discovered it. You’ll maybe say: boh, I already knew this from way back or really, that amazed you? But nonetheless, I found it cool because it really fit my needs. And like many many other things, I had no clue about this.

We all know how we can easily ajaxify our forms for quite a lot of uses cases. I talk about some of them in this Sitepoint article for example. But the other day I had a few entity autocomplete elements that needed to trigger an Ajax callback using the regular form API when the user made a selection. So I started with the regular “change” event like you normally have on other elements such as select. And it did the job…but not really. I mean, the user would look for the entity, select it, get the box filled, but no Ajax request. Only after the focus left the input would the callback kick in. This can work, maybe, but you are relying on the user’s intuition to unfocus from that form element. And that’s a nono.

Then I realised that the entity autocomplete element uses the jQuery UI autocomplete widget for finding entities. And this widget fires some events of its own. Enter autocompleteclose. This event is fired when the user has made the selection, the autocomplete closed, the selection was made and the element populated. Exactly what I needed and I guess many people need. So my form element #ajax definition now looks like this:

'#ajax' => [
  'callback' => '::ajaxRebuild',
  'event' => 'autocompleteclose',
  'wrapper' => 'form-container',
],

And this did the trick royally. The user would find the entity, click on it, the event would fire and my form rebuild with all the values available. Super.

Some hours of totally unrelated development later, I tried clearing the value of the element once selected. Oops, nothing would happen. But it should, at least in my case. The Ajax callback should be triggered to update stuff based on the (un)selected value. Hm…the change event would do that. Now what?!

Turns out you can use multiple events in one single Ajax definition. So I could use both of them which would trigger the same Ajax callback. Another freebie. So with the new element definition like this:

'#ajax' => [
  'callback' => '::ajaxRebuild',
  'event' => 'autocompleteclose change',
  'wrapper' => 'form-container',
],

Everything was peachy. Working seamlessly as the user would select something or erase the selection.

I hope this helps you as well, discovering it maybe a bit faster than it took me. Because you have it right here! :)

Profile picture for user admin

Daniel Sipos

CEO @ Web Omelette

Danny founded WEBOMELETTE in 2012 as a passion project, mostly writing about Drupal problems he faced day to day, as well as about new technologies and things that he thought other developers would find useful. Now he now manages a team of developers and designers, delivering quality products that make businesses successful.

Contact us

Comments

Christopher 02 May 2019 12:04

Managed Files Form element

Do you know the event triggered when a file has been uploaded & validated with a managed_file form element ?

If you try something like this, nothing happen. My trigger is... never triggered :

        '#required' => true,
        '#prefix' => '<div id="upload-file">',
        '#suffix' => '</div>',
        '#type' => 'managed_file',
        '#title' => $this->t('Uploader votre fichier CSV'),
        '#description' => [
          '#theme' => 'file_upload_help',
          '#upload_validators' => $validators
        ],
        '#upload_location' => 'public://csvfiles',
        '#upload_validators' => $validators,
        '#attributes' => [
          'class' => [
            'file-import-input',
          ],
        ],
        '#ajax' => [
          'event' => 'change',
          'callback' => '::refreshPreview',
          'wrapper' => 'preview',
          'progress' => [
            'type' => 'throbber',
            'message' => t('Verifying entry...'),
          ],
        ]
texas-bronius 07 May 2020 00:42

and what about autocompletecreate?

This was just what I needed, thank you! :D

Unfortunately, however, it does not seem that autocompletecreate (https://api.jqueryui.com/autocomplete/#create) does fire. I thought to dig in just a little and found that contrib autocomplete_deluxe does something with autocompleteclose, but I don't think that's what you're describing here, are you?

I would like to use autocompletecreate (or something else suitable) to allow a dependent field's creation to trickle down another dependent field's init: Change of Entity A on the form should ajax reload Entity B selector (which it does, thank you autocompleteclose) as well as Entity C selector (which it does not, because 1 element #ajax cannot spawn 2 elements in response. :( Ideas?

Add new comment