Bootstrap datepicker return focus after select

12,597

This is a little bit of a hack job, but you can conditionally hide and show the elements to avoid an infinite loop. On hide, check if this is the first time attempting to hide. If the input does not have focus (meaning they have used the dropdown and we've lost our tab order, then refocusing will cause the picker to show. We'll also catch this show and hide from there, entering back into our original code. We'll pass back and forth a property on the object so we can manage state.

That will look like this:

$(".datepicker").datepicker({
  autoclose: true
})
.on('hide', function () {
  if (!this.firstHide) {
    if (!$(this).is(":focus")) {
      this.firstHide = true;
      // this will inadvertently call show (we're trying to hide!)
      this.focus(); 
    }
  } else {
    this.firstHide = false;
  }
})
.on('show', function () {
  if (this.firstHide) {
    // careful, we have an infinite loop!
    $(this).datepicker('hide'); 
  }
})

Stack Snippet Demo:

$(".datepicker").datepicker({
  autoclose: true
})
.on('hide', function () {
  if (!this.firstHide) {
    if (!$(this).is(":focus")) {
      this.firstHide = true;
      // this will inadvertently call show (we're trying to hide!)
      this.focus(); 
    }
  } else {
    this.firstHide = false;
  }
})
.on('show', function () {
  if (this.firstHide) {
    // careful, we have an infinite loop!
    $(this).datepicker('hide'); 
  }
})
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/css/datepicker.css" rel="stylesheet"/>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/js/bootstrap-datepicker.js"></script>


<input type="text" class="datepicker" /><br/>
<input type="text" class="datepicker" /><br/>
<input type="text" class="datepicker" /><br/>
Share:
12,597
KyleMit
Author by

KyleMit

I've been writing software for the last decade or so at StackOverflow, DealerPolicy, the Vermont Department of Health, code camps, meetups, and online. I'm primarily focused on web dev, react, dotnet, and azure, but always in the mood to debug something new. Favorite SO Accomplishments: 67k+ rep given away via bounties - currently 1st of all time twitter-bootstrap - 3rd person to get the Gold Badge Socratic - Asked a well-received question on 100 separate days Sportsmanship - Up vote 100 answers on questions where an answer of yours has a positive score Refiner - Edit and answer 50 questions

Updated on June 27, 2022

Comments

  • KyleMit
    KyleMit almost 2 years

    If you initialize a bootstrap datepicker from eternicode with autoclose: true, two undesirable behaviors happen:

    1. After the picker closes, when you tab into the next field, you'll start at the beginning of the document again. This can be quite cumbersome on long forms.
    2. Because the picker changes the value programatically, any listeners that you have that care about the blur event on the input won't behave properly. The blur actually occurs when you select the picker value and the input's value hasn't changed. Then the bootstrap-datepicker programmatically updates the field so blur is never fired with the new value.

    Here's a demo in stack snippets:
    *select any field, select a value from the picker, and then hit Tab

    $(".datepicker").datepicker({
      autoclose: true
    });
    <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
    <link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/css/datepicker.css" rel="stylesheet"/>
    
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/js/bootstrap-datepicker.js"></script>
    
    
    <input type="text" class="datepicker" /><br/>
    <input type="text" class="datepicker" /><br/>
    <input type="text" class="datepicker" /><br/>

    According to the answer to Focus the field after selecting the jQuery UI datepicker, you can tap into the onClose or onSelect events, but the bootstrap picker doesn't offer those events.

    Simply replacing them with hide doesn't seem to work either, since the refocusing will create an endless loop that always keeps the picker open any time you try to close it.

    $(".datepicker").datepicker({
      autoclose: true
    })
    .on('hide', function () {
      $(this).focus();
    });
    

    Stack Snippet Demo:

    $(".datepicker").datepicker({
      autoclose: true
    })
    .on('hide', function () {
      $(this).focus();
    });
    <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
    <link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/css/datepicker.css" rel="stylesheet"/>
    
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.1/js/bootstrap-datepicker.js"></script>
    
    
    <input type="text" class="datepicker" /><br/>
    <input type="text" class="datepicker" /><br/>
    <input type="text" class="datepicker" /><br/>
  • jfbouz23
    jfbouz23 almost 9 years
    great fix! for those who need the datepicker class housed inside a div input group, and not the input itself, e.g. so as to display the glyphicon calendar, tweak the above .on('hide', function () var elem = $(this).find('input'); if (!this.firstHide) { if (!elem.is(":focus")) { this.firstHide = true; // this will inadvertently call show (we're trying to hide!)elem.focus();}