I'm doing a js function that will prevent some input data to be inserted within an input textbox (only DDDDDD,DD for example):
// decimal
$('.is-decimal').keydown(function (e) {
// prevent to insert non-decimal number (number with comma, max 2 digits after comma)
var elem = $(this);
var value = elem.val();
var regex = /^\d+,?\d{0,2}$/;
if (!regex.test(value)) {
e.preventDefault();
}
});
but I can't use keydown: first time is empty, so it won't check the following char.
Which method should I use? keyup is later (so it's just inserted); the same with .on("input propertychange", function ()
EDIT: my best attempt:
// decimal
$('.is-decimal').on("input propertychange", function (e) {
var elem = $(this);
var value = elem.val();
// prevent to insert non-decimal number (number with comma, max 2 digits after comma)
var regex = /^\d+,?\d{0,2}$/;
if (!regex.test(value)) {
elem.val(elem.attr('data-actual-value'));
e.preventDefault();
} else {
elem.attr("data-actual-value", value);
}
});
You define a lastValidValue can use keyup and change events to check the newly entered value and if the new value is invalid change it back to the lastValidValue.
Note: You modify the value without triggering keyup and keydown e.g. right-click and paste
Here's an example
let decField = document.querySelector('#decimal')
let lastValidValue = ''
const regex = /^\d+,?\d{0,2}$/;
const eventHandler = e => {
if( event.target.value.match(regex) ) {
lastValidValue = event.target.value
}
else {
event.target.value = lastValidValue
}
}
decField.addEventListener('keyup', eventHandler)
decField.addEventListener('change', eventHandler)
Edit: here's an example with multiple fields using data-regex attribute to have individual regexes
const eventHandler = e => {
let regex = new RegExp(event.target.dataset.regex);
if( regex.test(event.target.value) ) {
event.target.dataset.lastValidValue = event.target.value
}
else {
event.target.value = event.target.dataset.lastValidValue || ''
}
}
document.querySelectorAll('input[data-regex]').forEach(field => {
field.addEventListener('keyup', eventHandler);
field.addEventListener('change', eventHandler);
})
<input type="text" data-regex="^\d+,?\d{0,2}$" placeholder="digits" />
<input type="text" data-regex="^[\w\s]+$" placeholder="text" />
<input type="text" data-regex="^\W+$" placeholder="special chars" />
Related
I am trying to only allow certain characters a user can type / copy into a HTML-<input> field by using following Regex:
return /^[A-Za-z0-9 ]*$/.test(value);
It works for me properly, but only if I start with an allowed character (e.g.: "A").
However, if I am starting with a character which isn't allowed by my Regex (e.g.: "!"), I suddenly can type in characters which should be disabled:
For testing I have created following fiddle: >>Click<<
Full script as reference:
<input type="text" class="polarion-TextBox" name="targetDocument" style="width: 100%;">
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function() {
window.setTimeout ( function() {
// Restricts input for the given textbox to the given inputFilter.
function setInputFilter(textbox, inputFilter) {
["input"].forEach(function(event) {
textbox.addEventListener(event, function() {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
});
});
}
// Restrict input to digits and '.' by using a regular expression filter.
setInputFilter(document.getElementsByName("targetDocument")[0], function(value) {
return /^[A-Za-z0-9 ]*$/.test(value);
});
}, 1000);
}, false);
</script>
You don't have an oldValue when you enter any character for first time, so your code won't go into your second condition
Once your first character doesn't match, whatever you type next, the value never goes into first condition so oldValue is never set and as there is no existing oldValue your code won't go into second condition.
You can have an initial oldValue to empty string to fix this issue.
Add textbox.oldValue = ""; before textbox.addEventListener.
This works for me:
function setInputFilter(textbox, inputFilter) {
["input"].forEach(function(event) {
textbox.addEventListener(event, function() {
if (inputFilter(this.value)) {
if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
} else {
this.value = "";
this.setSelectionRange(0, 0);
}
} else {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
}
});
});
}
window.addEventListener("DOMContentLoaded", function() {
setInputFilter(document.getElementsByName("targetDocument")[0], function(
value
) {
return /[^A-Za-z0-9 ]/g.test(value);
});
});
<input type="text" class="polarion-TextBox" name="targetDocument" style="width: 100%;">
Main change is clearing out the value if there is no oldValue to restore on invalid input. I also inverted the logic and return true if there are any invalid characters.
I've read several questions [1], [2], [3] regarding this topic, but none seems to provide a general solution to this problem. All answers seems to be directed to some specific cases.
I have this simple input field
<input type="number" id="inputBox" min="0" max="255" step="1" />
and I do a strict input validation on it:
inputBox.addEventListener("input", function () {
validateInput(this);
});
inputBox.addEventListener("keydown", function (e) {
validateInput(this, e);
});
function validateInput(elm, e) {
// handle keydown event
if (e) {
// do not allow floating-point numbers, if it's not expected
if (!isFloat(elm.step)) {
if (e.key == ".") {
e.preventDefault();
}
}
}
// handle input event
else {
// do not allow leading zeros
while (elm.value.length > 1 && elm.value[0] === "0") {
elm.value = elm.value.toString().slice(1);
}
// input should be between min and max
if (elm.validity.rangeUnderflow) {
elm.value = elm.min;
}
else if (elm.validity.rangeOverflow) {
elm.value = elm.max;
}
}
}
All this seems to be working fine for user input.
var inputBox = document.getElementById("inputBox");
inputBox.addEventListener("input", function() {
validateInput(this);
});
inputBox.addEventListener("keydown", function(e) {
validateInput(this, e);
});
function validateInput(elm, e) {
// handle keydown event
if (e) {
// do not allow floating-point numbers, if it's not expected
if (!isFloat(elm.step)) {
if (e.key == ".") {
e.preventDefault();
}
}
}
// handle input event
else {
// do not allow leading zeros
while (elm.value.length > 1 && elm.value[0] === "0") {
elm.value = elm.value.toString().slice(1);
}
// input should be between min and max
if (elm.validity.rangeUnderflow) {
elm.value = elm.min;
} else if (elm.validity.rangeOverflow) {
elm.value = elm.max;
}
}
}
function isFloat(f) {
var f = parseFloat(f);
var floor = Math.floor(f);
var fraction = f - floor;
if (fraction > 0) {
return true;
}
return false;
}
<input type="number" id="inputBox" min="0" max="255" step="1" />
But the user can still modify the input field value programmatically. The user can enter the following values through the console to bypass the validation and these are invalid/unexpected values:
inputBox.value = "005";
inputBox.value = "2.5"
inputBox.value = "-05.5";
An ideal solution to this would be to call a function (e.g. validateProgrammaticInput()) if the user changes the field value using inputBox.value.
inputBox.value = -10; // magically call validateProgrammaticInput()
Note: I'm not using a form. There's no submit button. This will not be sent to a server. This is a client application. Value should be validated in real-time. If I want to modify the field value programmatically, I can trigger a custom event in my code to validate the input, but that's not the case. What I want is to validate the input, if the user enters it programmatically. So my use case is irrelevant to the problem. Thought I should point these out before a confusion.
you can trigger the event programmaticaly after changing the value like this
var inputBox = document.getElementById("inputBox");
inputBox.addEventListener("input", function () {
console.log("input");
// input should be between min and max
if (this.validity.rangeUnderflow) {
this.value = this.min;
}
else if (this.validity.rangeOverflow) {
this.value = this.max;
}
// do not allow leading zeros
while (this.value.length > 1 && this.value.toString()[0] === "0") {
this.value = this.value.toString().slice(1);
}
});
inputBox.addEventListener("keydown", function (e) {
// do not allow floating-point numbers, if it's not expected
if (!isFloat(this.step)) {
if (e.key == ".") {
e.preventDefault();
}
}
},false);
function change(){
inputBox.value = "005";
inputBox.dispatchEvent(new Event('input'));
}
function isFloat(n){
return Number(n) === n && n % 1 !== 0;
}
<input type="number" id="inputBox" min="0" max="255" step="1" />
<button onclick="change()">change</button>
So, to me, your event listeners aren't triggered at all because theyre not occurring. There's no "keydown" on the field when the values are changed programmatically, as no events are triggered in the DOM.
To me, I think you should wire some other event handler as well that's more "page level". In looking at the jQuery event categories (https://api.jquery.com/category/events/) what if you assigned these events to the page itself - on mouse x\y changing, on page enter\leave and focus\blur.
It may seem a little overboard to use all of these events, but this seems to be a unique case. To me, you never really trust user input, so I tend to recalculate\validate data when submit by the user, but for this scenario where the data isn't being submitted to you, I think triggering these items by some page level events rather than input specific events may get you over the hump...
I have text field which is wired up with Keyup & change event, to trim the field length.
#Html.TextBoxFor(m => m.zipCode, new {data_bind = "textInput: zipcode, event: { keyup: trimField, change: trimField }", maxlength = "5"})
Trim function,
function trimField(data, event) {
var obj = event.target;
var maxlength = parseInt(obj.getAttribute('maxlength'), 10);
obj.value = obj.value.substring(0, maxlength);
obj.focus();
return true;
}
If I type "123456", on the UI it shows "12345", but the model has "123456".
How to get model updated after the keyup event?
You are not updating the observable variable which is bound to your element. It is better to make it generic as an observable extend so it can be used everywhere based on your max-length and to make sure it follows your rule for an initial value.
Example : https://jsfiddle.net/kyr6w2x3/55/
HTML:
<input data-bind='textInput: zipCode' />
<div>
zip code in Model:<span data-bind="text:zipCode"></span>
</div>
JS:
function AppViewModel(input) {
this.zipCode = ko.observable(input).extend({ maxLength:5});
this.phone = ko.observable(input).extend({ maxLength:11});
}
ko.extenders.maxLenght = function(target, characters) {
//you can use this to show an error message on view
// target.validationMessage = ko.observable();
//define a function to do validation for maxLength
function validate(newValue) {
var maxlength = parseInt(characters, 10);
if(newValue){
target(newValue.substring(0, maxlength) );
}
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
ko.applyBindings(new AppViewModel("12345678910"));
change maxlength from 5 to 6:
#Html.TextBoxFor(m => m.zipCode, new {data_bind = "textInput: zipcode, event: { keyup: trimField, change: trimField }", maxlength = "6"})
Stop modifying the DOM. That's Knockout's job. You just modify the data item and Knockout will ensure that the UI is right.
function trimField(data, event) {
var obj = event.target;
var maxlength = parseInt(obj.getAttribute('maxlength'), 10);
data.zipcode(data.zipcode().substr(0, maxlength));
return true;
}
I have a basic enquiry form on my website and I want one of the fields to ONLY accept numbers and keyboard spaces (whitespace).
Currently, the phone number field only accepts numbers using:
if(isNaN(form.phone.value))
{
alert('Due to SPAM this field will only accept numbers');
form.phone.focus();
return false;
}
When I test the form and use a keyboard space the error message is displayed. I need this field to accept numbers and whitespace. I assume people will use spaces when entering their full telephone number including country/area codes.
You could do it like this
'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);
}
}
var keys = ' 0123456789';
function verify(e) {
var key = String.fromCharCode(e.keyCode || e.charCode);
return keys.indexOf(key) !== -1;
}
addEvent('test', 'keypress', verify);
<input id="test" type="text" />
Update: As everything supports EventTarget.addEventListener these days, you don't need all the additional boilerplate. And the above could be written like.
'use strict';
const element = document.getElementById('test');
const keys = ' 0123456789';
element.addEventListener('keypress', (e) => {
if (keys.includes(e.key) === false) {
e.stopPropagation();
e.preventDefault();
}
}, false);
<input id="test" type="text" />
Info:
keypress
KeyboardEvent
Event.stopPropagation
Event.preventDefault
Use html5 input type="tel" attribute (http://www.w3schools.com/tags/tag_input.asp).
I have a JS function that checks and restricts certain characters typed in input forms.
The code look like this:
var alphaOnly = /[sA-Za-z\söÖäÄüÜ]/g;
var alphaextraOnly = /[A-Za-z\-&/'"\öÖäÄüÜ]/g;
var alphadigitsOnly = /[sA-Za-z\söÖäÄüÜ\s1234567890]/g;
var digitsOnly = /[1234567890]/g;
var integerOnly = /[0-9\.]/g;
var mailOnly = /[a-z\.#]/g;
function restrictCharacters(myfield, e, restrictionType) {
if (!e) var e = window.event
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
var character = String.fromCharCode(code);
// if they pressed esc... remove focus from field...
if (code==27) { this.blur(); return false; }
// ignore if they are press other keys
// strange because code: 39 is the down key AND ' key...
// and DEL also equals .
if (!e.ctrlKey && code!=9 && code!=8 && code!=36 && code!=37 && code!=38 && (code!=39 || (code==39 && character=="'")) && code!=40) {
if (character.match(restrictionType)) {
return true;
} else {
return false;
}
}
}
It works when I add onkeypress to input like this:
<input type="text" class="span4 register_input" id="firma" name="firma" onkeypress="return restrictCharacters(this, event, alphaOnly);" />
But I want to do that with getElementById in the script. I tried to add this:
window.onload = function() {
document.getElementById("firma").onkeypress = restrictCharacters(this, event, alphaOnly);
}
But it didn't work... Help please.
You can't pass the arguments like that to onkeypress you would need to use a wrapper function
document.getElementById("firma").onkeypress = function (e)
{
return restrictCharacters(this,e,alphaOnly);
};
jsFiddle http://jsfiddle.net/BjU2e/5/
You are assigning to onkeypress the result of restrictCharacters(this,event,alphaOnly) instead of a function delegate. A correct version is in the following jsFiddle : http://jsfiddle.net/xL47r/1/
For future reference :
document.getElementById("firma2").onkeypress = function(e) {
return restrictCharacters(this,e,alphaOnly);
};
You can get this from e.target
document.getElementById("firma").onkeypress = function(e) {
restrictCharacters(e.target,e,alphaOnly);
}
document.getElementById("firma").onkeypress = function(){
return restrictCharacters.call(this/*becauseof 'this.blur()' */, this,event,alphaOnly);
};
You have wrong syntex to bind event with dom .here it is : window.onload = function () {
var ab = document.getElementById("firma");
ab.setAttribute("onkeypress", "restrictCharacters(this,event, true)");
}