breq
breq

Reputation: 25516

Select2 doesn't work when embedded in a bootstrap modal

When I use a select2 (input) in bootstrap modal, I can't type anything into it. It's like disabled? Outside the modal select2 works fine.

enter image description here

Working example: http://jsfiddle.net/byJy8/1/ code:

<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
        <h3 id="myModalLabel">Panel</h3>
    </div>
    <div class="modal-body" style="max-height: 800px">          
      <form class="form-horizontal">
        <!-- Text input-->
        <div class="control-group">
            <label class="control-label" for="vdn_number">Numer</label>
            <div class="controls">
                <!-- seleect2 -->
                <input name="vdn_number" type="hidden" id="vdn_number"  class="input-large" required=""  />
            </div>
        </div>
      </form>    
    </div>
    <div class="modal-footer">
        <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
        <button class="btn btn-primary">Save changes</button>
    </div>
</div>

JS

$("#vdn_number").select2({
    placeholder: "00000",
    minimumInputLength: 2,
    ajax: {
        url: "getAjaxData/",
        dataType: 'json',
        type: "POST",
        data: function (term, page) {
            return {
                q: term, // search term
                col: 'vdn'
            };
        },
        results: function (data) { // parse the results into the format expected by Select2.
            // since we are using custom formatting functions we do not need to alter remote JSON data
            return {results: data};
        }
    }
});

Upvotes: 434

Views: 446890

Answers (30)

Mahdi Bashirpour
Mahdi Bashirpour

Reputation: 18833

Just add the select2-in-modal class to the select box

jQuery('.select2-in-modal').each(function () {
    var parentModal = jQuery(this).closest('.modal');
    jQuery(this).select2({
        dropdownParent: parentModal
    });
});

Upvotes: 0

Viktor Ivliiev
Viktor Ivliiev

Reputation: 1334

If you are using the old "select2": "3.5.1" as and for whatever reason, it doesn't have a dropdownParent. Here is the solution that I applied for myself:

class Select2Attacher {
  static getOptions() {
    return {
      minimumResultsForSearch: 10,
      placeholder: 'Your placeholder'    
    };

  }

  static attachAll() {
    $('your selector').each(function() {
      if (!$(this).hasClass('select2-offscreen')) { 
         Select2Attacher.attach(this); 
      };
    });
  }

  static attach(element, options = {}) {
    if ($(element).parents('.modal-content').length) {
      let opts = Object.assign({}, Select2Attacher.getOptions(), $(element).data(), options);
      let multiple = false;

      opts.element = $(element);

      if (opts.element.get(0).tagName.toLowerCase() === "select") {
        multiple = opts.element.prop("multiple");
      } else {
        multiple = opts.multiple || false;
        if ("tags" in opts) {opts.multiple = multiple = true;}
      }

      let select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single();
      select2.init(opts);
      select2.body = $(element).parents('.modal-content');
    } else {
      $(element).select2(Object.assign({}, Select2Attacher.getOptions(), $(element).data(), options));
    }

  }
}

$(document).ready(() => { Select2Attacher.attachAll(); });
$(document).on('modal:loaded cocoon:after-insert ajaxComplete shown.bs.modal', Select2Attacher.attachAll);

Upvotes: 0

moneeb
moneeb

Reputation: 152

This will work for all

body .select2-container {
    z-index: 9999 !important;
}

please note to add width also to fix the interface:

$('.select2').select2({
    width: '100%'
});

Upvotes: 4

pymarco
pymarco

Reputation: 8185

I found a solution to this on github for select2

https://github.com/select2/select2/issues/1436

For bootstrap 3, the solution is:

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

Bootstrap 4 renamed the enforceFocus method to _enforceFocus, so you'll need to patch that instead:

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

Explanation copied from link above:

Bootstrap registers a listener to the focusin event which checks whether the focused element is either the overlay itself or a descendent of it - if not it just refocuses on the overlay. With the select2 dropdown being attached to the body this effectively prevents you from entering anything into the textfield.

You can quickfix this by overwriting the enforceFocus function which registers the event on the modal

Upvotes: 229

Yevgeniy Afanasyev
Yevgeniy Afanasyev

Reputation: 41410

fix for Select2 search input not working in Bootstrap Modal - just temporary delete attribute "tabindex" when your drop down is open

<script type="text/javascript">
    $(document).ready(function () {

        $(".select2-with-data-js").each(function (index) {
            const $select2 = $(this);

            $select2.select2().on("select2:opening", 
            function(){
                $("#modal--dealer-address").removeAttr("tabindex", "-1");
            }).on("select2:close", 
            function(){
                $("#modal--dealer-address").attr("tabindex", "-1");
            });
        });
    });
</script>

Upvotes: 0

Mahdi Akrami
Mahdi Akrami

Reputation: 643

Use Select2 Bootstrap 5 Theme in Bootstrap Modal like this:

  1. fix select2 & bootstrap modal search input bug.
  2. fix select2 & bootstrap modal scroll bug after select option.

jQuery(function() {

  $('.my-select2').each(function() {
    $(this).select2({
      theme: "bootstrap-5",
      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)
  })

})
<!DOCTYPE html>
<html>

<head>
  <!-- Styles -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/select2-bootstrap-5-theme.min.css" />

  <!-- Scripts -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>

</head>

<body>

  <!-- Button trigger modal -->
  <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
  Launch demo modal
</button>

  <!-- Modal -->
  <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          Select2 v4.1

          <select class="my-select2">
            <option>Test 1</option>
            <option>Test 2</option>
            <option>Test 3</option>
            <option>Test 4</option>
            <option>Test 5</option>
            <option>Test 6</option>
            <option>Test 7</option>
            <option>Test 8</option>
            <option>Test 9</option>
            <option>Test 10</option>
          </select>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
          <button type="button" class="btn btn-primary">Save changes</button>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

Upvotes: 7

Gaeguri
Gaeguri

Reputation: 509

You shouldn't stuck your dropdown to the modal as suggested in most of the answer. If your select2 is at the bottom of the modal and you need to scroll down to find it then you will have a dropdown's position problem because you stuck it on the modal.

Instead of this you should set the dropdown parent to the input parent. In your case it should look like this

$(document).ready(function() {
  $("#vdn_number").select2({
    dropdownParent: $("#vdn_number").parent()
  });
});

Upvotes: 1

Monzur
Monzur

Reputation: 1435

Use this code on your page

$(function () {
    $(".select2").select2({
        dropdownParent: $('#myModal')
    });

    $("#myModal").on('change', '#vdn_number', function () {
        var term = $(this).val();
        ajax: ({
            url: "getAjaxData/",
            dataType: 'json',
            type: "POST",
            data: function (term, page) {
                return {
                    q: term, // search term
                    col: 'vdn'
                };
            },
            results: function (data) { // parse the results into the format expected by Select2.
                // since we are using custom formatting functions we do not need to alter remote JSON data
                return { results: data };
            }
        });
    });
});

I think this will help you

Upvotes: 3

For bootstrap3 versions, just use this code on document ready:

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

Upvotes: 11

breq
breq

Reputation: 25516

Ok, I've got it to work.

change

<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
        <h3 id="myModalLabel">Panel</h3>
    </div>
    <div class="modal-body" style="max-height: 800px">

to

<div id="myModal" class="modal hide fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
        <h3 id="myModalLabel">Panel</h3>
    </div>
    <div class="modal-body" style="max-height: 800px">

(remove tabindex="-1" from modal)

Upvotes: 749

armel sauvy
armel sauvy

Reputation: 75

Remove tabindex="-1" from modal. I checked this solution and it's worked.

Ref: https://github.com/select2/select2-bootstrap-theme/issues/41

Upvotes: 4

Dawam Raja
Dawam Raja

Reputation: 449

If you using stisla and use firemodal :

$('#modal-create-promo').click(()=>{
    setTimeout(()=>{
        $('#fire-modal-1').removeAttr('tabindex');
    });
});

    $("#modal-create-promo").fireModal({
    ...
});

It's work for me

Upvotes: 0

pecito22
pecito22

Reputation: 145

I had a similar problem and I fixed with

    $('#CompId').select2({
              dropdownParent: $('#AssetsModal')
    });

and modal with select

    <div class="modal fade" id="AssetsModal" role="dialog" 
    aria-labelledby="exampleModalCenterTitle" 
    aria-hidden="true"  style="overflow:hidden;" >
<div class="modal-dialog modal-dialog-centered" role="document">
  <div class="modal-content">
      <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLongTitle" >Добави активи</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
      </div>
      <div class="modal-body">
          <form role="form" action="?action=dma_act_documents_assets_insert&Id=<?=$ID?>" 
                  method="post" name="dma_act_documents_assets_insert" 
                  id="dma_act_documents_assets_insert">
            <div class="form-group col-sm-12">
                  <label for="recipient-name" class="col-form-label">Актив:</label>
                  <span style="color: red">*</span>
                          <select class="form-control js-example-basic-single col-sm-12" 
                                 name="CompId" id="CompId">
                                  <option></option>
                          </select>
              </div>
          </form>
      </div>
  </div>
</div>

but I don't know why the select menu is smaller than other fields enter image description here

and it starting like that when start using select2. When I remove it, all is ok.

Is there some one to share some experince about that.

Thanks.

Upvotes: 12

chispitaos
chispitaos

Reputation: 927

to use bootstrap 4.0 with server-side(ajax or json data inline), you need to add all of this:

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

and then when modal is open, create the select2:

  // when modal is open
  $('.modal').on('shown.bs.modal', function () {
            $('select').select2({
                  // ....
            });
  });

Upvotes: 6

Sinatrya Yogi Rizal
Sinatrya Yogi Rizal

Reputation: 25

you can call select2 trigger again inside your $(document)

$(".select2").select2({ 
                width: '120' 
            });

Upvotes: 1

Juan Antonio
Juan Antonio

Reputation: 2614

In my case I had the same problem with two modals and all was resolved using:

$('.select2').each(function() { 
    $(this).select2({ dropdownParent: $(this).parent()});
})

As in the project issue #41 an user said.

Upvotes: 24

Zombaya
Zombaya

Reputation: 2258

I solved this generally in my project by overloading the select2-function. Now it will check if there is no dropdownParent and if the function is called on an element that has a parent of the type div.modal. If so, it will add that modal as the parent for the dropdown.

This way, you don't have to specify it every time you create a select2-input-box.

(function(){
    var oldSelect2 = jQuery.fn.select2;
    jQuery.fn.select2 = function() {
        const modalParent = jQuery(this).parents('div.modal').first();
        if (arguments.length === 0 && modalParent.length > 0) {
            arguments = [{dropdownParent: modalParent}];
        } else if (arguments.length === 1
                    && typeof arguments[0] === 'object'
                    && typeof arguments[0].dropdownParent === 'undefined'
                    && modalParent.length > 0) {
            arguments[0].dropdownParent = modalParent;
        }
        return oldSelect2.apply(this,arguments);
    };
    // Copy all properties of the old function to the new
    for (var key in oldSelect2) {
        jQuery.fn.select2[key] = oldSelect2[key];
    }
})();

Upvotes: 3

Anas
Anas

Reputation: 1503

According to the official select2 documentation this issue occurs because Bootstrap modals tend to steal focus from other elements outside of the modal.

By default Select2 attaches the dropdown menu to the element and it is considered "outside of the modal".

Instead attach the dropdown to the modal itself with the dropdownParent setting:

$('#myModal').select2({
   dropdownParent: $('#myModal')
});

See reference: https://select2.org/troubleshooting/common-problems

Upvotes: 16

In my case i did this and it works. I use bundle to load it and in this case it worked for me

 $(document).on('select2:select', '#Id_Producto', function (evt) {
   // Here your code...
  });

Upvotes: -2

ocobacho
ocobacho

Reputation: 541

$('.modal').on('shown.bs.modal', function (e) {
    $(this).find('.select2me').select2({
        dropdownParent: $(this).find('.modal-content')
    });
})

Upvotes: 10

bezz
bezz

Reputation: 1678

Set the dropdownParent. I had to set it on .modal-content within the modal or the text would end up centered.

$("#product_id").select2({
    dropdownParent: $('#myModal .modal-content')
});

Upvotes: 90

111
111

Reputation: 1918

I had a semi-related issue in an application so I'll put in my 2c.

I have multiple modals with forms containing select2 widgets. Opening modal A, then another modal inside modal A, would cause select2 widgets inside modal B to disappear and fail to initialize.

Each of these modals were loading the forms via ajax.

The solution was to remove the forms from the dom when closing a modal.

$(document).on('hidden.bs.modal', '.modal', function(e) {
    // make sure we don't leave any select2 widgets around 
    $(this).find('.my-form').remove();
});

Upvotes: 1

Vinoth Smart
Vinoth Smart

Reputation: 393

This Problem Sloved Working For Me Single Jquery Function

$('#myModal .select2').each(function() {  
   var $p = $(this).parent(); 
   $(this).select2({  
     dropdownParent: $p  
   });  
});

Upvotes: 12

dboswell
dboswell

Reputation: 4116

For Select2 v4:

Use dropdownParent to attach the dropdown to the modal dialog, rather than the HTML body.

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
        <select id="select2insidemodal" multiple="multiple">
          <option value="AL">Alabama</option>
            ...
          <option value="WY">Wyoming</option>
        </select>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>


<script>

$(document).ready(function() {
  $("#select2insidemodal").select2({
    dropdownParent: $("#myModal")
  });
});

</script>

This will attach the Select2 dropdown so it falls within the DOM of the modal rather than to the HTML body (the default). See https://select2.org/dropdown#dropdown-placement

Upvotes: 396

NoWar
NoWar

Reputation: 37632

I just get it working by including select2.min.css

Try iy out

My modal html of bootstrap 3 is

<div id="changeTransportUserRequestPopup" class="modal fade" role="dialog">
    <div class="modal-dialog" style="width: 40%!important; ">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h3>Warning</h3>
            </div>
            <div class="modal-body" id="changeTransportUserRequestPopupBody">
                <select id="cbTransport" class="js-example-basic-single" name="cbTransport" style="width:100%!important;"></select>
            </div>
            <div class="modal-footer">
                <button id="noPost" class="btn btn-default" name="postConfirm" value="false" data-dismiss="modal">Cancel</button>
                <button type="submit" id="yesChangeTransportPost" class="btn btn-success" name="yesChangeTransportPost" value="true" data-dismiss="modal">Yes</button>
            </div>
        </div>
    </div>
</div>

Upvotes: 0

joker
joker

Reputation: 3752

Okay, I know I'm late to the party. But let me share with you what worked for me. The tabindex and z-index solutions did not work for me.

Setting the parent of the select element worked as per the common problems listed on select2 site.

Upvotes: 2

Angelo Cavalet
Angelo Cavalet

Reputation: 113

Based on @pymarco answer I wrote this solution, it's not perfect but solves the select2 focus problem and maintain tab sequence working inside modal

    $.fn.modal.Constructor.prototype.enforceFocus = function () {
        $(document)
        .off('focusin.bs.modal') // guard against infinite focus loop
        .on('focusin.bs.modal', $.proxy(function (e) {
            if (this.$element[0] !== e.target && !this.$element.has(e.target).length && !$(e.target).closest('.select2-dropdown').length) {
                this.$element.trigger('focus')
            }
        }, this))
    }

Upvotes: 3

Gangai Johann
Gangai Johann

Reputation: 888

If you have a problem with the iPad keyboard which hide the bootstrap modal while clicking on the select2 input, you can resolve this by adding the following rule after the initialization of the select2 input :

if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
   var styleEl = document.createElement('style'), styleSheet;
   document.head.appendChild(styleEl);
   styleSheet = styleEl.sheet;
   styleSheet.insertRule(".modal { position:absolute; bottom:auto; }", 0);
   document.body.scrollTop = 0; // Only for Safari
}

Taken from https://github.com/angular-ui/bootstrap/issues/1812#issuecomment-135119475

EDIT: If your options are not shown properly, you need to use the dropdownParent attribute when initializing select2 :

$(".select2").select2({
    dropdownParent: $("#YOURMODALID")
});

Good luck (:

Upvotes: 4

Đọc truyện hay
Đọc truyện hay

Reputation: 2021

Just remove tabindex="-1" and add style overflow:hidden

Here is an example:

<div id="myModal" class="modal fade" role="dialog" style="overflow:hidden;">
    <!---content modal here -->
</div>

Upvotes: 57

ramazan polat
ramazan polat

Reputation: 423

$("#IlceId").select2({
    allowClear: true,
    multiple: false,
    dropdownParent: $("#IlceId").parent(),
    escapeMarkup: function (m) {
        return m;
    },
});

this code is working. Thank you.

Upvotes: 3

Related Questions