Select2 Bootstrap Modal 带模态滚动

问题描述 投票:0回答:6

更新:

我添加了这个:

$("#id_project").select2({dropdownParent: $(".modal-body")});

...这会导致下拉列表正确放置,并且可以输入搜索内容。不幸的是...这会导致传递的数据被清除,并且没有任何选项可供选择。

我有一个在 Bootstrap 模式中填充的表单,如下所示:

<form method="post" action="/dataanalytics/sparc/tasks/create/" class="js-task-create-form">
  <input type="hidden" name="csrfmiddlewaretoken" value="W6cnRq9zPDvUdQOpqceXPVulbWJAMFazRStzwnZhLi8UEqa87SYiRKmMoHAKwmvb">
  <div class="modal-body">
  <div class="form-group">
    <select name="project" data-minimum-input-length="2" class="form-control select2-hidden-accessible" required="" id="id_project" data-autocomplete-light-url="/dataanalytics/projectautocomplete/" data-autocomplete-light-function="select2" tabindex="-1" aria-hidden="true">
       <option value="" selected="">---------</option>
    </select>
    <span class="select2 select2-container select2-container--bootstrap select2-container--focus" dir="ltr" style="width: 505.091px;">
    <span class="selection"><span class="select2-selection select2-selection--single" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-id_project-container">
    <span class="select2-selection__rendered" id="select2-id_project-container">
    <span class="select2-selection__placeholder">
    </span>
    </span>
    <span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span></span></span><span class="dropdown-wrapper" aria-hidden="true">
    </span>
    </span>
  </div>
  <div class="form-group">
    <select name="dataSources" data-minimum-input-length="2" class="form-control select2-hidden-accessible" id="id_dataSources" data-autocomplete-light-url="/dataanalytics/datasourceautocomplete/" data-autocomplete-light-function="select2" multiple="" tabindex="-1" aria-hidden="true">
    </select>
    <span class="select2 select2-container select2-container--bootstrap" dir="ltr" style="width: 505.091px;">
    <span class="selection"><span class="select2-selection select2-selection--multiple" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="-1">
      <ul class="select2-selection__rendered">
         <li class="select2-search select2-search--inline">
         <input class="select2-search__field" type="search" tabindex="0" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="textbox" aria-autocomplete="list" placeholder="" style="width: 0.75em;">
         </li>
      </ul>
    </span>
    </span>
    <span class="dropdown-wrapper" aria-hidden="true">
    </span>
    </span>
  </div>
</div>
</form>
</div>
</div>

带有 select2 单曲的第一个表单组表现出有问题的行为。具有 select2 多个的第二个表单组按预期工作。为什么这里会有差距?

JavaScript:

  var loadForm = function () {
    var btn = $(this);
    $.ajax({
      url: btn.attr("data-url"),
      type: 'get',
      dataType: 'json',
      beforeSend: function () {
        $("#modal-task").modal("show");
      },
      success: function (data) {
        $("#modal-task .modal-content").html(data.html_form);
      }
    });
  };

版本:

  • jQuery:1.12.1
  • 选择2:4.0.5
  • 引导程序:4

Chrome 中一切都运行良好。在 Firefox 中,模式中的 Select2 框不允许输入搜索输入。这是一个已知问题(https://select2.org/troubleshooting/common-problems),但已知的解决方案似乎都不适合我。

为了解决这个问题,我添加了这段代码来设置每个Select2的

dropdownParent

$.fn.select2.defaults.set("dropdownParent", $('#modal-task'));

这允许输入搜索输入。但是,我的模式足够长,需要滚动。如果模式滚动超出原始位置,单击 Select2 框会导致选项和搜索输入出现在模式顶部的框上方。这是有道理的,因为所有 Select2 框都通过

dropdownParent
与模式本身绑定。

如何防止这种行为并强制 Select2 选择和搜索输入正常显示(直接位于 Select2 的上方或下方,具体取决于它相对于窗口边缘的位置)?另外,即使未激活模式,页面上也有 Select2 框,因此以这种方式影响所有 Select2 框并不理想。

更新:我尝试交换此行的其他代码:

$.fn.modal.Constructor.prototype.enforceFocus = function () {};

这与不执行任何操作具有相同的效果:搜索输入在 Firefox 中不起作用,但下拉菜单放置正确。

更新2:我尝试过这个:

$('#id_project').set("dropdownParent", $('#id_project'));

这导致下拉菜单没有出现在任何地方,并且选项消失了(由

---------
取代)。

更新3:我尝试过这个...

$('#modal-task').css('overflow','visible');

...这导致搜索输入工作...但模式滚动现在已损坏。此外,下拉列表在 Select2 框的左边缘上稍微未对齐。

javascript jquery twitter-bootstrap bootstrap-modal jquery-select2
6个回答
8
投票

只需像这样使用 select2 即可绕过引导模式错误:

$('.my-select2').each(function () {
    $(this).select2({
        dropdownParent: $(this).parent(),// fix select2 search input focus bug
    })
})

// fix select2 bootstrap modal scroll bug
$(document).on('select2:close', '.my-select2', function (e) {
    var evt = "scroll.select2"
    $(e.target).parents().off(evt)
    $(window).off(evt)
})

3
投票

这对我来说效果很好

$(document).ready(function () {
    $('select.select2:not(.normal)').each(function () {
        $(this).select2({
            dropdownParent: $(this).parent().parent()
        });
    });
});

1
投票

我已经迟到了,可以帮助别人。如果您的模式上有 tabindex = -1,那么您可能无法输入。尝试将其删除。为我工作。


1
投票

对我来说,我使用的是 select2 v4 和 bootstrap modal。更改事件适用于旧版本的 select2。

我需要从

更新我的事件侦听器
selectList.on('change', function(e) {

选择(添加项目)

selectList.on('select2:select', function(e) {

并取消选择(删除项目)

selectList.on('select2:unselect', function(e) {

https://select2.org/programmatic-control/events


1
投票

首先在select2选项中必须有

dropdownParent: $(this).parent(),// That fix weird positioning select2 input

之后我们在 select2 打开事件时做了一些小技巧。我意识到,当 select2 打开时,如果模态高度小于窗口高度,即使在需要滚动后也不会出现滚动问题。

因此我们对 select2 事件进行了溢出调整。打开select2时将模态体设置为不溢出,select2打开后设置回默认值。

    $(document).on("select2:opening", (e) => {
        $('.modal-body').css('overflow', 'visible');
    });
    $(document).on("select2:open", (e) => {
        $('.modal-body').css('overflow', 'auto');
    });

这将解决你的问题。


0
投票

我重写了下拉位置函数以包含滚动,对我有用!

只需在 sel2 之后和开始任何 sel2 之前复制并粘贴即可。

它仅适用于 bootstrap 5 中模态框内的 sel2。

var oldDropdownPosition = $.fn.select2.amd.require('select2/dropdown/attachBody');
        var originalPositionDropdown = oldDropdownPosition.prototype._positionDropdown;
        oldDropdownPosition.prototype._positionDropdown = function() {
            if (this.$dropdownParent && this.$dropdownParent.closest('.modal').length) {
                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 enoughRoomBelow = viewport.bottom > (container.bottom + dropdown.height);
                var enoughRoomAbove = viewport.top < (container.top - dropdown.height);
                var css = {
                    left: offset.left,
                    top: container.bottom
                };
                // Adjust position based on scrolling
                css.top = css.top - $window.scrollTop();
                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 - 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);
            } else {
                // Call the original function if not inside a modal
                originalPositionDropdown.apply(this, arguments);
            }
        };

© www.soinside.com 2019 - 2024. All rights reserved.