javascript - dist - Evita que select2 gire el menú desplegable hacia arriba
select2 ejemplo (6)
Según el título, ¿hay una manera de forzar a select2 a crear siempre un menú desplegable en lugar de un menú desplegable?
También parece haber algún javascript que está causando la inversión cuando se desplaza por encima del menú desplegable, agregando una nueva clase de CSS "select2-drop-above", o ambas.
EDITAR: Debería haber especificado que estoy tirando de la biblioteca a través de select2-rails. Espero que haya una forma de evitar esto que no implique tirar todo el select2 lib en mí y editar el archivo select2.js directamente.
Actualizado desde [shanabus] respuesta
jQuery("#line_item").select2({
formatResult: Invoice.formatLineItem
})
.on(''select2-open'', function() {
// however much room you determine you need to prevent jumping
var requireHeight = $("#select2-drop").height()+10;
var viewportBottom = $(window).height() - $("#line_item").offset().top;
// figure out if we need to make changes
if (viewportBottom < requireHeight)
{
// determine how much padding we should add (via marginBottom)
var marginBottom = requireHeight - viewportBottom;
// adding padding so we can scroll down
$(".aLwrElmntOrCntntWrppr").css("marginBottom", marginBottom + "px");
// animate to just above the select2, now with plenty of room below
$(''html, body'').animate({
scrollTop: $("#select2-drop").offset().top - 10
}, 1000);
}
});
Dado que modificar el código fuente no es una opción y agregar un gancho al evento select2:open
no es muy elegante, especialmente cuando tiene varias instancias de select2 en la misma página, he escrito una pequeña extensión para el complemento Select2
.
Mi implementación está inspirada en una PR del repositorio del complemento ( https://github.com/select2/select2/pull/4618 ) que aún no se ha fusionado.
Básicamente, el siguiente código anula la función de complemento original que maneja el posicionamiento desplegable y agrega una nueva opción ( dropdownPosition
) para forzar el posicionamiento desplegable arriba / abajo.
La nueva opción dropdownPosition
puede tomar los siguientes valores: - below
- el desplegable siempre se muestra en la parte inferior de la entrada; - above
- el menú desplegable siempre se muestra en la parte superior de la entrada; - auto
(predeterminado) - utiliza el comportamiento anterior.
Simplemente inserte el siguiente código después del archivo select2.js
:
(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);
El inicializar el plugin con lo siguiente:
$(document).ready(function() {
$(".select-el").select2({
dropdownPosition: ''below''
});
});
Fiddle aquí: https://jsfiddle.net/byxj73ov/
Repositorio de Github: https://github.com/andreivictor/select2-dropdownPosition
Puedes hacerlo sobrescribiendo CSS así:
.select-dropdown {
position: static;
}
.select-dropdown .select-dropdown--above {
margin-top: 336px;
}
Solía encontrar una solución más fácil / rápida para eso:
$("select").select2({
// Options
}).on(''select2:open'',function(){
$(''.select2-dropdown--above'').attr(''id'',''fix'');
$(''#fix'').removeClass(''select2-dropdown--above'');
$(''#fix'').addClass(''select2-dropdown--below'');
});
Es simple, solo cambia el .select2-desplegable - arriba al .select2-desplegable - abajo en el evento de apertura (select2: abierto).
Solo funcionará bajo el evento, y podría haber muchas otras formas de realizarlo simplemente cambiando las clases cuando se abre la selección.
PD. No funcionará si intenta completar su selección utilizando jquery.
Solo puedes editar select2.js
En donde dice
enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),
solo cámbiala a
enoughRoomBelow = true,
enoughRoomAbove = false,
La modificación del complemento no se prefiere como usted menciona. Tuve un problema similar y no pude encontrar una manera de usar select2
opciones de select2
para forzar que el menú desplegable se quede abajo. La solución con la que terminé es la siguiente:
$("#mySelect2").select2({ ...options... })
.on(''select2-open'', function() {
// however much room you determine you need to prevent jumping
var requireHeight = 600;
var viewportBottom = $(window).scrollTop() + $(window).height();
// figure out if we need to make changes
if (viewportBottom < requireHeight)
{
// determine how much padding we should add (via marginBottom)
var marginBottom = requireHeight - viewportBottom;
// adding padding so we can scroll down
$(".aLwrElmntOrCntntWrppr").css("marginBottom", marginBottom + "px");
// animate to just above the select2, now with plenty of room below
$(''html, body'').animate({
scrollTop: $("#mySelect2").offset().top - 10
}, 1000);
}
});
Este código determina si hay suficiente espacio para colocar el menú desplegable en la parte inferior y, de no ser así, lo crea agregando el margen inferior a algún elemento de la página. Luego se desplaza hasta justo encima de select2 para que el menú desplegable no se mueva.