Javascript clientHeight returns NaN in certain contexts - javascript

Interesting issue arising for me.
I am working on an infinite scroll thing in javascript that requires getting clientHeight of a div at some point:
here is the code:
document.addEventListener('DOMContentLoaded', init, false);
function init(){
var j = 0;
var inner1 = document.getElementById("innerDiv1");
inner1.addEventListener("scroll", function(event){ window.j = 2; checkForLoad();});
var inner2 = document.getElementById("innerDiv2");
inner2.addEventListener("scroll", function(event){ window.j = 1; checkForLoad();});
}
var i = 0;
var checkForLoad = function() {
var bottomDiv;
var bottomDivChild;
var offsetOfDiv;
var offsetOfPage;
if(window.j === 2){
bottomDiv = document.getElementById("innerDiv1");
bottomDivChild = bottomDiv.lastElementChild;
offsetOfDiv = bottomDivChild.offsetTop + bottomDivChild.clientHeight; //WORKS FINE
offsetOfPage = (document.getElementById("innerDiv1").pageYOffset) + (document.getElementById("innerDiv1").clientHeight); //THIS IS WHERE THE ISSUE IS
}
else if(window.j === 1){
bottomDiv = document.querySelector("innerDiv2 > div:last-child");
offsetOfDiv = bottomDiv.offsetTop + bottomDiv.clientHeight;
offsetOfPage = inner1.pageYOffset + inner1.innerHeight;
}
if(offsetOfPage > offsetOfDiv - 10) {
alert("time to add");
//eventually will be AJAX with XSL
if (i % 5 !== 0) {
i++;
alert("into the append part");
var newResults = document.createElement("div");
newDiv.innerHtml = "testing " + i;
if(window.j === 2){
document.getElementById("innerDiv1").appendChild(newResults);
}
else if(window.j === 1){
document.getElementById("innerDiv2").appendChild(newResults);
}
checkForLoad();
} else if (i%5 === 0) {
newDiv = document.createElement("div");
newDiv.innerHTML = "Show more Results! " + i;
document.getElementById("scrollingDiv").appendChild(newDiv);
newDiv.setAttribute("ID", "showResults");
newDiv.setAttribute("onClick", "showMore()");
}
}
};
I realize that there are some inconsistencies here, but they are in parts of the script i am not using. Here is the issue though, in the if(window.j === 2) statement, you can see that I use client height in a couple places. In the first one, it returns a number perfectly and life goes on as planned, but when I use it in the line where I get the "offSerOfPage", the sum becomes NaN. I am using firebug to debug it and when I add document.getElementById("innerDiv1").clientHeight to the watch list, it shows that it has a number attatched to it. Yet the sum is returned as NaN. I think my wording is a bit confusing here so if you need clarification, please ask! Thanks!

Related

Automatic moving Input

I'm trying to have the Input someone puts into the Cell "M19" move to "Z1" and if that Cell is full move it to "Z2" and so on so forth.
Currently my code accurately moves the first and second Input into "M19" into "Z1" and "Z2" but afterwards just stops doing anything.
function myFunction()
{
var ss = SpreadsheetApp.getActiveSheet();
var vZPos = "M19";
var zZPos = "Z1";
var vonZelle = ss.getRange(vZPos); //InputCell
var zuZelle = ss.getRange(zZPos); //FirstOutputCell
var i = 0;
var c = 2;
var cTos = c.toString();
var naechsteZuZelle = zZPos.replace("1", cTos);
var naechsteZuZelleRange = ss.getRange(naechsteZuZelle); //ChangingOutputCell
do
{
if (zuZelle.isBlank() == true && c == 2)
{
vonZelle.moveTo(zuZelle);
i++;
}
else
{
if (naechsteZuZelleRange.isBlank() == true)
{
vonZelle.moveTo(naechsteZuZelleRange);
i++;
}
else
{
c++;
}
}
}
while (i == 0);
}
Since I'm not that skilled at coding I've kinda hit a brick wall on how to go on about doing things, I would aprreciate any help and/or explanations on how to solve my Problem.
P.S. Since I'm coding in German some of the Variable names might seem weird, if there are any questions I'll do my best to translate/elaborate on them.
Change:
else
{
c++;
}
To:
else
{
c++;
cTos = c.toString();
var naechsteZuZelle = zZPos.replace("1", cTos);
var naechsteZuZelleRange = ss.getRange(naechsteZuZelle)
}
It was not in your loop.

Getting an infinite loop and can't see why - Javascript

I'm writing a simple little Connect 4 game and I'm running into an infinite loop on one of my functions:
var reds = 0;
var greens = 0;
function checkEmpty(div) {
var empty = false;
var clicked = $(div).attr('id');
console.log(clicked);
var idnum = parseInt(clicked.substr(6));
while (idnum < 43) {
idnum = idnum + 7;
}
console.log("idnum=" + idnum);
while (empty == false) {
for (var i = idnum; i > 0; i - 7) {
idnumStr = idnum.toString();
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
}
}
return divToFill;
}
function addDisc(div) {
if (reds > greens) {
$(div).addClass('green');
greens++;
console.log("greens=" + greens);
} else {
$(div).addClass('red');
reds++;
console.log("reds=" + reds);
};
$(div).removeClass('empty');
}
$(function() {
var i = 1;
//add a numbered id to every game square
$('.game-square').each(function() {
$(this).attr('id', 'square' + i);
i++;
//add an on click event handler to every game square
//onclick functions
$(this).on('click', function() {
var divToFill = checkEmpty(this);
addDisc(divToFill);
})
})
})
Here is a link to the codepen http://codepen.io/Gobias___/pen/xOwNOd
If you click on one of the circles and watch the browser's console, you'll see that it returns true over 3000 times. I can't figure out what I've done that makes it do that. I want the code to stop as soon as it returns empty = true. empty starts out false because I only want the code to run on divs that do not already have class .green or .red.
Where am I going wrong here?
for (var i = idnum; i > 0; i - 7);
You do not change the i.
Do you want to decrement it by 7?
Change your for loop to the one shown below:
for (var i = idnum; i > 0; i -= 7) {
// ...
}
You also do not use loop variable in the loop body. Instead, you use idnum, I think this can be issue.
while (empty == false) {
for (var i = idnum; i > 0; i -= 7) {
idnumStr = i.toString(); // changed to i
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
// and don't forget to stop, when found empty
if (empty) break;
}
}
I add break if empty found, because if we go to next iteration we will override empty variable with smallest i related value.
You can also wrap empty assignment with if (!empty) {empty = ...;} to prevent this override, but I assume you can just break, because:
I want the code to stop as soon as it returns empty = true
Offtop hint:
while (idnum < 43) {
idnum = idnum + 7;
}
can be easy replaced with: idnum = 42 + (idnum%7 || 7)
Change to this:
for (var i = idnum; i > 0; i = i - 7) {
You are not decrementing the i in your for loop
Building on what the others have posted You would want to change the value of empty inside the for loop. because obviously the string still checks the last string in the loop which would always return false.
while(empty==false){
for (var i = idnum; i > 0; i -= 7) {
// your other codes
if (!empty) {
empty = str.includes('empty');
}
}

Make eventlisteners unique?

So I have a problem where the eventlisteners I setup all happen to work with the same variable.
This is how it looks like:
// Prepare tooltips
for (var i = 0; i < document.getElementsByClassName("tooltip").length; i++) {
var tooltip = document.getElementsByClassName("tooltip")[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null) {
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
input.addEventListener("focus", function() { document.getElementById(tooltip.id).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(tooltip.id).style.display = "none"; });
}
In the last two lines I set the eventlisteners.
So whenever I focus an input field, no matter which one tooltip.id is always the same.
I checked the input.id before its different in every loop.
Javascript is a funny language :)
In each loop you're declaring a function which uses a reference to the variable tooltip.
Since you use the variable many times: its value changes but the reference remains the same.
When the function executes, it uses the reference (which has the last value).
Here is the solution:
(I recommend calling the method 'document.getElementsByClassName("tooltip")' only once since it causes DOM traverse.
==== CODE STARTS HERE
var toolips = document.getElementsByClassName("tooltip");
for (var i = 0; i < toolips.length; i++)
{
var tooltip = toolips[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null)
{
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
// assign tooltip id to the input
input.tooltipId = tooltip.id;
// add event listeners
input.addEventListener("focus", function() { document.getElementById(this.tooltipId ).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(this.tooltipId).style.display = "none"; });
}
==== CODE ENDS HERE

Create dynamic elements in javascript and visualize it on UI as soon as the node is created

I am working on a script that creates a tree. The problem i am facing is when large chunk of data comes it gets stuck for some time then rendering every thing at the end.
What i am looking for is can there be a way that make it more interactive. Like as soon as a node is being made it gets popup at the Interface.
For getting into the inside i am posting my code.
function recursiveGenerateTree(objNode, parntSpan, ulContainer, objEditParam) {
var cntLi = 0;
var spnApplyClass;
var rdbValue;
var cntrList = 0;
for (cntLi = 0; cntLi <= objNode.NodeList.length - 1; cntLi++) {
objEditParam.rdbGroup = objEditParam.rdbGroup;
rdbValue = objEditParam.orgRootID + '_' + objNode.NodeList[cntLi].Id;
objEditParam.rdbValue = rdbValue;
objEditParam.selector = 'radio';
objEditParam.selector = '';
objEditParam.isNewNode = false;
addChild('', parntSpan, ulContainer, objEditParam);
$('#txtParent').val(objNode.NodeList[cntLi].Name);
spnApplyClass = $('#txtParent').parents('span:first');
$('#txtParent').trigger('blur', [spnApplyClass]);
spnApplyClass.removeClass('bgLime');
var li = spnApplyClass.parents("li:first");
li.attr("nodeId", objNode.NodeList[cntLi].Id);
li.attr("rootnodeId", objNode.NodeList[cntLi].RootOrgUnitId);
var ulPrsnt = objNode.NodeList[cntLi].NodeList;
if (ulPrsnt != undefined && ulPrsnt.length > 0) {
recursiveGenerateTree(objNode.NodeList[cntLi], spnApplyClass, '', objEditParam);
}
}
}
Second function used is Add child
function addChild(currentbtn, parentSpn, parentUl, objEditParam) {
var spnElement;
if ($(currentbtn).length > 0) {
var dvClick = $(currentbtn).closest('div').siblings('div.OrgGroupLists')
spnElement = $(dvClick).find('span.bgLime');
}
else {
spnElement = parentSpn;
}
if (spnElement.length == 0 && parentUl.length == 0)
return;
var crtUlChild;
if (spnElement.length > 0) {
var dvCurrent = $(spnElement).closest("div");
crtUlChild = $(dvCurrent).find('ul:first');
}
if (parentUl.length > 0) {
crtUlChild = parentUl;
}
if (crtUlChild.length == 0) {
var ulChildrens = createUl();
}
//Next line needs to be updated.
var spnImage = $(dvCurrent).find("span:first");
$(spnImage).removeClass("SpanSpace");
$(spnImage).addClass("L7CollapseTree");
var liChildrens = document.createElement("li");
$(liChildrens).attr("isNew", objEditParam.isNewNode);
$(liChildrens).attr("isTextEdited", false);
var dvChildrens = createDivNode(objEditParam);
$(liChildrens).append(dvChildrens);
if (crtUlChild.length == 0) {
$(ulChildrens).append(liChildrens);
$(dvCurrent).append(ulChildrens);
}
else {
crtUlChild.append(liChildrens);
}
}
Feel free to ask any more details if required to understand the problem more clearly.
What #nnnnnn means is that you call subsequent recursion in setTimeout.
I did not spend time trying to replicate your code locally. Check out JavaScript code below for example. setTimeout works fine for the code below. You can vary variable j's length according to your browser. The inner loop j is to block JS thread.
<html><head>
<script>
var k = 0;
function recursiveTree(){
$("#holder").append("<div>Item</div>");
for(var j =0; j < 100000000; j++){
// blocking thread
}
if (k++ < 20) {
console.log(k);
setTimeout(function(){recursiveTree()},10);
}
}</script>
</head>
<body>
<div id='holder'></div></body>
</html>
I assumed that you are using JQuery.
Just to confirm you need to make recursive call as following
if (ulPrsnt != undefined && ulPrsnt.length > 0) {
setTimeout(function(){recursiveGenerateTree(objNode.NodeList[cntLi], spnApplyClass, '', objEditParam);},10);
}

Changing picture in javascript form on a click

In this code I get the following error:Exception... "Index or size is negative or greater than the allowed amount" code: "1" nsresult: "0x80530001 (NS_ERROR_DOM_INDEX_SIZE_ERR)". What is causing this? Thanks
function makecard(){
var bodypaint = document.getElementById('minaj');
var recipient = document.getElementById("recipient").value
var radioboxes = document.forms["cardform"].phrase.length
var i = document.getElementById("color").selectedIndex;
var z = document.getElementById("city").selectedIndex;
var tchatche= document.getElementById("color").options[i].text;
var malouba= document.getElementById("city").options[z].value;
for(c=0; c<radioboxes; c++){
if( document.forms["cardform"].phrase[c].checked){
var phrasevalue=document.forms["cardform"].phrase[c].value;
break;
}
}
if(document.getElementById("color").options[i].text === "White"){
bodypaint.style.backgroundColor ="White"
}
if(document.getElementById("color").options[i].text === "Red"){
bodypaint.style.background ="Red"
}
if(document.getElementById("color").options[i].text === "Blue"){
bodypaint.style.backgroundColor ="Blue"
}
var selectedcity = document.forms["cardform"].city.value
var paragraph = document.createElement("div");
paragraph.setAttribute("id","card")
document.body.appendChild(paragraph)
var picture = document.createElement("img")
picture.setAttribute("src", "")
paragraph.appendChild(picture)
paragraph.appendChild(document.createTextNode(phrasevalue + " from " + selectedcity + recipient))
if(malouba== "Paris"){
document.getElementById("picture").src = "paris.jpg"
}
if(malouba== "Venice"){
document.getElementById("picture").src = "venice.jpg"
}
if(malouba== "Rome"){
document.getElementById("picture").src = "rome.jpg"
}
}
document.getElementById("makeacard").onclick = makecard;
It's highly likely that one of the statements is producing a array of 0 elements and then when you try to use it later it freaks out:
var radioboxes = document.forms["cardform"].phrase.length
do a little console.log(radioboxes) on that and see if it comes back undefined or empty

Categories

Resources