document.getElementById("#"); Not Working [duplicate] - javascript

This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 4 years ago.
I am trying to replace:
function checkValue() {
if (remainingTime < 10) {
document.getElementById("leading-zero").style.display = "inline";
} else {
document.getElementById("leading-zero").style.display = "none";
}
}
..with this:
var leadingZero = document.getElementById("leading-zero");
function checkValue() {
if (remainingTime < 10) {
leadingZero.style.display = "inline";
} else {
leadingZero.style.display = "none";
}
}
The first block of code works just fine but I don't want to be accessing the DOM everytime checkValue() is called (every half a second). That's why I attempted assigning the object (is it called an object??) to the variable named leadingZero. Why will this not work??

Instantiate leadingZero after document is loaded:
var leadingZero;
document.addEventListener("DOMContentLoaded", function(){
leadingZero = document.getElementById("leading-zero");
);
function checkValue() {
if (remainingTime < 10) {
leadingZero.style.display = "inline";
} else {
leadingZero.style.display = "none";
}
}

Related

Functions only apply to the last div using .each function [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 2 years ago.
I've seen similar cases but I can't seem to figure it how on my case.
So I got 3 different divs all having the same class of "display-boxes". What I'm trying to do is to apply my functions for all 3 divs. At the moment it's only applying the function for the last div.
$(".display-boxes").each(function() {
var boxList = $(this).context;
function resizeTeasersTablet(teaserNumber, teaserCollection) {
if (teaserNumber == 1) {
teaserCollection[0].style.width = '73.834%';
teaserCollection[0].style.margin = '0 auto 40px';
for (let i = 1; i < teaserNumber; i++) {
teaserCollection[i].style.width = '25%';
}
} else if (teaserNumber == 2) {
for (let i = 0; i < teaserNumber; i++) {
teaserCollection[i].style.width = '50%';
}
} else if (teaserNumber == 4) {
for (let i = 0; i < teaserNumber; i++) {
teaserCollection[i].style.width = '50%';
}
} else if (teaserNumber == 5) {
for (let i = 0; i < teaserNumber; i++) {
teaserCollection[i].style.width = '50%';
}
} else if (teaserNumber == 3) {
for (let i = 0; i < teaserNumber; i++) {
teaserCollection[i].style.width = '33.33%';
}
}
}
function resizeTeasersMobile(teaserNumber, teaserCollection) {
for (let i = 0; i < teaserNumber; i++) {
teaserCollection[i].style.width = '100%';
}
}
document.addEventListener('DOMContentLoaded', function() {
if (window.innerWidth > 2024) {
displayTeasers(boxList.childElementCount, boxList.children);
} else if (window.innerWidth > 641) {
resizeTeasersTablet(boxList.childElementCount, boxList.children);
} else {
resizeTeasersMobile(boxList.childElementCount, boxList.children);
}
});
window.onresize = function() {
if (window.innerWidth > 2024) {
displayTeasers(boxList.childElementCount, boxList.children);
} else if (window.innerWidth > 641) {
resizeTeasersTablet(boxList.childElementCount, boxList.children);
} else {
resizeTeasersMobile(boxList.childElementCount, boxList.children);
}
};
});
<div id="section2" class="padding-margin-border column">
<div class="lobby-images-wrapper small-block-grid-1 display-boxes ongoingPromo">
<div class="display-box">
<div class="wrapper-lobby-image-item">
<span class="image-wrapper">
<a href="##Field.Teaser_Link##">##MarkComponentField(FieldPath+".Teaser_Image")##
<img src="##Field.Teaser_Image##" data-original="##Field.Teaser_Image##"/>
</a>
</span>
</div>
</div>
</div>
</div>
This is one of the 3 divs that I have since it won't let me post more code.
There are two problems here:
You've set window.onresize 3 times in a loop. Only the last assignment has an effect. You overwrite the previous two handlers. This is why your changes are only applied to your last div.
Document:DOMContentLoaded event is raised when the HTML document is fully loaded and parsed, which means either:
Your JavaScript code is run when the document is not loaded, and so your jQuery selector will not find your divs (it seems that it is not your case). This case happens when you load the code directly in a script at the beginning of the document's body.
Your JavaScript code is run after the document is loaded, so you'll find all your elements, but the event is already fired and your handler is never called. This case happens when you put the code inside an onload handler.
Your code is run after the divs are created but before the document is fully loaded. This case happens if you run the code before the end tag of </body> for example. This is the only case that works as expected. You better not put your code at such a risk! Your code should be robust and reliable.
The Fix
Here is how you can fix your issues (please pay close attention to my comments):
// Define your utility functions at the root level
function resizeTeasersTablet(teaserCollection) {
// No need to pass the collection size. It has a `length` property.
let width = undefined;
switch (teaserCollection.length) { // `swith`/`case` is simpler than those `if`s
case 1:
teaserCollection[0].style.width = '73.834%';
teaserCollection[0].style.margin = '0 auto 40px';
// The for loop is not needed. The length is 1!
break;
case 2:
case 4:
case 5:
width = '50%';
break;
case 3:
width = '33.33%';
break;
}
if (width)
for (let t of teaserCollection) // `for..of` is simpler
t.style.width = width;
}
function resizeTeasersMobile(teaserCollection) {
for (let t of teaserCollection)
t.style.width = '100%';
}
// The function name is clear
function resizeBasedOnWindowWidth(boxList) {
if (window.innerWidth > 2024)
displayTeasers(boxList.children);
else if (window.innerWidth > 641)
resizeTeasersTablet(boxList.children);
else
resizeTeasersMobile(boxList.children);
}
// The function name is clear
function resizeAllBoxListsBasedOnWindowWidth() {
$(".display-boxes").each(function () {
resizeBasedOnWindowWidth(this);
});
}
window.onresize = function () {
this.resizeAllBoxListsBasedOnWindowWidth(); // Just call the defined function.
}
$(function () { // See here: https://api.jquery.com/ready/
resizeAllBoxListsBasedOnWindowWidth(); // Do not repeat the code. Just call the function.
})
The principles I used in this code, are VERY important. I advise you to read the code multiple times :)
Good luck

Best performance Javascript conditionals based on countdown timer

I am currently working on a project that is showing and displaying DOM elements based on a countdown timer. There is another function calling this one every second.
Here is a code sample:
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x >= 0.0 && x < 30.0) {
document.getElementById('thing1').style.display = 'block';
document.getElementById('thing2').style.display = 'none';
}
else if (x >= 30.0 && x < 60.0) {
document.getElementById('thing1').style.display = 'none';
document.getElementById('thing2').style.display = 'block';
}
x++;
}, 1000);
}
I'm trying to increase performance, and I'm doing this by trying to reduce the number of DOM requests and looking at alternative ways to fire code based on the countdown timer.
Something like
function eventsOnTimer(id1, id2, ms) {
let toggle = false, thing1 = document.getElementById(id1), thing2 = document.getElementById(id2);
const interval = setInterval(() => {
if(toggle){
thing1.style.display = 'block';
thing2.style.display = 'none';
} else{
thing1.style.display = 'none';
thing2.style.display = 'block';
}
toggle = !toggle;
}, ms);
}
eventsOnTimer('thing1', 'thing2', 30000);
You can store all of nodes references before run your timer to dicrease DOM access time (getElementById).
After that, using className instead of style property will be faster. You juste need declared an specific CSS rule per state.
I propose to you an generic function to set automatically all of your nodes with the same CSS class name.
JS
var nodeArray = [];
var max_node = 2;
function storeNodeRef() {
for(var i =1; i <= max_node; i++) {
nodeArray.push( document.getElementById("thing"+i)); // Your nodes are declared with ID thing"X". "X" is a numeric value, set "max_node" with the latest "X" value.
}
eventsOnTimer();
}
function setNodeClass(nodeClassName) {
var i = 0;
while(i < max_node) {
nodeArray[i++].className = nodeClassName;
}
}
function eventsOnTimer() {
let x = 1;
const interval = setInterval(() => {
if (x==30 || x == 60) { // declare here your different state, you can use multiple if/elseif or multiple switch case.
setNodeClass('hide myClass'+x); // Param : new className
}
x++;
}, 1000);
}
storeNodeRef();
CSS
.process > div, .hide {display:none;}
#thing2.myClass30, #thing1.myClass60, .process > div.show {display:block; }
HTML EXAMPLE
<div class="process">
<div id="thing1" class="show" >Hello World 1</div>
<div id="thing2">Hello World 2</div>
</div>

Add different event listener to a set of elements in a loop [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
Hello people of the internet,
I have a set of buttons and if a button is clicked it's content should be appended to a text field's content.
Lets say I have three buttons: [first] [second] [third]
My addEventListener-implementation results in "third" appended to the in text field's content, regardless which button I press. I don't know hot to fix this.
function setupListeners() {
var targetInputField = d.querySelector("#expression");
var t = d.querySelectorAll(".expression-button").length;
for (var i = 1; i <= t; i++) {
var btnElem = d.querySelector("#expression-button-"+i);
btnElem.addEventListener('click', function() {
if (targetInputField.value == "") {
targetInputField.value = btnElemLocal.innerText;
}
else {
targetInputField.value += ";"+btnElemLocal.innerText;
}
});
}
}
What I want:
If I click all of the three buttons in a row, the text field's content should be :
"first;second;third"
And not :
"third;third;third"
Put the click event code inside another function (btnClick in my example) and just call it when you attach the event in .addEventListener() inside the loop, then use this to refer to the current clicked element :
function btnClick() {
var targetInputField = d.querySelector("#expression");
if (targetInputField.value == "") {
targetInputField.value = this.innerText;
}
else {
targetInputField.value += ";"+this.innerText;
}
}
Hope this helps.
var d = document;
function setupListeners() {
var t = d.querySelectorAll(".expression-button").length;
for (var i = 1; i <= t; i++) {
var btnElem = d.querySelector("#expression-button-"+i);
btnElem.addEventListener('click', btnClick);
}
}
function btnClick() {
var targetInputField = d.querySelector("#expression");
if (targetInputField.value == "") {
targetInputField.value = this.innerText;
}
else {
targetInputField.value += ";"+this.innerText;
}
}
setupListeners();
<button class='expression-button' id='expression-button-1'>First</button>
<button class='expression-button' id='expression-button-2'>Second</button>
<button class='expression-button' id='expression-button-3'>Third</button>
<input id='expression' />

how to attach click function to multiple divs without ID

I have a fade in function im trying to understand better. It works fine when I set up the
My question is if I have 8 links that already have the separate ID and class names how can I attach this function to each clickable link?
Is there a function to getElementbyClass or something and then just add the class to all my links?
here is my javascript:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Correcting the answer from BLiu1:
var fadeDivs = document.getElementsByClassName('fade');
for (var i=0, i<fadeDivs.length, i++){
// do stuff to all fade-divs by accessing them with "fadeDivs[i].something"
}
Have you considered using a javascript library like jQuery to manage this. They have some extensive, very easy to use "selectors" that allow you to easily get access to elements in the DOM and animate them with things like "fade ins" and "slides", etc. If you need more animations there are tons of plugins available for this. It also helps to deal with browser compatibility challenges too.
If you want to rely on pure JavaScript, you can use the document.getElementsByClassName() function defined here, but that function is only defined in IE9 and above as well as Safari, Chrome, FF, and Opera.
As said in the comments, there is a getElementsByClassName() method. Here is how you would use it.
for(var i=0; i<document.getElementsByClassName("fade").length; i++ ){
/*apply fade in function*/
}
I'm not sure whether getElementsByClassName() can detect one class name at a time. You might need regex for that.

how do you repeat a process multiple times with java script

I have found the following code and I was wondering how can I repeat this code 9 times before changing the newPage. What i am doing right now is making 10 html documents and i change newPage to page2.html, page3.html ,page4.html so after the count done it changes and eventually cycles through all these html documents. I want to keep it to only 2 documents. index.html with this code and end.html. index ill perform this code 9 times then change to end.html. Can anyone help?
var startTime = 45;
var newPage = "page2.html";
function countDown() {
startTime--;
document.getElementById("counter_display").innerHTML = startTime;
if (startTime == 0) {
window.location = newPage;
}
}
function gett(id) {
if (document.getElementById) {
return document.getElementById(id);
}
if (document.all) {
return document.all.id;
}
if (document.layers) {
return document.layers.id;
}
if (window.opera) {
return window.opera.id;
}
}
function watchNow() {
if (gett('counter_display')) {
setInterval(countDown, 1000);
gett("counter_display").innerHTML = startTime;
} else {
setTimeout(watchNow, 50);
}
}
document.onload = watchNow();
<p><b id="counter_display"></b></p>
<iframe frameborder="no" height="735" src="http://website.com/video.php" width="385"></iframe>
If you were loading the contents of the other pages with AJAX into the current page in a frame then you could replace the last line with:
document.onload = function () {
for (var i= 1; i < 10; i++) {
newPage = "page"+i+".html";
watchNow();
}
}
But as to how you do the first bit, I'll need more information about what the overal pages does etc.

Categories