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

Typeahead positioning bug with modals, scrolling and window resize #3529

Closed
ghost opened this issue May 18, 2012 · 8 comments
Closed

Typeahead positioning bug with modals, scrolling and window resize #3529

ghost opened this issue May 18, 2012 · 8 comments
Labels

Comments

@ghost
Copy link

ghost commented May 18, 2012

The dropdown list that appears when using typeahead() doesn't stick to the input when scrolling, or when resizing the window This occurs in modals, or anytime where the parent element is fixed position.

Here's is a demo:

http://jsfiddle.net/cBLUL/

How to reproduce:

  1. Focus the input and type until the suggestion list appears
  2. While the result list is visible, scroll the page or...
  3. Resize the "Result" pane in jsfiddle

Expected result: Suggestion list does not move at all, but stays "glued" to the input.

Actual Result: The suggestion list moves around, sometimes off screen.

Here's a screen capture to demonstrate: http://www.screenr.com/CNR8

I found the scroll issue by accidentally using the mouse wheel while focused in an input with typeahead. I found the resize issue while producing a test case for the scroll issue.

It appears that the typeahead list is appended to body. This could probably be easily fixed by putting the element just after the input itself instead, or even as a last child of the parent form (or just outside the parent form) so as not to mess up any CSS or JS that relies on certain adjacent elements being in place...

On second thought, not every input will have a parent form (should, but may not in the wild), and as mentioned, putting the element in the DOM anywhere else could cause other bugs, so I'm not sure that would be a real solution.

@virusman
Copy link

The issue still exists in the latest version.

@mdo
Copy link
Member

mdo commented Nov 28, 2012

Able to reproduce with latest 2.2.2-wip as well (by copying and pasting the docs' typeahead into the example modal).

@harnishg
Copy link

This doesn't seem that hard to fix ...

The problem isn't because the menu is "fixed", the problem is that the position of the menu is "relative" to the location that input was at when it was shown. It can be "fixed" with the addition of this css to the menu: position: fixed;

However, if you have other non-modal typeaheads, this will break them. They will remained fixed if you scroll ... basically replicating the same effect you are experiencing in modals. Also, typeaheads are not really configured for a modal; if you attempt to open on in a modal, it will hide behind the modal window. You need to increase it's z-index to 1051;

Since bootstrap-typeahead is altering the css everytime it shows, that is the function we need to modify. A quick hack would be to look at the element's parents to see if one of them is a modal. If so, append the z-index:1051; and the position:fixed; to it's css; we also need to modify the css positioning a bit to make fixed work right.

This code change worked for me:

show: function () {
    // For efficiency, we should probably cache the fact
    // that the element is in a modal in the constructor, 
    // but that would require more than just giving out 
    // the show function
    var isModal = (this.$element.closest('.modal').length > 0);

    var pos = $.extend({}, this.$element.offset(), {
        height: this.$element[0].offsetHeight
    });

    if (isModal){
        this.$menu.css({
            top: 0,
            left: 0,
            position: 'fixed',
            zIndex: '1051'
        });

        this.$menu.offset({
            top: pos.top + pos.height,
            left: pos.left              
        })
    } else {
        this.$menu.css({
            top: pos.top + pos.height,
            left: pos.left
        });
    }

    this.$menu.show();
    this.shown = true;

    return this;
},

@harnishg
Copy link

I just watched the video in the initial post and I realized that I didn't take resize into account. That is also easily fixed now.

So let's start again and do this properly

  1. Modify the constructor:
var Typeahead = function (element, options) {
    this.$element = $(element)
    this.isModal = (this.$element.closest('.modal').length > 0);
...
  1. Modify listen:
listen: function () {
...
    $(window).on('resize', $.proxy(this.resize, this));
...
  1. Modify show:
        show: function () {
            this.setMenuPosition();

            this.$menu.show();
            this.shown = true;

            return this;
        },
  1. Add two new functions before show:
    a) setMenuPosition
        setMenuPosition: function() {
            var pos = $.extend({}, this.$element.offset(), {
                height: this.$element[0].offsetHeight
            });

            if (this.isModal){
                this.$menu.css({
                    top: 0,
                    left: 0,
                    position: 'fixed',
                    zIndex: '1051'
                });

                this.$menu.offset({
                         top: pos.top + pos.height,
                         left: pos.left             
                })
            } else {
                        this.$menu.css({
                         top: pos.top + pos.height,
                         left: pos.left
                        });
            }
        },

b) resize

        resize: function() {
            if (this.shown) this.setMenuPosition();
            return this;
        },

Someone else, I'm sure, can make this prettier and more efficient but this should eliminate the bugs.

fat added a commit that referenced this issue Dec 8, 2012
note: this will likely break things for people in the same way that doing
this to tooltip did… however we think this is a better insertion model for
z-index,scrolling,modal,etc. applications
@fat
Copy link
Member

fat commented Dec 8, 2012

fixed

@fat fat closed this as completed Dec 8, 2012
@netcelli
Copy link

The new version of typeahed introuced another issue with the modal window. If you try the demo provided by wesley-murch (http://jsfiddle.net/cBLUL/) in the first post, the item selection is very hard to do because it depends on modal height.

@tesh11
Copy link

tesh11 commented Apr 24, 2013

This change breaks compatibility with previous versions as we needed the typeahead appended to the body. Is it possible to make this configurable?

@mathbr
Copy link

mathbr commented May 24, 2013

This is quite easy to fix, if you copy the container logic of the Bootstrap tooltips.

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

No branches or pull requests

7 participants