How can I validate field input against a regex when pasting? - javascript

I want to validate an input field with regex (replacing all vowels).
The input should always be matched against that regex, regardles if typed into or pasted into that field.
I know how to deal with the typing part, but I need help for copy - paste.
All vowels should be skipped (e.g.: "abcde" copy --> "bcd" paste)
$('document').ready(function(){
var pattern = /[aeiou]/ig;
$("#input").on("keypress keydown", function (e) {
if (e.key.match(pattern) !== null) {
e.preventDefault();
}
});
$("#input").on("paste", function (e) {
var text = e.originalEvent.clipboardData.getData('Text');
e.preventDefault();
//TODO... replace all vowels
console.log(text);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>
At first i tried to replace them and just set the value with $('#input').val($('#input').val() + copiedValue), but this only works if the cursor is at the end of the input.

A one in all solution subscribes to the input event. In addition to the sanitizing tasks the handler has to take care of reestablishing the input fields exact or most expected cursor/caret position in order to not break the user experience ...
function getSanitizedValue(value) {
return value.replace(/[aeiou]/ig, '');
}
function handleInput(evt) {
evt.preventDefault();
const elmNode = evt.currentTarget;
const currentValue = elmNode.value;
const sanitizedValue = getSanitizedValue(currentValue);
if (currentValue !== sanitizedValue) {
const diff = sanitizedValue.length - currentValue.length;
const { selectionStart, selectionEnd } = elmNode;
elmNode.value = sanitizedValue;
elmNode.selectionStart =
(selectionStart + diff > 0) ? selectionStart + diff : selectionStart;
elmNode.selectionEnd =
(selectionEnd + diff > 0) ? selectionEnd + diff : selectionEnd;
}
}
$('document')
.ready(() => {
$("#input").on("input", handleInput);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>

One method would be to manipulate the value of the text field from the paste event:
$('document').ready(function(){
var pattern = /[aeiou]/ig;
$("#input").on("keypress keydown", function (e) {
if (e.key.length == 1 && !e.ctrlKey && !e.altKey && e.key.match(pattern) !== null) {
e.preventDefault()
}
});
$("#input").on("paste", function (e) {
var text = e.originalEvent.clipboardData.getData('Text').replace(pattern, "");
e.preventDefault();
let input = e.originalEvent.target,
start = input.selectionStart,
end = input.selectionEnd;
input.value = input.value.substr(0, start) + text + input.value.substr(end);
input.selectionStart = start + text.length;
input.selectionEnd = input.selectionStart;
//TODO... replace all vowels
console.log(text, input.value);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>

Related

how to prevent a key input from appearing in input field?

I am trying to validate user input in a text input field.
I have written a javascript function for the same purpose which fires on onkeyup event.
The goal is to only allow user input if it's a numeric value less than 100 and with at most 1 decimal place.
The function is working fine but if a enter an invalid character ,say 'a', it will flash in the input box before being removed.
What I want is that if the entered character violates the defined condition it should not appear in the input box (as it is flashing right now for a split second).
Here's my code:
function validatePercent(event) {
var txt = $("#tds_input").val();
// alert(event.source);
if (!parseInt(txt)) {
$("#tds_input").val('');
}
if (isNaN(txt / 1)) {
txt = txt.substr(0, txt.length - 1);
$("#tds_input").val(txt);
}
if (txt > 100) {
//alert(2);
txt = txt.toString();
txt = txt.substr(0, txt.length - 1);
$("#tds_input").val(txt);
}
txt = txt.toString();
if (txt.indexOf('.') > -1) {
if (txt.substr(txt.indexOf('.') + 1, txt.length).length > 1) {
txt = txt.substr(0, txt.length - 1);
$("#tds_input").val(txt);
}
}
}
Using type=number (and not text) can help
function validatePercent(event)
{
var txt=$("#tds_input").val();
if(!parseInt(txt))
{
$("#tds_input").val('');
}
if(isNaN(txt/1))
{
txt=txt.substr(0,txt.length-1);
$("#tds_input").val(txt);
}
if(txt>100)
{
txt=txt.toString();
txt=txt.substr(0,txt.length-1);
$("#tds_input").val(txt);
}
txt=txt.toString();
if(txt.indexOf('.')>-1)
{
if(txt.substr(txt.indexOf('.')+1,txt.length).length>1){
txt=txt.substr(0,txt.length-1);
$("#tds_input").val(txt);
}
}
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" id = "tds_input" onkeyup="validatePercent()">
UPDATED
You could store the value of the when the focus is in the input.
When the user enters a valid percentage (integer only), replace the value stored. When inputs is incorrect, just replace with the old value.
var decimalSeparator = 1.1.toLocaleString().replace(/\d/g, ''),
pattern1 = "^(\\d{1,3})?([",
pattern2 = "]?\\d{1})?$",
regex = new RegExp(pattern1+decimalSeparator+pattern2),
resetContent = function () {
$('#tds_input').val($('#tds_input').data('val'));
},
matchRegex = function (value) {
return value.match(regex);
};
$('#tds_input').bind('focusin', (e) => {
$('#tds_input').data('val', $('#tds_input').val());
});
// handle input (keys, paste)
$('#tds_input').bind('input', (e) => {
let txtValue = $('#tds_input').val();
// input is empty
if (txtValue === "") {
$('#tds_input').data('val', "");
return;
}
// value does not match regex
if (!matchRegex(txtValue)) {
// maybe it ends with the decimal character?
if (txtValue[txtValue.length - 1] === "." && txtValue !== "100.") {
// simulate the user enters a decimal next
if (matchRegex(txtValue + "1")) {
$('#tds_input').data('val', txtValue);
return;
}
}
resetContent();
return;
}
// check between 0 and 100
let value = parseFloat(txtValue);
if (value >= 0 && value <= 100) {
// store new valid number
$('#tds_input').data('val', value);
// put the value as an integer in the input
$('#tds_input').val(value);
return;
} else resetContent();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="tds_input"/>

Textbox Maxlength Issue for amount field

I have a situation having a textbox having 15 as a max length property. That field works as a amount field. it is working correctly in normal cases.
lets say if i enter 11234567890.99 this amount in textbox it displays it as 112,34,567,890.99 which is expected.
But, if i copy & paste 112,34,567,890.99 amount in textbox last two digits gets truncated because the length gets out of bound.
Is there any ways to change this without modifying the exact behavior? allowing to paste whole 112,34,567,890.99 amount.
$(document).on("focusout","#txtformate1",(function () {
if (this.value != null && this.value != "") {
$((this.parentElement).nextElementSibling).hide()
}
else{
$((this.parentElement).nextElementSibling).show()
}
}));
$(document).on('keyup', '.Amt', function () {
var val = $(this).val();
val = val.replace(/([~!#$%^&*()_+=`{}\[\]\|\\:;'<>,\/? ])+/g, '');
if(isNaN(val) && val!="-")
{
val="";
}
$(this).val(val);
/*if (isNaN(val)) {
val = val.replace(/(?!^)-/g, '');
if(val.indexOf("-")>-1)
{
val = val.replace(/[`*\/]/g, '');
}
else{val = val.replace(/[^0-9\.]/g, '');}
if (val.split('.').length > 2)
{
val = val.replace(/\.+$/, "");
}
else if(val==".")
{
val ="";
}
}*/
});
$(document).on('focusout', '.Amt', function () {
var val = $(this).val();
val = val.replace(/(?!^)-/g, '');
if(isNaN(val) && val.indexOf(',')>-1){
val=$(this).val();
}
if (val == "0.00"){
val="";
}
$(this).val(val);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="form-control Amt" id="txtformate1" maxlength="15" />`

html Input type number with Thousand Separator

i want to add thousand separator on keyup event in input type number
but this work just in 6 character, if more than 6 character, value on input has reseted
this my short code
<input type="number" id="tanpa-rupiah" step="any">
var dengan_rupiah = document.getElementById('dengan-rupiah');
dengan_rupiah.addEventListener('keyup', function(e)
{
dengan_rupiah.value = formatRupiah(this.value, 'Rp. ');
});
function formatRupiah(bilangan, prefix)
{
var number_string = bilangan.replace(/[^,\d]/g, '').toString(),
split = number_string.split(','),
sisa = split[0].length % 3,
rupiah = split[0].substr(0, sisa),
ribuan = split[0].substr(sisa).match(/\d{1,3}/gi);
if (ribuan) {
separator = sisa ? '.' : '';
rupiah += separator + ribuan.join('.');
}
rupiah = split[1] != undefined ? rupiah + ',' + split[1] : rupiah;
return prefix == undefined ? rupiah : (rupiah ? 'Rp. ' + rupiah : '');
}
this my fiddle https://jsfiddle.net/C2heg/4619/
This might suit you. On keydown prevent the default action if it is not a number key. On keyup, parse the value and update it. Use the data- attributes to store and get the original value.
var elem = document.getElementById("num");
elem.addEventListener("keydown",function(event){
var key = event.which;
if((key<48 || key>57) && key != 8) event.preventDefault();
});
elem.addEventListener("keyup",function(event){
var value = this.value.replace(/,/g,"");
this.dataset.currentValue=parseInt(value);
var caret = value.length-1;
while((caret-3)>-1)
{
caret -= 3;
value = value.split('');
value.splice(caret+1,0,",");
value = value.join('');
}
this.value = value;
});
function showValue()
{
console.log(document.getElementById("num").dataset.currentValue);
}
<input type="text" id="num" maxlength="30">
<button onclick="showValue()">Get Value</button>
Ok I have posted answer below. I have added limit of 20 numbers. You can change it as per your need.
You can use Number.toLocaleString() for this purpose.
Below is working example:
// When ready.
$(function() {
var extra = 0;
var $input = $("#amount");
$input.on("keyup", function(event) {
// When user select text in the document, also abort.
var selection = window.getSelection().toString();
if (selection !== '') {
return;
}
// When the arrow keys are pressed, abort.
if ($.inArray(event.keyCode, [38, 40, 37, 39]) !== -1) {
if (event.keyCode == 38) {
extra = 1000;
} else if (event.keyCode == 40) {
extra = -1000;
} else {
return;
}
}
var $this = $(this);
// Get the value.
var input = $this.val();
var input = input.replace(/[\D\s\._\-]+/g, "");
input = input ? parseInt(input, 10) : 0;
input += extra;
extra = 0;
$this.val(function() {
return (input === 0) ? "" : input.toLocaleString("en-US");
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="amount" name="amount" type="text" maxlength="20" />
change your the input type equal to "text" then its work
<input type="text" id="tanpa-rupiah" step="any">
checkout jsfiddle

comma format as typing in angular

In jqxwidget
http://www.jqwidgets.com/jquery-widgets-demo/demos/jqxnumberinput/index.htm
by default the comma’s are already in place and separated by underscore.
what i want is to have the field empty and as soon as user starts typing the comma should come as and when similarly to F2 cell render-er.
so when typed 100 is should show 100
when typed 10000 ,it should show 10,000
also i have angular in my app as we are using jqxwidget in conjucation with so any angular way is also fine
one plugin i have found does the job but when focus out not when typing
https://www.npmjs.com/package/angular-numeric-directive
Hey I have solved this before by creating a directive that applies a filter to your HTML input. Here is a jsfiddle example
This is the directive. It both formats the user's input and keeps the cursor where the user is typing. My one issue with this is the logic behind where the cursor should be pointed.
fessmodule.directive('format', ['$filter', function ($filter) {
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) return;
var parts = attrs.format.split(':');
attrs.foramtType = parts[0];
attrs.pass = parts[1];
ctrl.$formatters.unshift(function (a) {
return $filter(attrs.foramtType)(ctrl.$modelValue, attrs.pass)
});
ctrl.$parsers.unshift(function (viewValue) {
var cursorPointer = elem.context.selectionStart;
var plainNumber = viewValue.replace(/[^\d|\-+|\.+]/g, '');
elem.val($filter(attrs.foramtType)(plainNumber, attrs.pass));
elem.context.setSelectionRange(cursorPointer, cursorPointer);
return plainNumber;
});
}
};
And the HTML to activate it
<input type="text" ng-model="test" format="number:2" />
Angular already provides pretty basic formatting filters
like
html : {{val | number:0}}
script: $scope.val = 1234.56789;
ref:
https://docs.angularjs.org/api/ng/filter/number
https://docs.angularjs.org/api/ng/filter/currency
https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters
Demo
<input value="100000000" id="testInput" />
Simply apply this .formatInput(numberOfCharactersForSeparator, Separator ); to your input
$(document).ready(function()
{
$("#testInput").formatInput(3,"," );
});
using this plugin that i just made :p
$.fn.formatInput = (function(afterHowManyCharacter,commaType)
{
if(afterHowManyCharacter && commaType != ".")
{
var str = $(this).val();
var comma = commaType != undefined ? commaType : "," ;
var strMod ;
if($(this).val().indexOf(".") == -1)
strMod = replaceAll(comma,"",$(this).val());
else
{
strMod = replaceAll(comma,"",$(this).val());
strMod = strMod.substring(0,strMod.indexOf("."));
}
if($(this).val().indexOf(".") != -1)
$(this).val(splitByLength(strMod,afterHowManyCharacter).join( comma )+ $(this).val().substring($(this).val().indexOf(".")));
else
$(this).val(splitByLength(strMod,afterHowManyCharacter).join( comma ));
var nowPos = 0;
$(this).on("keyup",function(e)
{
nowPos = doGetCaretPosition($(this)[0]);
var codePressed = e.which ;
if(" 8 37 38 39 40 46 17".indexOf(" "+codePressed) == -1 && !e.ctrlKey)
{
if($(this).val().length >afterHowManyCharacter)
{
strMod ;
if($(this).val().indexOf(".") == -1)
strMod = replaceAll(comma,"",$(this).val());
else
{
strMod = replaceAll(comma,"",$(this).val());
strMod = strMod.substring(0,strMod.indexOf("."));
}
if($(this).val().indexOf(".") != -1)
$(this).val(splitByLength(strMod,afterHowManyCharacter).join( comma )+ $(this).val().substring($(this).val().indexOf(".")));
else
$(this).val(splitByLength(strMod,afterHowManyCharacter).join( comma ));
if((strMod.length-1)%afterHowManyCharacter == 0)
{
setCursor($(this)[0],nowPos+1);
}
else
{
setCursor($(this)[0],nowPos);
}
}
}
});
}
else if( commaType == ".")
{
console.log("You can't use . as Separator");
}
function splitByLength(str,maxLength)
{
var reg = new RegExp(".{1,"+maxLength+"}","g"); ;
return reverseStringInArray(str.split("").reverse().join("").match(reg).reverse());
}
function replaceAll(find, replace, str) {
return str.replace(new RegExp(find, 'g'), replace);
}
function reverseStringInArray(arr)
{
$.each(arr,function(i,val)
{
arr[i] = arr[i].split("").reverse().join("");
});
return arr ;
}
// Author of setCursor is nemisj
function setCursor(node,pos)
{
node = (typeof node == "string" || node instanceof String) ? document.getElementById(node) : node;
if(!node){
return false;
}else if(node.createTextRange){
var textRange = node.createTextRange();
textRange.collapse(true);
textRange.moveEnd(pos);
textRange.moveStart(pos);
textRange.select();
return true;
}else if(node.setSelectionRange){
node.setSelectionRange(pos,pos);
return true;
}
return false;
}
// Author of setCursor is bezmax
function doGetCaretPosition (oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus ();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart ('character', -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0')
iCaretPos = oField.selectionStart;
// Return results
return (iCaretPos);
}
});
<html>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('app',[]);
app.controller('myCtrl',function($scope){
$scope.name = "1232.33";
$scope.changeFormat = function(value){
$scope.name = Number(value).toLocaleString('en');
}
});
</script>
<body>
<div ng-app="app" ng-controller="myCtrl">
<p>Input something in the input box:</p>
<p>Number: <input type="text" ng-model="name" placeholder="Enter name here" ng-blur="changeFormat(name)"></p>
<h1>Formatted value {{name}}</h1>
</div>
</body>
</html>
Here is a hackish solution. The idea is to watch for changes in the input text and format the input accordingly.
HTML
<div ng-controller="so">
<input ng-model="salary"></input>
</div>
Javascript
app.controller('so', function($scope) {
$scope.salary = '12567';
$scope.$watch('salary', function(){
// strip out all the commas and dots
var temp = $scope.salary;
if (!temp) return; // ignore empty input box
var lastChar = temp[temp.length-1];
if (lastChar === ',' || lastChar === '.') // skip it/allow commas
return;
var a = temp.replace(/,/g,''); //remove all commas
//console.log(a);
if (isNaN(a))
$scope.salary = temp.substring(0, temp.length-1); // last char was not right
else {
var n = parseInt(a, 10); // the integer part
var f = ''; // decimal part
if (a.indexOf('.') >= 0) // decimal present{
if (lastChar === '0') // 0's after decimal point are OK
return;
f = ('' + parseFloat(a)).substr(a.indexOf('.'));
}
var formatted_salary = '';
var count = 0;
var ns = '' + n; // string of integer part
for (var i=ns.length-1; i>=0; i--) {
if (count%3===0 && count>0)
formatted_salary = ',' + formatted_salary;
formatted_salary = ns[i] + formatted_salary;
count += 1;
}
formatted_salary = formatted_salary + (f ? f : '');
$scope.salary = formatted_salary;
}
})
})
Here is the JSFiddle
It gracefully handles things like
won't allow any characters other than numbers , and .
multiple commas and dots formatted correctly
PS:- you might want to handle the proper positioning of the caret yourself using text range. I haven't included that here.
100 => 100
1000 =>1,000
10000 => 10,000
100000 => 100,000
...
10000000 => 10,000,000
10000000.540 => 10,000,000.540
I use ng-change event to make this example
// on-change event
$scope.ngchanged = function (val) {
$scope.iputval = numberWithCommas(val);
};
function numberWithCommas(n) {
while (n.toString().indexOf(",") != -1)
{
n = n.replace(",", "");
}
var parts = n.toString().split(".");
return parts[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}
Use it
<input type="text" ng-model="iputval" ng-change="ngchanged(iputval)" />
Updated add demo and code by following link
Full code and demo >> here
Please check out ng-number-input
I think it accomplishes the task easily.
https://www.npmjs.com/package/ng-number-input
I made it for my project and I thought I'd share it with the community.
Source code available on git hub and link is available in npm page.

Validate input value before it is shown to user

I have an html <input> and some pattern (e.g. -?\d*\.?\d* float-signed value).
I should prevent typing the not matched value.
I did it in next way
jQuery.fn.numeric = function (pattern)
{
var jqElement = $(this), prevValue;
jqElement.keydown(function()
{
prevValue = jqElement.val();
})
jqElement.keyup(function(e)
{
if (!pattern.test(jqElement.val()))
{
jqElement.val(prevValue);
e.preventDefault();
}
prevValue = ""
})
};
JSFiddle DEMO
But in this case, value is shown to user and then corrected to right value.
Is it way to vaidate value before it is shown to user?
I can use pattern attribute from html5
$("#validateMe").on('keydown', function() {
var charBeingTyped = String.fromCharCode(e.charCode || e.which); // get character being typed
var cursorPosition = $(this)[0].selectionStart; // get cursor position
// insert char being typed in our copy of the value of the input at the position of the cursor.
var inValue = $(this).value().substring(0, cursorPosition) + charBeingTyped + $(this).value().substring(cursorPosition, $(this).value().length);
if(inValue.match(/-?\d*\.?\d*/)) return true;
else return false;
});
How about this POJS, I'm using a cross-browser addEvent function instead of jquery and not using any regexs, but I believe it achieves what you are looking for. Pressing + or - changes the sign of the value.
HTML
<input id="test" type="text" />
Javascript
/*jslint maxerr: 50, indent: 4, browser: true */
(function () {
"use strict";
function addEvent(elem, event, fn) {
if (typeof elem === "string") {
elem = document.getElementById(elem);
}
function listenHandler(e) {
var ret = fn.apply(null, arguments);
if (ret === false) {
e.stopPropagation();
e.preventDefault();
}
return ret;
}
function attachHandler() {
window.event.target = window.event.srcElement;
var ret = fn.call(elem, window.event);
if (ret === false) {
window.event.returnValue = false;
window.event.cancelBubble = true;
}
return ret;
}
if (elem.addEventListener) {
elem.addEventListener(event, listenHandler, false);
} else {
elem.attachEvent("on" + event, attachHandler);
}
}
function verify(e) {
var target = e.target, // shouldn't be needed: || e.srcElement;
value = target.value,
char = String.fromCharCode(e.keyCode || e.charCode);
if (value.charAt(0) === "-") {
if (char === "+") {
e.target.value = value.slice(1);
}
} else if (char === "-") {
e.target.value = char + value;
return false;
}
value += char;
return parseFloat(value) === +value;
}
addEvent("test", "keypress", verify);
}());
On jsfiddle
I think I used the correct values keyCode || charCode
but you may want to search and check. A summary of the correct ones are available here
You could use this code to find out what character is pressed. Validate that character and, if it validates, append it to the input field.
Try this code:
jQuery.fn.numeric = function (pattern)
{
$(this).keypress(function(e)
{
var sChar = String.fromCharCode(!e.charCode ? e.which : event.charCode);
e.preventDefault();
var sPrev = $(this).val();
if(!pattern.test(sChar)){
return false;
} else {
sPrev = sPrev + sChar;
}
$(this).val(sPrev);
});
};
$("#validateId").numeric(/^-?\d*\.?\d*$/);
jsfiddle.net/aBNtH/
UPDATE:
My example validates each charachter while typing. If you prefer to check the entire value of the input field instead, I would suggest to validate the value on an other Event, like Input blur().

Categories

Resources