Search code examples
javascripttwitter-bootstrapeventsbootstrap-4dropdown

Bootstrap's .dropdown('toggle') works a bit too well: dropdown is then unusable


I've got a dropdown menu containing a text zone. When the return key is pressed on the text zone, I'd like the dropdown to close. This is what the following does:

$(document).ready(function(){
  $('#edit').keypress(function(e) {
    var KeyEnter = 13;
    var keycode = (e.keyCode ? e.keyCode : e.which);
    if (keycode == KeyEnter) {
      $('#menu').dropdown('toggle');
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

<div class="dropdown" id="menu">
  <button class="w-75 text-left btn btn-light dropdown-menu-toggle dropdown-toggle" type="button" data-toggle="dropdown" data-default-label="localhost:8080" aria-expanded="true">
    <code class="dropdown-toggle-text is-default" id="server">localhost:8080</code>
  </button>
  <div class="dropdown-menu dropdown-select w-75">
    <div class="dropdown-input">
      <input type="search" id="edit" class="dropdown-input-field form-control">
    </div>
    <div class="dropdown-content" id="list">
      <div class="dropdown-divider"></div>
      <a class="dropdown-item" href="#"><code>localhost:8080</code></a>
      <a class="dropdown-item" href="#"><code>172.17.0.2:8080</code></a></div>
  </div>
</div>

The thing is, once the dropdown has been closed with .dropdown('toggle'), the user cannot use the text zone anymore: when clicking on it to give it focus, the dropdown closes.

How to fix that?


How to reproduce bug

  1. Click on the dropdown button labelled localhost:8080; the dropdown menu opens.
  2. Click the empty text zone; it gets focus.
  3. Press the Return key of your keyboard; the dropdown menu closes.
  4. Repeat #1. (Click on the dropdown button labelled localhost:8080; the dropdown menu opens.)
  5. Repeat #2. (Click the empty text zone; it gets focus.)

Observed behavior

The dropdown menu closes.

Expected behavior

The dropdown menu stays open, its state after #5 is the same as after #2.


Solution

  • The issue with your code is that the click event from the field is bubbling up to the parent. It's hitting the dropdown event and then acting as a click. The solution is to stop these clicks from propagating up the tree.

    $("#edit").click(function(e){
        e.stopPropagation();
    }).keypress(function(e) {
        // ... your code
    });
    

    Note that return false; in lieu of e.stopPropagation(); will also act as if e.preventDefault(); was called which might cause other issues in the future.