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

Wrong search box position when dropdown opens above #4614

Closed
1 task done
xumix opened this issue Oct 3, 2016 · 23 comments · Fixed by #5592
Closed
1 task done

Wrong search box position when dropdown opens above #4614

xumix opened this issue Oct 3, 2016 · 23 comments · Fixed by #5592

Comments

@xumix
Copy link

xumix commented Oct 3, 2016

Steps to reproduce the issue

  1. Go to https://select2.github.io/examples.html
  2. Scroll to ajax section
  3. Place the select2 control near the bottom of the screen
  4. Try to search and select some value
  5. Try to search for another value.

Expected behavior and actual behavior

When I follow those steps, I see the search box disconnected from the select control

I was expecting it near the select control

Environment

Browsers

  • [ x] Google Chrome
  • [x ] Mozilla Firefox
  • jQuery version 1.9.x:
  • Select2 version 4.0.3:

Isolating the problem

  • [x ] This bug happens on the examples page
  • The bug happens consistently across all tested browsers
    filtering
@jmiguel-localvox
Copy link

I was able to fix something similar by doing this after initializing the select2 instance:

var select2Instance = $(selectNode).data('select2');
select2Instance.on('results:message', function(params){
  this.dropdown._resizeDropdown();
  this.dropdown._positionDropdown();
});

In my case I had a multiple selection box whose dropdown was detaching much the same way that your box single selection results box was detaching.

@LuuchoRocha
Copy link

Many thanks for the fix!

@alexweissman
Copy link
Contributor

Has anyone submitted a PR for this as a proper fix?

@alexweissman alexweissman changed the title Wrong search box position after ajax select Wrong search box position when dropdown opens above Sep 17, 2017
@alexweissman
Copy link
Contributor

It would appear that this problem is not limited to AJAX-sourced dropdowns. It occurs any time there are "no results" after previously making some selections.

@AStoker
Copy link

AStoker commented Dec 14, 2017

There anybody actively working on this one? If not, anybody got ideas on where to start solving this issue? I'll make a PR if I can fix it, but I'd appreciate a starting point on where to look.

@alexweissman
Copy link
Contributor

@AStoker that would be great! You can check some of the duplicate issues listed above, which may have more insight or proposed solutions.

@AStoker
Copy link

AStoker commented Dec 15, 2017

Workaround that works with the latest version of select2 (and for us) was found here.
It seems that the results need to be cleared out before you can appropriately reposition the drop down. Would it be appropriate to always clear out your previous results when opening the select box?

@alexweissman
Copy link
Contributor

Just for reference, that workaround is:

$(that._countrySelect).data('select2').on('open', function (e) {
    this.results.clear();
    this.dropdown._positionDropdown();
});

@alexweissman
Copy link
Contributor

Clearing out the previous results could work, but on the other hand it could have other unintended side effects. I'd rather if someone dug into the code more thoroughly to find the root of this problem.

@AStoker
Copy link

AStoker commented Dec 18, 2017

What seems to be happening is that when the window is opened, any previous results are still in the DOM, so the search box appears correctly above where we'd normally expect. But then when Select2 goes in sees that the results should be different (empty), it clears the results, but doesn't reposition the drop down. So it appears to be a case of repositioning when clearing results (as it does reposition when the results are changing live). Hints of where that logic (clearing/restarting search on open) would reside?

@alexweissman
Copy link
Contributor

I have no idea - I'm not all that familiar with the codebase myself.

@AStoker
Copy link

AStoker commented Jan 5, 2018

So, I can see that when we get new results, we are repositioning the dropdown (line). So that leaves the two use cases that we have to fix.

  1. Typing in values in search, closing search, opening search back up, and the search box (empty) appears in last location.
  2. Type values in search (when using minimumInputValues), clear out search, search box stays in last location.

In case 1, we start (more or less) at this this line. At this point, we're opening back up the search box (line 299) if it's not open yet. We haven't cleared out our previous results yet (that happens next), and that's why this fix with the open trigger works, we manually clear out the results and reposition the drop down. Continuing down this event chain, after we've triggered the open event, we make our query call (which currently has an empty string for the search).
This is where we come to case 2. On reopening the select2, or clearing out a result, such that we have less than the minimum number of input characters, we trigger the results:message event, which triggers the displayMessage here, which ultimately calls clear here.
What we've now done is clear out our search results without ever repositioning our dropdown. I believe that we could put a function here that would call the reposition function on the container dropdown so that it would be repositioned correctly any time a message is shown (which seems to be the consistent issue).
That would make the results display message function something like this:

  Results.prototype.displayMessage = function (params) {
    var escapeMarkup = this.options.get('escapeMarkup');

    this.clear();
    this.hideLoading();
    this.data.container.dropdown._positionDropdown(); //This line added
...

Functionally, that works, but conceptually, I don't like calling "hidden" functions (functions starting with underscore) in this way. Is there a more front facing function that could be called here?

@AStoker
Copy link

AStoker commented Jan 5, 2018

Actually, a better way would be to put a listener on the results:message event here (there are already listeners that do the same for results:all and results:append). This would make the AttachBody.prototype.bind function like this:

AttachBody.prototype.bind = function (decorated, container, $container) {
    var self = this;

    var setupResultsEvents = false;

    decorated.call(this, container, $container);

    container.on('open', function () {
      self._showDropdown();
      self._attachPositioningHandler(container);

      if (!setupResultsEvents) {
        setupResultsEvents = true;

        container.on('results:all', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });

        container.on('results:append', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });

        container.on('results:message', function () { //This listener added as messages clear results and need to reposition the dropdown
          self._positionDropdown();
          self._resizeDropdown();
        });
      }
    });
...

I'll write up a PR for review real quick.

AStoker added a commit to AStoker/select2 that referenced this issue Jan 5, 2018
Resolves: select2#4614
Previous behavior: whenever a message is displayed, results are cleared
out, but dropdown is not repositioned, resulting in a floating search
box based off of last position.
Fixed behavior: when a message is displayed, reposition the dropdown
accordingly
@slipmatt
Copy link

One thing i found is that when i removed the minimumInputLength: 1, the issue went away, leaving this here in case it helps anyone, i changed my ajax call to work of a delay rather

@laudeco
Copy link

laudeco commented Aug 8, 2018

Why this issue is not yet merged ?
It's blocking for us

@AStoker
Copy link

AStoker commented Aug 10, 2018

@laudeco , I think at this point the library lacks a dedicated maintainer. Maintaining an open source project can be a lot of work, and I think there's really only been 1 for the last year (who has since dropped off). As a result, Select2 doesn't seem to be getting updates or bug fixes merged in.
Sad day, but I've noticed an overall trend of various input boxes dropping off being replaced by framework specific implementations (Aurelia, Angular, Vue...). If you're using a framework, I'd look to see if there's an implementation there that works for you.

As an alternative, I've left my fork that I'm using for the PR open because we needed the fix as well. So our project references my fork directly in our package.json. You can do the same if you need the fix.
"select2": "github:astoker/select2#4.0.6-rc.2",

@pedrofurtado
Copy link
Contributor

Continue discussion here -> #5196

@MinionWarrior
Copy link

Have you ever considered changing the position of the dropdown?
here -> select2/select2-bootstrap-theme#41 (comment)

kevin-brown pushed a commit that referenced this issue Jul 28, 2019
This fixes an issue which was usually observed when working with
AJAX results sets and having a message being displayed, usually the
minimum characters message or an error. The dropdown would display
up, like it was supposed to, but the message would appear to be
floating above the container and detached.

This was occuring because the dropdown position was not being
calculated whenever a message was displayed in the results, only
when the results were loaded or new results were appended to an existing
results set. There are plenty of situations where this could have
caused issues, but somehow most of the reports were around a very
specific situation with AJAX which could be reproduced on the
examples site.

Fixes #4614
Fixes #4616
Fixes #5253
Closes #5196
kevin-brown added a commit that referenced this issue Jul 28, 2019
This fixes an issue which was usually observed when working with
AJAX results sets and having a message being displayed, usually the
minimum characters message or an error. The dropdown would display
up, like it was supposed to, but the message would appear to be
floating above the container and detached.

This was occuring because the dropdown position was not being
calculated whenever a message was displayed in the results, only
when the results were loaded or new results were appended to an existing
results set. There are plenty of situations where this could have
caused issues, but somehow most of the reports were around a very
specific situation with AJAX which could be reproduced on the
examples site.

Fixes #4614
Fixes #4616
Fixes #5253
Closes #5196
@bennettstuart
Copy link

Hey guys, I just ran into this problem on a wordpress website I'm working on..

Because I was logged in on the site a margin-top: 32px !important was being applied to my <html> tag, to make space for the WP admin bar - However this was being taken into account when positioning the select dropdown.

When I logged out, and the html top margin was removed, the select dropdown positioned fine.

I did a bit of digging and found in attachBody.js

// ln 192
    var parentOffset = {
      top: 0,
      left: 0
    };

    if (
      $.contains(document.body, $offsetParent[0]) ||
      $offsetParent[0].isConnected
      ) {
      parentOffset = $offsetParent.offset(); // returns `{left: 0, top: 32}` when logged in
    }

the $offsetParent.offset(); would return {left: 0, top: 32} when I was logged in, offsetting the dropdown positioning by that top amount.

Hope this helps :)

@ashwani-pandey
Copy link

ashwani-pandey commented Oct 15, 2020

I had a similar problem where the top position of the dropdown was messed up specifically on mobile devices. Nonetheless, the solution was simple for this problem. You need to add the dropdownParent property in your select2 call. Something like what I have mentioned below.

this.$('#country').select2({
  placeholder: 'Please select',
  dropdownParent: this.$('#country').parent(),
})

This is needed because if dropdownParent attribute is not present, it is equivalent to saying
dropdownParent: $(document.body) and therefore you will find your dropdown html attached at the very end of the body.

@estani
Copy link

estani commented Aug 25, 2021

@ashwani-pandey take care that if you have multiple selects you'll break things (as I did :)
Just iterate over the results from the jquery selector:

$(".select2").each((_i, e) => {
  var $e = $(e);
  $e.select2({
    dropdownParent: $e.parent()
  });
})

Why on earth is this not the default behavior in select2?
If it needs to know the parent, that the default should be the parent of the node being converted to select2... am I missing something here?

@abubakar62545
Copy link

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

@seb350
Copy link

seb350 commented Jun 12, 2023

I had the same problem @bennettstuart did but in case you're using woocommerce they are using a forked polished version of select2 where this issue is taken care of. You can use the woocommerce forked version like this:

wp_enqueue_style('select2');
wp_enqueue_script('selectWoo');

And initialize with .selectWoo() like mentioned here: https://github.com/woocommerce/selectWoo

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