Stopping a function inside a namespace - javascript

I have a namespace with a method to stop some characters being entered on a keypress event for inputs. If the character is detected, it returns false but I think that because it's called when the keypress is fired, the character still gets entered. How do I fix this problem?
If I take the function out of the namespace it works as intended but I don't want that.
HTML
<div id="personal-info">
<input id="first-name" class="personal-info" autofocus/><p id="error-first-name" class="error-text"></p>
<input id="last-name" class="personal-info"/><p id="error-last-name" class="error-text"></p>
</div>
Javascript:
fsa = (function() {
//OK - get selected element ID and write ID
var inputId = "";
var sigId = "";
var errId = "";
function GetAndSetLoc() {
inputId = document.activeElement.id;
sigId = "sig-" + document.activeElement.id;
errId = "error-" + document.activeElement.id;
}
var thisId = "";
// on button down, if the character is illegal, change the css of the error box
function showError(keyCode) {
var keys = [13,
"<".charCodeAt(0),
">".charCodeAt(0),
"$".charCodeAt(0),
"(".charCodeAt(0),
")".charCodeAt(0),
"?".charCodeAt(0),
"{".charCodeAt(0),
"}".charCodeAt(0),
"/".charCodeAt(0),
"#".charCodeAt(0),
"&".charCodeAt(0),
"*".charCodeAt(0),
"#".charCodeAt(0),
"~".charCodeAt(0)
];
var index;
for (index = 0; index < keys.length; ++index) {
if (keys[index] === keyCode) {
errorObject = $('#' + errId);
errorObject.html("Sorry, invalid character.").addClass('error');
setTimeout(function() {
errorObject.html("Sorry, invalid character.").removeClass('error');
}, 2000);
return false;
}
}
}
return {
GetAndSetLoc: GetAndSetLoc,
showError: showError
}
})();
// --------- Call the functions
//OK - get current read and write ids
$('.personal-info').focus(function(){
fsa.GetAndSetLoc();
});
$("input").keypress(function(e) {
fsa.showError(e.keyCode);
});

return false from keypress event in case of error
$("input").keypress(function(e) {
return fsa.showError(e.keyCode);
});

Related

Why dies JQuery throw a syntax error on compound names? [duplicate]

This question already has answers here:
jQuery dot in ID selector? [duplicate]
(6 answers)
Closed 2 years ago.
I'm working on a legacy web app, that's using JQuery.
There's a place where we're trying to save all of the form data to local storage, before we redirect to a different page, so that we can restore it when we return.
This pattern is working on a number of pages:
$(document).ready(function () {
var searchForm = $('form.full-investigation');
var searchFormElements = searchForm.find(':input');
var saveSearchElements = function saveSearchElements() {
var saveData = [];
searchFormElements.each(function(index, element) {
var item = $(element);
var name = element.name;
var value = item.val();
var type = element.type;
var add = true;
if (type === "checkbox") {
value = element.checked;
} else if (type === "radio") {
if (!element.checked) {
add = false;
}
}
if (add) {
saveData.push({ name: name, value: value });
}
});
var serialized = JSON.stringify(saveData);
sessionStorage.setItem('FullInvestigation_criteria', serialized);
};
var loadSearchElements = function loadSearchElements(serializedForm) {
var foundOne = false;
if (serializedForm) {
var saveData = JSON.parse(serializedForm);
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name;
var value = saveData[i].value;
try {
var element = searchForm.find(':input[name=' + key + ']');
if (element.length > 1) {
for (var j = 0; j < element.length; j++) {
var each = element[j];
var type = each.type;
if (type === 'radio' && each.value === value) {
each.checked = true;
foundOne = true;
}
}
} else {
element.val(value);
if (value)
foundOne = true;
}
} catch (e) {
var msg = e;
}
}
}
return foundOne;
};
$("#redirectbutton").on('click',
function(event) {
try {
saveSearchElements();
} catch (e) {
}
});
var fullInvestigation_criteria = sessionStorage.getItem('FullInvestigation_criteria');
loadSearchElements(fullInvesigation_criteria);
sessionStorage.setItem('FullInvesigation_criteria', '{}');
});
As I said, this is working on a number of pages.
But when I try to use it on a different page, where it had not been used before, I'm getting syntax errors. The problem is that on this new page, saveSearchElements() encounters :input elements with dotted names. E.g., ticketAndMarking.actualnearinter. So we're saving name/value pair with a key of "ticketAndMarking.actualnearinter"
So when we process that key in
And then when we call loadSearchElements, and it processes that key, the line:
var element = searchForm.find(':input[name=' + key + ']');
throws an exception with the message:
Syntax error, unrecognized expression: :input[name=ticketAndMarking.actualnearinter]
I was asking this question for the group, but found the answer before I posted.
So here it is, in case anyone else runs into something similar:
jQuery dot in ID selector?
Having a period in an element name is perfectly acceptable. But JQuery selector syntax requires that they be escaped.
The fix in the code above is simple:
for (var i = 0; i < saveData.length; i++) {
var key = saveData[i].name.replace(".", "\\.");
var value = saveData[i].value;

Access array in if statement

I have JavaScript calculator wherein I have defined two arrays as follows:
var degInc, degArr = [];
var radInc, radArr = [];
var PI = Math.PI;
var radStart = (-91*PI/2), radEnd = (91*PI/2);
for (degInc = -8190; degInc <= 8190; degInc+=180) {
degArr.push(degInc);
}
for (radInc = radStart; radInc <= radEnd; radInc+=PI) {
var radIncFixed = radInc.toFixed(8);
radArr.push(radIncFixed);
}
to be used in conjunction with the tangent function (below) so as to display a value of Undefined in an input (HTML below) should the user attempt to take the tangent of these values (I have included other relavent function as well):
Input -
<INPUT NAME="display" ID="disp" VALUE="0" SIZE="28" MAXLENGTH="25"/>
Functions -
function tan(form) {
form.display.value = trigPrecision(Math.tan(form.display.value));
}
function tanDeg(form) {
form.display.value = trigPrecision(Math.tan(radians(form)));
}
function radians(form) {
return form.display.value * Math.PI / 180;
}
with jQuery -
$("#button-tan").click(function(){
if (checkNum(this.form.display.value)) {
if($("#button-mode").val() === 'DEG'){
tan(this.form); // INSERT OTHER 'if' STATEMENT HERE FOR RAD ARRAY
}
else{
tanDeg(this.form); // INSERT OTHER 'if' STATEMENT HERE FOR DEG ARRAY
}
}
});
I would like to incorporate an array check within the .click function such that if the user input is contained in the array (degArr or radArr depending on the mode), the calculator returns Undefined. Now, I know how to display Undefined in the input display ($('#disp').val('Undefined')), but I cannot figure out how to configure an if statement that checks the relevant array. Is there a way to do so within the #button-tan function where I have commented?
Loop through the arrays on click and set a variable if you find a matched value.
You can do something like this:
$("#button-tan").click(function(e) {
e.preventDefault();
var userInput = $('#disp').val();
var buttonMode = $('#button-mode').val();
var displayVal = '';
if (buttonMode === 'DEG') {
var radFound = false;
radArr.forEach(function(item) { // changed from degArr
if (item === userInput) {
radFound = true;
}
if (radFound) {
displayVal = 'undefined';
} else {
tan(this.form);
}
});
} else {
var degFound = false;
degArr.forEach(function(item) {
if (item === userInput) {
degFound = true;
}
if (degFound) {
displayVal = 'undefined';
} else {
tanDeg(this.form);
}
});
}
});
You could create a simple object of a Calculator class, which keeps a reference to these arrays, and use like this. I changed some methods to receive the input as parameter rather than form.
$(function () {
function Calculator()
{
var degInc;
this.degArr = [];
var radInc;
this.radArr = [];
var PI = Math.PI;
var radStart = (-91*PI/2);
var radEnd = (91*PI/2);
for (degInc = -8190; degInc <= 8190; degInc+=180) {
this.degArr.push(degInc);
}
for (radInc = radStart; radInc <= radEnd; radInc+=PI) {
var radIncFixed = radInc.toFixed(8);
this.radArr.push(radIncFixed);
}
}
var calc = new Calculator();
function tan(input) {
alert("tan called");
var value = Math.tan(input.value);
alert("tan called. value: " + value);
input.value = value;
}
function tanDeg(input) {
alert("tanDeg called");
var value = Math.tan(radians(input));
alert("tanDeg called. value: " + value);
input.value = value;
}
function radians(input) {
alert("radians called");
var value = input.value * Math.PI / 180;
alert("radians called. value: " + value);
return value;
}
$("#button-tan").click(function(){
alert (calc.degArr);
alert (calc.radArr);
var displayInput = $("#disp");
alert("user input: " + displayInput.val());
if (!isNaN(displayInput.val()))
{
if($("#button-mode").val() === 'DEG')
{
if (calc.radArr.indexOf(displayInput.val()) > -1)
{
alert("user input is in radArr");
}
else
{
alert("user input IS NOT in radArr");
tan(displayInput);
}
}
else
{
if (calc.degArr.indexOf(displayInput.val()) > -1)
{
alert("user input is in degArr");
}
else {
alert("user input IS NOT in degArr");
tan(displayInput);
}
}
}
else
alert("Not a number in input");
});
});
If you wanna do some tests, I created a JSFiddle demo here. Type -8190 in the first input, then click the button. It's gonna be inside the array. Then try typing "DEG" in the second input and clicking again, you'll notice code will check against another array (due to IFs). I couldn't make your auxiliar functions to calculate a value, but I think this helps you with your initial problem.
indexOf should work...
$("#button-tan").click(function(){
if (checkNum(this.form.display.value)) {
if($("#button-mode").val() === 'DEG'){
if (radArr.indexOf(Number(this.form)) > -1) {
$('#disp').val('Undefined');
} else {
tan(this.form);
}
}
else{
if (degArr.indexOf(Number(this.form)) > -1) {
$('#disp').val('Undefined');
} else {
tanDeg(this.form);
}
}
}
});

How do I invoke my function on keyup?

I have a JavaScript function that I want to fire once the user enters text inside an input element. Currently I can only see the function firing if I console.log it. How do I get it to fire using keyup method?
The relevant code is below.
var $ = function (selector) {
var elements = [],
i,
len,
cur_col,
element,
par,
fns;
if(selector.indexOf('#') > 0) {
selector = selector.split('#');
selector = '#' + selector[selector.length -1];
}
selector = selector.split(' ');
fns = {
id: function (sel) {
return document.getElementById(sel);
},
get : function(c_or_e, sel, par) {
var i = 0, len, arr = [], get_what = (c_or_e === 'class') ? "getElementsByClassName" : "getElementsByTagName";
if (par.length) {
while(par[I]) {
var temp = par[i++][get_what](sel);
Array.prototype.push.apply(arr, Array.prototype.slice.call(temp));
}
} else {
arr = par[get_what](sel);
}
return (arr.length === 1)? arr[0] : arr;
}
};
len = selector.length;
curr_col = document;
for ( i = 0; i < len; i++) {
element = selector[i];
par = curr_col;
if( element.indexOf('#') === 0) {
curr_col = fns.id(element.split('#'[1]));
} else if (element.indexOf('.') > -1) {
element = element.split('.');
if (element[0]) {
par = fns.get('elements', element[0], par);
for ( i =0; par[i]; i++) {
if(par[i].className.indexOf(element[1]> -1)) {
elements.push(par[i]);
}
}
curr_col = elements;
} else {
curr_col = fns.get('class', element[1], par);
}
} else {
curr_col = fns.get('elements', element, par);
}
}
return elements;
};
You need to bind your method to the keyup event on the page.
You could try
document.addEventListener('keyup', $)
Or assuming you have the input element as element you could do
element.addEventListener('keyup', $)
Your function will be passed the event which you could use to investigate the state of the element if you needed that information to trigger or not trigger things in the function.
Here's a quick sample where the function that get's run on keypress is changeColor.
var COLORS = ['red', 'blue','yellow', 'black']
var NCOLORS = COLORS.length;
function changeColor(ev) {
var div = document.getElementById('colored');
var colorIdx = parseInt(Math.random() * NCOLORS);
console.log(colorIdx);
var newColor = COLORS[colorIdx];
div.style.color = newColor
console.log("New color ", newColor)
}
document.body.addEventListener('keyup', changeColor)
Though I'm not using the event (ev), I like to show, in the code, that I expect that variable to be available.
See it in action here - http://codepen.io/bunnymatic/pen/yyLGXg
As a sidenote, you might be careful about calling your function $. Several frameworks (like jQuery) use that symbol and you may run into conflicts where you're overriding the global variable $ or where the framework overrides your version if it.

charAt is not a function

I'm trying to create a key mapping that keeps track of the frequency for each character of a string in my createArrayMap() function but I keep getting this error from firebug: TypeError: str.charAt(...) is not a function
I found the charAt() function on Mozilla's developer website it should be a function that exists.
var input;
var container;
var str;
var arrMapKey = [];
var arrMapValue = [];
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
}
function createArrayMap() {
str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.find(str.charAt(i)) == undefined) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
function keyPressHandler() {
createArrayMap();
console.log(arrMapKey);
console.log(arrMapValue);
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value == "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
The problem is not with String.charAt(), but with Array.find().
The first argument to find is a callback, but the result of str.charAt(i) is a character and not a callback function.
To search for an element in your array, you could use Array.indexOf() as #adeneo already suggested in a comment
function createArrayMap() {
var str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.indexOf(str.charAt(i)) == -1) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
See JSFiddle
You're not going about things in the most efficient manner... What if you changed it to look like this so you are continually updated with each keypress?
var keyMap = {};
...
input.onkeyup = keyPressHandler;
function keyPressHandler(e) {
var char = String.fromCharCode(e.keyCode);
if(!(char in keyMap))
keyMap[char] = 1;
else
keyMap[char]++;
}
This has been answered, but here's my version of your problem JSBIN LINK (also has an object option in addition to the array solution).
I moved some variables around so you'll have less global ones, added comments, and mocked with the output so it'll show it on the page instead of the console.
besides the Array.find() issues, you weren't initializing your arrays on the build method, and so, you would have probably ended with the wrong count of letters.
HTML:
<div id="container">
<textArea id="inputbox"></textArea></div>
<p id="output">output will show here</p>
JS:
var input, // Global variables
container, //
output; //
/**
* Initialize components
*/
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
output = document.getElementById("output");
}
/**
* Creates the letters frequency arrays.
* Note that every time you click a letter, this is done from scratch.
* Good side: no need to deal with "backspace"
* Bad side: efficiency. Didn't try this with huge texts, but you get the point ...
*/
function createArrayMap() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
arrMapKey = [], // our keys
arrMapValue = []; // our values
for (var i = 0 ; i <len ; i++) {
// These 2 change each iteration
tempChar = tempStr.charAt(i);
index = arrMapKey.indexOf(tempChar);
// If key exists, increment value
if ( index > -1) {
arrMapValue[index]++;
}
// Otherwise, push to keys array, and push 1 to value array
else {
arrMapKey.push(tempChar);
arrMapValue.push(1);
}
}
// Some temp output added, instead of cluttering the console, to the
// a paragraph beneath the text area.
output.innerHTML = "array keys: "+arrMapKey.toString() +
"<br/>array values:"+arrMapValue.toString();
}
function keyPressHandler() {
createArrayMap();
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value === "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
BTW, as the comments suggest, doing this with an object will is much nicer and shorter, since all you care is if the object has the current char as a property:
/**
* Same as above method, using an object, instead of 2 arrays
*/
function createObject() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
freqObj = {}; // our frequency object
for (var i = 0 ; i <len ; i++) {
tempChar = tempStr.charAt(i); // temp char value
if (freqObj.hasOwnProperty(tempChar))
freqObj[tempChar]++;
else
freqObj[tempChar] = 1;
}
}

need to pass variable to function

I am trying to pass a variable to a a function that I believe calls another function (I think) but am having problems. The variable I need to use in the second function is productid but several ways thAt I have tried have not worked. either a fix in javascript or Jquery will be great!!!
This is the line that I need the variable for
var error_url = '/ProductDetails.asp?ProductCode' + productid;
this is where the variable originates from...
var productid = form.elements['ProductCode'].value;
and here is the whole js code
function addToCart2(form, button) {
var softAdd = true;
var productid = form.elements['ProductCode'].value;
var qstr;
var bttnName = button.name;
button.disabled = true;
if (form.elements['ReturnTo']) {
form.elements['ReturnTo'].value = "";
}
qstr = serialize(form, bttnName + '.x', '5', bttnName + '.y', '5');
sendAjax('POST','/ProductDetails.asp?ProductCode=' + productid + '&AjaxError=Y', qstr , retrieveProductError2 ,displayServerError,false);
button.disabled = false;
return false;
}
function retrieveProductError2(result, statusCode) {
var ele = document.getElementById('listOfErrorsSpan');
var errorIndex = result.indexOf('<carterror>');
var productIndex = result.indexOf('<ProductIndex>')
if (errorIndex > -1 && productIndex == -1) {
var error_url = '/ProductDetails.asp?ProductCode' + productid;
window.location = error_url;
}
if (errorIndex != -1) {
//ele.innerHTML = result.slice(errorIndex + 11, result.indexOf('</carterror>'));
}
else {
ele.innerHTML = "";
if (productIndex == -1) {
sendAjax('GET','/AjaxCart.asp?GetIndex=True', '', showCart, null, false);
}
else {
productIndex = result.slice(productIndex + 14, result.indexOf('</ProductIndex>'));
sendAjax('GET','/AjaxCart.asp?Index=' + productIndex, '', showCart, null, false);
}
}
}
The easiest way is to just move your variable declaration outside of your method. So change the declaration of product id outside your addToCart2 method. So outside of that method you do this:
var product_id;
Then inside your method remove var from product_id and it will just be an assignment and not declaration.
Where you pass in retrieveProductError2 as your error callback for the sendAjax call, you could instead pass in:
function(result, statusCode) { retreiveProductError2(result, statusCode, productId);}
Then change the definition of your retreiveProductError2 function to accept the additional parameter.

Categories