How to place autocomplete menu above the text input?
Asked Answered
J

4

9

Is there any way to display the Autocomplete result set above the text input?

The problem is that I am using it in a lighbox application. The background element being set to 100% of the pages' height and width, it will naturally not expand with its content. So if the content above the text box increases so much that the input is forced towards the bottom of the page, and then the user types something into it, the autocomplete menu appears, and the input being towards the end of the page, the menu causes scrollbars to appear

Since the background element (dark colored) won't expand to accommodate it, as the menu is absolutely positioned, it looks visually ugly that the bottom of the page appears white (consistent with the actual page's color) while the top of the page dark.

So is there anyway to accomplish this, that prior to the autocomplete menu appearing, the position of the input should be checked. If it is, say, at more than 300px from the top, then the menu should appear above the input? This is the code:

<!DOCTYPE html>
<html>
<head>
<title>Filter</title>
<link type="text/css" href="ui/ui.css" rel="stylesheet" />
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript" src="ui.js"></script>
<style>
div.filtertab { display: inline-block; height: 30px; background:url(filter.png); border-radius: 5px; position: relative;  margin: 10px 45px 10px 8px; cursor: pointer; -moz-user-select: none; box-shadow: 4px 2px 2px #aaaaaa; }

div.filtertab span.filtertext { position: relative;  margin-top: 4px; margin-left: 11px; margin-right: 1px;font-family:cursive,"Comic Sans"; font-size: 0.9em; float: left; display: inline-block; }

span.arrow { display: inline-block; border-top: 5px solid transparent; width: 0px; height: 0px; border-bottom: 5px solid transparent; border-right: 8.66px solid transparent; border-left: 8.66px solid #333333; margin-left: 7px; margin-top: 10.5px; }

.dateheaders { background: url(select.png); width: 120px; height: 28px; position: absolute; top: 0px; left: 0px; border-radius: 5px; cursor: pointer; display: inline-block; z-index: 55; }

.toheader { left: 183px }

.spandatew { font-weight: bold; position: relative; top: 2px; left: 6px; color: white; font-family: "lucida grande",tahoma,verdana,arial,sans-serif; font-weight: bold; color: white; font-size: 0.8em; }

div.arrow { height: 0px; width: 0px; position: absolute; display: inline-block; border-bottom: 5px solid transparent; border-right: 5px solid transparent; border-left: 5px solid transparent; border-top: 5px solid white;  right: 8px; top: 12px; }

input#from,input#to {width:107px;height:20px; position: relative; top: -30px; opacity: 0.01; cursor: pointer; }

input#from { left: 22px; }

input#to { left: 79px; }

div#ui-datepicker-div { left: -10px; }

div#diva1 {  width: 190px; position: absolute; display: none; z-index: 10; outline: none;}

div#diva2 {  width: 190px; position: absolute; display: none; z-index: 10; outline: none;}

#datecontainer { position: relative; width: 400px; height: 30px; background: red; left: 10px; }

.inpdiv { position: relative; margin-top: 6px; margin-left: 7px; background: #E2E6FF;  border-radius: 3px;  margin-bottom: 5px; display inline-block; float: left; margin-right: 3px; }

.inpdiv span.content { position: relative; top: 1px; left: 2px; padding: 2px 5px 6px 2px; font-size: 0.9em; display: inline-block; font-family: cursive,"Comic Sans";}

.inpdiv span.cancel { display: inline-block; border-radius: 3px; position: relative; top: 5px; margin: 3px 3px 3px 4px; height: 12px; width:12px; background: #bdbbae; cursor: pointer; }

.letter { position: absolute; display: inline-block; right: 4.4px; top: 4.7px; cursor: pointer; FONT-FAMILY: SANS-SERIF; FONT-SIZE: 0.9EM; }

div.friends { width: 400px;   position: relative;  overflow: hidden; border: 1px solid #4496e7; border-radius: 5px; cursor: text; height: 35px; height: auto !important; min-height: 35px;  left: 5px; }
div.friends2 { margin-top: 10px; }

div.friendsc { position: relative; top: 100px; left: 350px; width: 410px;  padding: 10px 0px; height: auto !important; height: 80px; min-height: 80px; background: green;}

div.clear { clear: both; width: 100%; height: 10px; }

button { position: absolute; top: 300px; left: 450px; }

input { position: relative; margin: 9px 0px 10px 10px; border: 0px solid white; float: left; max-width: 382px; }

div#outerfilter { width: 900px; background: grey;  position: relative; min-height: 400px; max-height: 500px; margin:auto; top: 10px; overflow: auto; padding-bottom: 20px; }
div#innerfilter { position: relative; top: 0px; left: 0px; width: 880px; min-height: 400px;background: #eaeaea; }
.filtersection { position: relative; float: left; width: 440px; min-height: 400px; height: auto !important; }
</style>
<script type="text/javascript">
$(document).ready(function(){
(function($){

$.fn.autoGrowInput = function(o) {

            o = $.extend({
                maxWidth: 1000,
                minWidth: 0,
                comfortZone: 70
            }, o);

            this.filter('input:text').each(function(){

                var minWidth = o.minWidth || $(this).width(),
                    val = '',
                    input = $(this),
                    testSubject = $('<tester/>').css({
                        position: 'absolute',
                        top: -9999,
                        left: -9999,
                        width: 'auto',
                        fontSize: input.css('fontSize'),
                        fontFamily: input.css('fontFamily'),
                        fontWeight: input.css('fontWeight'),
                        letterSpacing: input.css('letterSpacing'),
                        whiteSpace: 'nowrap'
                    }),
                    check = function() {

                        if (val === (val = input.val())) {return;}

                        // Enter new content into testSubject
                        var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,'&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                        testSubject.html(escaped);

                        // Calculate new width + whether to change
                        var testerWidth = testSubject.width(),
                            newWidth = Math.min((testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, o.maxWidth - 1),
                            currentWidth = input.width(),
                            isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                                                 || (newWidth > minWidth && newWidth < o.maxWidth);

                        // Animate width
                        if (isValidWidthChange) {
                            input.width(newWidth);
                        }

                    };

                testSubject.insertAfter(input);

                $(this).bind('keyup keydown blur update', check);

            });

            return this;

        };

    })(jQuery);

arr = ["Soumyashree Chakraborty", "Payel","Jinia","Soujinia","Apoorva","Mona","Shamarpita","Pratik","Pranendra","Bhushan","Bijesh","Salma","Swift","Anushka","Radhe","Amol","Bardha","Sujata","Rohit","Amit","Anuradha","Amrita","Ajay","Sumil","Sachin","Sourav","Anmol","Britannia","Anamika","Priyanka"];
$("span.letter").live('click',function() {
$(this).parent().parent().find("input").focus();
$(this).parent().remove();
  });

options = {
            source: arr.slice(0,5),
            minLength: 1,
            select: function(event,ui) {
            $('<span class = "inpdiv"><span class = "content">'+ui.item.value+'</span><span class = "cancel"></span><span class="letter">X</span></span>').replaceAll(this);
            $("<input type='text' size='3' />").appendTo(curautocomp).focus();
            event.preventDefault();
            },
            focus: function(e,ui) {
            e.preventDefault();
            },
            autoFocus: true,
            delay: 0
            };
$("input").live("focus", function (event) {
curautocomp = $(this).parent();
$(this).autocomplete(options);
$(this).autoGrowInput({
    comfortZone: 5,
    minWidth: 15,
    maxWidth: 382
});
});
















});
</script>
</head>
<body>
<div id = 'outerfilter'>
<div id = 'innerfilter'>
<div class = 'filtersection'>
<div class="filtertab"><span class="filtertext">Filter by Forum</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
<div class="filtertab"><span class="filtertext">Not Asked by</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
<div class="filtertab"><span class="filtertext">Has No Answer by</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
<div class="filtertab"><span class="filtertext">No of Answers</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
</div>
<div class = 'filtersection'>
<div class="filtertab"><span class="filtertext">Asked by</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
<div class="filtertab"><span class="filtertext">Has Answer by</span><span class='arrow'></span></div>
<br />
<div class = "friends">
<input type = "text" size = "2" value = "" />
</div>
<div class="filtertab"><span class="filtertext">Filter by Date</span><span class='arrow'></span></div>
<br />
<div id = 'datecontainer'>
<div class = 'dateheaders fromheader'>
<span class = 'spandatew'>Select a date</span>
<div class = 'arrow'></div>
</div>
<div class = 'dateheaders toheader'>
<span class = 'spandatew'>Select a date</span>
<div class = 'arrow'></div>
</div>
<div id = 'diva1'></div>
<div id = 'diva2'></div>
</div>
</div>
<div class = 'clear'></div>
</div>
</div>
</body>
</html>
Jurdi answered 16/7, 2012 at 9:41 Comment(4)
You should include some demo or source we can look at :)Ozone
The source code is huge, there are many CSS files from where different styles have been gleaned, it's very difficult to include all that!Jurdi
Is the site available online? I understand what you are trying to do, but it's hard to find a solution without seeing how everything is put together. It's like trying to walk without legs in pitch darkness.Ozone
Ummm, ok, tell you what, you just include the minified core UI file (which includes everything, around 202 KB size) as ui.js, the ui darkness file as ui.css inside the ui folder, alongwith the core JQuery file, then use the code I am posting. I have stripped it down to only the essentials...Jurdi
G
7

You'll want to add an open function to your autocomplete options. From there, you can adjust the results based off of its current position and height. This should get you close:

open: function(event, ui){
    var $input = $(event.target),
        $results = $input.autocomplete("widget"),
        top = $results.position().top,
        height = $results.height(),
        inputHeight = $input.height(),
        newTop = top - height - inputHeight;

    $results.css("top", newTop + "px");
}
Georgeanngeorgeanna answered 16/7, 2012 at 15:45 Comment(2)
Thanks! That was exactly what I was looking for! Of course I don't want the menu to display above always, so I added a check that if the offset().top + height() of $results exceeds the document height, only then should it enter the last line of your code, else display the menu as it naturally does below. Thanks again!Jurdi
@Cupidvogel I'm glad it worked for you! I had to do something really similar to this a few weeks ago, so it was still fresh in my mindGeorgeanngeorgeanna
C
5

This puts together Ibstr's solution and Cupidvogel's comment while adding window scroll position detection:

open: function (event, ui) {
    var $input = $(event.target);
    var $results = $input.autocomplete("widget");
    var scrollTop = $(window).scrollTop();
    var top = $results.position().top; 
    var height = $results.outerHeight();
    if (top + height > $(window).innerHeight() + scrollTop) {
        newTop = top - height - $input.outerHeight();
        if (newTop > scrollTop)
            $results.css("top", newTop + "px");
    }
}

Note that I'm using outerHeight instead of height because I want to take into consideration the border thickness as well.

The autocomplete will orient itself to the top only if there is enough room for it to fully fit in above the input box.

Cafard answered 16/7, 2012 at 9:41 Comment(0)
S
2

Use the position option to activate collision detection:

    $( "#someElement" ).autocomplete({
       source: [...]
       position: {  collision: "flip"  }
    });​
Stoltzfus answered 16/6, 2022 at 10:50 Comment(0)
B
1
$( "#input_box input" ).autocomplete({
      position: { my: "left bottom", at: "left top"},
      source: availableTags
    });

This code means "left bottom" of autocomplete menu(my) should be placed at "left top" of input box(at).

Try Demo to understand this : https://www.plus2net.com/jquery/msg-demo/autocomplete-position.php

Bremser answered 28/5, 2019 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.