jQuery if statement triggered twice - javascript

I'm attempting to write a read only values in a html input using jQuery, and I've run into a problem where a single if statement fires twice.
Basically the input starts with a default value in the html [this is the readonly value]:
<input id="main-field" type="text" value="dan" >
Then, a jQuery 'keypress keydown' function checks the index of the pressed key in relation to the readonly word and if the index is before or after the word it returns 'true' which will add the characters, otherwise it will return false which will prevent adding chars. The problem is that if I type before the word it increases the index of the readonly word twice, where it should be increased by one (since the readonly word has moved by one index for each char).
Here's the 'keypress keydown' function; hopefully it's easy to understand (let me know if not, I want to get better at that as well):
var readOnlyEnd = $('#main-field').val().length,
readOnlyStart = 1;
$('#main-field').on('keypress keydown', function(event) {
var character = String.fromCharCode(event.keyCode).toLowerCase();
// note: using the jquery caret plugin
var pos = $('#main-field').caret();
// handling new character between 'a' and 'z' and the delete char.
if (((character >= 'a') && (character <= 'z')) || (event.which == 8)) {
// if delete is pressed:
if (event.which == 8) {
if (pos == readOnlyEnd) return false;
else if (pos < readOnlyStart) {
if (pos == 0) return true;
if (pos > 0) {
console.log('reudce index!!');
// Will reduce indexes.
readOnlyStart -= 1;
readOnlyEnd -= 1;
return true; // Will delete.
}
}
else if ((pos >= readOnlyStart) && (pos < readOnlyEnd)) return false;
}
// within the word.
else if ((pos >= readOnlyStart) && (pos < readOnlyEnd)) return false;
// before the readonly word. - HERE IS THE PROBLEM, INCREASING TWICE.
else if (pos < readOnlyStart) {
readOnlyStart += 1;
readOnlyEnd += 1;
return true; // Will add character
}
else {
return true;
}
}
else {
// In case something that doesn't affect the input was pressed (like left/right arrows).
return true;
}
});
Note: I'm using the jQuery caret plugin for the cursor place.
Please let me know if you have any ideas or suggestions, or if the solution to my problem is similar to a solution to another problem on here

You should use only one event. Either keypress or keydown in following statement:
$('#main-field').on('keypress keydown', function(event) {
This will fire event twice on a single key press.
So, change your statement to:
$('#main-field').on('keypress', function(event) {

Related

Checking if a letter in a String is Upper Case

I am trying to complete the Caesar Cipher in JavaScript. I need a peice of code that checks to see if a letter in a string is upper case or lower case.
const caesar = function(str) {
for (i = 0; i < str.length; i++) {
if (str[i] === str[i].toUpperCase) {
console.log('YES');
} else {
console.log('NO');
}
}
}
caesar("HeLLO")
Where am I going wrong?
UPDATE: Additional Question
Here is my full code - I swapped out my check for str[i] = str[i].toUpperCase() TO 64 < asciiNum < 91 but the check doesn't work.
Any idea why using ASCII numbers to check for capital is not working in this instance?
const caesar = function(str, shift) {
var solved = "";
for (i=0; i < str.length; i++){
var asciiNum = str[i].charCodeAt();
console.log(asciiNum);
if (64 < asciiNum < 91) { // check for upper cased
newNum = asciiNum + shift;
if(newNum > 90){
solved += String.fromCharCode(newNum - 26);
} else {
solved += String.fromCharCode(newNum);
}
} else if (96 < asciiNum < 123) { //check for lower case
newNum = asciiNum + shift;
if(newNum > 122){
solved += String.fromCharCode(newNum - 26);
} else {
solved += String.fromCharCode(newNum);
}
}
}
console.log(solved);
}
caesar("Hello, World!", 5);
Your issue was you weren't calling toUpperCase(). The computer saw it but didn't know it was supposed to run the function. To fix it, just put parentheses.
However, to make it cleaner, I'd restructure this like so:
// Gets a string from the user to test
// Replace this with whatever string should be tested (probably a variable)
var str = prompt("What string should be tested?");
const caesar = function(arg) {
return arg.split("").every(function(e) {
/* Makes an array of characters and tests to see
if every character satisfies the conditions */
if (e === e.toUpperCase()) { // If the character is upper case
return true; // Return true; the program should test the next character
} else {
console.log(`${e} was not uppercase`);
return false;
// Return false
// The program should stop, because it detected a lowercase character
}
});
}
console.log(`The result of running caesar() on string '${str}' was ${caesar(str)}`);
/* Instead of using console.log inside the function
Return the *result* of the function so that you can use it later */
This method is faster to run and a little cleaner.
If you want to check if every letter is uppercase, leave it as it is. If you want to check if some letters are uppercase, change the every to some. If you want to reverse and check if all characters (or some) are lowercase, replace the e === e.toUpperCase() with e === e.toLowerCase() or e !== e.toUpperCase(). If a letter is not uppercase, it puts which one it was in the console and stops checking others. After it's finished, it puts whether all were uppercase in the string.
Only missing part in your code is a paranthesis () in toUpperCase.
You're missing parentheses after toUpperCase.
if (str[i] === str[i].toUpperCase) {
For JS you're trying to access a toUpperCase property instead call a function.

Wrapping a word in a textarea that has a per-line character limit and a total-line-number limit

I implemented a previous answer given here, and now I need to automatically wrap the word around the line instead of always having to manually press the enter key. Any ideas? I'm having quite a bit of trouble with this.
Code:
jQuery('#gift-message-whole-message').on('keypress', function (event) {
var text = jQuery('#gift-message-whole-message').val();
var lines = text.split('\n');
var currentLine = this.value.substr(0, this.selectionStart).split('\n').length;
if (event.keyCode == 13) {
if (lines.length >= jQuery(this).attr('rows')) return false;
} else {
if (lines[currentLine - 1].length >= jQuery(this).attr('cols')) {
return false;
}
}
});
Here is the working fiddle for your case.
I slightly changed the else branch as follows:
if (lines[currentLine - 1].length >= ($(this).attr('cols') - 1)) {
$('textarea').val($('textarea').val() + "-\n");
// return false; // prevent characters from appearing
}
As you can see in the fiddle, code adds a - and a new line, when typed text reaches to col limit. Then it goes on on the next line as user types.

validate input with decimal precision and scale

I am trying to create a javascript function which is called on keypress event on a input which does the following:
Input should be a valid decimal with format (5,2) => (XXXXX.YY) which are variable to the function. Input is restricted if user adds any value which does not conform to the format above.
If existing input starts with . append 0 to the starting automatically
HTML
<input type="text" onkeypress="return checkDecimal(event, this, 5, 2);" id="price2" value="27.15">
Javascript
function checkDecimal(evt, item, lenBeforeDecimal, lenAfterDecimal) {
var charCode = evt.which;
var trimmed = $(item).val().replace(/\b^0+/g, "");
if(checkStartsWith(trimmed, '.') == true){
trimmed = '0' + trimmed;
}
//Allow following keys
//8 = Backspace, 9 = Tab
if(charCode == 8 || charCode == 9){
return true;
}
//Only a single '.' is to be allowed
if(charCode == 46){
var dotOccurrences = (trimmed.match(/\./g) || []).length;
if(dotOccurrences != undefined && dotOccurrences == 1){
return false;
}else{
return true;
}
}
if (charCode > 31 && ((charCode < 48) || (charCode > 57))) {
return false;
}
if ($(item).val() != trimmed){
$(item).val(trimmed);}
//Check the start and end length
if(trimmed.indexOf('.') == -1){
if(trimmed.length >= parseInt(lenBeforeDecimal)){
return false;
}
}else{
var inputArr = trimmed.split(".");
if(inputArr[0].length > parseInt(lenBeforeDecimal) || inputArr[1].length >= parseInt(lenAfterDecimal)){
return false;
}
}
return true;
}
function checkStartsWith(str, prefix){
return str.indexOf(prefix) === 0;
}
Issues
If user inputs 12345.9 and then moves the caret position after 5, user is able to add another digit before the decimal 123456.9 which should not be allowed.
If user inputs 1.9 and then remove 1 and add 5, 5 is added at the end and the entered value becomes 0.95 and not 5.9
JS Fiddle
Consider using a regular expression like:
/^(\d{0,5}\.\d{0,2}|\d{0,5}|\.\d{0,2})$/;
that allows everything up to and including your required format, but returns false if the number part is more than 5 digits or if the fraction is more than 2 digits, e.g.:
<input type="text" onkeyup="check(this.value)"><span id="er"></span>
<script>
function check(v) {
var re = /^(\d{0,5}\.\d{0,2}|\d{0,5}|\.\d{0,2})$/;
document.getElementById('er').innerHTML = re.test(v);
}
</script>
You'll need separate validation for the final value, e.g.
/^\d{5}\.\d{2}$/.test(value);
to make sure it's the required format.
I don't understand the requirement to add a leading zero to "." since the user must enter 5 leading digits anyway (unless I misunderstand the question).

JavaScript on IE and Chrome? (It works on Firefox)

function ord(string) {
var str = string + '',
code = str.charCodeAt(0);
if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
var hi = code;
if (str.length === 1) {
return code; // This is just a high surrogate with no following low surrogate, so we return its value;
// we could also throw an error as it is not a complete character, but someone may want to know }
var low = str.charCodeAt(1);
return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
}
if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate return code; // This is just a low surrogate with no preceding high surrogate, so we return its value;
// we could also throw an error as it is not a complete character, but someone may want to know
}
return code;
}
}
$(document).ready(function () {
var maxTxtNumber = 8;
var arrTxtNumber = new Array();
var txtvalues = new Array();
var arr = {};
$('.numericonly').keypress(function (e) {
var t = $(this).val();
var k = e.which;
delete arr[8];
if ((e.which >= 49 && e.which <= 55) || e.which == 8) {
if (e.which == 8) {
var s = new String(t);
s = s.charCodeAt(0);
delete arr[s];
}
if (arr[k]) {
e.preventDefault();
} else {
arr[k] = e.which;
}
} else {
e.preventDefault();
}
});
});
The code works on Firefox but not on IE and Chrome?
Other browsers use e.keyCode to tell you which key was pressed. Cross-browser:
var k = e.keyCode || e.which;
Also make sure you use k rather than repeating e.which every time.
All that code is not required. If you want to test that an input's value is only digits, then something like the following will do:
<input type="text" onblur="check(this);" ...>
function check(el) {
if (!isDigits(el.value)) {
alert('Hey!!\nThe element you just left should only contain digits');
}
}
function isDigits(s) {
return /^\d*$/.test(s);
}
It's much more friendly to give the user a hint about the format you require and wait until they either leave the control or submit the form before offering a warning about invalid values. You really don't care how the user gets to a valid value, just so long as it's valid when the form is submitted.
And you must validate on the server again.
I recommend running your code through a validator such as http://www.jslint.com/ to make sure that everything adheres to universal standards.

How to pass parameter to mousewheel event?

for (var n = 0; n < 10; n++) {
$('#content-scroll' + n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(n - 1);
else if (delta < 0) sliderDown(n - 1);
return false; // prevent default
});
n++;
}
I have a problem with this code, variable "n" is not passed right to the mouswheel function which will add mousewheel only to number 9 (last number) and not to all 10 elements.
Can anyone explain how to pass a variable to this function so that it stays?
My take on this using a fully jQuery solution.
$("[id^='content-scroll']").mousewheel( function(event,delta) {
var n = this.id.replace(/content-scroll/,'');
if (delta > 0)
sliderUp(n);
else if (delta < 0)
sliderDown(n);
event.preventDefault();
});
EDIT: Actually, I may even try to figure out a way to pass the actual matching control to the slider* functions, but not knowing what they actually do I have no idea how or if that would work.
I believe this is an issue of closures in javascript, the n is actually a reference to the outside n variable. I believe the following should work instead:
for(var n=0;n<10;n++)
{
var localN = n;
$('#content-scroll'+n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(localN-1);
else if (delta < 0) sliderDown(localN-1);
return false; // prevent default
});
//is this really needed??
//n++;
}
This is asked a lot on SO (case in point). You need a closure to "trap" the value of n in each iteration:
for(var n=0;n<10;n++)
{
(function(n){
$('#content-scroll'+n).mousewheel(function(event, delta) {
if (delta > 0) sliderUp(n-1);
else if (delta < 0) sliderDown(n-1);
return false; // prevent default
});
})(n);
}
Are your n values supposed to go from 0-9 or 1-10?
If it's 0-9, change all n-1 expressions to just n.
If it's 1-10, change the for loop to var n=1,n<=10;n++, and all n-1 references to just n.
Also, remove the n++ on the bottom because your for loop already increments the value of n.
The reason that the code doesn't work is because the n variable is not evaluated during the loop.
You are creating an anonymous function in the loop that you pass to the mousewheel function, so the code in the anonymous function isn't executed until the mouse wheel even occurs. By then the value of the n variable is 10, or perhaps something completely different if you are using the variable anywhere else in the code.
If you instead use the Function function to create the function from a string, you can inject the current value of the n variable into the code:
for(var n=0; n<10; n++) {
$('#content-scroll' + n).mousewheel(
Function('event', 'delta',
'if (delta > 0) sliderUp(' + (n-1) + ');' +
'else if (delta < 0) sliderDown(' + (n-1) + ');' +
'return false; // prevent default'
)
);
}
However, should it be (n-1)? Should the mousewheel event for the content-scroll0 element call sliderup(-1)?
JQuery specifically allows the passing of event data, which may, or may not, be of use to you in this case:
for(var n=0;n<10;n++)
{
$('#content-scroll'+n).bind('mousewheel', {index:n}, function(event, delta) {
var innerN = event.data.index;
if (delta > 0) sliderUp(innerN-1);
else if (delta < 0) sliderDown(innerN-1);
return false; // prevent default
});
}

Categories