queryselector only happen once on text element - javascript

I'm struggling understanding some basics concept I guess,
I have this JavaScript function which take a dom element and should increase it's number every time the button is clicked, the thing is, the number increase once and never increase again, console.log show the actual number but not the stPage element. From my understanding it has to deal with the DOM element stored, so I have to kill the first child, I think I did so, but it doesn't seems to work.
If some can help me, please do, thank you really much <3
function stpage(){
//Setting child element + simple increment function
let numberNode = document.getElementById('stPage');
let articleNumber = 0;
articleNumber++;
//killing the child then display the element on the page
numberNode.removeChild(numberNode.childNodes[0]);
document.querySelector('#stPage').innerHTML = articleNumber;
};
Edit: articleNumber has to be outside the function scope.
let articleNumber = 0;
function stpage(){
articleNumber++;
document.querySelector('#stPage').innerHTML = articleNumber;
};

You are re-initializing articleNumber to 0 every time the function is called on this line:
let articleNumber = 0;
It should be something like:
let articleNumber = 0; // outside function scope, doesn't reset
function stpage() {
let numberNode = document.getElementById('stPage');
articleNumber++;
numberNode.innerHTML = articleNumber;
};

Related

I want to get an element tag printed in the console just by clicking on it

I want to get an element tag printed in the console just by clicking on it but it doesn't seem to work and I don't get why?
can anyone point the error in my logic?
let bodyChildren = document.body.children;
let bodyArr = Object.values(bodyChildren);
for (i = 0; i < bodyChildren.length; i++) {
bodyArr[i].onclick = function () {
console.log(bodyArr[i].tagName);
};
}
The problem is that when you define a function, everything in it is contained in a separate scope. Within the function bodyArr is not known. You can use this instead to refer to the clicked element, like below:
document.body.children will only refer to the direct children of the body element. If you want to refer to every element in the DOM, you can use document.getElementsByTagName("*") instead.
When the code is written globally, like in the snippet below, the variable bodyArr is actually available in the global scope, as is the variable i. But keep in mind that the code inside the function is only executed when an element is clicked. At that point in time the for loop has been fully executed leaving i with the value 3 (since in the snippet below the script tag also counts). bodyArr will always contain exactly 1 element less, no matter how many elements are in the DOM. In this case it has 3 elements with the last element being saved at position 2 (zero based) in the array, hence bodyArr[i] equals undefined.
let bodyChildren = document.body.children;
let bodyArr = Object.values(bodyChildren);
for (i = 0; i < bodyChildren.length; i++) {
bodyArr[i].onclick = function () {
console.log(this.tagName);
}
}
<span>child1</span>
<p>child2</p>
You need to get ALL elements from the document body and this is KEY: var all = document.getElementsByTagName("*");
var all = document.getElementsByTagName("*");
let bodyArr = Object.values(all);
for (i = 0; i < bodyArr.length; i++) {
bodyArr[i].onclick = function () {
console.log(this.tagName);
};
}
<span>Hello world</span>

Multiple of document.getElementById("elementId").innerHTML = () causing second one to return as null

First, let me explain what I'm trying to do: I want to make a script for a video game that counts how much money is in the game, and create an element to display it. The tracking the money part was easy, but apparently making elements is like the most confusing thing i've tried to do yet.
Lightshot screenshot of chrome console: https://prnt.sc/shszc2
The blue-highlighted line in the screenshot gave an error after being executed twice. I boxed the error message in red.
I'll take some code out of the script I have, mainly aiming for code that is important for the issue i want help with, leaving out code that I understand.
Also note that I am extremely new to generating graphics in Javascript, so if my ways of making elements are horrendous, then it's because I just kept trying random crap until something seemed to work and stuck with whatever that was.
// The elements that I created. Again i know next to nothing about elements, so the only thing that I
// know will work is this catastrophe.
var initialDiv = document.getElementById('onecup');
mainText = initialDiv.appendChild(document.createElement('mainText'));
mainText.style.position = 'absolute';
mainText.style.left="50%";
mainText.style.top="64px"
mainText.style.width = "290px";
mainText.style.height = "160px";
mainText.style.color = "white";
mainText.style.zindex = 1;
mainText.style.fontSize = "18px"
trackerBack = mainText.appendChild(document.createElement('trackerBack'));
trackerBack.style.position = 'absolute';
trackerBack.style.left="-200px"
trackerBack.style.top="0px"
trackerBack.style.width = "400px";
trackerBack.style.height = "160px";
trackerBack.style.backgroundColor = "black";
trackerBack.style.opacity = ".20"
trackerBack.style.zindex=1;
diffTotal = trackerBack.appendChild(document.createElement('diffTotal'));
diffTotal.id = "diffTotal"
diffTotal.style.position = 'absolute';
diffTotal.style.top="20%"
diffTotal.style.left="40%";
diffTotal.style.color = "rgba(255,255,255,255)";
diffTotal.style.opacity = "1"
diffTotal.style.zindex = 2;
diffTotal.style.fontSize = "30px"
diffFielded = diffTotal.appendChild(document.createElement('diffFielded'));
diffFielded.id = "diffFielded"
diffFielded.style.position = 'absolute';
diffFielded.style.top="-15px"
diffFielded.style.left="0px";
diffFielded.style.color = "rgba(255,255,255,255)";
diffFielded.style.opacity = "1"
diffFielded.style.zindex = 2;
diffFielded.style.fontSize = "20px"
// This function is used by a latter function to set the values of the text elements. I initially didn't
// have this but thought adding it would help, but nothing changed.
// By the way, "toBna2" stands for to "big number abbreviation". It doesn't do anything major, besides
// shrink down numbers. Tried removing it, problem still persists.
conductValues = function(targetName, targetAssignment) {
document.getElementById(targetName).innerHTML = toBna2(targetAssignment)
}
// This looping function controls the values that the elements display. However, I removed the code that
// tells the function what values to make the elements, so if you want to test it, I guess just define
// the 4 values as anything or make your own.
findValueDiff = setInterval(function() {
// If i make one of these lines a comment, it works, regardless of which one it is. But if i let both of
// them run, the second document.getElementById("elementId") returns as null. Always the second one.
conductValues("diffTotal", (aValP + aValU - bValP - bValU))
conductValues("diffFielded", (aValU - bValU))
}
I even tried doing this:
conductValues = function(targetName, targetAssignment) {
if (document.getElementById(targetName) != "undefined") {
document.getElementById(targetName).innerHTML = toBna2(targetAssignment)
}
}
But all that does is make the function fail on the first attempt, because always the second document.getElementById("elementId") returns as null.
I'm not entirely sure if I included enough information, but I don't know what else to add so hopefully I did. But if you need more information, just ask and i'll try to edit this post as swiftly as possible.
Thanks to all responders, and I hope you stay healthy as you have fun coding.
Edit 1: Thought i would get something different if I set the entity's variables one at a time like this:
conductValues = function(targetName, targetAssignment) {
document.getElementById(targetName).innerHTML = toBna2(targetAssignment)
}
loopMode=0
findValueDiff = setInterval(function() {
if (loopMode == 0) {
conductValues("diffTotal", (aValP + aValU - bValP - bValU))
loopMode = 1
} else {
conductValues("diffFielded", (aValU - bValU))
loopMode = 0
}
}, 1000
);
But the problem still hasn't changed. Second time it tries to update, it fails.
Ah, I got it:
diffTotal = trackerBack.appendChild(document.createElement('diffTotal'));
diffFielded = diffTotal.appendChild(document.createElement('diffFielded'));
conductValues("diffTotal", (aValP + aValU - bValP - bValU))
conductValues("diffFielded", (aValU - bValU))
conductValues = function(targetName, targetAssignment) {
document.getElementById(targetName).innerHTML = toBna2(targetAssignment)
}
Those are the lines, which cause the error.
diffFielded is a child of diffTotal. In the first conductValues call, you replace the innerHTML of diffTotal. When you are doing this, you are removing diffFielded, because it's replaces by the new value and then it cannot by found anymore because it does not exist anymore.
I assume diffFielded should actually be another child of trackerBack, so you should do:
diffFielded = trackerBack.appendChild(document.createElement('diffFielded'));
Tip:
Move the style stuff into a css file.

JavaScript code execution delay

function append(what) {
$("#drawer").append(what);
}
function outerHtml(o) {
return $("<div />").append($(o).clone()).html();
}
var allPixel = [];
$(".pix").each(function() {
allPixel.push(outerHtml($(this)));
});
$("#drawer").empty();
var index;
for (index = 0; index < allPixel.length; index++) {
pixel = allPixel[index];
setTimeout(append(pixel), 100);
}
I have a Container (#drawer) that is full of many div elements. In this function the HTML of each of these div elements gets saved in an array individually. When its done doing that the div element gets cleared.
In the Array allPixel are now all div elements. I want it so that each div element gets added to #drawer with a delay of 100ms.
Problem:
If I run this function nothing happens (the divs are not disappearing/ appearing). What did I do wrong?
If anything is unclear feel free to let me know and I will edit my question.
Question aswered... See it in action: https://wiese2.lima-city.de/test/
You are invoking the method invoking immediately and passing its return value i.e. undefined to setTimeout.
You can set additional parameters to be passed to append function when timer expires to setTimeout method.
Use
setTimeout(append, 100 * (i + 1), pixel);
Additionally you also need to increase timer based on element index

Understanding Private Variables (Closure?) in Javascript with specific example

OK, I have tried to use a closure to no avail on the following code to keep a variable private. I am brand new to javascript and have read a number of posts about closures and can still not wrap my head around them. Below, I have a function that, upon each press of a particular button, displays the next word in an array. I want my counter variable ("whatNumber" below) that I am using in this function to not be global but I cannot figure out how. Here is my simple code:
var wordList = ["jumper", "stumpy", "smelly gumdrops", "awesome puttputt", "soilent green"];
var whatNumber = 0;
function changeWord(){
if (whatNumber < wordList.length) {
alert(wordList[whatNumber]);
whatNumber++;
}
};
function changeWord(){
var wordList = ["jumper", "stumpy", "smelly gumdrops", "awesome puttputt", "soilent green"];
var whatNumber = 0;
return function alertWord(){
if (whatNumber < wordList.length) {
alert(wordList[whatNumber]);
whatNumber++;
}
}
};
//to run this
var alertNewWord = changeWord();
alertNewWord() //jumper
alertNewWord() //stumpy
This comes with a bonus of being able to have different functions having different levels of alerting. e.g: if you do another var anotherAlertFn = changeWord() and you call anotherAlertFn() it will result in "jumper". The initial functions (i.e: alertNewWord()) will still have it's own state, i.e: whatNumber === 3 while anotherAlertFn has whatNumber === 1. This can be very useful, imagine a function keeping score for different players in a game. Every player can use the same function without being able to cheat (i.e: change their score) and never affecting other players' scores.

JavaScript DOM references not holding up

For some reason ss.transition() does not affect the appropriate DOM elements after ss.goTo() is triggered by an onclick. The ss.transition() call under //Init does work as expected. I assume this is a scope problem. Little help?
var ss = {};
ss.goTo = function(i) {
ss.old = ss.current;
ss.current = ss.slides[i];
ss.transition();
}
ss.transition = function() {
ss.old.style.display = "none";
ss.current.style.display = "block";
}
// Hooks
ss.div = document.getElementById("slides");
ss.as = ss.div.getElementsByTagName("a");
// References
ss.slides = [];
for (i in ss.as) {
if (ss.as[i].rel == "slide") {
ss.slides.push(ss.as[i]);
}
}
ss.first = ss.slides[0];
ss.last = ss.slides[ss.slides.length-1];
// Init
ss.current = ss.first;
ss.old = ss.last;
ss.transition();
for (i in ss.as) {
You shouldn't use the for...in loop over an Array or, in this case, NodeList. You'll get member properties you don't want, like item and length. You also can't rely on the items being returned in any particular order; it is very likely that at least ss.last will not be what you expect. If it's a non-item property, ss.old.style.display will definitely fail with an exception, breaking the script.
The correct loop for a sequence is the old-school C construct:
for (var i= 0; i<ss.as.length; i++)
Also, where are you binding the calls to goTo? If you are doing it in a loop with a function inside you, you may well also have the classic loop closure problem. See eg. this question.
The reason for the failure is because you lose the reference to the currently hidden element before you make it show up again. You need to assign old to display:block, then do the switch of old = current, current = variable, then hide old.

Categories