Replacing Dropstrap Dropdown with Dropup (different activity on two implementations close to them)

I am working on a project on github pages that I will replace bootstrap .dropdown with .dropup if the div overflow-y: scroll will disable / overflow the dropdown menu. You can see that the function works correctly on jsfiddle . Please note that if you click on the ellipsis icon on the right in the upper lines, it will fall; if you click on the icon in the lower lines, it will go down.

Now, my actual implementation ( github page ), the code is exactly the same (below), but it wants to replace all .dropdown classes with .dropup when opened, including the topmost line, which is disabled, as shown in the photo below. enter image description here I struggled with this for a week and cannot understand. I tried a few different things that I thought I fixed it, but in the end it turned out to be hacked and did not work on my mobile phone, or replaced some, but not all, etc.

Here is the Javascript / jQuery that I am using, which can be seen in jsfiddle and my github source here .

 $(document).on("shown.bs.dropdown", ".dropdown", function () { // calculate the required sizes, spaces var $ul = $(this).children(".dropdown-menu"); var $button = $(this).children(".song-menu"); var ulOffset = $ul.offset(); // how much space would be left on the top if the dropdown opened that direction var spaceUp = (ulOffset.top - $button.height() - $ul.height()) - $('#playlist').scrollTop(); // how much space is left at the bottom var spaceDown = $('#playlist').scrollTop() + $('#playlist').height() - ((ulOffset.top + 10) + $ul.height()); // switch to dropup only if there is no space at the bottom AND there is space at the top, or there isn't either but it would be still better fit if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown)) $(this).addClass("dropup"); }).on("hidden.bs.dropdown", ".dropdown", function() { // always reset after close $(this).removeClass("dropup"); }); 

Edit: To eliminate any confusion, here is an example of behavior without my added .dropup function. jsfiddle Notice when you click the last menu item, it opens the menu, but requires scrolling. I specifically want to remove the .dropdown class and add .dropup in this case, so scrolling is not required.

+6
source share
3 answers

It took some basic math, but I managed to figure out what you wanted to do. This code changes the boot classes between the drop-down and drop-down lists depending on the available room for a normal drop-down list.

I figured this out by reducing the height of the button, dropdownmenu and how far the button scrolled in scrollContainer from the height of scrollContainer. I got the value of how much the div was scrolled down using the button offset and decreasing the offset from scrollContainer.

Here is my jQuery (I chose the .playlist class because it was attached to your scrollContainer, but you have to replace it with id or select it in other ways):

 $(".dropdown, .dropup").click(function(){ var dropdownClassCheck = $(this).hasClass('dropdown'); var buttonOffset = $(this).offset().top; var scrollboxOffset = $('.playlist').offset().top; var buttonHeight = $(this).height(); var scrollBoxHeight = $('.playlist').height(); var dropDownButtonHeight = $(this).children('ul').height(); dropdownSpaceCheck = scrollBoxHeight>buttonOffset-scrollboxOffset+buttonHeight+dropDownButtonHeight; if(dropdownClassCheck && !dropdownSpaceCheck){ $(this).removeClass('dropdown').addClass('dropup'); } else if(!dropdownClassCheck && dropdownSpaceCheck){ $(this).removeClass('dropup').addClass('dropdown'); } }); 

Working jsfiddle

Let me know if there are parts of the code that could be improved / made easier or there were problems with my solution.

+4
source

I did not check thoroughly, but .scrollTop() is probably why the code does not work when it is combined with other elements in the DOM, so here is a solution without it:

 function checkHeights(){ // LOOP through each dropdown $('.dropdown,.dropup').each(function(index,element){ var $dropDown = $(element), $dropDownMenu = $dropDown.find('.dropdown-menu'), dropDownTop = $dropDown.offset().top, visibleHeight = $dropDown.height(), hiddenHeight = $dropDownMenu.height(), ddTop = dropDownTop - hiddenHeight, ddBottom = dropDownTop + visibleHeight + hiddenHeight; // LOOP through all parents $dropDown.parents().each(function(ix,el){ var $el = $(el); // CHECK if any of them have overflow property set if( $el.css('overflow') !== 'visible' ){ var limitTop = $el.offset().top, limitBottom = limitTop + $el.height(); // CHECK if parent is better fit when dropped upside if( limitBottom < ddBottom && ( ddTop - limitTop ) > ( limitBottom - ddBottom ) ) $dropDown.removeClass('dropdown').addClass('dropup'); else $dropDown.removeClass('dropup').addClass('dropdown'); // BREAK LOOP return false; } }); }); } $(document).ready(function() { checkHeights(); $('.playlist').scroll(checkHeights); }); 

JS Fiddle is here .

This does not require class or id tags, with the exception of dropdown , dropdown-menu and dropup (all of which are the default values ​​for Bootstrap) and will work fine even if there are several playlists on the page.


UPDATE

The code is modified and certified in a function to allow it to be called when the scroll event is triggered.

+2
source

I think the problem is that you have a big header, but jsFiddle does not. So ulOffset.top is always big, and spaceDown always negative

+1
source

All Articles