문제

I'm using this great piece of javascript (http://www.deadosaurus.com/detect-a-usb-barcode-scanner-with-javascript/) to recognize USB barcode scanners input (just really fast typed keyboard strokes) without having the focus on any input field in a website. The thing works great as it is, but what I need to do is to figure out if the scanned item is of type A or type B before I can do anything with the scan result, and that is where the Ajax-call comes into play like this:

$(document).ready(function() {
var pressed = false; 
var chars = []; 
$(window).keypress(function(e) {
    if (e.which >= 48 && e.which <= 57) {
        chars.push(String.fromCharCode(e.which));
    }
    console.log(e.which + ":" + chars.join("|"));
    if (pressed == false) {
        setTimeout(function(){
            if (chars.length >= 10) {
                var barcode = chars.join("");
                console.log("Barcode Scanned: " + barcode);
                // Here is the ajax-call.
                checkItemType(barCode).success(function(response) {
                // Do stuff with the response.
                });
            }
            chars = [];
            pressed = false;
        },500);
    }
    pressed = true;
});
});

And the function:

function checkItemType(barCode) {
    // Example parsing for the id I want to do work with.
    var itemId = parseInt(barCode.substr(9, 6).replace(/^[ 0]/g, ''));
    var data =  { itemId: itemId };
    return $.ajax({
        type: 'POST',
        url: 'Controller/CheckItemType',
        traditional: true,
        dataType: 'json',
        data: data
    });
}

For the first time when I scan the item, all things work fine. The second time I do a scan, the checkItemType-function gets called 2x and the third time it gets called 4x, usually capping at 8x.

I just cant get my head around this.. there is a if-clause for chars.length >= 10 and the chars list should clear out after the barcode scanners input stops. Removing the ajax-call fixes the issue as I said before, but I am unable to really figure out a way to make the call outside of the timeout function. Guess I should add that I'm still learning javascript and I'm really out of ideas for this one. Thanks in advance.

EDIT: Success code didn't really matter so removed it as suggested.

도움이 되었습니까?

해결책

The bug you describe sounds like some other place in your code binds the handler again.

Do you somehow reload some portion of your page (maybe through ajax), which could trigger the $(window).keypress( ... ) binding a second time ?

다른 팁

I've had a look at the code and think I've got it fixed. I've simply added chars = []; pressed = false; after you have created the barcode and it then resets after a barcode is scanned. Have a look below:

JSFiddle

    if (pressed === false) {
        setTimeout(function () {
            console.log("Timeout");
            if (chars.length >= 10) {
                var barcode = chars.join("");
                chars = [];
                pressed = false;
                console.log("Barcode Scanned: " + barcode);
                // Here is the ajax-call.
                checkItemType(barCode).success(function (response) {
                    // Do stuff with the response.
                });
            }
            chars = [];
            pressed = false;
        }, 500);
    }
    pressed = true;

I would say it is a timing/synchronization issue. You setup for each event/keystroke a timeout in 500 ms: that means that after 500 ms from the first keystroke you start to run your (first) function: chars.length > 10 and then while you do the Ajax call (because it is slow) the second timeout fires: chars.length is still > 10 so you go and run again checkItemType... and so on until the first call will set the chars = [].

The number of times checkItemType si executed is related to the delay between the keystrokes and the time to run checkItemType. If you only reset chars = [] after you check it for >= 10 you still can't be sure then the second timeout didn't already passed that condition.

One way to be sure that you run checkItemType only once would be to have only one timeout set on the first keystroke and then if chars.lenngth < 10 when it fires set it up again to run in another x ms...etc.

if (pressed == false) -> if(!pressed) or if(pressed === false)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top