سؤال

We have a web app that allows users to scan a barcode or click a link that will hide the barcode input and show a JQuery Chosen select menu.

To save users having to manually swap between the product search select menu and the barcode input I'm checking for a spacebar press in the barcode input field and then switching the inputs and prefilling the chosen select menu with the users search terms. It works correctly but I'm finding that the barcode input is laggy as a result of checking for a spacebar press.

I'm new to Javascript and this is my first attempt. Would somebody be able to show me a faster or more efficient way to check for a spacebar press? This is an internal web app for our staff and is only required to work in Safari or Chrome running on MacOS. Any help would be much appreciated.

$("input#barcodeIn").keyup(function(e){
// CHECK FOR SPACEBAR PRESS IN THE BARCODE INPUT FIELD
if (e.keyCode == 32) {
    // SHOW CHOSEN MENU INSTEAD OF BARCODE INPUT BECAUSE WE'RE TYPING A PRODUCT NAME
    $("#inputSwitch").trigger("click");

    // AUTOMATICALLY OPEN THE CHOSEN MENU
    $("#cbProduct").trigger("chosen:open");

    // GRAB WHAT WAS ENTERED INTO THE BARCODE INPUT
    var input = $("#barcodeIn").val()+" ";

    // ENTER THE INPUT TEXT INTO THE CHOSEN SELECT MENU
    $(".chosen-search input").val(input);

    // CLEAR THE BARCODE INPUT BECAUSE WE"RE USING THE CHOSEN SELECT MENU INSTEAD
    $("#barcodeIn").val("");
    return false;
}});
هل كانت مفيدة؟

المحلول

There are a few potential causes to your unresponsive behaviour:

  1. You're waiting for the keyup event, so no matter how fast they push the spacebar, your code will only respond when they release it.
  2. Inside your event you are doing a few slow things which can also call a (tiny) delay
    1. finding elements by selector is slow, cache the results where possible
      • In my example I avoided caching $('.chosen-search input') as I wasn't sure whether that dynamically changes.
      • Either way, to speed it up you could still cache: var $chosenSearch = $('.chosen-search') and then later on select with: $('input', $chosenSearch)
    2. any code which executes in an event handler should return ASAP unless it intends on delaying the native behaviour (and other handlers)
      • It's complete overkill in this case, but I've shown how you can use setTimeout() to execute your code asynchronously so that the event handler returns, and then your code executes.
      • whilst it might not be obvious why you'd do this, imagine that your code took (say) 1.5 seconds to execute - in that case there would be a 1.5second delay before every key the user typed showed up in the input box
      • by sticking it in a setTimeout() you ensure that no matter how long your processing takes, the key will at least react first.

I hope that helps!


$(function() {

  // cache the selectors to avoid re-scanning inside the event handler
  var $inputSwitch = $('#inputSwitch');
  var $cbProduct = $('#cbProduct');
  var $barcodeIn = $('#barcodeIn');

  // Not strictly necessary, but saves the messiness of callback-in-callback
  function swapContext() {
      // SHOW CHOSEN MENU INSTEAD OF BARCODE INPUT BECAUSE WE'RE TYPING A PRODUCT NAME
      $inputSwitch.trigger("click");

      // AUTOMATICALLY OPEN THE CHOSEN MENU
      $cbProduct.trigger("chosen:open");

      // GRAB WHAT WAS ENTERED INTO THE BARCODE INPUT
      var input = $("#barcodeIn").val()+" ";

      // ENTER THE INPUT TEXT INTO THE CHOSEN SELECT MENU
      $(".chosen-search input").val(input);

      // CLEAR THE BARCODE INPUT BECAUSE WE"RE USING THE CHOSEN SELECT MENU INSTEAD
      $barcodeIn.val("");    
  }

  $("input#barcodeIn").on('keydown', function(e){
  // CHECK FOR SPACEBAR PRESS IN THE BARCODE INPUT FIELD

  if (e.keyCode == 32) {
      // Ensures we can return from the handler quickly
      setTimeout( swapContext, 0 );
      return false;
  }});  

});

Since you're also new to Javascript, note that the var statements below are local to the wrapper function, definitely avoid using globals in JS - better to learn the slightly odd ways of avoiding them (and in the process, learn many cool tricks with javascript!)

نصائح أخرى

Maybe try "bind" the keyup event to input#barcodeIn see: http://www.solicitingfame.com/2011/11/09/jquery-keyup-vs-bind/

In a nutshell the link does something like this:

// detect the change
$('input#barcodeIn').bind("change keyup input",function(e) {
    if (e.keyCode == 32) {
        //enter code here
    }
});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top