Local variables giving global trouble - javascript

I'm a JS super n00b.
I asked about an aspect of this problem in this post (Puzzling behavior from IF ( ) statement) on IF statements but it looks like the actual issue is related to the scope of a variable I've created. It seems that after declaring (what I think is) a global variable, other functions in the code cannot access the variable.
I'm doing JS project/program that prompts a user to input a word and the program reverses the word input.
In the previous post (PP) a user correctly determined that I was getting the 'false' console message (see code) no matter what the length of the word input because I was assigning value the variable when the page loads but not reading it again when the user clicks the button on the page.
If the variable 'word' is local I'm only able to get a 'false' console message and when the variable 'word' is global I'm only able to get a 'ReferenceError.'
Any ideas anyone has are greatly appreciated.
See JS code below:
var word = document.getElementById('wordChoice').value;
var lttrs = [];
function flipFail () {
alert("Please enter a word of at least two characters.");
console.log(false);
var inputErrArr = ['has-error', 'has-feedback'];
var inputErrFdbk = ['glyphicon', 'glyphicon-remove'];
wordChoice.style.backgroundColor = "#FFDBAA";
for (var i = 0; i < inputErrArr.length; i ++) {
addClass(wordInput, inputErrArr[i]);
}
for (var i = 0; i < inputErrFdbk.length; i ++) {
addClass(glyph, inputErrFdbk[i]);
}
document.getElementById('wordChoice').value = " ";
} // END flipFail()
function flipSuccess (){
for (var i = 0; i < word.length; i ++) {
lttrs.push(word.charAt(i));
}
lttrs.reverse();
var reversedWord = lttrs.join('')
alert("Your reversed word is: " + reversedWord);
console.log(true);
document.getElementById("flip").innerHTML = "Flip Again!";
document.getElementById('wordChoice').value = " ";
} // EN flipSuccess ()
function flipChk () {
if (word.length < 2) {
flipFail ();
} else {
flipSuccess ();
}
}
See fully implemented code here: http://supsean.com/supsean/flipr/flipr.html

You need to set word in flipChk(). You're setting it when the page is first loaded, before the user has entered anything into the form, not when the user clicks on the Flip button.
Then, instead of using a global variable, pass it as an argument to the function. In general, avoid using global variables unless you really have to.
function flipChk () {
var word = document.getElementById('wordChoice').value;
if (word.length < 2) {
flipFail ();
} else {
flipSuccess (word);
}
}
function flipSuccess (word){
var lttrs = [];
for (var i = 0; i < word.length; i ++) {
lttrs.push(word.charAt(i));
}
lttrs.reverse();
var reversedWord = lttrs.join('')
alert("Your reversed word is: " + reversedWord);
console.log(true);
document.getElementById("flip").innerHTML = "Flip Again!";
document.getElementById('wordChoice').value = " ";
} // EN flipSuccess ()

Related

Insert Logging In Functions ASP.NET

I have an .ascx containing javascript and div elements.
I want insert a log statement inside a function for troubleshooting.
May I know how can I achieve it?
Below is my code snippet:
function SaveGroupCheck() {
var isValid = true;
var haveError = false;
var schedule = document.getElementById("<%=ddlExecutionSchedule.ClientID%>").value;
//INSERT LOGGING HERE - Value of 'schedule'//
if (schedule == "Weekly")
{
var xday = document.getElementById("<%=chkSelectDay.ClientID%>");
var checkbox = xday.getElementsByTagName("input");
var counter = 0;
for (var i = 0; i < checkbox.length; i++) {
if (checkbox[i].checked) {
counter++;
}
}
//INSERT LOGGING HERE - Value of 'counter'//
if (counter < 1) {
$("#chkSelectDay").addClass('errorbox');
$("#divSelectDay").addClass('has-error has-feedback');
$("#lblSelectDay").addClass('has-error has-feedback');
haveError = true;
}
else {
$("#chkSelectDay").removeClass('errorbox');
$("#divSelectDay").removeClass('has-error has-feedback');
$("#lblSelectDay").removeClass('has-error has-feedback');
}
}
//INSERT LOGGING HERE - Value of 'haveError'//
Below is a log which I attempted but failed. I will use a try-catch if the error info needs to be provided.
var logFileName = ConfigurationManager.AppSettings["logpath"] + "Debug_" + DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".log";
var itemPerPage = document.getElementById("<%=txtItemsPerPage.ClientID%>").value;
Log(DateTime.Now.ToString("ddMMyyyy_hhmmss") + " - itemPerPage = " + itemPerPage);
*logpath configured in app.config.
Thank you for your time.
To log any javascript variables you can use :
console.log("Hello I'm the variable value");
and open chrome console to see the value.
If you want to send variable value to server you must go to ajax call by calling server method for logging.
I hope that I understood your question.

JavaScript Chrome extension using variables and functions from different JS files

I have 5 content_script.js (1-5) and each contains its own function inside each of these content scripts. However, I ran into an issue where I need to use a variable or function from another content script, it throws me an error saying variable/function undefined. So I have to redeclare the variable again in the same script to be able to use it.
Is there a way to pass variables and functions from one content script to another? In this case I want to use the setSelectedValue() function and objSelect variable.
content_script:
function clickUpdate() {
var updateArray = document.getElementsByClassName("updateButton");
var saveArray = document.getElementsByClassName("saveButton");
var updateArraySelector = document.querySelectorAll(".updateButton");
[].slice.call(updateArray).forEach(function(item) {
if (saveArray.length == 0)
setSelectedValue(objSelect, "P"); //it doesnt recognize this function from my other content_script
console.log("object select is: " + objSelect); //it also doesnt recongize this variable
});
console.log("this is the update array legnth: " + updateArray.length);
console.log("this is the save array legnth: " + saveArray.length);
console.log("this is the update array selector: " + updateArraySelector);
}
clickUpdate();
content_script1:
var objSelect = document.querySelectorAll('.engpf')
//Set selected
setSelectedValue(objSelect, "P");
function setSelectedValue(selectObj, valueToSet) {
for (var i=0; i<selectObj.length; i++) {
for(var j=0; j<selectObj[i].options.length; j++){
if (selectObj[i].options[j].value == valueToSet) {
selectObj[i].options[j].selected = true;
}
}
}
}

Arguments in Parse.com query.find success callback

Thanks for the help in advance.
I'm working on an practice assigment using Phonegap and Javascript. Long story short: I need to use Parse.com to store information about some Lego minifigures. The problem I'm having right now is due mostly to my inexperience in Javascript.
I'm working on letting the user add tags to the figures. The user enters them, separated by comma, and I then split the string. That's working OK.
Now, I need to add the tags that don't exist yet to my database. For this, I search for any tags with that description (using query.find) and then, if it exists, I don't create it, I just modify the relationship. If it doesn't exist, I create it and then modify the relationship.
My problem is: I can't seem to be able to access the tag description (the string) from within the success callback of query.find. I'm pretty sure it's because of the scope. Is there any proper way to access variables from withing a success callback, besides the results array?
My current code is as follows:
var Figure = Parse.Object.extend("Figure");
var Tag = Parse.Object.extend("Tag");
var nombre = $('#nombre').val();
var serie = $('#serie').val();
var figure = new Figure({"Name":nombre,"Series":serie});
var tags = $('#tags').val();
res = tags.split(","); //split the
figure.save().then(function() {
for (var i = 0; i < res.length; i++) { //for each tag
var query = new Parse.Query(Tag); //create the query.
query.equalTo("Description", res[i]);
query.find( {//execute query
success: function(results, res[i]) {
if (results.length > 0){ //if there are results.
var tag = results[0]; //get the tag
var relation_tag = tag.relation("figures"); //get the relation
relation_tag.add(figure); //add figure to relation
tag.save();
}
else { //if there are no results, the tag does not exist.
new_tag = new Tag({"Description":res[i]});
//ABOVE THIS LINE: res[i] is always undefined.
var relation_tag = new_tag.relation("figures"); //get the relation
relation_tag.add(figure); //add the figure
new_tag.save();
}
},
//error with query
error: function() {
alert("ERROR");
}
});
}
}, function(error) {
alert("No se pudo guardar la figura");
});
In the success callback, res[i] always is undefined, I assume that it's because of the scope.
This is a very common problem in async Javascript programming. You are doing something like this:
for (var i = 0; i < array.length; i++) {
anAsyncFunction(function(result) { // inner function
doSomethingWith(array[i]);
}
}
The problem is that in Javascript functions store outer variables by reference and not by value, which means that a function looks up the value of a variable from an outer scope, when it is executed and not when it is defined. Since the code is async the the inner function is called after the for loop completed and at this point we have i === array.length, so array[i] === array[array.length] === undefined.
To avoid this you can use an immediately invoked function expression (IIFE, pronounced "iffy"):
for (var i = 0; i < array.length; i++) {
anAsyncFunction((function(j) { // IIFE
return function innerFunction(result) { // inner function
doSomethingWith(array[j]); // j instead of i
}
})(i); // passing "value of i"
}
Because the IIFE is invoked immediately, the current value is of i is passed and stored into j and when the inner function executes it uses the correct value.
So in your case this should work:
success: (function(j) { // IIFE
return function(results) {
if (results.length > 0) {
var tag = results[0];
var relation_tag = tag.relation("figures");
relation_tag.add(figure);
tag.save();
}
else { //if there are no results, the tag does not exist.
new_tag = new Tag({"Description":res[j]}); // j instead of i
var relation_tag = new_tag.relation("figures");
relation_tag.add(figure);
new_tag.save();
}
}
})(i) // pass "value of i"
If you prefer, you can also pass the description itself instead of just the index to the IIFE (I think I would do it that way):
success: (function(description) { // IIFE
return function(results) {
if (results.length > 0) {
var tag = results[0];
var relation_tag = tag.relation("figures");
relation_tag.add(figure);
tag.save();
}
else { //if there are no results, the tag does not exist.
new_tag = new Tag({"Description":description}); // description
var relation_tag = new_tag.relation("figures");
relation_tag.add(figure);
new_tag.save();
}
}
})(res[i]) // pass description
var Tag = Parse.Object.extend("Tag");
var query = new Parse.Query(Tag);

mulitple url hashtags not being read in properly

I have recently nabbed an example of reading in multiple hashtags from a url, while the first split works perfectly fine the second time I try to spilt the values a second time it seems not to be read in as seen I have tried to use the alerts to determine the problem and they stop working shot of the keyValuePair is initialized .
var mangaNumber = 0;
var chapterNumber = 0;
var i, variables = window.location.hash.split(';');
if (variables.length > 0) {
// Variables present in hash
for (i = 0; i < variables.length; i++) {
var keyValuePair = variables.split('=');
if (keyValuePair[0] == mangaNo) {
mangaNumber = unescape(keyValuePair[1]);
alert(mangaNumber);
}
if (keyValuePair[0] == chapterNo) {
chapterNumber = unescape(keyValuePair[1]);
alert(chapterNumber);
}
if (keyValuePair[0] == pageNo) {
pageNumber = unescape(keyValuePair[1]);
alert(pageNumber);
}
}
}
else {
// No variables in the hash
alert('this is a fail foo');
}
Perhaps this is just an error you made when you posted it here, but try this:
var keyValuePair = variables[i].split('=');
Also, unless mangaNo etc actually are variables (and not strings), you need to quote them:
if (keyValuePair[0] == "mangaNo") {
mangaNumber = unescape(keyValuePair[1]);
alert(mangaNumber);
}
...
if (keyValuePair[0] == "chapterNo") {
...
if (keyValuePair[0] == "pageNo") {

Javascript e-mail validation of specific domains

I can’t figure out what is missing so that when e-mail is valid it will skip the last invalid message and move to next item on form for validation:
enter code here
if (document.form1.email.value.length > 0) {
var tst = document.form1.email.value;
var okd = ['bankofamerica.com','baml.com','magner.com','ml.com','ust.com','ustrust.com']
for (var i = 0; i < okd.length; i++) { okd[i] == okd[i].toLowerCase() }
var emailRE = /^[a-zA-Z0-9._+-]+#([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})$/
var aLst = emailRE.exec(tst)
if (!aLst) {
alert(tst + ' is not a valid e-mail')
} else {
var sLst = aLst[1].toLowerCase()
for (var i = 0; i < okd.length; i++) {
if (sLst == okd[i]) {
// alert(aLst[1] + ' is allowed');-->
}
}
if (i == okd.length) alert(aLst[1] + ' is not allowed. Please enter an email address with an authorized domain.')
document.form1.email.select();
return false;
}
}
I'd recommend placing this code into a function, maybe named ValidateEmail().
In your loop: if you've determined the email is valid, return true;. This will prevent further execution. If that domain doesn't match, have it continue looping to check the others.
If the loop completes without returning true, you'll know it didn't match anything so return false; at the very end.
EDIT: Use try/catch instead:
if (document.form1.email.value.length > 0) {
var tst = document.form1.email.value;
var okd = ['bankofamerica.com','baml.com','magner.com','ml.com','ust.com','ustrust.com']
for (var i = 0; i < okd.length; i++) { okd[i] == okd[i].toLowerCase() }
try {
var emailRE = /^[a-zA-Z0-9._+-]+#([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})$/
var aLst = emailRE.exec(tst)
if (!aLst)
throw (tst + ' is not a valid e-mail');
// isValidDomain will be changed to 'true' only if it matches an item in the array
var isValidDomain = false;
var sLst = aLst[1].toLowerCase()
for (var i = 0; i < okd.length; i++) {
if (sLst == okd[i]) {
isValidDomain = true;
// We break here because a match has been found - no need to compare against the other domain names.
break;
}
}
if(!isValidDomain)
throw (aLst[1] + ' is not allowed. Please enter an email address with an authorized domain.');
// If execution reaches here, you know it passed both tests!
return true;
}
catch(err) {
// This code block runs whenever an error occurs
alert(err);
document.form1.email.select();
return false;
}
}
throw basically acts like a goto command. It will jump directly to the catch(err) portion of the code.
More info about try, catch, and throw:
http://www.w3schools.com/js/js_try_catch.asp
http://www.w3schools.com/js/js_throw.asp
Thank you very much Colin!
I had to remove the following 2 lines to avoid halting the code from running on to next validation field:
isValidDomain = true;
// We break here because a match has been found - no need to compare against the other domain names.
// break - exits code from running on down to next item on page
}
}
if (!isValidDomain)
throw (aLst[1] + ' is not allowed. Please enter an email address with an authorized domain.');
// If execution reaches here, you know it passed both tests!
// return true; - was not needed, stops code from running on page
}
catch (err) {

Categories

Resources