Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search not auto focusing in jQuery 3.6.0 #5993

Closed
ryanb opened this issue Mar 3, 2021 · 80 comments
Closed

Search not auto focusing in jQuery 3.6.0 #5993

ryanb opened this issue Mar 3, 2021 · 80 comments

Comments

@ryanb
Copy link

ryanb commented Mar 3, 2021

I'm running Select2 4.0.13 with jQuery 3.6.0 and the search box does not auto-focus when opening select2. I believe this is caused by the "fix" in jQuery 3.6.0 related to triggering a focus event within another focus event.

See the release notes for details: http://blog.jquery.com/2021/03/02/jquery-3-6-0-released/

Update: This issue has been fixed in jQuery 3.7.

@estebancano-dev
Copy link

same here!

@floranpagliai
Copy link

Hello, similar problem here the search doesn't focus at all with jQuery 3.6.0, this make the search impossible. I had to downgrade jQuery to a lower version to make it work.

@kylefarris
Copy link

I'm not sure if this is a different issue but I can't search (won't focus the input) at all when the select2 dropdown is within a modal. Works fine when not in a modal (it doesn't auto-focus but it does focus if you click on the input).

@PlippiePlop
Copy link

I think it has something to do with the fix for focus as noted in the jq 3.6 blog post.

Fixes
One bug worth highlighting has to do with redirecting focus to another element in a focus handler. Take this example where a focus handler is triggered inside another focus handler:

elem1.on( "focus", function() {
elem2.trigger( "focus" );
} );
Due to their synchronous nature everywhere outside of IE, a fix added in 3.4.0 to leverage native events caused the native .focus() method to be called last for the initial element, making it steal the focus back. While the code continues to leverage native focus and blur events, we were able to fix this by aligning even more with native methods and only propagating the last focus event up the DOM tree.

@Intelli32
Copy link

Same issue here on jQuery 3.6

@joaquimds
Copy link

Just spent 3 hours debugging this very issue ... wish I was smart enough to check here first! 😭

@tagliala
Copy link

tagliala commented Mar 14, 2021

This is an issue also in 4.1.0.rc-0

Ref: jquery/jquery#4382

tagliala added a commit to tagliala/select2-bootstrap4-theme that referenced this issue Mar 14, 2021
tagliala added a commit to tagliala/select2-bootstrap4-theme that referenced this issue Mar 14, 2021
tagliala added a commit to tagliala/select2-bootstrap4-theme that referenced this issue Mar 14, 2021
@blq
Copy link

blq commented Mar 15, 2021

Triggering a 'focus' on the ".select2-search__field" in the "select2:open" event seems like a workaround.

@ioki-klaus
Copy link

i have been trying to fix this with multiple solutions like @blq mentioned, but no form of $('.select2-search__field').trigger('focus') worked, as they all got caught by the new jquery protection for the focusing. But using the normal DOM APIs worked fine... I am not happy with the hacky solution, but at least this fixes the issue for us until this issue is resolved:

  /*
   * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
   * see: https://github.com/select2/select2/issues/5993
   * see: https://github.com/jquery/jquery/issues/4382
   *
   * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
   */

  $(document).on('select2:open', () => {
    document.querySelector('.select2-search__field').focus();
  });

@martinbarilik
Copy link

martinbarilik commented Mar 17, 2021

same here, select2 4.1.0-rc0 and jquery 3.6.0

fiddle

https://jsfiddle.net/mArtinko5MB/dsejxvn9/22/

@bradcater
Copy link

Failing for me, too. Here's a small repro. To see it work with jQuery 3.5.1, toss it in a file, open a browser, and click on the select. To see it fail with 3.6.0, comment out jQuery 3.5.1 in the head and uncomment 3.6.0.

<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <!-- <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> -->
    <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
    <script type="text/javascript">
      $(function() {
        $('#test_select').select2();
      });
    </script>
  </head>
  <body>
    <form>
      <select id="test_select" style="width:100px">
        <option value="0">Zero</option>
        <option value="1">One</option>
        <option value="2">Two</option>
      </select>
    </form>
  </body>
</html>

@blq
Copy link

blq commented Mar 17, 2021

@ioki-klaus Yes, forgot to say that you had to use native event focus triggering. I think the biggest hack is that there's no good way to find the search-field via the select2 object API? A global query would be a bug if you have multiple select2-instances on the page. In the common case of using element IDs I used document.querySelector('[aria-controls="select2-' + elementID + '-results"]') as a first test, with document.querySelector('.select2-search__field') as fallback. (since select2 apparently assumed ID when generating that aria-element)
(I used select2 in a wrapper so I attach the workaround on each instance instead of a global document-listener)

@toxpal
Copy link

toxpal commented Mar 19, 2021

Any news or this?

@toxpal
Copy link

toxpal commented Mar 19, 2021

i have been trying to fix this with multiple solutions like @blq mentioned, but no form of $('.select2-search__field').trigger('focus') worked, as they all got caught by the new jquery protection for the focusing. But using the normal DOM APIs worked fine... I am not happy with the hacky solution, but at least this fixes the issue for us until this issue is resolved:

  /*
   * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
   * see: https://github.com/select2/select2/issues/5993
   * see: https://github.com/jquery/jquery/issues/4382
   *
   * TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
   */

  $(document).on('select2:open', () => {
    document.querySelector('.select2-search__field').focus();
  });

This one fixed the issue with Jquery 3.6.0 and select2 4.0.13. I'm using select2 in custom CMS and open dropdowns hundreds of times a day, so your solution was extremely useful for me. Thank you!

@ioki-klaus
Copy link

ioki-klaus commented Mar 22, 2021

I think the biggest hack is that there's no good way to find the search-field via the select2 object API? A global query would be a bug if you have multiple select2-instances on the page. In the common case of using element IDs I used document.querySelector('[aria-controls="select2-' + elementID + '-results"]') as a first test, with document.querySelector('.select2-search__field') as fallback. (since select2 apparently assumed ID when generating that aria-element)

@blq I did not look into it too deeply, but inspecting the DOM, the code for the popup window gets injected into the DOM, when the select2 input is opened. So, on my side, even if I have a bunch of select2-fields on the same page, there is only ever one .select2-search__field in the DOM.

@matthttam
Copy link

I'm using multiple Select2 fields and the workaround provided would work only half of the time for some reason. My workaround was to use the dropdownParent option for each one and create a DIV with a name that uses that element's ID.

<label for="asset">Asset:</label>
<select name="asset" class="form-control" id="asset" required>
</select>
<div name='someID_search'>
</div>
$('#someID').select2({
...
dropdownParent: $('div[name=someID_search]'),
...
});
$(document).on('select2:open', (e) => {
        var id = e.target.id
        $(document.querySelector('div[name='+id+'_search]')).find('input').get(0).focus()
});

This works even when I use $('#someID').select2('open').trigger('select2:open') to trigger an open

@toxpal
Copy link

toxpal commented Apr 15, 2021

i have been trying to fix this with multiple solutions like @blq mentioned, but no form of $('.select2-search__field').trigger('focus') worked, as they all got caught by the new jquery protection for the focusing. But using the normal DOM APIs worked fine... I am not happy with the hacky solution, but at least this fixes the issue for us until this issue is resolved:

Just a quick update - after some more testing, I found it only works if page has one select2 dropdown. If there are many dropdowns, this fix always autofocus on the first dropdown, which means that if you open 2nd dropdown and start typing, search is initialized in the 1st dropdown.

Another update: discovered that autofocus only has problems with non-multiple selects. In other words, if dropdown has multiple="multiple" attribute, autofocus works fine.

@matthttam
Copy link

i have been trying to fix this with multiple solutions like @blq mentioned, but no form of $('.select2-search__field').trigger('focus') worked, as they all got caught by the new jquery protection for the focusing. But using the normal DOM APIs worked fine... I am not happy with the hacky solution, but at least this fixes the issue for us until this issue is resolved:

Just a quick update - after some more testing, I found it only works if page has one select2 dropdown. If there are many dropdowns, this fix always autofocus on the first dropdown, which means that if you open 2nd dropdown and start typing, search is initialized in the 1st dropdown.

Another update: discovered that autofocus only has problems with non-multiple selects. In other words, if dropdown has multiple="multiple" attribute, autofocus works fine.

My workaround works for more than one select2 box however I have seen a bug where it visually looks like it focuses the 2nd select2 but upon typing/searching it will actually be selecting for the first one... very trippy honestly but for my purposes it works good enough for now. I hope either Jquery or Select2 roll out an update to fix this officially.

@Juan-Fragoso
Copy link

open modal and focus select, for me it worked this code

$('#name_modal').modal('show').on('shown.bs.modal', function(){
$('#select').select2('open').trigger('select2:open')
});

@selected-pixel-jameson
Copy link

Wow..... I just came across this. How has this been an issue for so long?

@mwhesse
Copy link

mwhesse commented Feb 9, 2023

I think many people just downgraded their jQuery dependency back to 3.5.1 when this popped up, or had some other workaround. This issue has been fixed with jQuery 3.6.1 as far as I know.

@tagliala
Copy link

tagliala commented Feb 9, 2023

This issue has been fixed with jQuery 3.6.1 as far as I know.

Unfortunately it wasn't: #5993 (comment)

It is still an issue on 3.6.3: https://jsfiddle.net/tagliala/ro3v807f/1/

How has this been an issue for so long?

Because it is not trivial to fix. Fortunately, a lot of workarounds have been kindly shared in comments here. I think that a possible solution could be the one used by jQuery UI in jquery/jquery-ui#1946 (but I'm not a JavaScript developer, I may be terribly wrong)

@lal65
Copy link

lal65 commented Feb 16, 2023

I see quite a few code snippets in this issue, but no associated pull request.

Can a maintainer weigh in on a preferred solution so we can get some community traction on this issue and possibly get a PR in the works?

Linking to PR: #6044

@ArsaLabs
Copy link

ArsaLabs commented Mar 8, 2023

Same to me... i used

  • Tempus Dominus Bootstrap4 v5.39.0
  • Select2 4.1.0-rc.0
  • jQuery v3.6.3

showing this error, when i click select2 on bootstrap modal

jquery-3.6.3.min.js:2

   jQuery.Deferred exception: t.slice is not a function TypeError: t.slice is not a function
at e.removePlaceholder (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:46292)
at r.removePlaceholder (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:3306)
at e.append (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:46098)
at r.append (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:3306)
at o.<anonymous> (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:9451)
at e.invoke (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:3881)
at e.trigger (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:3700)
at o.trigger (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:66940)
at http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:65339
at Object.<anonymous> (http://ci4-servis.test/aset/plugins/select2/js/select2.min.js:2:39430) undefined

@mgol
Copy link

mgol commented Mar 28, 2023

The issue is likely fixed by jquery/jquery#5224 which will be included in jQuery 3.7.0. You can check if this fixes your issues now by trying the jQuery 3.x git build from: https://releases.jquery.com/jquery/ (please don't use this version in production, though!). Please test and report if this works. The more confirmations we have about this fixing various focus-related issues, the more confident we can be we're on a good path.

The test case from #5993 (comment) with jQuery 3.x git seems to be working fine: https://jsfiddle.net/m_gol/xdcfvjag/

@pierre-alain-b
Copy link

I've just tested and in my settings it indeed works well with 3.x git! This is better than having a patched version of select2, thanks!

@davequested
Copy link

Ignore my previous comment (deleted), 3.x does indeed fix all focusing issues. Hurrah!

@mgol
Copy link

mgol commented May 11, 2023

jQuery 3.7.0 with focus fixes has been released: https://blog.jquery.com/2023/05/11/jquery-3-7-0-released-staying-in-order/

@pierre-alain-b @davequested Thanks for confirming it works!

@pierre-alain-b
Copy link

Hurrah! Thank you!

@ryanb I therefore recommend to close this issue and recommend to use 3.7 and not 3.6 branch for jQuery

@ryanb
Copy link
Author

ryanb commented May 12, 2023

@pierre-alain-b @mgol thanks! Closing this issue since jQuery 3.7 fixes it.

@jayaddison
Copy link
Contributor

Hi folks - although this does appear to be fixed with jQuery 3.7.0 I've been trying to write a test case for it.

That's partly to avoid future regressions, and partly because it'd be nice to upgrade the vendored jQuery3-variant used in the unit tests (vendored jQuery1 and jQuery2 lineages are also vendored within select2 for backwards-compatibility testing).

The test I've developed so far unexpected passes when using jQuery 3.6.3 (a version where commentors have confirmed that the focus problem still exists). I'd like to develop an illustrative test case that passes with jquery1 and jquery2, and that fails for jquery3 versions starting with 3.6.0 and passes again at version 3.7.0 and beyond.

Can anyone tell whether I'm doing something obviously (or not obviously) wrong in the test code below?

Thanks for your help!

test('open sets the focus to the search control', function (assert) {
  var $container = $('#qunit-fixture .event-container');
  var container = new MockContainer();
  var selection = new DropdownSearch(
    $('#qunit-fixture .single'),
    options
  );

  var $selection = selection.render();
  selection.bind(container, $container);

  $container.append($selection);

  var $search = $selection.find('input');

  assert.notEqual(
    document.activeElement,
    $search[0],
    'The selection had focus originally'
  );

  container.trigger('open');

  assert.equal(
    document.activeElement,
    $search[0],
    'After close, focus must be set to selection'
  );
});

To run tests for this repository, you can invoke:

$ yarn install   # downloads and installs javascript package dependencies
$ yarn run grunt test  # runs the test suite

@mgol
Copy link

mgol commented May 25, 2023

@jayaddison I can't help with the exact test code as I'm unaware of select2 internals but the actual issue fixed here was most likely .trigger( "focus" ) being broken if it was previously called when the target was hidden. Simplifying the focus logic by making focus & blur synchronous in all browsers - including IE - fixed this issue.

You can see the test case I added for this in my fixing PR:
jquery/jquery@59f7b55?w=1#diff-33e49eecc6e72e95002a32fb85d2cc6b699803bacc62e6d944907d92f903bba1R3399-R3413
Maybe that will help you with your select2 tests.

Posting the test contents here as well for easier reference:

QUnit.test( "trigger(focus) works after focusing when hidden (gh-4950)", function( assert ) {
	assert.expect( 1 );

	var input = jQuery( "<input />" );

	input.appendTo( "#qunit-fixture" );

	input
		.css( "display", "none" )
		.trigger( "focus" )
		.css( "display", "" )
		.trigger( "focus" );

	assert.equal( document.activeElement, input[ 0 ], "input has focus" );
} );

@jayaddison
Copy link
Contributor

Thank you, @mgol. I'll experiment with the visibility of the relevant element(s) during the test. The mention of browser versions also has me wondering whether the usage of PhantomJS (webkit-based, I think) during the select2 tests could be relevant - I'll try to find out more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests