How to preview the result of a beforeinput event? - javascript

Does the beforeinput event provide a convenient way to preview the result of a proposed modification so that it can be blocked if necessary for validation purposes?
I'm not looking for alternative ways to do input validation; I'm already well-aware of methods involving the keypress and input events, as well as HTML5 validation, etc.. Right now, I'm specifically looking into the beforeinput event to see what it offers.
So far, this is the best I've come up with:
document.getElementById("phone").addEventListener("beforeinput", function(e) {
if(!/^(\d{0,7}|\d{3}-\d{0,4}|)$/.test(e.target.value + (e.data ?? ""))) {
e.preventDefault();
}
return;
});
<input id="phone">
The text field in the above snippet should accept a simple 7-digit phone number with optional dash after the 3rd digit.
Notice that I'm appending the event's data property to the input's current value to create a preview of the modified value. This works fine if you only enter input sequentially. But if, for example, you type in all 7 digits and then arrow back to just after the 3rd and try to insert the dash, you can't do it, because the validation assumes you're at the end where a dash would be invalid. Other problems arise if you try to replace or delete a selection.
An accurate preview will be required to solve these problems. Is there a simple way to get one from the beforeinput event?

You'd have to get the selectionStart and selectionEnd to figure out how many characters were removed / replaced / etc, but yeah, pretty simple:
document.getElementById("phone").addEventListener("beforeinput", function(e) {
const nextVal =
e.target.value.substring(0, e.target.selectionStart) +
(e.data ?? '') +
e.target.value.substring(e.target.selectionEnd)
;
console.log(nextVal)
if(!/^(\d{0,7}|\d{3}-?\d{0,4}|)$/.test(nextVal)) {
e.preventDefault();
}
return;
});
<input id="phone">

Related

How do I send Chars to a text Input using Javascript

In my project: CSSHTML Keyboard I have setup a keyboard based off my old laptop keyboard, it was a small project I made as a homework piece for school. The issue is, Im not sure how to add the Specific Chars to the keyboard, like, for example: Say I click Shift and then A/a, I want it to place "A" in the input. If someone could bring me a little information for this, I would appreciate it. Also for the later notice, Im not trying to make Every key work like it should, only base keys (Letters, Numbers, Capitalization, Set Symbols, Caps Lock, Shift, Space, and Backspace)
I made a Calculator: Simple Calculator
and I tried using a similar method of sending a symbol/character to the Input, but it didn't seem to work well.
the method I tried was by using an input:
<input id="butn" class="output" type="textfield" name="ans" value="!The
Text input is Currently Not Available!"></input>
and then using a small bit of Javascript to send math equations from buttons to the form and then to the input, then solving them with an evaluation Javascript snippet
Here is the link to the current code: CSSHTML Keyboard Finished
By the way, apologies if the keyboard is put together "duck tape and glue" style, I'm still decently new to perfecting CSS Sizing and aligning, so for now I write everything manually with margins and sizing.
After a while of testing the calculator method above that I used, I had managed to sorta get it to work at one point, but it placed undefined, so in a way I kind of gave up on the project temporarily, Either way, I'm happy with my finished Product, even if I cant use it to type out the characters.
You can add this simple JS to get the keydown event, get the value of the pressed key and print it in the input.
Then you should configure keys that you don't want to be written when you type them ( especial actions for example)
I've put the backspace and some example keys for you.
var output = document.querySelector('.output');
addEventListener('keydown', function(e) {
e.preventDefault();
// Backspace
if ( e.key === 'Backspace' ){
output.value = output.value.substr( 0, ( output.value.length -1 ) );
// The values you dont want to write literally
} else if( e.key === 'Shift' ||
e.key === 'Control' ||
e.key === 'Alt' ||
e.key === 'AltGraph' ) {
output.value += '';
} else {
// The keydown values
output.value += e.key;
}
});
additions
For the question about how to send value with a button:
First you must set "something" for select them with js (for example a class),
and you should set a value attribute tu get it later.
<button type="button" class="letter keys" value="1" >!<br>1</button>
Then select all buttons with a loop and add an event when click them.
At last just take the attributes.value of the element and do what you want with it.
here is an example:
var buttons = document.querySelectorAll('.letter');
for( let button of buttons ){
button.addEventListener('click',function(e){
console.log(button.attributes.value);
})
}
That will work for you but i recomend you to read something more about basics of JS to manage all you want to do before this, because this is only the beginning.
Hope it helps you.

How to make a field only editable by scanning in a bar code as values?

I was wondering if someone can point me into the right direction. I have a text input field, that I now need to update so a user can only "edit" through a scan gun to capture a bar code. My code so far was updated to prevent the user from adding data via keyboard but I am unsure how I can make it "editable" again via scan. During testing scanning was treated similar to key presses:
$('#barCodeNum').keydown(function(){
$('#barCodeNum').attr('readonly', true);
});
$('#barCodeNum').keyup(function(){
$('#barCodeNum').attr('readonly', true);
alert("You cannot manually edit this field. Please Scan the item.");
});
What event should I be using, if there is any form of an event to capture the "action" of scanning? Or has anyone found another solution to handle this kind of scenario?
EDIT
Another idea... From Anthony's comment about an hidden field...
But! An hidden field just can't be focussed... And you need it to use the codebar reader.
So what about to place that "other" input outside the viewport (using CSS) instead of hiding it... Doing this, no one can focus it and just type in.
So in order to focus it, you will also need an "enable scan" button. The button will also start an interval to check for a value inputed fast! say... within 100ms... Then blur the field.
Here, there's only one delay to handle: The full scan minimum time. So that is easier...
No human can enter a complete code so fast.
Then you just need to validate that the code length is correct, based on your typical codes. If just one or two character are in... It's sure invalid.
You'll have to adjust the "maxScanDelay" by testing your scanner... 100ms may be too short. But make it as short as possible. ;)
Look below:
var ScanCheck;
var maxScanDelay = 100;
$('#barCodeNum').on("keydown",function(e){
e.preventDefault();
}); // End keydown on the visible
$('#barCodeNumHidden').on("input",function(e){
$('#barCodeNum').val($(this).val());
}); // End keydown on the hidden
$("#scanEnable").on("click",function(){
// Clear the fields
$('#barCodeNum,#barCodeNumHidden').val("");
$("#barCodeNumHidden").focus();
$(this).text("Waiting for the code.");
ScanCheck = setInterval(function(){
console.log("interval");
if($('#barCodeNumHidden').val()!=""){
$("#barCodeNumHidden").blur();
$("#scanEnable").text("Enable scan.");
clearInterval(ScanCheck);
console.log("interval stopped");
}
},maxScanDelay);
});
#barCodeNumHidden{
position:fixed;
top:-100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="barCodeNum" readonly>
<input type="text" id="barCodeNumHidden">
<br>
<br>
<button id="scanEnable">Enable scan.</button>
Typing speed solution
If you make it readonly... The codebar reader won't be able to fill the input.
Since just return false; does not work...
I think I found a way to grab the characters typed FAST, like no human can, and get rid of the character typed more slowly.
I have no codebar reader to test that...
You will have two delays to adjust :
A threshold (key must be typed faster than this delay)
An "output" delay (to allow all characters to be collected before an output)
Here the code to try:
var string = "";
var timeout;
var lastEventTime = 0;
// ADJUST THOSE TWO!
var threshold = 35;
var outputDelay = 100;
$('#barCodeNum').on("keydown",function(e){
e.preventDefault();
var codebarInput = $(this);
// Get current time.
var thisEventTime = Date.now();
console.log(lastEventTime);
console.log(thisEventTime);
// Grab the character.
string += String.fromCharCode(e.keyCode)
console.log(string);
// If this event occurs sooner than the threshold delay, use the timeout to output the value when all characters are in string.
if(lastEventTime+threshold > thisEventTime){
console.log("OK");
// Output the string after a delay.
clearTimeout(timeout);
timeout = setTimeout(function(){
codebarInput.val(string);
},outputDelay);
// If this event occurs after the threshold delay, clear string and input value.
}else{
console.log("NOT OK");
codebarInput.val("");
string = "";
console.log("Key prevented.");
}
// Keep this event time.
lastEventTime = thisEventTime;
}); // End keydown
From my tests on CodePen, a HOLDED down key works with a 35ms threshold... That seems to be the lowest, since 30ms block everything. With this threshold, even if I type as fast as I can, no single keys are passing. ;)
Usually barcode scanners act as a keyboard input, which would prevent you from knowing whether its a keyboard or a scanner.
One way to get around this is to check the timing between keypresses. The barcode scanner inputs much faster than a human, and I believe you can modify this speed.
If the typing is slow enough you'll know its a keyboard. If the typing is within some threshold you will know its the scanner.

Input value sometimes doesn't apply

To be straightforward, on a page, there is a search input.
var input = document.getElementById('search-input');
function handle(e) {
if (e.keyCode === 13) {
window.location = '../?s=' + input.value;
}
}
<div class="search-form-mobile">
<input type="text" id="search-input" onkeypress="handle(event)" class="form-control" placeholder="Search">
</div>
I know that this is a correct JavaScript code, but my question is, why does it sometimes accepts the input value and sometimes it doesn't? I've been scratching my head for a while and can't figure out what's wrong.
Should I wrap it up in a <form> or can i leave it like that?
The <script> is at the very bottom in footer.php.
It's a WordPress site.
Use onkeydown (or onkeyup, if you want the event to fire when the key is released, not when pressed) instead of onkeypress.
You can find a full list of keys that fire onkeypress event here.
Following the comments, it looks like this is not a JavaScript issue at all, but has to do with escaping the query string, specifically about what characters you can and cannot use without escaping in a $_GET parameter.
This has been asked and answered before.

How to get the final pasted text in jquery?

I want to trim a text in a field when the user is writing or paste text on it, the following code works great but has only one problem, when the user selects all the text to replace it with the pasted text or put the cursor to insert the pasted text inside, the code repeats the present value + the new value at the end, How can I fix it?
$(document).on('paste', "input[type='text'], textarea", function(e) {
let val = $(this).val();
val = val.trim();
val = val.replace(/(?:^\s+|\s+?(\s))(\S+)/g, "$1$2");
val = val.replace(/\s+(\s)$/, "$1");
$(this).val( val );
} );
I believe what I need to do is to paste normally, get the final pasted text and trim it, but that is the question How to get the final pasted text? Can you help?
In short, the paste event isn't a pipeline that allows you to change the pasting text on the fly. You can access the clipboard, but getting the data from it is a bit challenging as there is questionable browser support not only for the paste event, but for the clipboardData within said event.
onChange or onBlur are your best bets, as this is a great time to update your values even after a user pastes their value:
$("input[type='text'], textarea").bind('blur', function(e) {
$(this).val($.trim($(this).val()));
} );
This will work, whether they type in the whitespaces, or paste them in. If it has to be pasted, then you may want to instead have the above, and a paste event, but the paste event merely sets a shared boolean like "valueIsPasted" to be true, and then you can do the above only when that value is true. I don't love that solution, but unfortunately, the paste support isn't great. On top of that, that still will not work in IE, which doesn't support the paste event.
Update:
Looks like W3Schools begs to differ on browser support; however, I still feel that onChange or onBlur are your best bets as it will allow you to change the value once the user is done editing the value or done with the control, and definitely work. Check out my codepen.
The issue is that your trim code is running first (causing one copy of the data to be placed in the element) and the paste is happening second (causing a second copy of the data at the end).
If we delay the trim code, the issue is resolved very simply:
$("#txtInput, textarea").on('paste', function(e) {
// Store the invocation context (the input element)
// because it will change in the setTimeout
var ctx = this;
// Wait 1/10th of a second before trimming the data
// This will allow the paste to complete normally.
setTimeout(function(){
$(ctx).val($(ctx).val().trim());
}, 100);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="txtInput" size="40" value=" there are leading and trailing spaces here ">
<textarea></textarea>

Putting text in a number input doesn't trigger change event?

example
It appears that entering text into <input type="number"/> does not trigger a change event. I would like a change event so that I can warn the user to fix their input. How can I get a change event for this, and get the current value so that I can verify the bad input?
I've been testing in Chrome.
$('input').on('change', function() {
alert('change');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
put letters in me and press tab: <input type="number"/>
Try using the other keyboard events then. For example, I just added
$("input").on('keyup', function() {
alert('keyup' + $(this).val());
})
To your JSFiddle example, and the alert appears after pressing a within the number textbox.
Note: Checking $(this).val() will not return you invalid characters (at least in Chrome). It strips invalid values before returning the result (e.g., 1a becomes blank). This is also why the change event appears to not be fired when its value hasn't actually changed because the input is all invalid. To catch invalid characters, you must instead check the event's keyCode:
$("input").on('keyup', function(e) {
if (e.keyCode < 48 || e.keyCode > 57) {
// not 0-9 (note: ignores -)
alert('error!');
}
});
After messing around a bit more, I noticed that Chrome and IE10 behave similarly, but IE10 seems to have a bug in its stripping:
If you start the number input with a non-number, then IE10 (possibly 9 as well) will consider the rest of the input to be a valid number regardless of what characters follow (e.g., 1a2 is just as valid as 12 in the eyes of IE). However, in Chrome, if you enter a non-number, then it will immediately ignore the input and declare it to be invalid; in IE10, if you start with a non-number, then the behavior is the same.
One big difference in behavior is that IE10 will clear an invalid number field after blur, but, again, they only consider it invalid if the field starts with a non-number (e.g., a1). - can precede numbers, but not more than one of them.
In both browsers, if the number is considered invalid, then this.value (and consequently $(this).val()) will return blank. In IE10, you can be get the raw, invalid value if the number starts with a number (0-9). Both browsers will only fire change events when they consider the input to have actually changed and--in IE10's case--that means if the user enters abcd and then blurs the input, then IE10 will clear the field and fire a change event if it had a valid value before being changed. In Chrome, the change occurs whether the input is valid or not; if it's invalid then it is changed to a blank value.
What this means is that you can handle valid and invalid number input, but you cannot dependably get the actual value that the user has typed into the textbox.
HTML
put letters in me and press tab:
<br />
<input type="number"/>
<br />
<p id="event" />
<p id="text" />
JavaScript
function checkValid(e) {
var $this = $(this);
$("#event").text(e.type);
$("#text").html("this.value: " +
this.value +
"<br />$(this).val(): " +
$this.val() + "<br />$(this).is(:valid): " +
$this.is(":valid") +
"<br />$.isNumeric(this.value): " +
$.isNumeric(this.value)); // <- helps check
}
$('input[type="number"]').on('change', checkValid).on("keyup", checkValid);
You can check to see if it is a valid number by checking $.isNumeric. The :valid and :invalid pseudo classes do not work in IE10 with number except when the field is marked as required (not at all in IE9), but they both work in Chrome without marking it as required.
As pickypg has noted, if a user types 'abcd' into an <input type='number'> element, you cannot get the value 'abcd' via $(this).val(). (Caveat: I've only tested in Chrome.)
However, you can determine whether the HTML5 input validity constraints are satisfied (valid) or not by calling myDOMelement.checkValidity(), or looking at the individual properties of the myDOMelement.validity object. This at least lets you distinguish between a blank field (valid) and one containing 'abcd' (not valid). Check here for more on HTML5 validity.
What is rather confusing, at least in Chrome, is that if an <input type='number'> element is initially blank and then you type in 'abcd', the 'change' event is not fired on blur. Likewise when you delete 'abcd' from the field so the field becomes blank.
A workaround is testing for changes in the HTML5 validity on blur. Here's a jsFiddle to illustrate the technique. Note that you still cannot tell if the user has changed 'abcd' to 'efgh', since those are both not valid.
The event change is triggered on losing focus and it is working as it is supposed to be, you may need to use keyup.
Live Demo
$('input').on('keyup', function() {
alert('change');
});

Categories