Textarea input length check in JavaScript - javascript

I'd like to create an SMS gateway which alerts the user each time when 160 chars are written (or pasted). I need to store a variable n containing number of message parts of 160 chars. The code will be like this, just the n needs to be stored globally. Is there any better way than e. g. storing it into a hidden form field?
Note: an assumption that less than 160 chars will be pasted at once is safe in this particular case.
window.onload = function() {
var n=1;
var t=document.getElementById('msg');
t.addEventListener('input', function() {
var l=t.value.length;
if(l>n*160){
n++;
alert('Message will be split into '+n+' parts');
}
}, false);
}

As mentioned in my comment, it depends on what you want to do with n ultimately.
If you just want it to show the user a message, you can update the DOM once you've calculated this value.
Your current example doesn't allow the user to delete text after they've typed/pasted it in. A better example would be stateless, i.e. don't compare n to itself, as in my example below:
var t = document.getElementById('msg');
var splitSize = 10;
var n = 1;
t.addEventListener('input', function() {
var nextN = 1;
if (t.value.length > 0) {
nextN = Math.ceil(t.value.length / splitSize);
}
if (n !== nextN) {
n = nextN;
var label = document.getElementById('label');
if (n === 1) {
label.innerHTML = '';
} else {
label.innerHTML = 'The message will be split into ' + n + ' parts';
}
}
});
<p id="label"></p>
<textarea id="msg"></textarea>

Related

JavaScript Dynamically created object undefined

I am doing the freecodecamp algorithmic challenge "Caesars Cipher". I have a problem with my code. I try to generate a lookup table as a dynamic object and for some reason it doesn't register. When doing console.log it is says "lookup table is undefined". It is the same with the Acode variable. If I comment out the console.logs then it will work but it will not encrypt anything because of the below part which checks if the char from strArr exists in the lookupTable, if not, it should assign the same value to the encryptedArr (this was done to not encrypt commas, spaces etc):
strArr.forEach(function(thisArg) {
var newValue;
if(lookupTable[thisArg] !== undefined ) {
newValue = lookupTable[thisArg];
} else {
newValue = thisArg;
}
encryptedArr.push(newValue);
});
Ofcourse lookupTable[thisArg] is always undefined.
Here is the whole function with the above part as well:
function rot13(str) { // LBH QVQ VG!
var strArr;
var encryptedArr = [];
var Acode;
var lookupTable = {}; //this object will contain the mapping of letters
var encryptedString;
//check the code of A , this will be a reference for the first letter as the algorith will use Modular Arithmetic
Acode = 'A'.charCodeAt(0);
console.log(Acode);
//generate an object containing mappings (I din't want to do it initially but theoreticaly just making lookups in a table would be more efficiant for huge workloads than calculating it every time)
//this algorithm is a little bit complecated but i don't know how to do modular arithmetic in code properly so I use workarrounds. If a = 101 then I do 101 + the remainder from current letter((Acode + 1) - 13) divided by 26 which works
for (i = 0; i < 26; i++) {
lookupTable[String.fromCharCode(Acode + i)] = String.fromCharCode(Acode + ((Acode + i) - 13) % 26);
console.log(lookupTable[String.fromCharCode(Acode + i)]);
}
//save the string into the array
strArr = str.split("");
//change letters into numbers and save into the code array
strArr.forEach(function(thisArg) {
var newValue;
if (lookupTable[thisArg] !== undefined) {
newValue = lookupTable[thisArg];
} else {
newValue = thisArg;
}
encryptedArr.push(newValue);
});
encryptedString = encryptedArr.join("");
return encryptedString;
}
// Change the inputs below to test
rot13("SERR PBQR PNZC");
console.log(Acode);
What am I doing wrong with the lookupTable object creation AND with the below?
Acode = 'A'.charCodeAt(0);
There's no undefined variable. The problem with your code is in how you calculate the lookup table entries. Your code is mapping every character to itself, not shifting by 13. The correct formula is
Acode + ((i + 13) % 26)
Acode is the ASCII code for the letter, and you shouldn't be including that when performing the modular shift. You just want to apply the modulus to the offset from the beginning of the alphabet after shifting it by 13.
function rot13(str) { // LBH QVQ VG!
var strArr;
var encryptedArr = [];
var Acode;
var lookupTable = {}; //this object will contain the mapping of letters
var encryptedString;
//check the code of A , this will be a reference for the first letter as the algorith will use Modular Arithmetic
Acode = 'A'.charCodeAt(0);
// console.log(Acode);
//generate an object containing mappings (I din't want to do it initially but theoreticaly just making lookups in a table would be more efficiant for huge workloads than calculating it every time)
//this algorithm is a little bit complecated but i don't know how to do modular arithmetic in code properly so I use workarrounds. If a = 101 then I do 101 + the remainder from current letter((Acode + 1) - 13) divided by 26 which works
for (i = 0; i < 26; i++) {
lookupTable[String.fromCharCode(Acode + i)] = String.fromCharCode(Acode + ((i + 13) % 26));
// console.log(lookupTable[String.fromCharCode(Acode + i)]);
}
//save the string into the array
strArr = str.split("");
//change letters into numbers and save into the code array
strArr.forEach(function(thisArg) {
var newValue;
if (lookupTable[thisArg] !== undefined) {
newValue = lookupTable[thisArg];
} else {
newValue = thisArg;
}
encryptedArr.push(newValue);
});
encryptedString = encryptedArr.join("");
return encryptedString;
}
// Change the inputs below to test
var result = rot13("SERR PBQR PNZC");
console.log(result);

Make field required based on dropdown

I'm hoping for some help getting around an issue I just can't seem to solve.
I need to make a field required based on a value of "new" in a select box. I have googled, and looked at some questions here, but can't seem to get it to work in my case.
Here's my current code, which doesn't quite seem to work - I keep getting undefined for dd, and for the builder fields.
function selection() {
alert("got in");
var x;
var number_of_input = $("#formtable select").length;
alert(number_of_input);
for (var i = 1; i < number_of_input; i++) {
if (i > 1) { x = (i * 9) + 5; }
else { x = 14 };
alert(x);
var name = "vnew_or_resold" + x;
var sel = document.getElementById(name);
var opt = sel.options[sel.selectedIndex];
var dd = opt.text;
alert(dd);
var builder = "vbuilder_name" + (x + 1);
alert(builder);
var build = builder.val();
alert(build);
if (dd == "new") {
if (build == "") {
alert('Mandatory');
return false;
}
}
}
return true;
}
I have include the "alerts" because I need to see the values that are being inputted.
Also, the values of x in the for loop work...there are six static fields then 9 static in a table, and 9 in an unlimited number of dynamic rows. The x is reading the correct rows - that I know for sure. My problem really starts with the section starting at
var sel = document.getElementById(name);
Additionally, it's not actually going through all the dynamic rows, probably because either true or false are being registered - but I'm not sure.
I appreciate any help in advance.

Currency Exchange - How to call a function within a function from onclick

Stackers: I coded up a foreign exchange calculator (Indian Rupees to US Dollars) with additions for the Indian counting system of crore and lakh. It works well enough as you see here: [Foreign Exchange Calculator][1] .
In order to improve it, I want to figure a way to have the code go out and grab a JSON object with today's exchange rate which is available via API in many places. While I can write a function that gets the exchange rate, I am having no luck getting an onclick call to make it work.
I looked at the jQuery page but couldn't find an answer to this. If I use the load function, the format is this:
$('selector').load('url',callback) {
do some callback of some kind
};
With a simple page, I can get this to work each time, but -
Because I want to trigger the call for the latest exchange rate with an onclick html call, I want to use a function from the onclick. My first question is, what should my selector be? Normally I would direct it to innerHTML via an id or a class but this doesn't seem to work here.
Secondly, it would seem that I should set my code so that when the page loads, it goes out and notes the current exchange rate. Is there a way for JavaScript/jQuery to do this upon page load even if I haven't called on the function yet? Optimally, I would set the variable to today's rate once and save it locally so I only need to update once a day.
Finally, I have set the function call related to the onclick as:
onclick = run(123.45) with 123.45 being today's rate.
is there a way to replace 123.45 with a function, so a function within a function? I want to use today's rate as returned from the jQuery .load method as the argument to populate the run function call. No matter how I try, I can't get it to work. I have searched google and haven't found anything which leads me to believe that I am going about this all wrong.
Thanks for any assistance.
// js logic to run calculator with the assumption that each
// calculation involves some pos or negative number and then
// an operator (+-/*) which always yields a positive number.
// ex: 2 + 2 = (4 elements) adding another number and operator
// ex: / 3.5 is now 6 elements in the array.
arr = [];
var total = 0, rupee;
var box = document.getElementById("display");
//jquery call for current Rupee to USD exhcange rate
var url = "https://api.fixer.io/latest?base=USD";
// BELOW IS THE CODE FROM MY FIRST QUESTION
$(**WHATSHOULDTHISSELECTORBE?**).load(url, function(responseTxt) {
var obj = JSON.parse(responseTxt);
rupee = obj.rates.INR;
});
// end of rupee to dollar call
function run(digit) {
x = box.value;
if (x !== '.' && isNaN(x)) {
box.value = "";
}
box.value += digit;
}
function runPlus() {
var digits = box.value;
if (digits === "") {
return;
}
arr.push(Number(digits)); // tried parseInt but dropped decimal nos.
box.value += "+";
arr.push("+");
console.log(arr);
}
function runMinus() {
var digits = box.value;
if (digits === '') {
arr.push("-");
return;
}
arr.push(Number(digits));
box.value = "";
box.value = "-";
arr.push("-");
console.log(arr);
}
function runMult() {
var digits = box.value;
if (digits === "") {
return;
}
arr.push(Number(digits));
box.value = "";
box.value += "*";
arr.push("*");
console.log(arr);
}
function runDiv() {
var digits = box.value;
if (digits === "") {
return;
}
arr.push(Number(digits));
box.value = "";
box.value += "/";
arr.push("/");
console.log(arr);
}
function runEquals() {
var digits = box.value;
if (digits === "") {
return;
}
arr.push(Number(digits));
arr.push("=");
box.value = "";
total = arr[0];
var ans = calculateArr(arr);
box.value = ans;
}
function runClear() {
box.value = "";
arr = [];
}
function calculateArr(arr) {
for (var i = 0; i < arr.length; i = i + 2) {
if (arr[i + 1] === "+") {
total = total + arr[i + 2];
} else if (arr[i + 1] === "-") {
total = total - arr[i + 2];
} else if (arr[i + 1] === "*") {
total = total * arr[i + 2];
} else if (arr[i + 1] === "/") {
total = total / arr[i + 2];
} else if (arr[i + 1] === "=") {
total = total;
} else alert("Error");
}
return ReplaceNumberWithCommas(total);
}
function ReplaceNumberWithCommas(yourNumber) {
//Seperates the components of the number
var n = yourNumber.toString().split(".");
//Comma-fies the first part
n[0] = n[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
//Combines the two sections
if (n[1]) {
n[1] = n[1].split("").slice(0, 2);
n[1] = n[1].join("");
}
return n.join(".");
}
[1]: http://codepen.io/Qstreet/pen/GovZdg
Since you need to retrieve values automatically on page load , you need to use xhr request.
$.get( "your-url", function( data ) {
$( "where you want to insert it" ).html( data );
//or call your-custom-function(data);
});
If you want to fetch values upon click event , insert above code as a function to jquery click event handler
Thanks so much #Anmol. I got it working with this:
var url = "http://api.fixer.io/latest?base=USD";
function runRup() {
var xhr = new XMLHttpRequest();
xhr.open("GET",url,false);
xhr.send(null);
var rt = JSON.parse(xhr.responseText);
return rt.rates.INR;
};

Keypress event for Japanese text

$(document).ready(function () {
$("#id").keydown(function () {
});
})
This code perfectly works for everything(number,alphabet,symbol etc) except Japanese text. On key press it doesn't pass through this event. Does anybody know any solution?
There's hardly anything you can do. "Japanese text" means an IME, which is a piece of software intercepting the keyboard input and helping you turn it into Japanese text. How this software interacts or doesn't interact with the browser and the browser's Javascript engine depends on the OS, IME, browser and the browser's Javascript engine. On some platforms the keypress is signaled through, in others it isn't. You can try binding to other events like keyup or keypress, some may be signaled even when using an IME.
The best you can do is to make sure you're not depending on keypress events and have fallback options if you can't intercept them; e.g. bind to change events on the text field as well and handle entire text changes, which will be triggered at the end of the IME input.
I got the same issue, instead of prevent user input the text i set the input value to null because the api event.preventDefault(); is not working correctly.
$(document).ready(function () {
$("#id").keyup(function () {
this.value = ''
});
})
I had the same issue and I solved it using the input event.
//calculate the length of a character
function getLen(str){
var result = 0;
for(var i=0;i<str.length;i++){
var chr = str.charCodeAt(i);
if((chr >= 0x00 && chr < 0x81) ||
(chr === 0xf8f0) ||
(chr >= 0xff61 && chr < 0xffa0) ||
(chr >= 0xf8f1 && chr < 0xf8f4)){
//half width counted as 1
result += 1;
}else{
//full width counted as 2
result += 2;
}
}
return result;
};
// trim the string by processing character by character
function getTrimmedString(theString, maxLength){
var tempLength = 0;
var trimmedString = "";
for (var i = 0; i < theString.length; i++) {
tempLength = getLen(theString.charAt(i)) + tempLength;
if(tempLength > maxLength){
break;
}else{
trimmedString = trimmedString + theString.charAt(i);
}
}
return trimmedString;
}
// limit the size of a field
function limitCity(){
var maxChars = 30;
var cityVal = $("#city").val();
var cityLength = getLen(cityVal);
if (cityLength >= maxChars) {
var trimmedString = getTrimmedString(cityVal, maxChars);
$("#city").val(trimmedString);
}
}
//bind the input event
$("#city").bind("input", limitCity);

Modifying Luhn checker function to check for Laser cards

I use the following script to validate the card details entered in a form. I would like to add a function to this so that a visitor using a Laser card is alerted that we don't accept them.
The start digits of the Laser are 6304, 6706, 6771 & 6709
function Calculate(Luhn)
{
var sum = 0;
for (i=0; i<Luhn.length; i++ )
{
sum += parseInt(Luhn.substring(i,i+1));
}
var delta = new Array (0,1,2,3,4,-4,-3,-2,-1,0);
for (i=Luhn.length-1; i>=0; i-=2 )
{
var deltaIndex = parseInt(Luhn.substring(i,i+1));
var deltaValue = delta[deltaIndex];
sum += deltaValue;
}
var mod10 = sum % 10;
mod10 = 10 - mod10;
if (mod10==10)
{
mod10=0;
}
return mod10;
}
function Validate(Luhn)
{
var LuhnDigit = parseInt(Luhn.substring(Luhn.length-1,Luhn.length));
var LuhnLess = Luhn.substring(0,Luhn.length-1);
if (Calculate(LuhnLess)==parseInt(LuhnDigit))
{
return true;
}
alert("\n\nError with your card number! \nPlease check and correct.\n\n")
return false;
I wouldn't modify these functions to check the card type - they have a specific goal. If you change the Validate(Luhn) function so that it fails a card that passes its Luhn check but that has specific starting digits, you're making trouble for yourself later. Instead, add a new function, something like this:
function checkCardType(CardNumber) {
var CardStart = CardNumber.substring(0, 4);
if ((CardStart == '6304') || (CardStart == '6706') || (CardStart == '6771') || (CardStart == '6709')) {
alert('We do not accept Laser cards.');
return false;
} else {
return true;
}
}
Could you just keep a blacklist? You'd need to have a process to keep it up-to-date (e.g. load it from a database, manage it there - keeping it in the source is more hassle in the long term), but for such a small number of items, it would be useful:
function LoadBlacklist() {
// this is the simplest example; you may want to load the array dynamically
var bad_prefixes = [ "6304", "6706", "6771", "6709" ];
return bad_prefixes;
}
function Validate(Luhn)
{
var blacklist = LoadBlacklist();
var luhn_prefix = Luhn.substring(0,4); // only check the first 4 characters
for (var bl_pos = blacklist.length - 1; bl_pos >= 0; bl_pos--) {
if (blacklist[bl_pos] == luhn_prefix) {
// this card matches one of the blacklist prefixes
return false;
}
}
// if we're here, no match was found
// go on with validation...
}

Categories

Resources