Mind boggling javascript failure at handling some basic addition! - javascript

This is killing me! I'm trying to add the values of four fields together, and I get allllll kinds of wierd results!
The code I have so far:
$('input.percent').change(function() {
var totalup = 1;
var totalup = totalup*1;
$('input.percent').each(function(){
var current = $(this).val();
var curvalue = current * 1;
console.log(curvalue);
console.log(totalup);
var totalup = curvalue + totalup;
});
});
This should be ungodly simply. Start with a value of zero, get the value of each input, add it to that totaling value. The console log always shows UNDECLARED or NaN for totalup, but if I remove the last decleration of totalup (where it adds more to totalup) it suddenly doesn't become undefined or Nan.
Why is this not ungodly simply!!! I must be missing something dumb, or Javascript just STINKS!
Thanks in advance for your help!

var percentInputs = $('input.percent');
percentInputs.change(function() {
var total = 0;
percentInputs.each(function(){
total += Number($(this).val());
});
});
Update
Caching those selectors would be a good idea too.

the main problem is the declaration of already declared fields. Leaf the var keyword for the second and third assignment of totalup and it'll work.

add the parseInt() while the calculation for an example
var totalup = parseInt(curvalue) + parseInt(totalup);

Okay! Here is where the issue was arising!!!!
When you write:
var FOO = 'whatever';
...Inside of a function, it is a LOCAL VARIABLE! If however you simply go:
FOO = 'whatever';
You hit the global variable (variable declared outside of the function).
So while the code above is the solution, this is where the explained solution to the problem exists!

Related

How do increment value while it being declared inside function

I have a small issue where i'm trying to increment/decrement the buttons in x steps this is all dynamic dependant on what ever the quantity step is, my code works fine when its increments of one because i am just using ++ there is no scope issue
I've tried a few things but no much luck i can't really declare it outside of the function as there is multiple input boxes and i'd need to do some sort of mapping to know which one relates to which input.
I know what the issue is its because of scoping im defining a variable inside a function but its not a simple thing to do it outside of it any other solutions to get past this without defining it outside ?
When i had it like this this.$refs[codeForRef][0].value++ it worked fine and would increment by one
increment: function(e) {
e.preventDefault();
var codeForRef = e.srcElement.id;
var test = parseInt(this.$refs[codeForRef][0].value, 10); //the value of the qty
test += this.dyQty //whatever it needs to go up in
},
what i understood from your question, this should work for you.
increment: function(e) {
e.preventDefault();
var codeForRef = e.srcElement.id;
var test = parseInt(this.$refs[codeForRef][0].value, 10); //the value of the qty
test += this.dyQty //whatever it needs to go up in
this.$refs[codeForRef][0].value = test;
}

Can't assign querySelectorAll() to a variable - weird behaviour

I was trying to crawl a very old website for a specific tag, I need to get it by it's for= attribute. So I used this piece of code.
var character = document.querySelectorAll("label[for=char_1]");
For some reason it returns an undefined, but I was using this script for a few days now and it worked like a charm. Here's the fun part. Typing that command in browsers console will result in undefined. But typing this alone:
document.querySelectorAll("label[for=char_1]");
Will return a proper NodeList. Why it won't assign to a variable...?
edit: It seems that deleting var and typing character without it will make it work. It's resolved but I would still love to get an answer to "why is this happening"?
edit2:
for (var i = 0; i < 15; i++) {
var character = document.querySelectorAll("label[for=char_" + i +"]");
console.log(character); // this will return [] from the script.
var color = character[0].children[0].style.color;
}
A simple for loop. All I get is Cannot read property 'children' of undefined. But I can type in the very same command document.querySelectorAll... and it will work in the browser and will return NodeList.
I had it working like this in a very hacky script. It worked.
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
edit3:
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
var character2 = document.querySelectorAll("label[for=char_2]");
var characterColor2 = character2[0].children[0].style.color;
// ...
The above code works without a single problem though. I don't think it's DOM not being ready as this code is also run from Greasemonkey script and it works. The only difference is the for loop.
var x = ""; // returns undefined, because it's a var assignment.
var elements = document.querySelectorAll('div');
That's expected behavior when pasted into the console.
edit: It seems that deleting var and typing character without it will make it work. It's resolved
I'm afraid you're creating a global scope variable now. or perhaps characters is an already defined variable in that scope.
Buhah, as I said in edit 3 "the only difference is the for loop". I was so busy trying to find an answer in the DOM-related things that I made the simplest mistake ever done in programming.
See?
char_1
With...
for(var i = 0...)
0! And I was testing char_1 in the browser instead of char_0. Which - truly - returns [] instead of something useful. Time to go on a holiday break I guess, my brain seems to be there already. :)

Javascript function cannot be executed twice

I'm kind of new to Javascript and I've bee wondering for hours how to solve my problem. I have a litle function associated to a button. It work once but I cannot get it to execute after the first time.
function CheckEmpty1(){return "false";}
function Generate(){
if(CheckEmpty1() == "true"){
alert("Please fill all mandatory field.\n\nAll missing field are black colored.\n\nPlease also make sure to make a choice for all radio button.");
}
else{
document.getElementById('TemplateOutput').style.display = "block";
lol = "lol";
document.getElementById('TemplateOutput').value = lol;
lol = "test2";
}
return;
}
"TemplateOutput" is a simple textarea centered in the browser. The code is originally more complicated than that but while doing the test to ensure the problem was not coming from somewhere else, it reduced to that but still doesn't work.
The second "lol = "test2";" is just to check that if I make a change to the variable, it is suposed to apply the second time I hit the button.
it seems to be basic for me but I can't figure out why... any help?
thanks.
EDIT:
I think I found the source of my error in my original script. My original code look like this:
function Output(){
Output = "CSD Troubleshooting: " + Troubleshoot + "\n";
return Output;
}
function Generate(){
FillVars();
GenerateOutput = Output();
alert(GenerateOutput);
}
function FillVars(){
Troubleshoot = document.getElementById('Troubleshoot').value;
}
I reduced it to the minimum but it still behave the same way.
The problem is coming from the Output() function because it work fine if I do it like this:
GenerateOutput = document.getElementById('Troubleshoot').value;
alert(GenerateOutput);
or
GenerateOutput = Troubleshoot;
alert(GenerateOutput);
BEHAVIOR: I click the button. The alert is filling like it is suposed to be. The second time I click the button, it just do nothing.
regards,
Updated Answer:
Your edit changes things markedly. The central issue is here:
function Output(){
Output = "CSD Troubleshooting: " + Troubleshoot + "\n";
return Output;
}
The first time you run that function, you replace the function with a string. The Output symbol is a reference to the function.
It looks like you might have a Visual Basic background. In JavaScript, you simply do this:
function Output(){
return "CSD Troubleshooting: " + Troubleshoot + "\n";
}
or if you want it in a variable first, declare the variable (with var) and probably to avoid confusion use a different name:
function Output(){
var result = "CSD Troubleshooting: " + Troubleshoot + "\n";
return result;
}
Original Answer:
The second "lol = "test2";" is just to check that if I make a change to the variable, it is suposed to apply the second time I hit the button.
It won't, because your previous
lol = "lol";
...line runs, setting it back to "lol". You'll never see the code put "test2" into the input.
The line
document.getElementById('TemplateOutput').value = lol;
copies the value from lol to the value property. It does not make the value property a reference to the variable lol. Changing the variable later has no effect, because there is no continuing link between it and the value property.
Since the if block in your code will never run, let's just look at the else block. Here, in detail, is what happens:
// 1
document.getElementById('TemplateOutput').style.display = "block";
That looks in the DOM for the element with the id "TemplateOutput", and sets its style object's display property to "block".
// 2
lol = "lol";
That assigns the value "lol" to the lol variable. Unless you've declared lol somewhere you haven't shown, it also creates an implicit global variable. Details: The Horror of Implicit Globals.
// 3
document.getElementById('TemplateOutput').value = lol;
That copies the value "lol" from the lol variable into the value property of the input.
// 4
lol = "test2";
That copies the value "test2" into the lol variable.

dojo foreach function

I am quite new to dojo and I'm stuck with a problem here
I have a zend dojo form where I need to take sum of four elements and set the value to another element. I have assigned a class (score) to those four elements
".score" : {
"found" : function (ele) {
var widgetId = ele.getAttribute('widgetid');
dojo.connect(dijit.byId(widgetId),'onBlur', function(){
var sum = 0;
dojo.query('.score')
.forEach(function(ele){
var widgetId = ele.getAttribute('widgetid');
sum += parseInt(dijit.byId(widgetId).get('value'));
});
//***cannot get the value of sum here
dijit.byId('score_total').set('value', sum);
});
}
}
As commented I am unable to get the sum of those values outside the foreach. Is there any way to get the value out of the loop? Am I doing any thing wrong?
It seems that I had made a mistake in the code and since I am quite new to jscript I was unable to debug. foreach indeed is not a asynchronous and sum was being calculated just that the parseInt(dijit.byId(widgetId).get('value')) was returning not a number NaN hence I was unable to populate the form element, I simply added an if condition and it worked
if(parseInt(dijit.byId(widgetId).get('value'))){
sum = sum + parseInt(dijit.byId(widgetId).get('value'));
}
Sorry for the trouble
One thing to note... dojo.foreach is deprecated ...
http://livedocs.dojotoolkit.org/dojo/forEach
instead ... array.forEach
http://livedocs.dojotoolkit.org/dojo/_base/array#forEach
but i think you might also have a scoping issue as well.. try something like this..
var sum = 0;
var elements = dojo.query('.score');
array.forEach(elements, function(ele) {
var widgetId = ele.getAttribute('widgetid');
sum += parseInt(dijit.byId(widgetId).get('value'));
});
in your case, the parent context has the variable, so it will work as you have used it.
Just a side point that if you want to access the sum variable outside the parent context, you will need to use dojo.hitch or pass the context to dojo.forEach
http://www.ibm.com/developerworks/web/library/wa-aj-dojo/
see the section on "Setting method context"

Password Strength Meter

I'm trying to create my own JS Password Strength Meter.
It was working before but i didn't like how it worked so I tried using
{score +=10;}
Instead of just:
score++
This is my code:
http://jsfiddle.net/RSq4L/
Best Regards,
Shawn,
Hope someone can help
Multiple issues:
Your passwordStrength() function was not defined in the global scope in the jsFiddle so it wasn't getting called. This is probably an artifact of how you set up the jsFiddle, perhaps not an issue in your real code.
The method of getting the appropriate ratingMsg will not work because you don't have array values for every possible score so many scores will generate an "undefined" ratingMsg.
Your CSS classes are also sparse so there are many score values that they will not match for either and no appropriate CSS class/style will be in effect. If you want a specific class for each rating value, then perhaps you should put the classname in the ratings array so it can be fetched from there along with the ratingsMsg.
For the first issue, in your jsFiddle, you also have to make sure the password processing function is defined in the global scope. The way your jsFiddle is set up, it is not (it's in the onload handler). You can fix this in the jsFiddle by just setting the first drop-down in the upper left to "no wrap (head)".
For the second issue, you are using:
ratingMsg[score]
but, your array is a sparse array not guaranteed to have an entry for most possible scores. You simply can't do it that way because many elements you access will have undefined values which won't give you a meaningful message. For example, if score was 15, you would be accessing ratingMsg[15], but there is no value in that space in the array so you won't get a meaningful rating message.
The solution is to find a different way to select the right message. The simplest way would just be an if/else if/else if statement that would check which range the score is in and set the appropriate msg. There are more elegant table driven ways, but all will involve searching through a data structure to find which two values the current score is between and using that msg.
If you look at this jsFiddle http://jsfiddle.net/jfriend00/dA7XC/, you'll see that your code is getting called, but it only hits values in the array sometimes.
And, here's a rewritten algorithm that finds the appropriate msg no matter what the score show in this fiddle: http://jsfiddle.net/jfriend00/jYcBT/.
It uses a data structure like this:
var ratingMsg = [
0, "Unclassified",
10, "Weak",
20, "Fair",
50, "Better",
60, "Medium",
70, "Good",
90, "Strong"
];
and a for loop like this to get the appropraite ratingMsg:
for (var i = ratingMsg.length - 2 ; i >= 0; i-=2) {
if (score >= ratingMsg[i]) {
msg = ratingMsg[i+1];
break;
}
}
Here you go: http://jsfiddle.net/RSq4L/11/
The first problem is that in your fiddle you have the onLoad option set, so your passwordStrength function is not actually being declared in the global scope. It is being declared inside of the onLoad block that jsFiddle wraps your code with. This causes the page to error out when the keypress handler tries to invoke the function.
You can fix this problem in several different ways:
By explicitly declaring the function as global as per my example above.
By choosing one of jsFiddle's "no wrap" options instead of onLoad.
By dynamically binding your event-handler instead of setting it through the element's onkeydown attribute in the markup.
The second problem is how you are keying your score messages. You have:
var ratingMsg = new Array(0);
ratingMsg[0] = "Unclassified";
ratingMsg[10] = "Weak";
ratingMsg[30] = "Fair";
ratingMsg[50] = "Better";
ratingMsg[60] = "Medium";
ratingMsg[70] = "Good";
ratingMsg[90] = "Strong";
...and you lookup the message by doing ratingMsg[score]. This will only work if the score exactly matches one of your indices. And based upon your math this will not always be the case.
I would suggest doing something like:
ratingMsg = {};
ratingMsg[0] = "Unclassified";
ratingMsg[10] = "Weak";
ratingMsg[30] = "Fair";
ratingMsg[50] = "Better";
ratingMsg[60] = "Medium";
ratingMsg[70] = "Good";
ratingMsg[90] = "Strong";
function closestRating(score) {
var bestKey = 0;
var bestMatch = 100;
for (var key in ratingMsg) {
if (key <= score && score - key < bestMatch) {
bestMatch = score - key;
bestKey = key;
}
}
return ratingMsg[bestKey];
}
On an unrelated note, are you sure you want to be using onkeydown? I think onkeyup would work better.
Your fiddler script had several errors. Here's the corrected one: new script.
You were missing a semicolon here: document.getElementById("passwordDescription").innerHTML = "" + ratingMsg[score] + ""
You forgot to escape '^' on your regular expression
I just wrote this for it:
Jquery Plugin for password strength forcing

Categories