Problem/Motivation

In Select2 Entity Reference field widgets, with autocomplete enabled, for multivalued fields, removing a selected option doesn't always work on the first click. When the issue occurs, it needs 3 clicks. See screen recording @ https://www.drupal.org/files/issues/2022-03-23/Screen%20Recording%202022... .

Steps to reproduce

  1. Install standard Drupal
  2. Install select2 module
  3. Configure the Select2 Entity Reference field widget for the Tags field on Article content type
  4. Make sure autocomplete is enabled for the Select2 Entity Reference field widget
  5. Create 10 tags or so
  6. Create an Article with those 10 tags
  7. Navigate to the edit form of the Article you just created
  8. Start clicking on the X-icons in the tags field 1 by 1. Eventually you'll come across a tag that needs 3 clicks before it get removed.

Proposed resolution

Unsure what the solution is, but I did track the root cause of the issue: the drag & drop functionality that is initiated here:

        // Copied from https://github.com/woocommerce/woocommerce/blob/master/assets/js/admin/wc-enhanced-select.js#L118
        if (Object.prototype.hasOwnProperty.call(config, 'ajax') && config.multiple) {
          var $select = $(this);
          var $list = $select.next('.select2-container').find('ul.select2-selection__rendered');
          Sortable.create($list[0], {
            draggable: 'li:not(.select2-search)',
            forceFallback: true,
            onEnd: function () {
              $($list.find('.select2-selection__choice').get().reverse()).each(function () {
                $select.prepend($select.find('option[value="' + $(this).data('optionValue') + '"]').first());
              });
            }
          });
        }

The usage of SortableJs was introduced in #3104877: Replace jquery.ui.sortable with SortableJs.

Issue fork select2-3271205

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

rp7 created an issue. See original summary.

tuuuukka’s picture

This seems to be a really random thing, hard to say where the problem actually lies. One way to reproduce this is to grab any selected tag, move it a little but not change the order, release it and then try to remove it -> requires 2 clicks on the X before it's actually removed. The first click adds draggable="false" to the element.

tuuuukka’s picture

StatusFileSize
new530 bytes

Not an actual fix, but this helps anyway: https://github.com/SortableJS/Sortable#fallbacktolerance-option

I noticed that when you're clicking the X's, it sometimes fires the SortableJS stuff 'cause it counts the click as a drag if your mouse moves even a little bit. It's simple to try out when it happens:

diff --git a/js/select2.js b/js/select2.js
index 8aaec4c..cd8432a 100644
--- a/js/select2.js
+++ b/js/select2.js
@@ -67,6 +67,7 @@
             draggable: 'li:not(.select2-search)',
             forceFallback: true,
             onEnd: function () {
+              console.log('Dragged');
               $($list.find('.select2-selection__choice').get().reverse()).each(function () {
                 $select.prepend($select.find('option[value="' + $(this).data('optionValue') + '"]').first());
               });

I added fallbackTolerance: 10, and it does help with those unwanted drags when you're just trying to click. But this still doesn't completely solve the actual problem. I still think it's better than the default behavior though, so here's a simple patch.

tuuuukka’s picture

StatusFileSize
new924 bytes

Had a sudden thought of this being caused by the order of the items not changing, but the code inside onEnd being run nevertheless. So I tried checking if the order has changed before running the piece code, and that seems to fix it -> if the order has changed, run the code, if the order is the same, do nothing.

Patch included.

recrit’s picture

Status: Active » Needs review
StatusFileSize
new592 bytes

I ran into this same issue. The patch #4 did not fix this issue for me. The patch #3 did not fix this issue for me.
Field setup:
- autocomplete
- multiple values

Select2: 4.1.0-rc.0

Browsers:
Chrome, FireFox

To Reproduce:
I was able to reproduce this with only 1 or 2 tags. You just have to drag 1 item left or right but keep it in the same position.

Troubleshooting:
It works ok when I remove only the Sortable option forceFallback: true.
From https://github.com/SortableJS/Sortable#options:
"forceFallback: ignore the HTML5 DnD behaviour and force the fallback to kick in"

I do not see this option set in any Drupal core usage of the Sortable library.

Fix:
The attached patch removes the option "forceFallback".

Maintainers - any feedback on why the forceFallback option was used?
It was added in this commit Issue #3104877 by angela_G, chr.fritsch, volkerk: Replace jquery.ui.sortable with SortableJs, #3104877: Replace jquery.ui.sortable with SortableJs

tuuuukka’s picture

The patch #4 did not fix this issue for me.

Tested #4 again on a vanilla install of D9 and Select2 with no other modules installed, and the patch works (autocomplete, multivalue). Do you have any customization that might be interfering with it?

Removing forceFallback works, but it also requires you to first focus the element before you can drag anything in it. Plus it might cause some UI/UX issues on certain themes (although that's more of a theme related issue, but anyways).

recrit’s picture

@Tuuuukka I do not have any customization to the Select2 element. The admin theme is Seven. With patch #4, I could still reproduce the bug as stated above.

Select2: 4.1.0-rc.0

For FireFox - it worked without having to focus the input. I was able to just dragged an item. I suspect its a timing issue with Select2 autofocus and Sortable draggable code.

For Chrome - I attempted to drag an item without focusing and it did not work. The focus was then auto set (i suspect Select2 is doing that). Then it works when attempting to drag again.

UPDATE:
I tested with the original code with forceFallback: true, and had the same results in Chrome where you first have to focus (either directly or by clicking an item) before you can drag an item.
So this suggests that forceFallback does not affect the focusing.
As stated in the docs https://github.com/SortableJS/Sortable#options:
"forceFallback: ignore the HTML5 DnD behaviour and force the fallback to kick in"
This affects DnD (Drag n Drop).

recrit’s picture

StatusFileSize
new995 bytes
new961 bytes

The patch #4 makes sense to me to check if the index changed. The attached combines both patches - #4 and #5.

shivamitakari’s picture

Status: Needs review » Reviewed & tested by the community

I have tested the patch select2-check-indexes-3271205-8.patch and it works fine.

heatherwoz’s picture

Also tested patch in #8 and it's working for us.

pawelgorski87’s picture

select2-check-indexes-3271205-8.patch
Working also on Drupal 10, thx

chr.fritsch made their first commit to this issue’s fork.

chr.fritsch’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

himanshu raj’s picture

I have tested the patch select2-check-indexes-3271205-8.patch on Drupal 9.5.2 with PHP 8.1 and the Select2 module.

Issue:
In multivalued entity reference fields with autocomplete, removing a selected option required multiple clicks.
After applying the patch:

Selected items are removed on the first click consistently.

Drag-and-drop sorting still works correctly.

No JavaScript or UX issues noticed in testing.

Marking as “Works for me.” Based on the results, this patch looks ready for RTBC (Reviewed and Tested by the Community).

Thanks to the contributors for resolving this frustrating usability bug.

avpaderno’s picture

@himanshu This is a closed issue, and its merge request has been already merged.
There is no need to report the merge request works for you, since it has been already merged. What eventually could be done, in this case, is opening a new issue for any problem caused by this merge request.