Limit html text input to a particular number of bytes? - javascript

Using HTML5 (or less preferably JavaScript) is it possible to limit the maximum length of an input to a particular number of bytes?
I realise that I can limit to a number of characters with:
<input type="text" maxlength="4" />
But that's not good enough because I can input up to four two-byte chars in it.
Obviously I am validating this server-side, but I would like this on the browser-side too.
Edit: Just to be clear, I do wish to be able to support UTF-8. Sorry #elclanrs.

this script has a couple minor UX glitches that can be cleaned up, but it does accomplish the basic task outlined when i tested it in chrome:
<input id=myinp />
<script> // bind handlers to input:
myinp.onkeypress=myinp.onblur=myinp.onpaste= function vld(e){
var inp=e.target;
// count bytes used in text:
if( encodeURIComponent(inp.value).replace(/%[A-F\d]{2,6}/g, 'U').length > 4){
// if too many bytes, try to reject:
e.preventDefault;
inp.value=inp.val||inp.value;
return false;
}
// backup last known good value:
inp.val=inp.value;
}
</script>

Throughout my own findings, I figured this works really well:
function limit_input(n) { // n = number of bytes
return function(e) {
const is_clipboard = e instanceof ClipboardEvent;
if(is_clipboard && e.type != "paste") {
return;
}
let new_val = e.target.value;
if(is_clipboard) {
new_val += e.clipboardData.getData("text");
} else {
new_val += e.key;
}
if(new TextEncoder().encode(new_val).byteLength -
e.target.selectionEnd + e.target.selectionStart > n) {
if(e.target.value == "" && is_clipboard) {
const old = e.target.placeholder;
e.target.placeholder = "Text too long to paste!";
setTimeout(function() {
e.target.placeholder = old;
}, 1000);
}
e.preventDefault();
}
};
}
let el = document.getElementById("your_input");
el.onkeypress = el.onpaste = limit_input(4);
I started out with dandavis' answer and kept on improving it to adapt to all situations. I still don't think this is perfect, and it's still using the deprecated onkeypress handler, but nothing else worked better than this.
You can delete the part of the code that changes placeholder to say the text is too long to paste (delete the whole if, keep only e.preventDefault() in). It's just something I added myself to notify the user why the input is still empty after they try pasting something in. That way they won't blame me for writing faulty code and I won't have to answer a horde of complaints.

If estimating isn't good enough, I'd filter all the non single-byte chars and count them.

Related

How to validate single lines in Html TextAreaFor against regular expression(s)

I am stuck with the following problem. On a web page in my current C# / MVC project, I added some control elements to fill a model. Among these control elements is a text area, designed using #Html.TextAreaFor:
<div class="smt-textarea ">
#Html.LabelFor(m => m.Numbers):
#Html.TextAreaFor(m => m. Numbers, new
{
#class = "form-control",
id = "smt-textarea",
rows = 25,
})
</div>
Users should enter a sequence of numbers into that text area. The number sequence follows a specific pattern. The pattern is later evaluated in code-behind methods, which are working well, and which are not part of my question here.
As a new feature, the numbers entered in the text area should now be validated regarding the amount of numbers in the actual sequence. The rule states that only digits from 0-9 can be entered in the text area. A number sequence should consist of exactly 19 digits.
Since I need to directly access the text area, I figured it might be a good idea to opt for Javascript in this particular case. I should note that I am quite new to JS and this might be one part of the problem. Be that as it may, based on some posts here on SO, I came up with the following preliminary solution.
console.log(textArea.value);
var reg = /\d{19,19}/;
let regex = new RegExp(reg);
if (regex.test(textArea.value)) {
console.log(regex.test(textArea.value));
alert("IT'S A MATCH !!!");
} else {
alert("SORRY, NO MATCH.");
}
}
window.onload = function () {
var textArea = document.getElementById("smt-textarea");
textArea.onkeyup = function (evt) {
evt = evt || window.event;
if (evt.keyCode === 13) {
validateTextArea(this);
}
};
};
Unfortunately, the code seems to validate the entire text area, meaning I do get a match whenever there are one more digit sequences matching the pattern, e.g. when entering the following
12345
0276114931111401167
skjfsjgrs
ksgfskgjsgjsrgs
skjfsjgrs and ksgfskgjsgjsrgs are valid because they are preceded by a "valid" number sequence.
What I would like to accomplish is that upon pressing the <ENTER> key, only the current line of the text area should be validated against the regular expression outlined in the sample. If the current line does not match, a warning message should be displayed. Once the user corrected his/her digit sequence, validation should continue moving to the next line until the next error pops up.
At the moment your validation will be passed if your string from text area contains a sequence from 19 numbers. In order to make sure each line is valid you'd better use ^ and $ anchors to match the whole string from start to end. Something like this:
/^(\d{3}\n?)*$/
var textArea = document.getElementById("smt-textarea");
textArea.onkeyup = function(evt) {
evt = evt || window.event;
if (evt.keyCode === 13) {
validateTextArea(this);
}
};
function validateTextArea(textArea) {
let regex = new RegExp(/^(\d{19}\n?)*$/);
if (regex.test(textArea.value)) {
alert("IT'S A MATCH !!!");
} else {
alert("SORRY, NO MATCH.");
}
}
<textarea name="" id="smt-textarea" rows="25"></textarea>
Also it might be a good idea to trim your string value in order to avoid problems with white-space characters in the end.
Update
Here is another version which validate line by line:
var textArea = document.getElementById("smt-textarea");
textArea.onkeyup = function(evt) {
evt = evt || window.event;
if (evt.keyCode === 13) {
validateTextArea(this);
}
};
function validateTextArea(textArea) {
let lines = textArea.value.trim().split('\n');
let regex = new RegExp(/^\d{19}$/);
let invalid = lines.some(function(line, index) {
let lineInvalid = !regex.test(line);
if (lineInvalid) {
alert(`Line ${index+1} is invalid`);
}
return lineInvalid;
});
console.log(`Text area is ${(invalid ? 'invalid' : 'valid')}`);
}
<textarea name="" id="smt-textarea" rows="25"></textarea>

How to remap keyboard within the same textarea

Currently i am doing a project with remapping characters to words by detecting the keyup function. Unfortunately, i have only been able to retrieve the first character and remap to the word i want. In my project, i need to directly retrieve all of my keyboard input and directly convert it to the word that i want within the same textarea. For example when i type in the textarea, it will convert to "are" directly. I don't know why it stopped retrieving the second character and remapping not function. Below is my code, hope someone can tell me my error. Thank you.
<textarea class="width-100" id="translated-text" onkeyup="myFunctionkey(event);" rows="10"></textarea>
<script>
function myFunctionkey(e) {
conversion();
}
function conversion(){
var x = document.getElementById('translated-text');
if(x.value == 'a'){
x.value='yes';
}
if(x.value == 'q'){
x.value = 'are';
}
}
</script>
From what I understand, you only want to grab the input and replace a key stroke with a complete word.
Maybe this will do. I've changed onkeyup to onkeypress because this is more reliable from what I remember.
<textarea id="translated-text" cols="50" rows="10" onkeypress="replaceInputChar(event);"></textarea>
<script type="text/javascript">
//create replacement map
var map = {
"a": "and",
"b": "bold",
"c": "change"
};
function replaceInputChar(e)
{
var ctl = document.getElementById("translated-text"); //control
var char = String.fromCharCode(e.keyCode); //typed char
if (char in map) //check if letter is defined in map
{
//insert replacement instead of letter
if("selectionStart" in ctl)
{
//in modern browsers we can easily mimic default behavior at cursor position
var pos = ctl.selectionStart;
ctl.value = ctl.value.substr(0, pos) + map[char] + ctl.value.substr(ctl.selectionEnd);
ctl.selectionStart = pos + map[char].length;
ctl.selectionEnd = ctl.selectionStart;
}
else
ctl.value += map[char];
if ("preventDefault" in e) //modern browser event cancelling
e.preventDefault();
else
{
//old browser event cancelling
e.returnValue = false; //IE8
return false;
}
}
}
</script>
You should use comparison operator '==' instead of assignment operator '=' while remapping the value, like this:
x.value=='a'
Edit:
You should check the updated code for your problem here:
https://jsfiddle.net/o4coLr5t/1/
Now, the characters you choose to remap in javascript will display the string, that you map the character to. Otherwise it will display nothing on pressing keys. So, try and add all the character keycodes to the javascript code. Hope that helps.

Delaying regex for more specific matches

I have a scenario where I need to run regex tests on a numeric input that represents phone company operator services.
In one instance, there is a prefix 118 which can act on its own or with a suffix of up to two digits.
At the moment, my function looks something like the below. My problem is that the least specific '118' exact match fires before the more specific one.
There is no sleep/wait in Javascript and unless I'm mistaken, I don't think I can get setTimeout to return a simple "return true" ?
I don't mind if the answer to this question is in pure Javascript or Jquery, but not having a dependency on Jquery would be preferable.
function isOperatorService(vNumber) {
var vNumber = vNumber.replace(/\D/g,'');
if (/^((44){0,1}118[0-9]{3})$/.test(vNumber)) {
console.log("118 specific");
return true;
}
if(/^((44){0,1}[19]{1}[0-9]{1}[0-79]{1})$/.test(vNumber)) {
console.log("Other shortcodes");
return true;
}
return false;
}
UPDATE: Re: "Provide your input and expected output."
Pretty much as I described above, in Pseudo-code :
if == 118
wait incase the user has not finished typing (e.g. wait incase 118118...)
else
do other regex cheks
Add a simple debouncer:
var timeout;
var typeDelay = 300; // wait after last type
var changeEvents = "propertychange keyup input paste change";
$('#yourinput').on(changeEvents, function () {
//clear your timeout
clearTimeout(timeout);
// Add another listener
timeout = setTimeout(function () {
// Do your regex here
function_ended_typing();
}, typeDelay);
});

Javascript - Detecting the first character and alerting the user

I have a question. I'm wanting to run a basic function in Javascript which takes an input field from a form and checks the very first character to ensure it does not have a £ sign (GBP) infront of the value
I can't seem to find the right code anywhere to do this? - Anyone have any idea's... I'm a bit of a noob to all this programming to be honest so any help would be gratefully received.
If you have an input field and you want to get it's value and check the first character of the value, you can do so like this:
<input type="text" id="price">
var str = document.getElementById("price").value;
if (str.charAt(0) == "£") {
// do whatever you need to do if there's a £ sign at the beginning
}
If the £ sign isn't supposed to be there, perhaps you could just safely remove it or ignore it rather than make the end user remove it like this:
var el = document.getElementById("price");
if (el.value.charAt(0) == "£") {
el.value = el.value.substr(1);
}
Assuming your HTML is something like this:
<input type="text" id="my_input" />
<button onClick="checkInput();">Check input</button>
Then you want to build your script like this:
function checkInput() {
var inp = document.getElementById('my_input'); // get the input field
inp = inp.value; // get the value
inp = inp.charAt(0); // get the first character
if( inp == "£") {
// do something
}
}
That can be condensed into:
function checkInput() {
if( document.getElementById('my_input').value.charAt(0) == "£") {
// do something
}
}
The trick to any code-writing is breaking a big problem into smaller ones. Step by step.
charAt should do it
var str = "Foo";
var firstChar = str.charAt(0);

Find the first character of input in a textbox

I am stuck in implementing the following:
User starts typing in a textbox.
The javascript on page captures the first character typed, validates that it is an english alphabet (a-z,A-Z) and converts it to lowercase (if necessary).
Make an XMLHttp request based on the input (i.e. if first input character is a, get a.xml, if b get b.xml and so on).
I know how to do the last part (make the xmlhttp request) but am kind of stuck on how to capture the first character and validate it (in a way that works on all browsers). Please guide. Thanks.
Clarification: This is to create a Google Suggest like autocomplete-drop-down menu without the need for server side programs.
Something like this should work:
HTML:
<input type="text" id="myField" />
And in JS:
window.onload = function() {
document.getElementById('myField').onkeyup = function() {
// Validate that the first letter is A-Za-z and capture it
var letter = this.value.match(/^([A-Za-z])/);
// If a letter was found
if(letter !== null) {
// Change it to lowercase and update the value
letter = letter[0].toLowerCase();
this.value = letter + this.value.substring(1);
// Do the request
}
}
}
My vanilla-JS skills are a bit rusty but this should do the trick. Just for the heck of it, here's the same using jQuery:
$(function() {
$('#myField').keyup(function() {
var letter = $(this).val().match(/^([A-Za-z])/);
// If a letter was found
if(letter !== null) {
// Change it to lowercase and update the value
letter = letter[0].toLowerCase();
$(this).val(letter + $(this).val().substring(1);
// Do the request
}
});
});
What part of the problem do you not know how to do? Here's an approach that you can follow. Very likely to need adjustments, but a good starting point
if our text field's id is 'txt'
document.getElementByID('txt').onkeypress = function(e) {
var textInField = this.value;
if (textInField.length == 1) {
var firstChar = textInField.charAt(0);
if (/[a-zA-Z]/.test(firstChar)) {
sendXHR(textInField.value.toLowerCase())
}
} else {
// What do you do if there is one or more chars???
}
}
Note that the other answers here mention onchange, that doesn't fire until the focus leaves the field, which I don't think is what you want

Categories

Resources