Unexpected break in nested loop doesn't show up in debugger - javascript

The purpose of the code is to build a series of nested HTML using information in objects:
Here are the informational objects I created:
function branch(level,sciname,comname,parent,children){
this.level = level;
this.sciname = sciname;
this.comname = comname;
this.parent = parent;
this.children = children;}
var animalia = new branch(1,'Animalia','Animals',"",['chordata']);
var chordata = new branch(2,'Chordata','Chordates',animalia,['petromyzontida','actinopterygii']);
var actinopterygii = new branch(3,'Actinopterygii','Ray-finned Fishes',chordata,['siluriformes','scorpaeniformes','salmoniformes','percopsiformes','perciformes','osteoglossiformes','osmeriformes','lepisosteiformes','gasterosteiformes','gadiformes','esociformes','cyprinodontiformes','cypriniformes','clupeiformes','atheriniformes','anguilliformes','amiiformes','acipenseriformes']);
var petromyzontida = new branch(3,'Petromyzontida','Lampreys',chordata,['petromyzontiformes']);
And here is the script:
function CreateDiv(parent,child,z,width,height,top,left,bgcolor){
var parent_ = document.getElementById(parent);
var newdiv = document.createElement("div");
newdiv.setAttribute("id",child);
newdiv.style.zIndex = z;
newdiv.style.position = "absolute";
newdiv.style.width = width + "%";
newdiv.style.height = height + "%";
newdiv.style.top = top + "%";
newdiv.style.left = left + "%";
newdiv.style.backgroundColor = bgcolor;
parent_.appendChild(newdiv);}
function CreateTree(){
var firstdiv = document.createElement("div");
firstdiv.setAttribute("id","animalia");
document.getElementById("container1").appendChild(firstdiv);
var parent1 = "animalia";
var children1 = window[parent1].children;
var numbchildren1 = children1.length;
var rowcounter1 = 1;
var columncounter1 = 0;
for (i=0;i<numbchildren1;i++){
var child1 = children1[i];
var z1 = 2;
var columns1 = Math.ceil(Math.sqrt(numbchildren1));
var width1 = (100/columns1) - 2;
var rows1 = Math.ceil(numbchildren1/columns1);
var height1 = (100/rows1) - 2;
var top1 = rowcounter1*height1 - height1 + 1;
var left1 = columncounter1*width1 + 1;
var bgcolor1 = "#B43333";
CreateDiv(parent1,child1,z1,width1,height1,top1,left1,bgcolor1);
var numbchildren2 = window[child1].length;
if ((i/rowcounter1) == columns1){
rowcounter1 = rowcounter1 + 1;}
else {rowcounter1 = rowcounter1;}
if (columncounter1 == columns1){
columncounter1 = 1;}
else {columncounter1 = columncounter1 + 1;}
var rowcounter2 = 1;
var columncounter2 = 0;
console.log("before:" + columncounter2);
for (j=0;j<numbchildren2;j++){
console.log("after:" + columncounter2);
var child2 = children2[j];
var z2 = 3;
var columns2 = Math.ceil(Math.sqrt(numbchildren2));
var width2 = (100/columns2) - 1;
var rows2 = Math.ceil(numbchildren2/columns2);
var height2 = (100/rows2) - 1;
var top2 = rowcounter2*height2 - height2 + 1;
var left2 = columncounter2*width2 - width2 + 1;
var bgcolor2 = "#B48233";
CreateDiv(parent2,child2,z2,width2,height2,top2,left2,bgcolor2);}}}
I've run the code through a debugger dozens of times and I get no errors. Yet the script does not fully execute. I suspected an infinite loop but I fail to see why that would occur and after going over the code in great detail, I can find no real problems. I can tell where the code seems to break. There are two console.log() statements in the above code. The first console statement gets properly logged, but the second one does not. The debugger shows no errors (Firebug), but the code still fails to fully execute. Please help! And suggestions or criticism will be very welcome as I'm still learning some of the basics.
As a note: Eventually, I will add to this process to create several layers of nested elements, but wanted to get just the first couple layers right before I begin nesting things further as once I do that additional nesting should be relatively easy.

Compare
var children1 = window[parent1].children;
to
var numbchildren2 = window[child1].length;
I think the second one is missing a ".children" before the length. As Shaed, pointed out, numbchildren2 being incorrectly initialized was the most probable cause of the for loop not running, so you should have been investigating that.

I am not familiar with your syntax of window[elementID] to get an element, but I am pretty sure it does not work. Try using document.getElementById instead.
http://jsfiddle.net/M9jtt/

Related

JavaScript: How Can I Make A Var "Array" Work?

Is there a way to name a var using a sort of "Array?" My code is this:
for(var i = 0; i < (getHorizontalSquares * getVerticalSquares); i++){
var Square[i] = document.createElement("div");
Square[i].style.position = "relative";
Square[i].style.float = "left";
Square[i].style.width = "50px";
Square[i].style.height = "50px";
Square[i].id = "square" + (i + 1);
for(var ii = 0; ii < 6; ii++){
var TestColor = TestColorArray[Math.round(Math.random()*(TestColorArray.length - 1))];
getTestColor += TestColor;
}
Square[i].style.backgroundColor = "#" + getTestColor;
SquareCont.appendChild(Square[i]);
}
I know my code doesn't work, but I want to implement the same idea so I can get a result of this:
var Square1...
var Square2...
var Square3...
var Square4...
var Square5...
etc
I also tried doing a "Concentration" var, but it didn't work. How do I do this so the document doesn't append the same square multiple times?
var Square = {};
var SquareCont = document.createElement('div');
var getHorizontalSquares = 10;
var getVerticalSquares = 10;
var TestColorArray = ['a','b','c','f','e','0','1','2','3','3','4','5'];
var getTestColor = '';
for(var i = 0; i < (getHorizontalSquares * getVerticalSquares); i++){
Square['Square'+i] = document.createElement("div");
Square['Square'+i].style.position = "relative";
Square['Square'+i].style.float = "left";
Square['Square'+i].style.width = "50px";
Square['Square'+i].style.height = "50px";
Square['Square'+i].id = "square" + (i + 1);
for(var ii = 0; ii < 6; ii++){
var TestColor = TestColorArray[Math.round(Math.random()*(TestColorArray.length - 1))];
getTestColor += TestColor;
}
Square['Square'+i].style.backgroundColor = "#" + getTestColor;
SquareCont.appendChild(Square['Square'+i]);
getTestColor = '';
}
console.log(Square);
This example does what you want using an object instead of an array, but meets your desire to dynamically create accessible Square1, Square2, etc... They are all contained in Square. In the console with this snippet, you will see that 100 squares are created and added to the Square object. They will be accessible by Square.SquareX (where X is some number), or Square['SquareX'], or Square['Square'+X] where X is some number again.
Your declaration syntax is not valid. But, I think the larger point you are trying to get to is to be able to populate an array with dynamically created elements and that you can do:
var squares = []; // Array must exist before you can populate it
var testColorArray = ["green", "yellow", "blue", "orange", "silver"];
var getTestColor = null;
function makeSquares(count){
for(var i = 0; i < count; i++){
// Just create the element and configure it. No need to worry about the array yet
var element = document.createElement("div");
element.style.float = "left";
element.style.width = "75px";
element.style.height = "75px";
element.id = "square" + (i + 1);
element.style.backgroundColor = testColorArray[Math.floor(Math.random()* testColorArray.length)];
element.textContent = element.id;
squareCont.appendChild(element);
// Now, add the element to the arrray
squares.push(element);
}
// Test:
console.log(squares);
}
makeSquares(10);
<div id="squareCont"></div>

Javascript- Dynamic variable loop

I'm trying to reduce the amount of code I repeat.
Currently I have the below:
var item1H = $(".item-1").height();
var item1W = $(".item-1").height();
$(".item-1 .text").css('margin-left', -item1W/2);
$(".item-1 .text").css('margin-bottom', -item1H/2);
var item2H = $(".item-2").height();
var item2W = $(".item-2").height();
$(".item-2 .text").css('margin-left', -item2W/2);
$(".item-2 .text").css('margin-bottom', -item2H/2);
I'm looking to put this into a for loop where the variable number would count up to whatever number I needed it to stop.
You can make function like this and use whenever you want
toSetMargin(".item-2")
toSetMargin(".item-2")
function toSetMargin(objStr){
var widthTmp = $(objStr + ' .text').height();
var heightTmp = $(objStr + ' .text').height();
obj.css('margin-left', -widthTmp/2);
obj.css('margin-bottom', -heightTmp/2)
}
This code not impact any other code.
You could use $('[class^="item-"]') to get all the elements that have a class that starts with item-, and the loop over them
$('[class^="item-"]').each(function(){
var $elem = $(this);
var item1H = $elem.height();
var item1W = $elem.width();
$elem.find('.text').css({'margin-left': -item1W/2,'margin-bottom':-item1H/2});
});
Ooh boy, one of these problems. This should help (untested):
for(i=1;i<=STOPPING_NUMBER;i++){
window["item"+i+"H"] = $(".item-"+i).height();
window["item"+i+"W"] = $(".item-"+i).width(); //Was height, accident?
$(".item-"+i+" .text").css('margin-left', 0-window["item"+i+"W"]/2); //Hope this works lol
$(".item-"+i+" .text").css('margin-bottom', 0-window["item"+i+"H"]/2);
}
Guessing these lines:
var item1W = $(".item-1").height();
var item2W = $(".item-2").height();
Should have been:
var item1W = $(".item-1").width();
var item2W = $(".item-2").width();
You could do something like:
function setCSS(item,attr,val) {
$(item +" .text").css(attr, (val * -1)/2);
}
var i, max = 10;
for(i=1;i<=max;i++) {
setCSS(".item-"+ i,"margin-left",$(".item-"+ i).width());
setCSS(".item-"+ i,"margin-bottom",$(".item-"+ i).height());
}
Or something less flexible within the function:
function setCSS(item,w,h) {
$(item +" .text").css("margin-left", (w * -1)/2);
$(item +" .text").css("margin-bottom", (h * -1)/2);
}
var i, max = 10;
for(i=1;i<=max;i++) {
setCSS(".item-"+ i,$(".item-"+ i).width()),$(".item-"+ i).height());
}
Something like this should be pretty acceptible in your case, I guess:
for (var i = 1, len = someN; i < len; i++) {
var $item = $('.item-' + i);
$item.find('.text').css({
'margin-left': -$item.width() / 2,
'margin-bottom': -$item.height() / 2
});
}

Run javascript on multiple selected checkboxes

Hello I am currently writing a web application that calculates a number based on what a user has checked.
You can see it here.
If you go to the link you can see that a person will check a checkbox first and enter a value from the dropdown and type 2 values to get an output.
What I need help with is being able to calculate the value for more than one checkbox at a time.
Right now I can only calculate the value for a checkbox one at a time even if multiple are selected. So basically I need help try to figure how to calculate for more than one checkbox at a time.
I was using an if statement inside my javascript file but thats not giving me the result that I want.
Just remove else if statements, change for IF only. But I have to say that's solution its not that scalable, and for a big application could turns into a nightmare.
I recommend you try to use $("input:checked").each(function() {}); if you dont want to store it and just show the values on the client to avoid further problems and bad code. With your line of thought, you'll need everytime make copy and paste those IF's everytime you want to implement new form labels.
$(document).ready(function(){
function check(){
if($('#checkbox1').is(':checked')){
var pokemonCount = parseInt($("#pokecount1").val());
var candyCount = parseInt($("#candycount1").val());
var reqCandy = parseInt($("#dropdown1 :selected").val());
var evolveAmount = 0;
evolveAmount = Math.floor(((candyCount + pokemonCount) - 1) / (reqCandy));
$("#p1").html(evolveAmount);
}
if($('#checkbox2').is(':checked')){
var pokemonCount2 = parseInt($("#pokecount2").val());
var candyCount2 = parseInt($("#candycount2").val());
var reqCandy2 = parseInt($("#dropdown2 :selected").val());
var evolveAmount2 = 0;
evolveAmount2 = Math.floor(((candyCount2 + pokemonCount2) - 1) / (reqCandy2));
$("#p2").html(evolveAmount2);
}
if ($('#checkbox3').is(':checked')){
var pokemonCount3 = parseInt($("#pokecount3").val());
var candyCount3 = parseInt($("#candycount3").val());
var reqCandy3 = parseInt($("#dropdown3 :selected").val());
var evolveAmount3 = 0;
evolveAmount3 = Math.floor(((candyCount3 + pokemonCount3) - 1) / (reqCandy3));
$("#p3").html(evolveAmount3);
}
}
$("#compute").click(function(){
check()
});
});
Just remove Else if to if only
$(document).ready(function(){
function check(){
if($('#checkbox1').is(':checked')){
var pokemonCount = parseInt($("#pokecount1").val());
var candyCount = parseInt($("#candycount1").val());
var reqCandy = parseInt($("#dropdown1 :selected").val());
var evolveAmount = 0;
evolveAmount = Math.floor(((candyCount + pokemonCount) - 1) / (reqCandy));
$("#p1").html(evolveAmount);
}
if($('#checkbox2').is(':checked')){
var pokemonCount2 = parseInt($("#pokecount2").val());
var candyCount2 = parseInt($("#candycount2").val());
var reqCandy2 = parseInt($("#dropdown2 :selected").val());
var evolveAmount2 = 0;
evolveAmount2 = Math.floor(((candyCount2 + pokemonCount2) - 1) / (reqCandy2));
$("#p2").html(evolveAmount2);
}
if ($('#checkbox3').is(':checked')){
var pokemonCount3 = parseInt($("#pokecount3").val());
var candyCount3 = parseInt($("#candycount3").val());
var reqCandy3 = parseInt($("#dropdown3 :selected").val());
var evolveAmount3 = 0;
evolveAmount3 = Math.floor(((candyCount3 + pokemonCount3) - 1) / (reqCandy3));
$("#p3").html(evolveAmount3);
}
}
$("#compute").click(function(){
check()
});
});
You've used elseif, so if the first checkbox is checked then it runs that code and stops. You need a series of if blocks:
if(1.isChecked){
}
if(2.isChecked){
}
You are using else if statements in your code, which means that the code of only one of the 3 if statements can be executed. More info here.
You need to replace them with simple if statements, like this:
$(document).ready(function(){
function check(){
if($('#checkbox1').is(':checked')){
var pokemonCount = parseInt($("#pokecount1").val());
var candyCount = parseInt($("#candycount1").val());
var reqCandy = parseInt($("#dropdown1 :selected").val());
var evolveAmount = 0;
evolveAmount = Math.floor(((candyCount + pokemonCount) - 1) / (reqCandy));
$("#p1").html(evolveAmount);
}
if($('#checkbox2').is(':checked')){
var pokemonCount2 = parseInt($("#pokecount2").val());
var candyCount2 = parseInt($("#candycount2").val());
var reqCandy2 = parseInt($("#dropdown2 :selected").val());
var evolveAmount2 = 0;
evolveAmount2 = Math.floor(((candyCount2 + pokemonCount2) - 1) / (reqCandy2));
$("#p2").html(evolveAmount2);
}
if ($('#checkbox3').is(':checked')){
var pokemonCount3 = parseInt($("#pokecount3").val());
var candyCount3 = parseInt($("#candycount3").val());
var reqCandy3 = parseInt($("#dropdown3 :selected").val());
var evolveAmount3 = 0;
evolveAmount3 = Math.floor(((candyCount3 + pokemonCount3) - 1) / (reqCandy3));
$("#p3").html(evolveAmount3);
}
}
$("#compute").click(function(){
check()
});
});

Code is working fine in firefox but not working in chrome. Why?

In my web application I've the following code in a function. And when I execute the code in firefox it works fine and gives me the output. But when I execute the same code in chrome the function is entering infinite loop and returning (its not throwing any exception or error).
And the Info: elem is an xml element not html element; and that xml is a SVG image
The Code is like this:
Function call:
buildElemView(viewElement, container, 1, viewType);
and then the function:
function buildElemView(elem, container, start, viewType){
var vwType = viewType;
var cat = $(elem).find('cat:first').text();
//alert("cat is "+cat);
var type = $(elem).find('type:first').text();
var id = $(elem).find('eid:first').text();
var mid = $(elem).find('mid:first').text();
var parentMids = $(elem).parents().map(function () {
return $(this).find('mid:first').text();
})
.get().reverse().join("");
if (viewType==1 && Number(eleCat>60) && Number(cat)<40)
return;
var parentElementId = parentMids;
var elementGroupId = parentMids+mid;
var grp = $(elem).find('gr:first').text();
var cz = $(elem).find('cz:first').text();
var zo = $(elem).find('zo:first').text();
var yo = $(elem).find('yo:first').text();
var rotate = ($(elem).find('rt:first').text().split(';'))[0];
var scale = ($(elem).find('sc:first').text().split(';'))[0];
var positionx = ($(elem).find('px:first').text().split(';'))[0];
var positiony = ($(elem).find('py:first').text().split(';'))[0];
var positionz = ($(elem).find('pz:first').text().split(';'))[0];
var dimension = $(elem).find('dm:first').text();
var parentdimension = $(elem).parent().find('dm:first').text();
var parentheight=0;
if (parentdimension !='')
parentheight = (parentdimension.split(';'))[2];
if (parentheight==undefined || parentheight=="null")
parentheight =0;
var height = 0;
if (dimension !='')
height = (dimension.split(';'))[2];
if (height==undefined || height=="null")
height =0;
var transformStr = "";
var num =0;
if (start && start==1)
{
transformStr= "translate(0,0) rotate(0) scale(1,1)";
if (viewType==1 && Number(eleCat)<100) {
var px = 0;
var py = 0;
if (scaleX==-1) px = 15000;
if (scaleY==-1) py = 15000;
transformStr = "translate("+ px+","+py +") rotate(0) scale("+ scaleX+","+scaleY+ ")";
}
if (Number(type)==50 || Number(type)==80 || Number(type)==100)
vwType=4;
}
else {
if (viewType<3 || Number(cat)>40)
{
if (viewType==2) {
var px = positionx;
var py = positiony;
var pz = positionz;
if (parentheight)
positiony = Number(parentheight)-Number(positionz)-Number(height);
}
//And there is a lot of Code here but its not even executing the entire code //strightly coming to alert box after clicking debug stepover.
}
The Function is too big I can give you this much only...
But by debugging the problem happens here...
var cat = $(elem).find('cat:first').text();
var type = $(elem).find('type:first').text();
var id = $(elem).find('eid:first').text();
var mid = $(elem).find('mid:first').text();
I came to a conclusion after putting an alert message in between them like this.
var cat = $(elem).find('cat:first').text();
var type = $(elem).find('type:first').text();
alert("Alert");
var id = $(elem).find('eid:first').text();
var mid = $(elem).find('mid:first').text();
In firefox alert is shown once and all the lines are executed and returned. But in chrome alert is keep on coming. It's not executing first two lines and last two lines just executing alert and that too continuously doing it.
Info: This worked fine with chrome version 47 but now not working in version 49 after updation.
Please do help why this weird behavior of Chrome.
I had a related issue a monte ago, and i solved it writing the definition of the function after the call

GridView Freeze Header

I am using this tutorial to freeze the header of the GridView. I did everything as explained in the tutorial but I got the following error in IE9 and I don't know why.
Error:
Line: 182
Error: Unable to get value of the property 'offsetWidth': object is
null or undefined
I defined the GridView in the Javascript code as show below:
<script type = "text/javascript">
var GridId = "<%=GridView1 %>";
var ScrollHeight = 300;
window.onload = function () {
var grid = document.getElementById(GridId);
var gridWidth = grid.offsetWidth;
var gridHeight = grid.offsetHeight;
var headerCellWidths = new Array();
for (var i = 0; i < grid.getElementsByTagName("TH").length; i++) {
headerCellWidths[i] = grid.getElementsByTagName("TH")[i].offsetWidth;
}
grid.parentNode.appendChild(document.createElement("div"));
var parentDiv = grid.parentNode;
var table = document.createElement("table");
for (i = 0; i < grid.attributes.length; i++) {
if (grid.attributes[i].specified && grid.attributes[i].name != "id") {
table.setAttribute(grid.attributes[i].name, grid.attributes[i].value);
}
}
table.style.cssText = grid.style.cssText;
table.style.width = gridWidth + "px";
table.appendChild(document.createElement("tbody"));
table.getElementsByTagName("tbody")[0].appendChild(grid.getElementsByTagName("TR")[0]);
var cells = table.getElementsByTagName("TH");
var gridRow = grid.getElementsByTagName("TR")[0];
for (var i = 0; i < cells.length; i++) {
var width;
if (headerCellWidths[i] > gridRow.getElementsByTagName("TD")[i].offsetWidth) {
width = headerCellWidths[i];
}
else {
width = gridRow.getElementsByTagName("TD")[i].offsetWidth;
}
cells[i].style.width = parseInt(width - 3) + "px";
gridRow.getElementsByTagName("TD")[i].style.width = parseInt(width - 3) + "px";
}
parentDiv.removeChild(grid);
var dummyHeader = document.createElement("div");
dummyHeader.appendChild(table);
parentDiv.appendChild(dummyHeader);
var scrollableDiv = document.createElement("div");
if(parseInt(gridHeight) > ScrollHeight){
gridWidth = parseInt(gridWidth) + 17;
}
scrollableDiv.style.cssText = "overflow:auto;height:" + ScrollHeight + "px;width:" + gridWidth + "px";
scrollableDiv.appendChild(grid);
parentDiv.appendChild(scrollableDiv);
}
</script>
So how I fix this problem?
You have written code incorrectly
Instead of
var GridId = "<%=GridView1 %>";
Change to
var GridId = "<%=GridView1.ClientID %>"; //<= Check this
When ASP.Net controls are rendered their Id gets mangled and to get the mangled on client side the notation is as shown above.
Hope this solves your problem.

Categories

Resources