Javascript array in loop - javascript

I am trying to loop through all elements in an xml file with the name "playerhash" with javascript.
for(var i = 0; i < 4; i++) {
alert(i);
if(getCookie('riskinfo') == xmldoc.getElementsByTagName("playerhash"[i].childNodes[0].nodeValue) {
player = xmldoc.getElementsByTagName("playerhash")[i].getAttribute('color');
break;
}
}
When I try to run the js it gives me Line 3: Uncaught TypeError: Cannot read property 'nodeValue' of undefined With the alert() function I figured out that the error is occurring when i = 0 and I know that there are at least four playerhash elements.
How can I loop through all of the elements without the error?

As deceze said, you have errors in the code. You should write your code in much smaller steps so that it is easier to debug. Also, check each step before proceeding so that if it fails unexpectedly, it will not throw errors at the user. Condition expresssions should not do assignment as that makes debugging more difficult, use them just for testing conditions:
// Should have already checked that xmldoc is a valid document
var riskinfo = getCookie('riskinfo');
var playerhash = xmldoc.getElementsByTagName("playerhash");
var max = 4; // or playerhash.length
var node, player;
for(var i = 0; i < max; i++) {
node = playerhash[i];
if (node && node.nodeValue == riskinfo) {
player = node.getAttribute('color');
i = max; // break out of for loop
}
}

.getElementsByTagName("playerhash"[i].childNodes[0].nodeValue)
You're missing a ) in there. Should be something along the lines of this:
if (getCookie('riskinfo') == xmldoc.getElementsByTagName("playerhash")[i].childNodes[0].nodeValue) {
Of course, repeating xmldoc.getElementsByTagName("playerhash") in every loop is rather expensive, you should do this once before the loop and save the result in a variable.
You should probably also check whether the ith element actually exists and whether it actually has any child nodes before trying to access that child node.

Related

Two conditions in for loop

I have this code which im echoing data from jquery success .
for(i = 0;i < dat.id.length; i++){
// im echoing data here
}
and i want check for the highest value in dat.voteup
like that (It works)
var maxvoteup = 0;
if (dat.voteup[i] - dat.votedown[i] ==maxvoteup) {
console.log(maxvoteup);
//i want fetch maxvoteup here
}
But i want make just one For loop not two . How can i do that pls?
EDIT:
var maxvoteup = 0;
for (i = 0;i < (dat.voteup-dat.votedown).length ;i++) {
if (dat.voteup[i] - dat.votedown[i]>maxvoteup) {
maxvoteup = dat.voteup[i] - dat.votedown[i];
console.log(maxvoteup);
//i want fetch maxvoteup here
}
}
EDIT2:
this is what im getting in my jquery response , But actually my max vote is 10 not 8 . 8 is just voted up to 8 , but there is other votes which is 10.
{"status":"success","message":[],"date_edited":[2016-04-21 21:31:25],"voteup":[],"votedown":[8],"id":[]}
Your code is a little hard to read, but if I understand correctly I believe all you need to do is combine both into a single loop with maxvoteup defined outside.
var maxvoteup = 0;
for(i = 0;i < dat.id.length; i++){
// echo data...
// max upvote
if (dat.voteup[i] - dat.votedown[i] == maxvoteup) {
console.log(maxvoteup);
}
}
EDIT:
Unfortunately getting the maximum value from a list requires you to iterate through the list, i.e., a maximum value cannot be found in constant time. I suggest you first find the maximum, and then proceed with your for loop.
Also, if you know your maximum is a list of numbers, you can actually use Javascript's apply to make the code a little cleaner:
var maxvoteup = Math.max.apply(Math, listOfMaxVotes);
See here: How does the Math.max.apply() work?
EDIT2:
If you want to continuously keep track of the maximum, then all you need to do is move the maxvoteup variable to outside of your response handlers so you can always keep track.
// global scope...
var maxvoteup = 0;
// your jquery response handler
var onSuccessData = function(data) {
// get the highest possible max from the `voteup` and `votedown` lists
var responseMax = Math.max.apply(Math, data.voteup.concat(data.votedown));
// check if it's greater than our global maxvoteup
if (responseMax > maxvoteup) {
// if it is, then update our global `maxvoteup` to the new value
maxvoteup = responseMax;
}
// continue with your other processing...
};

JavaScript throws TypeError saying that my variable is undefined

I don't have much experience in JavaScript, so far I have this:
function loop() {
var authorDivs = document.getElementById('ctl00_MainContent_MCPObjectInfo_dvCreatorView').getElementsByTagName("div");
for (var i = 0; i < authorDivs.length; i++) {
var divOfDiv = authorDivs[i].getElementsByTagName("div");
if (typeof divOfDiv.item(i) === 'undefined' || divOfDiv.item(i) === null) {
console.log("This is undefined or null");
}
else {
var realDivs = divOfDiv.item(i);
realDivs.item(i).textContent = "please work plz";
}
}
}
I get the following error from the console in FireFox: TypeError: realDivs is undefined on this line: realDivs.item(i).innerHTML = "please work plz";
Essentially what I have (in my mind) is a loop that goes through authorDivs and gets all of the divs within those divs and saves them in divOfDiv. I then check to see if the divs in divOfDiv are undefined or null, if they are not then those divs get saved in a variable realDivs which I then use to edit the innerHTML. That's what I'd ideally like to see happen, what is causing the error? What am I doing wrong?
Note: I do not have access to jQuery but only JavaScript.
Edit: I've added the changes suggested below and its fixed that -- thanks! But I'm now getting the following error: TypeError: realDivs.item is not a function
What is causing that? And on another note how do I know when I'm dealing with an array and when I'm dealing with an HTMLCollection? Do you just assume? I've never used a loosely typed language before so its new to me.
Well, you'll need to move that code inside the conditional block that is supposed to prevent it! Also, || "null" is not going to work as you expect, you'll need to check for || divOfDiv.item(i) === null explicitly.
So try
for (var i = 0; i < authorDivs.length; i++) {
var divOfDiv = authorDivs[i].getElementsByTagName("div");
if (divOfDiv.item(i) == null) {
console.log("This is undefined or null");
} else {
var realDivs = divOfDiv.item(i)
realDivs.item(i).innerHTML = "please work plz";
console.log(divOfDiv.item(i));
}
}
However, that still doesn't really work for two reasons:
The i index you use to access the i-th divOfDiv comes from the iteration over authorDivs - hardly what you want. Instead, use a second loop over all divOfDivs.
Your realDivs variable does hold a single <div>, which does not have an .item method. You'd just directly access its .innerHTML property.
So you should use
var authorDivs = document.getElementById('authorView').getElementsByTagName("div");
for (var i=0; i<authorDivs.length; i++) {
var divsOfDiv = authorDivs.item(i).getElementsByTagName("div");
for (var j=0; j<divsOfDiv.length; j++) {
var realDiv = divsOfDiv.item(j);
realDiv.innerHTML = "please work plz";
console.log(realDiv);
}
}
it will happen in case when your if (typeof divOfDiv.item(i) === 'undefined' || 'null') returns true. Then you never initialize realDivs (what would happen if condition was falsy). Later you try to call item function on that unitialized object
There are two problems in the code.
comparing DOM object with 'undefined' and null. If div tag is not available in authorDivs[i], it will return empty DOM array. So, comparision of empty DOM array with undefined and null is not good approach. We can use array length property for doing validation.
divOfDiv = authorDivs[i].getElementsByTagName("div");
if(divOfDiv.length > 0) { console statement}
As item(i) is already return single DOM element, item(i) of "realDivs" variable is not proper approach. In addition to this, innerHTML method needs to be used after validating whether realDivs contains DOM element. Please update the code as below.
var realDivs = divOfDiv.item(i);
realDivs ? (realDivs.innerHTML = "please work plz"): null;
Note : item(i) will return null if DOM is not available.

For Loop Behaviour

This question is regarding Javascript for loops, where I've been having some weird behaviour.
My For loop currently looks like this:
var UnitAmount = 2;//(value verified, yet not declared like this)
var DamageAmount = [1,3];//(value verified, yet not declared like this)
function forcerefresh () {
for( i=0 ; i < UnitAmount ; i++ ) {
//(10 lines of Stuff)
var check = 0;
for (c = 0; c < DamageAmount[i] ; c++ ) {
debug[0] = damage[i][c].getElementsByClassName("writedamage")[0];
debug[1] = damage[i][c];
debug[2] = unit[i];
check = check + 1;
console.info("Unit:",i,"Loop:",c,"Debug:",debug,"Check:",check, "Race:",unitrace[i], unit[i].dataset.race);
alert("Debug:"+ debug );
damageCalc(damage[i][c].getElementsByClassName("writedamage")[0],damage[i][c],unit[i]);
}
}
}
In here, debug, alert, Check and the console write call are already added to attempt to find the problem - I'm getting an infinite loop here.
The output im getting in the console shows that while the i constant walks as intended, but the c Iteration count starts at 0, jumps to 2, and then stays 2 - and since the DamageAmount[1] = 3, this creates an infinite loop. And where the c might stick at value 2, the check values does walk up through the iterations.
As for the amount of variables involved, I've checked time and again with the console, and all of them are defined, and the values I expected. The Code is located at http://age-of-wonders-3.wikia.com/wiki/MediaWiki:Units.js, but if any parts are requested I'll of course post them here.
Any help is appreciated!
Try using for of or .forEach on an array

delete specific xml node Javascript

My xml file is like:
it contains different 'object' nodes and in different objects there are different parameters one is deleted parameter.
I want to delete the all 'object' nodes that contains the deleted parameter 1.
This is the code that deletes the node object which has a parameter node deleted =1:
x=xmlDoc.documentElement;
for(var count=0; count<5;count++){
var y=x.getElementsByTagName("deleted")[count]; //Find that nodes arent
if(y.textContent == "1") {
var z=y.parentNode; //delete the node from the parent.
x.removeChild(z);
Xml2String1= new XMLSerializer().serializeToString(x);
}
}
Your loop is incorrect:
for(var x1=0; x1<5;x1++){
var y=x.getElementsByTagName("deleted")[x1];
Your loop runs for 5 iterations without regard for the number of <deleted> elements are found. Each time through the loop you search again and get a new NodeList/HTMLCollection of the remaining <deleted> elements, but your loop counter is incremented regardless.
Try this instead:
var deletedNodesList = x.getElementsByTagName("deleted");
var nodesToDelete = [];
for (var index = 0; index < deletedNodes.length ; index += 1)
{
var node = deletedNodes[index];
if (node.textContent == "1")
{
nodesToDelete.push( node.parentNode ); //delete the node from the parent
}
}
nodesToDelete.forEach( function() { x.removeChild(this); } );
Note that, per the documentation on MDN, the NodeList is a live collection, so don't modify it while you are processing it.
PS.
I second raam86's recommendation to use sane (meaningful) variable names. Meaningful variable names make it easier to understand the code, which makes it easier to write correct code and to resolve problems in incorrect code.

TypeError: 'undefined' is not an object

I have a currently fairly dysfunctional Javascript program that's been causing me problems. However, it throws one error that I just don't understand:
TypeError: 'undefined' is not an object (evaluating 'sub.from.length')
What I'm trying to do, as you can probably guess, is check the length of a certain "from" array in the sub dict. Here's the source code for the entire function, and here's the code of the loop that I think is causing the error:
console.log(afcHelper_ffuSubmissions.length); // just for debugging, returns the correct number
for (var i = 0; i < afcHelper_ffuSubmissions.length; i++) { // this whole section works fine
var sub = afcHelper_ffuSubmissions[i];
//console.log("THIS IS BROKEN DOWN BY LINK",afcHelper_Submissions[i]);
if (pagetext.indexOf(afcHelper_ffuSections[sub.section]) == -1) {
// Someone has modified the section in the mean time. Skip.
document.getElementById('afcHelper_status').innerHTML += '<li>Skipping ' + sub.title + ': Cannot find section. Perhaps it was modified in the mean time?</li>';
continue;
}
var text = afcHelper_ffuSections[sub.section];
var startindex = pagetext.indexOf(afcHelper_ffuSections[sub.section]);
var endindex = startindex + text.length;
console.log(sub);
if (typeof(sub.from) != 'undefined' && sub.from.length > 0) { // ** problem spot?? this is the code i recently added.
for (var i = 0; i < sub.from.length; i++) {
mainid = sub.from[i]['id'];
var sub = afcHelper_Submissions[mainid]; // and then it goes on from here...
Any ideas would be great. Frankly, I just can't see why I'm getting a TypeError about something that I've already explicitly checked the type of (typeof(sub.from))...
I'm not sure how you could just check if something isn't undefined and at the same time get an error that it is undefined. What browser are you using?
You could check in the following way (extra = and making length a truthy evaluation)
if (typeof sub !== 'undefined' && sub.from && sub.from.length) {
[update]
I see that you reset sub and thereby reset sub.from but fail to re check if sub.from exist:
for (var i = 0; i < sub.from.length; i++) {//<== assuming sub.from.exist
mainid = sub.from[i]['id'];
var sub = afcHelper_Submissions[mainid]; // <== re setting sub
My guess is that the error is not on the if statement but on the for(i... statement. In Firebug you can break automatically on an error and I guess it'll break on that line (not on the if statement).
try out this if you want to assign value to object and it is showing this error in angular..
crate object in construtor
this.modelObj = new Model(); //<---------- after declaring object above

Categories

Resources