Patrick Sasquatch
Patrick Sasquatch

Reputation: 33

Keeping focus on a textbox except when in certain other elements

I'm attempting to keep focus on a textbox for a touch screen kiosk in the event someone clicks out of it. However, I'd like to give them the option to move the cursor to a drop down box too. With the code below, it's still jumping back to the textbox even when in my designated class.

Am I using activeElement properly in my if statement?

this.textbox = $('<input class="full-width" type="text" tabindex=1/>'); //Change the tab index number to the position you need it to be
this.host.append(this.textbox);
var _this = this;
this.textbox.blur(async function() {
  if (!document.activeElement.className.match("dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes")) {
    function sleep(duration) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve()
        }, duration * 250)
      })
    };
    await sleep(1);
    _this.textbox.focus();
    _this.textbox.select();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes" style="font-family:Roboto;font-size:25px;color:Black;;font-style:normal;font-weight:normal;text-decoration:none;;height:100%" tabindex="-1">

Upvotes: 0

Views: 95

Answers (1)

Andrew L
Andrew L

Reputation: 5486

The problem you are having is checking the active element right after the text box loses focus. There is a instant where the active element is actually the body of the document before the dropdown becomes the active element.

You can fix this by simply moving your sleep above your check for active element. I have another solution in the second snippet you can take a look at as well.

this.textbox = $('<input class="full-width" type="text" tabindex=1/>'); //Change the tab index number to the position you need it to be

//this.host.append(this.textbox);

$("body").append(this.textbox); //only for this example since idk what this.host is

var _this = this;

this.textbox.blur(async function() {
  await sleep(1);
  if (!document.activeElement.className.match("dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes")) {
    _this.textbox.focus();
    _this.textbox.select();
  }
});

function sleep(duration) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve()
    }, duration * 250)
  })
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes" style="font-family:Roboto;font-size:25px;color:Black;;font-style:normal;font-weight:normal;text-decoration:none;;height:100%" tabindex="-1">

You can also look at focusout's relatedTarget property. It will tell you the next element that was clicked when a certain element loses focus.

this.textbox = $('<input class="full-width" type="text" tabindex=1/>'); //Change the tab index number to the position you need it to be

//this.host.append(this.textbox);

$("body").append(this.textbox); //only for this example since idk what this.host is

var _this = this;

this.textbox.on("focusout", event => {
  let nextElement = event.relatedTarget;
  if (!nextElement || !event.relatedTarget.className.match("dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes")) {
    _this.textbox.focus();
    _this.textbox.select();
  }

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes" style="font-family:Roboto;font-size:25px;color:Black;;font-style:normal;font-weight:normal;text-decoration:none;;height:100%" tabindex="-1">

Another "catch-all" solution could be to just set an interval for every second and do your check. This way you don't have to keep track of losing focus (blur) for the text box and having to sleep.

This case also handles the initial case where the input box isn't focused/active to begin with. This will focus on the text box on load too.

this.textbox = $('<input class="full-width" type="text" tabindex=1/>'); //Change the tab index number to the position you need it to be

//this.host.append(this.textbox);

$("body").append(this.textbox); //only for this example since idk what this.host is

var _this = this;

setInterval(() => {
  if (!document.activeElement.className.match("dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes")) {
    _this.textbox.focus();
    _this.textbox.select();
  }
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="dp-combobox__input dp-combobox__input--has-clear dp-combobox__input--has-arrow DropDownBoxes" style="font-family:Roboto;font-size:25px;color:Black;;font-style:normal;font-weight:normal;text-decoration:none;;height:100%" tabindex="-1">

Upvotes: 1

Related Questions