dojo foreach function - javascript

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"

Related

javascript - function doesn't fire when it should

So I have a function which is meant to calculate whether or not a coupon code should be applied. The function checks the value of several divs and forms on the page to see if the code should be automatically applied.
However it isn't working. I only want to run the function if the url contains checkout (complex cms issue make me do it this way) and I wanted to know if anyone could spot any errors in the code as to why it isn't working. If anyone could help me out, that would be really appreciated.
The code I am using is as follows:
<script>
var totalValue = document.getElementsByClassName("wsite-price").innerText;
var couponHere = document.getElementsByClassName("wsite-coupon-input");
if (-1 != location.pathname.indexOf('checkout')) {
if (totalValue > 240) {
codeHere.value = "COUPONCODEDISCOUNT";
document.getElementById('apply-coupon-button').click();
window.alert("sometext");
}
}
</script>
getElementsByClassName returns an HTMLCollection, so innerText most likely isn't a property on an HTMLCollection object. You can use the .item() method with an index to get the element, or use the querySelector method to get the single item.
var totalValue = document.getELementsByClassName('wsite-price');
if (totalValue.length > 0) {
var val = totalValue.item(0).innerText;
// ...
}

Is a recursive function an effective way to add table rows dynamically?

In my research and attempts to use JavaScript to add rows to a HTML Table dynamically, it was important that each id tag be incremented according to the row number. I found various suggested ways of doing this. Finally, I thought I'd give a try at writing a recursive function to do the trick. The following works. But I do not know if it could be optimized. Kindly let me know what I can do to improve it.
function incrementElementID(element, incrementVal) {
if(element.hasAttribute("id")) {
idVal = element.getAttribute("id");
element.setAttribute("id",idVal+incrementVal);
}
var numChildren = element.childElementCount;
for (var i=0; i<numChildren; i++)
incrementElementID(element.children[i],incrementVal);
return;
}
Best done with a closure variable if you're not intentionally trying to use recursion.
Set a variable outside the function scope and increment it within the function.
You're better off with some simple jQuery:
var incrementVal = ...
$("[id]").each(function(index, value) {
elem = $(value);
elem.attr("id", +elem.attr("id") + incrementVal);
});
$("[id]") selects any element that has an id attribute: http://api.jquery.com/has-attribute-selector/
.each iterates through all the items in the collection: https://api.jquery.com/jQuery.each/
The + at the front of +elem.attr("id") converts the attribute value from a string to an int.

Accessing a Dynamically Named array in jQuery/javascript

I wish to name an array according to the table row containing the button that was clicked.
I get the table row thus:
var rowNum = $(this).parent().parent().index();
Now, I wish to name the array and access it.
var arrayName = 'arrTR' + rowNum;
window[arrayName] = new Array();
window[arrayName]["First"] = "Bob";
window[arrayName]["Last"] = "Roberts";
window[arrayName]["email"] = "me#there.com";
//The array should be accessible as arrTR__
alert(arrTR1["Last"]);
The alert does not work, so I am doing something wrong.
How should I refactor the code to allow me to update and access the array?
jsFiddle
What you're doing with the dynamically named variables is essentially creating an array of those variables (one for each rowNum), but giving each of those array elements its own individual named variable.
There is a much better way to do this. Instead of generating a series of dynamically named variables, make a single array or an object. Then add an element or property for each of the dynamically named variables you were going to generate.
Your test code could look like this:
var arrTR = [];
var rowNum = 1;
arrTR[rowNum] = {
First: 'Bob',
Last: 'Roberts',
email: 'me#there.com'
};
alert( arrTR[1].Last );
Alternatively, you can do something with $.data as mentioned in Johan's answer. But if you do use plain JavaScript code, use a single array as described here instead of multiple dynamically named variables.
There are several reasons to do it this way. It's cleaner and easier to understand the code, it may be faster when there are large numbers of entries, and you don't have to pollute the global namespace at all. You can define the var arrTR = []; in any scope that's visible to the other code that uses it.
Arrays and objects are made for keeping track of lists of things, so use them.
There is nothing wrong with your code, and the only place it has error is the alert since it is not defined on the first click button
see this fiddle with a little update
if(rowNum === 1)
alert(arrTR1["Last"]);
else if(rowNum === 2)
alert(arrTR2["Last"]);
fiddle
How about something like this?
$('.getinfo').click(function() {
var result = $('table tr:gt(0)').map(function(k, v){
return {
firstName: $(v).find('.fname').val(),
lastName: $(v).find('.lname').val(),
email: $(v).find('.email').val(),
}
}).get();
//update to show how you use the jQuery cache:
//1. set the value (using the body tag in this example):
$('body').data({ result: result });
//2. fetch it somewhere else:
var res = $('body').data('result');
});
Not sure how you want to handle the first row. I skip in in this case. You can access each row by result[index].
As you might have noticed, this saves all rows for each click. If you want to use the clicked row only, use the this pointer.
http://jsfiddle.net/nwW4h/4/

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

Mind boggling javascript failure at handling some basic addition!

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!

Categories