Javascript: Hidden Input Barcode Scanner - javascript

Here's my current setup:
I have a barcode scanner in keyboard mode. I am trying to scan to a hidden and out of focus input.
The barcode I am trying to read is as follows: asterisk [barcode-info] asterisk.
<form method="post">
<input type="hidden" name="action" value="barcode-scan"/>
<input type="hidden" name="barcode-input" value="" id="barcode-input" onchange="this.form.submit()" />
</form>
When a barcode input is made, Javascript should capture it and update the "barcode-input" hidden input, which will then submit itself to the server.
Someone recommended trying to use a paste event listener, but it simply didn't seem to capture the input at all.
Update: because of wonderful suggestions below, I've been able to get the input working! The form will test to see if two specific inputs follow each other, then it will execute the next function. Otherwise, it will erase any information contained in the log const. Ultimately, yes, I got this working correctly!
document.addEventListener('keyup', function(e){
const log = document.getElementById('barcode-input');
log.textContent += ' ' + e.code;
document.getElementById('barcode-input').value = log.textContent;
if (log.textContent.startsWith(' ShiftLeft')) {
if (log.textContent.startsWith(' ShiftLeft Backslash')) {
document.getElementById('barcode-input').form.submit();
console.log('e.code, submit barcode info');
}
}
else {
log.textContent = '';
document.getElementById('barcode-input').value = '';
}
});

Without an input[type="text"] element on the screen, you will need to capture the keyboard input manually. Something along the lines of:
document.addEventListener('keydown', (ev) => {
if (ev.ctrlKey || ev.altKey) return; // Ignore command-like keys
if (ev.key == 'Enter') {
// ...submit the content here...
} else if (ev.key == 'Space') { // I think IE needs this
document.getElementById('barcode-input').value += ' ';
} else if (ev.key.length == 1) { // A character not a key like F12 or Backspace
document.getElementById('barcode-input').value += ev.key;
}
});
That should get you most of the way...

Alternatively, rather than looking for events on the input or values of the input (*'s), define an event on the value and use the input event to simply set the value.
Once input has stopped, be it 1 second (or most likely much less) then fire off the form.
If you have to place the cursor into input, then scan. your prob only option is to use autofocus attribute and hide the input as you cant focus a hidden element, though you also cant focus multiple so keep that in mind if you're looking to scan into multiple inputs, then you will have to show the inputs, no way around it.
For example
let elm = document.querySelector('input[name="barcode-input"]')
// watcher on the value, after 1 second, it invokes an event, i.e post form
let timer = 0
Object.defineProperty(window, 'barcode', {
get: function () { return this.value },
set: function (value) {
clearTimeout(timer)
this.value = value
timer = setTimeout(() => {
console.log('Post form')
}, 1000) // do some tests, tweak if much less then 1 second to input the value
}
})
// it should trigger input even if its a keyboard
elm.addEventListener("input", e => barcode = e.target.value)
// ignore, below this line..
// set a value of barcode at intervals, only when its stopped entering (>1 second), then will it fire the callback
let i = 0
let t = setInterval(() => {
barcode = (barcode || '')+"X"
if (i >= 40) clearInterval(t)
i++
}, 100)
// ignore... grab value from hidden input, put in #current
setInterval(() => document.querySelector('#current').innerHTML = barcode, 1000)
<input type="text" name="barcode-input" autofocus style="display:none" />
<div id="current"></div>

Here's demonstrator using keypress that scans the incoming key stream for *[ and captures the barcode until it sees ]*. Then it sends the code to the server. Although I've reproduced the form in your HTML, the code here doesn't use it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Working...
<form method="post">
<input type="hidden" name="action" value="barcode-scan"/>
<input type="hidden" name="barcode-input" value="" id="barcode-input" onchange="this.form.submit()" />
</form>
<p id="response"></p>
<script>
(function(){
"use strict";
const bcAst = '*';
const bcLeft = '[' ;
const bcRight = ']';
let barcodeIncoming = false;
let lastChar = 0;
let barcode = '';
document.addEventListener('keypress', function(e){
function sendCode(barcode) {
console.log(barcode);
let fd = new FormData();
fd.append('barcode', barcode);
fetch('myFile.php', {
method: 'POST',
body: fd
})
.then(resp=>{
resp.text().then(txt=>{document.getElementById('response').innerText = txt;})
});
}
console.log(e.key);
switch (e.key) {
case bcAst:
if (barcodeIncoming && (lastChar === bcRight)) {
barcodeIncoming = false;
sendCode(barcode);
}
break;
case (bcLeft):
if (lastChar === bcAst) {
barcodeIncoming = true;
barcode = '';
}
break;
case (bcRight):
break;
default:
barcode += (barcodeIncoming)?e.key:'';
break;
}
lastChar = e.key;
});
})();
</script>
</body>
</html>
The current server file is very rudimetary, but serves the purpose here:
<?php
if (isset($_POST['barcode'])) {
echo "Your barcode is {$_POST['barcode']}";
} else {
echo "No barcode found";
}
Note - this has had only basic testing. You'll want to improve its resilience against possible collisions with similar data in the key stream.

transfrom
<input type="hidden" name="barcode-input" value="" id="barcode-input" onchange="this.form.submit()" />
in
<input type="test" name="barcode-input" value="" id="barcode-input" onchange="this.form.submit()" style="display:none;" />

Related

how to read multiple value length in javascript?

I am working on a barcode scanner and currently have a problem where I need the barcode to read 2 different value lengths, currently I have it set to submit the value at 9 length.
<span>
<input type="text" id="IC-input" name="IC" onkeyup="autofill(this.value)" placeholder="Enter your IC Number" required maxlength="12">
<label><button type="button" id="theButton" onclick="theButtonIsPressed()">Submit</button></label>
</span>
function autofill(value){
console.log("Autofill:"+value)
//console.log(9 digits);
button = document.getElementById("theButton");
if(value.length == 9){
console.log('form is ready to submit');
theButtonIsPressed(value);
}
}
now i need it to read from 12 value as well but it auto submits when the value hits 9 digits. I have tried OR function .
function autofill(value){
console.log("Autofill:"+value)
//console.log(9 digits);
button = document.getElementById("theButton");
if(value.length == 12 || value.length == 9){
console.log('form is ready to submit');
theButtonIsPressed(value);
}
}
i also tried the Else function
function autofill(value){
console.log("Autofill:"+value)
//console.log(9 digits);
button = document.getElementById("theButton");
if(value.length == 12){
console.log('form is ready to submit');
theButtonIsPressed(value);
}
else if(value.length == 9){
theButtonIsPressed(value);
}
}
But it would always read the first 9 value and leave the 3 other value unread. Does anyone have a solution for this? Thank you in advance.
Seems like you are listening to the keypress. Use a timer to cancel it. Basic idea of a debounce method.
var timer;
function autofill(value){
if (timer) window.clearTimeout(timer);
if(value.length === 9){
timer = window.setTimeout( function () {
processIt(value);
}, 50);
} else if(value.length === 12){
processIt(value);
}
}
function processIt(value){
console.log('here', value);
}
BUT That is a bad solution. Typically you set up the scanner to fire a tab or enter press so you know it is done. I would check to see if that is happening and listen for that instead. You can then just listen for that and you know the scanner is done.
var inp = document.getElementById("barcode");
inp.addEventListener("keydown", function (evt) {
if (["Tab", "Enter"].includes(evt.key)) {
evt.preventDefault();
console.log('scanner is done', evt.target.value);
}
});
<input type="text" id="barcode" />
The problem is that the autofill function runs to press the button as soon as the input box has 9 characters. It is because you are running the autofill function by the 'onkeyup' event listener attached to the input tag.
The solution is to run the autofill function after making sure there is a full length value intended. Good luck.
For a most common scene, the scanner will trigger such event one by one: focus, input character....input final 'Enter' character, so you have to take attention to the last event.
<script type="text/javascript">
window.addEventListener("load", function () {
var ic = document.getElementById("IC-input");
ic.addEventListener("focus", function (args) {
ic.value = "";
});
ic.addEventListener("keyup", function (args) {
if (args.key == "Enter") {
autofill(ic.value);
}
});
});
function autofill(value) {
console.log("Autofill:" + value)
//console.log(9 digits);
button = document.getElementById("theButton");
if (value.length == 9) {
console.log('form is ready to submit');
theButtonIsPressed(value);
}
}
</script>
<span>
<input type="text" id="IC-input" name="IC" onkeyup="input_keyup" placeholder="Enter your IC Number" required maxlength="12">
<label><button type="button" id="theButton" onclick="theButtonIsPressed()">Submit</button></label>
</span>

keypress event - handle multiple scanners concurrently

I have a requirement to handle the input of up-to four scanners. These scanners can read bar-codes concurrently. Depending on their configured prefix, I need to load the bar-code in the correct text-box on my web page.
Assuming the scanners will be prefixed with 1, 2, 3, 4. Here is my code -
<input type="text" id="barcode1" />
<input type="text" id="barcode2" />
<input type="text" id="barcode3" />
<input type="text" id="barcode4" />
Above text boxes may/may not have the focus, hence using addEventListener for keypress below
<script>
var barcodewithPrefix = "";
document.addEventListener("keypress", function(e) {
if (e.keyCode != 13) {
barcodewithPrefix += e.key;
}
else {
var prefix = barcodewithPrefix.substring(0, 1);
var barcode = barcodewithPrefix.substring(1, barcodewithPrefix.length); //remove the prefix and get the actual barcode
//display in correct text box
if (prefix == "1") {
document.querySelector("#barcode1").value = barcode;
}
else if (prefix == "2") {
document.querySelector("#barcode2").value = barcode;
}
else if (prefix == "3") {
document.querySelector("#barcode3").value = barcode;
}
else{
document.querySelector("#barcode4").value = barcode;
}
barcodewithPrefix = ""; //clear for next input
}
e.preventDefault();
});
</script>
This code is working fine for one scanner as well as for keyboard input.
However, it does not run correctly if there is more than one scanner and are used concurrently. The bar-codes digits get all jumbled up and doesn't appear correctly in their respective text-box.
I understand this is expected - looking at the code where each input char is interpreted with a keypress event.
Can anyone please guide how can I make it work. Are there any workarounds to tackle it?
Thank you!

Having trouble displaying an array value within console.log event using .push function in Jquery

The issue here is that I have designed a basic website which takes in a users input on a form, what I then intend to do is print that value out to the console.log. however, when I check the console under developer tools in Google Chrome, all I get printed out is []length: 0__proto__: Array(0)
and not the value the user has inputted.
<input type="text" name="username" value="testuser">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function error() {
var error1 = [];
var list_of_values = [];
username_error = $('input[name="username"]').val();
if (!username_error){
error1.push('Fill in the username field.');
}
console.log(error1);
if (error1.length > 0){
for(let username_error of error1){
alert(username_error);
return false;
}
}
string = $('input[name="username"]').val('');
if(string.length <= 1){
for (let list_of_values of string){
string.push();
}
console.log(string);
return true;
}
}
error();
</script>
Suggestion, you can make it actually things easier with the following code.
the function below scans all input fields under fieldset element
$("fieldset *[name]").each....
the issue above is multiple alert, what if you have a lot of inputs, it would alert in every input, which wont be nice for the users :) instead you can do this
alert(error1.toString().replace(/,/g, "\n"));
to alert the lists of errors at once.
string = $('input[name="username"]').val('');
that is actually clearing your value.. so it wont give you anything in console.log().
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<fieldset>
<input type="text" name="name" value="" placeholder="name"/><br/><br/>
<input type="text" name="username" value="" placeholder="username"/><br/><br/>
<button onclick="error()">check</button>
</fieldset>
<script>
function error() {
var error1 = [];
var list_of_values = [];
$("fieldset *[name]").each(function(){
var inputItem = $(this);
if(inputItem.val()) {
return list_of_values.push(inputItem.val());
}
error1.push('Fill in the '+inputItem.attr('name')+' field!')
});
if(error1.length > 0) {
console.log(error1);
alert(error1.toString().replace(/,/g, "\n"));
}
if(list_of_values.length > 0) {
console.log(list_of_values);
}
}
</script>
Register the <input> to the input event. When the user types anything into the <input> the input event can trigger an event handler (a function, in the demo it's log()).
Demo
Details commented in demo
// Reference the input
var text = document.querySelector('[name=username]');
// Register the input to the input event
text.oninput = log;
/*
Whenever a user types into the input...
Reference the input as the element being typed into
if the typed element is an input...
log its value in the console.
*/
function log(event) {
var typed = event.target;
if (typed.tagName === 'INPUT') {
console.log(typed.value);
}
}
<input type="text" name="username" value="testuser">

Filtering value in textarea in 'input' event

What I want is filtering user's input. Remove newline and limit its length.
I tried two methods.
https://jsfiddle.net/mj111/356yx1df/3/
html
<div>
<textarea id="text1" placeholder="write down"></textarea>
</div>
<div>
<textarea id="text2" placeholder="write down"></textarea>
</div>
script
document.getElementById('text1')
.addEventListener('input', function (evt) {
evt.preventDefault(); // prevent value change
const msg = evt.target.value.replace(/\n/g, '')
if (msg.length <= 10) {
document.getElementById('text1').value = msg
}
})
document.getElementById('text2')
.addEventListener('input', function (evt) {
const msg = evt.target.value.replace(/\n/g, '').slice(0, 10)
document.getElementById('text2').value = msg
})
First one is not working, because preventDefault is not working. As MDN doc says. 'input' event is not cancelable.
So, I tried second method; just overwrite textarea value.
I think there's a better way to do this. If anyone has a good idea, please answer.
use keyup event to limit length or you can just add maxlength manually to the HTML as an attribute. If you want to set it dynamically you can use Element.setAttribute. For preventing new lines you can prevent the return key, as long as it is not shift. You can still use replace to replace things you feel need replacing, a regular expression will most effectively get the job done.
var text = document.getElementsByTagName('textarea');
var text1 = text[0];
var text2 = text[1];
text1.addEventListener('keydown', function(event) {
let val = event.target.value;
let limit = 25;
// limit the value once you reach a particular length
if (val.length > 3) {
event.target.value = val.substr(0, limit)
};
// prevent new line by preventing enter key press
if (event.keyCode === 13 && !event.shiftKey) {
event.preventDefault();
alert('no new lines please');
return false;
}
// and you can filter with replace
})
<div>
<textarea id="text1" placeholder="write down"></textarea>
</div>
<div>
<textarea id="text2" placeholder="write down"></textarea>
</div>

Javascript push input into Array causes several arrays not one

This is a follow up to my question, seen here
I am trying to write that when a user enters in their name (string) into the field and hits enter, it pushes it into an array. It works, kinda. But I get an error when I try it one and then it produces multiple arrays when I try it another. I don't want to use jQuery.
Here is the HTML
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
Here is my js that works but it creates multiple arrays instead of pushing everything into one array (because the nextElementSibling is not called, I know this, see next block
let namesOfPlayers = [];
let currentValue = document.getElementById("bind").value;
let button = currentValue.nextElementSibling;
document.addEventListener('keypress', function (e) {
const key = e.which || e.keyCode;
if (key === 13) {
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
}
});
Here is my js that throws an error (I don't want to use jQuery)
I want that when a user hits enter or clicks the button that the string is submitted and added into the empty array. I can't for the life of me figure out how to make that work.
Thanks for your help!
You fetch the value of the input too soon. You should fetch it only when the button is clicked, not before.
Secondly, the button does not have a keypress event, nor a keyCode associated with it. You need to listen to the click event.
So do this:
let namesOfPlayers = [];
let input = document.getElementById("bind");
let button = input.nextElementSibling;
button.addEventListener('click', function (e) {
namesOfPlayers.push(input.value);
console.log('namesOfPlayers', namesOfPlayers);
});
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names" />
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
Try this code, i added a click (for the button) and keypress (for the text input) events
so if you click enter when you focus on the text input the text in the input will be in the array.
and the same will happen if you click "Go" button
let namesOfPlayers = [];
let currentElement = document.getElementById("bind");
let button = currentElement.nextElementSibling;
let addPlayer = () => {
namesOfPlayers.push(currentElement.value);
console.log(namesOfPlayers); // Just for testing
}
currentElement.addEventListener('keypress', function (e) {
if (e.which === 13 || e.keyCode === 13) {
addPlayer();
}
});
button.addEventListener('click', addPlayer);
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
CurrentValue is defined outside of the event listener, so it only gets called once, on initialisation. That's why the push call only injects empty strings. Also, the button doesn't do anything because it doesn't have a listener.
Here's the updated code:
let namesOfPlayers = [];
// It's better to get the button by id instead of getting it by a previous child.
// This is because it might cause some unexpected behaviour if someone changed the HTML.
const button = document.getElementById("thego");
button.addEventListener('click', function (e) {
addItemToArray(namesOfPlayers);
});
document.addEventListener('keypress', function (e) {
const key = e.which || e.keyCode;
if (key === 13) {
addItemToArray(namesOfPlayers);
}
});
function addItemToArray(namesOfPlayers) {
const currentValue = document.getElementById("bind").value;
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
}
https://fiddle.jshell.net/4k4a9m6y/
But, you're better off with a form to improve performance.
let namesOfPlayers = [];
const form = document.getElementById("form");
form.addEventListener('submit', function (e) {
const currentValue = document.getElementById("bind").value;
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
});
<form id="form"
action="javascript:void(0);">
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="submit" id="thego" class="pre enterteam" value="click">Go</button>
</form>
https://fiddle.jshell.net/4k4a9m6y/2/

Categories