If you have dropdown that's at the bottom of your page. The hidden dropdown menu is pushing the bottom of the page down. That needs to be hidden so that it doesn't effect the styles of the page, it would be nice if the drop down detected the bottom of the page, did a little math to figure out if it has room to expand or not and if it doesn't have room it will switch styles to appearing above and now bellow.
+1
+1
+1
+1
Wrote a little function into it, works perfect for pagination now
http://jsfiddle.net/adamelevate/WFejY/
Mine is driven off of a css class on the select box, so it still isn't dynamic, sry....
+1
+1
+1
This is a must-have feature
+1
still not fixed yet?
+1. In our case, Chosen is placed at the bottom of a modal dialog, and is causing a "phantom" vertical scrollbar to show. So need Chosen to appear above when it is at the bottom of a viewport (not just page).
I've successfully avoided this by making sure that all parent elements have overflow:visible.
+1
fixed on my project like this
#selectId_chzn .chzn-drop {
bottom: 20px;
top: auto !important;
}
but I hope you can do this automatically
So nobody has figured out a way to deal with this that involved intelligent edge detection? My project doesn't afford me the luxury of concretely identifying Chosen elements based on a container that is guaranteed to induce overflow. I have given a little thought to how to get Chosen to recognize if there's room to expand downward, and if not, apply a style similar to what @coldman333 suggested, and haven't figured out a great or reliable way to do it, yet. It would also need to give the dropdown list a border-top and remove its border-bottom, to keep the styles consistent. Perhaps it should just apply a special CSS class instead, using jQuery's addClass() to save processing power.
+1
Okay, I've got a working solution, but it's just kinda hacked up in the compiled javascript file. I'll paste the code here though if anyone want's to create a pull request from it.
If it detects that the dropdown will extend below the window, it will resize it and add a scrollbar, but still drop DOWN. UNLESS there is less than 100px between the dropdown and the window, then it will add a chzn-above class to the dropdown and show it above the input.
/chosen/chosen.jquery.js
[around line 326]
``` .js
this.search_results = this.container.find('ul.chzn-results').first();
// Start additional code
this.search_results.data('initialMaxHeight', this.search_results.css('max-height'));
// End additional code
this.search_field_scale();
[around line 568]
``` .js
Chosen.prototype.results_show = function() {
var dd_top;
if (!this.is_multiple) {
this.selected_item.addClass("chzn-single-with-drop");
if (this.result_single_selected) {
this.result_do_highlight(this.result_single_selected);
}
}
dd_top = this.is_multiple ? this.container.height() : this.container.height() - 1;
this.dropdown.css({
"top": dd_top + "px",
"left": 0
});
// Start additional code
this.search_results.css('max-height', 'none');
var windowHeight = $(window).height() + $('html').scrollTop(),
dropdownHeight = this.dropdown.height(),
dropdownTop = Math.ceil(this.dropdown.offset().top),
totalHeight = dropdownHeight + dropdownTop;
if (totalHeight > windowHeight) {
var difference = totalHeight - windowHeight,
height = dropdownHeight - difference;
if (height > 100) {
this.search_results.css('max-height', height);
} else {
this.dropdown.addClass('chzn-above');
this.search_results.css('max-height', this.search_results.data('initialMaxHeight'));
}
} else {
this.search_results.css('max-height', this.search_results.data('initialMaxHeight'));
}
// End additional code
this.results_showing = true;
this.search_field.focus();
this.search_field.val(this.search_field.val());
return this.winnow_results();
};
/chosen/chosen.css
.css
/* Add this rule */
.chzn-container .chzn-drop.chzn-above {
top:auto !important;
bottom:29px;
border:solid #aaa;
border-width:1px 1px 0 1px;
}
牛逼
+1
Hi,
This issue is fixed. But in the case of chzn-select-deselect option is not working for this feature. Please check this.
Thanks,
Sathish Babu
+1
I can’t see the fix in the examples…
I wanted to let my dropdown list 'drop up'. I fixed my issue by changing the top for .chzn-drop to the negative value of the max-height of chzn-results. Also changed max-height to just height else it produces an empty space if there aren't enough results in the drop list. It's an ugly fix I know, but it worked for me.
p.s. Changing the styling a bit is required. For example: the border will be missing on the top and needs to be removed on the bottom of the drop list.
Please work on #1330 so this can be resolved! Ran into this bad bug in our app -- chosen is just non-functional when placed near the bottom edge of the screen.
+1
lot of +1
+1
+1
+1
anyone with a working solution yet?
+1
guys, seems like huge demand, whats up?
Hi!
Add this to the CSS file:
.chosen-container-active.chosen-with-dropup .chosen-single{
-moz-border-radius-topright: 0 !important;
border-top-right-radius: 0 !important;
-moz-border-radius-topleft: 0 !important;
border-top-left-radius: 0 !important;
}
.chosen-dropup {
top: auto !important;
bottom: 23px;
border: solid #aaa;
border-width: 1px 1px 0 1px;
margin-top: -1px;
border-radius: 4px 4px 0px 0px !important;
}
Then modify the JS file:
Find Chosen.prototype.results_hide = function() then add this:
this.container.removeClass("chosen-with-drop");
//Added by Fenistil
this.container.removeClass("chosen-with-dropup");
//End
this.form_field_jq.trigger("chosen:hiding_dropdown", {
Find Chosen.prototype.close_field = function() then add this:
this.container.removeClass("chosen-container-active");
//Added by Fenistil
this.container.removeClass("chosen-with-dropup");
//End
this.clear_backstroke();
Find Chosen.prototype.activate_field = function() then add this:
this.container.addClass("chosen-container-active");
//Added by Fenistil
var windowHeight = $(window).height() + $('html').scrollTop(),
totalHeight = this.dropdown.height() + Math.ceil(this.dropdown.offset().top);
if (totalHeight > windowHeight) {
this.container.addClass("chosen-with-dropup");
this.dropdown.addClass('chosen-dropup');
}
//End
this.active_field = true;
Find Chosen.prototype.results_show = function() then add this:
this.container.addClass("chosen-with-drop");
//Added by Fenistil
var windowHeight = $(window).height() + $('html').scrollTop(),
totalHeight = this.dropdown.height() + Math.ceil(this.dropdown.offset().top);
if (totalHeight > windowHeight) {
this.container.addClass("chosen-with-dropup");
this.dropdown.addClass('chosen-dropup');
}
//End
this.results_showing = true;
this.search_field.focus();
Greetings!
PS.: Thanks to coreyworrell, this is based on his code.
UPDATE:
Hey thanks for this solution @fenisteel. This works well only with one little exception. It calculates whether to drop up or down based on the window height, not the scroll position.. It is not dynamic as the bootstrap select. For example on page load, user is on the top of the page, chosen at the bottom of the page will dropup. But if the user, scroll down the page, which eventually creates more space for that bottom chosen, it should then drop down as usual
http://silviomoreto.github.io/bootstrap-select/
When you scroll the page up and down, the dropdown should open-up or down based on the new positions not the positions on page load.
Thanks @fenisteel. It's great to see that after three years have a decent solution.
Why there is no dynamic solutions after all the years? I like the control very much except this problem.
Thanks @fenisteel. Your solution works great and very clear instructions on what needed to be changed.
@fenisteel can you send a PR with your changes ?
+1 to a PR from @fenisteel. I use Chosen via Bower in production, and can't edit library files in the repository.
+1 wish this could get out asap in v1.3.1
I've turned the changes by @fenisteel into a PR, see https://github.com/harvesthq/chosen/pull/2312.
This works for me
jQuery('.chosen-single').click(function() {
var $chosePosition = this.getBoundingClientRect(),
$choseDropListHeight = $(this).next().outerHeight();
if($(this).hasClass('above')) $(this).removeClass('above');
if (($chosePosition.bottom + $choseDropListHeight + 10) > $(window).height() && ($chosePosition.top - $choseDropListHeight) > 10) {
$(this).next().addClass("above");
$(this).addClass("above");
}
else {
$(this).next().removeClass("above");
$(this).removeClass("above");
}
$chosensingle = $(this);
$chosenvar = this;
$(window).bind('mousewheel DOMMouseScroll', function(event){
$chosePosition = $chosenvar.getBoundingClientRect(),
$choseDropListHeight = $chosensingle.next().outerHeight();
console.log($chosePosition.bottom + $choseDropListHeight + 10, '-',$(window).height(), '-',$chosePosition.top - $choseDropListHeight);
if (($chosePosition.bottom + $choseDropListHeight + 10) > $(window).height() && ($chosePosition.top - $choseDropListHeight) > 10) {
$chosensingle.next().addClass("above");
$chosensingle.addClass("above");
}
else {
$chosensingle.next().removeClass("above");
$chosensingle.removeClass("above");
}
});
});
@peimn this not worked for me
This was opened how long ago? why hasn't this been a priority to fix?
+1...
+1
+1
Any ETA on this? A much needed feature. I am currently using the solution above, but having to hack it in. It'd be great if this was part of the source.
+1 - this has been an outstanding request for 4 years. Any chance of getting it in there?
+1
+1
I would recommend using Tether.js for positioning the dropdown, it's a much better way because it places it in the body and not where the select element itself is located, so any overflow:hidden on a parent element won't clip it. Also, Tether.js is very smart at positioning according to the viewport and you can control everything.
Seems like the author isn't interested in fixing this and I don't like the idea of messing with the core files, so I came up with the below, which uses chosen's events to trigger adding/removing a 'chosen-drop-up' class where appropriate. You can include it anywhere after you've initialised your select(s).
The code is a bit verbose -- deliberately so, so that you can see what's going on.
$('#my-select').on('chosen:showing_dropdown', function(event, params) {
var chosen_container = $( event.target ).next( '.chosen-container' );
var dropdown = chosen_container.find( '.chosen-drop' );
var dropdown_top = dropdown.offset().top - $(window).scrollTop();
var dropdown_height = dropdown.height();
var viewport_height = $(window).height();
if ( dropdown_top + dropdown_height > viewport_height ) {
chosen_container.addClass( 'chosen-drop-up' );
}
});
$('#my-select').on('chosen:hiding_dropdown', function(event, params) {
$( event.target ).next( '.chosen-container' ).removeClass( 'chosen-drop-up' );
});
I haven't posted any CSS because mine is custom so it wouldn't help anyone. But you can start with
.chosen-container.chosen-drop-up .chosen-drop{
top: auto;
bottom: 100%;
}
...which will put the drop-down above the input element. The rest is all about fiddling with borders and so on.
Hope this helps someone.
@Taeon Thank you very much for your solution, it works perfectly!
This should really be merged in.
Would you submit a pull request? (one more in 80, I know, but still...)
@claudio-silva : since the author has ignored all related PRs so far I'm not sure there's much point. And anyway, this code is specifically NOT intended to be merged into the core -- it's meant to work without modifying core files. That way it will still work even if I update chosen.
+1
I've implemented the solution proposed by @Taeon (well, more or less, computation is different due to application specific stuff)
Here is the css I came up with to make it looks ok. (Not a css pro here)
.chosen-container.chosen-drop-up .chosen-drop {
border-bottom: 0;
border-radius: 4px 4px 0 0;
border-top: 1px solid #aaa;
bottom: 100%;
box-shadow: none;
top: auto;
}
.chosen-container-active.chosen-with-drop.chosen-drop-up .chosen-single {
background-image: -webkit-gradient(linear,50% 0,50% 100%,color-stop(40%,#eee),color-stop(90%,#fff));
background-image: -webkit-linear-gradient(#fff 40%,#eee 90%);
background-image: -moz-linear-gradient(#fff 40%,#eee 90%);
background-image: -o-linear-gradient(#fff 40%,#eee 90%);
background-image: linear-gradient(#fff 40%,#eee 90%);
border-radius: 0 0 4px 4px;
border-top: 0;
box-shadow: 0 1px 0 #fff inset;
}
I've improved upon my excellent peers (above this comment) with a complete solution which uses a little better JS and SCSS to achieve the important goal for countless people worldwide, the despicable maintainer is so happily ignoring:
$('select').on('chosen:showing_dropdown chosen:hiding_dropdown', function(e){
var chosen_container = $( e.target ).next( '.chosen-container' ),
classState = e.type == 'chosen:showing_dropdown' && dropdownExceedsBottomViewport();
function dropdownExceedsBottomViewport(){
var dropdown = chosen_container.find( '.chosen-drop' ),
dropdown_top = dropdown.offset().top - document.documentElement.scrollTop,
dropdown_height = dropdown.height(),
viewport_height = document.documentElement.clientHeight;
return dropdown_top + dropdown_height > viewport_height;
}
chosen_container.toggleClass( 'chosen-drop-up', classState );
});
.chosen-container {
&.chosen-drop-up .chosen-drop {
border-bottom: 0;
border-radius: 4px 4px 0 0;
border-top: 1px solid #aaa;
bottom: 100%;
box-shadow: 0 -4px 5px rgba(#000, .15);
top: auto;
}
}
.chosen-container-active {
&.chosen-with-drop {
.chosen-single:not(.chosen-drop-up) {
border: 1px solid #aaa;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
//background-image:linear-gradient(#eee 20%, #fff 80%);
//box-shadow: 0 1px 0 #fff inset;
}
&.chosen-drop-up{
.chosen-drop{
display:flex;
flex-direction: column-reverse;
}
.chosen-single {
// background-image: linear-gradient(#FFF 40%, #EEE 90%);
border-radius: 0 0 4px 4px;
border-top: 0;
box-shadow: 0 1px 0 #FFF inset;
border-top-right-radius: 0;
border-top-left-radius: 0;
}
}
}
}
}
@Taeon his solution works great for me
+1
ok I had the same issue. So I fixed it, may not be the most elegant, but it worked for me. I just added a margin-top: -332px; on .chzn-drop
@Taeon Thanks for this code! It saved me a few hours or frustration :)
@yairEO - That should totally find its way into the core! Works like a charm!
@yairEO - Nice solution, but if we have more than one dropdown with this solution, if one of the select dropdowns is triggering an ajax reload, the "chosen-drop-up" class is not added anymore on the chosen list.
@Taeon - your solution worked a treat when I changed the ID selector to a class for multiple chosen selects on the page 👍
Most helpful comment
Seems like the author isn't interested in fixing this and I don't like the idea of messing with the core files, so I came up with the below, which uses chosen's events to trigger adding/removing a 'chosen-drop-up' class where appropriate. You can include it anywhere after you've initialised your select(s).
The code is a bit verbose -- deliberately so, so that you can see what's going on.
I haven't posted any CSS because mine is custom so it wouldn't help anyone. But you can start with
...which will put the drop-down above the input element. The rest is all about fiddling with borders and so on.
Hope this helps someone.