Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent select2 from flipping the dropdown upward

As per title, is there a way to force select2 to always create a dropdown instead of a drop-up?

There also appears to be some javascript that is either causing the flip when you scroll above the dropdown, adding a new CSS class "select2-drop-above", or both.

EDIT: I should've specified that I'm pulling the library in via select2-rails. I'm hoping there is a way around this that doesn't involve pulling the whole select2 lib in myself and editing the select2.js file directly.

like image 809
kjb Avatar asked Nov 14 '13 16:11

kjb


People also ask

How do I create a Select2 dynamically?

HTML. Create a <select class="select2_el" > element to initialize select2 on page load and create <div id="elements" > container to store <select > element on button click using jQuery AJAX.

What does Select2 () do?

Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options.

How do I set Select2 values?

// Set up the Select2 control $('#mySelect2').select2({ ajax: { url: '/api/students' } }); // Fetch the preselected item, and add to the control var studentSelect = $('#mySelect2'); $.ajax({ type: 'GET', url: '/api/students/s/' + studentId }).then(function (data) { // create the option and append to Select2 var option ...

What Select2 dropdown?

By default, Select2 will attach the dropdown to the end of the body and will absolutely position it to appear above or below the selection container. Select2 will display the dropdown above the container if there is not enough space below the container, but there is enough space above it.


1 Answers

Since modifying the source code is not an option and adding a hook to the select2:open event is not very elegant, especially when you have multiple select2 instances in the same page, I have written a small extension for the Select2 plugin.

My implementation is inspired by a PR from the plugin's repository (https://github.com/select2/select2/pull/4618) that is not yet merged.

Basically, the following code overrides the original plugin function that handles the dropdown positioning and adds a new option (dropdownPosition) to force the dropdown positioning above/below.

The new dropdownPosition option can take the following values: - below - the dropdown is always displayed at the bottom of the input; - above - the dropdown is always displayed at the top of the input; - auto (default) - it uses the old behavior.

Just insert the following code after select2.js file:

(function($) {    var Defaults = $.fn.select2.amd.require('select2/defaults');    $.extend(Defaults.defaults, {     dropdownPosition: 'auto'   });    var AttachBody = $.fn.select2.amd.require('select2/dropdown/attachBody');    var _positionDropdown = AttachBody.prototype._positionDropdown;    AttachBody.prototype._positionDropdown = function() {      var $window = $(window);      var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');     var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');      var newDirection = null;      var offset = this.$container.offset();      offset.bottom = offset.top + this.$container.outerHeight(false);      var container = {         height: this.$container.outerHeight(false)     };      container.top = offset.top;     container.bottom = offset.top + container.height;      var dropdown = {       height: this.$dropdown.outerHeight(false)     };      var viewport = {       top: $window.scrollTop(),       bottom: $window.scrollTop() + $window.height()     };      var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);     var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);      var css = {       left: offset.left,       top: container.bottom     };      // Determine what the parent element is to use for calciulating the offset     var $offsetParent = this.$dropdownParent;      // For statically positoned elements, we need to get the element     // that is determining the offset     if ($offsetParent.css('position') === 'static') {       $offsetParent = $offsetParent.offsetParent();     }      var parentOffset = $offsetParent.offset();      css.top -= parentOffset.top     css.left -= parentOffset.left;      var dropdownPositionOption = this.options.get('dropdownPosition');      if (dropdownPositionOption === 'above' || dropdownPositionOption === 'below') {       newDirection = dropdownPositionOption;     } else {        if (!isCurrentlyAbove && !isCurrentlyBelow) {         newDirection = 'below';       }        if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {         newDirection = 'above';       } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {         newDirection = 'below';       }      }      if (newDirection == 'above' ||     (isCurrentlyAbove && newDirection !== 'below')) {         css.top = container.top - parentOffset.top - dropdown.height;     }      if (newDirection != null) {       this.$dropdown         .removeClass('select2-dropdown--below select2-dropdown--above')         .addClass('select2-dropdown--' + newDirection);       this.$container         .removeClass('select2-container--below select2-container--above')         .addClass('select2-container--' + newDirection);     }      this.$dropdownContainer.css(css);    };  })(window.jQuery); 

The initialize the plugin with as follows:

$(document).ready(function() {   $(".select-el").select2({     dropdownPosition: 'below'   }); }); 

Fiddle here: https://jsfiddle.net/byxj73ov/

Github repository: https://github.com/andreivictor/select2-dropdownPosition


UPDATE December 30, 2019

Fiddle with the latest Select2 Version (v4.0.12): https://jsfiddle.net/g4maj9ox/

like image 171
andreivictor Avatar answered Sep 20 '22 13:09

andreivictor