Array of elements with certain class becomes undefined in setTimeout - javascript

I am using a JavaScript file to hide various div's all with the same class name, the program gets as far as hiding them but when I want them to be visible after "x" number of seconds the array of elements becomes undefined and has length 0, not sure what is going on. I have tried changing "lowerDash" to a global variable to no avail.
function newBaseHandler(){
if (document.getElementById("Base6").innerHTML == `<br><p>Create new base</p>`) {
let lowerDash = document.getElementsByClassName("LowerDashboard");
let message = document.getElementById("Message");
for (let button of lowerDash) {
button.style.visibility = "hidden";
}
message.innerHTML = `<br><p>Base created successfully</p>`;
setTimeout(function() {
message.innerHTML = ``;
console.log(lowerDash.length);
for (let button of lowerDash) {
button.style.visibility = "visible";
}
}, 1000);
}
}

If you want them to become visible again after a timeout, try
button.style.visibility = "visible"
in your for loop insie setTimeout

Related

How can i toggle innerHTML inside a setInterval() function with JS

I am trying to alternate the innerHTML of a at set Intervals.
Dear friends,
I am new to coding. I have created a div with an image, and a < p > element (that includes a < span >.
I have assigned two classes to the div, and I want it to alternate between the 2 classes at set intervals.
In addittion, I am trying to toggle the text inside the span, by using innerHTML.
So far I have managed succesfully to toggle the class, but I can't make the innerHTML to work.
I have the following code:
if(categProducts[idx].discount && categProducts[idx].low){
var Interval = setInterval(
function changeClass(){
document.getElementById('myDiv').classList.toggle("low");
},3000
)
var Interval2= setInterval(function changeText(){
var x=document.getElementById('mySpan').innerHTML
if (x==="<br> Only Few Cakes Left!!"){
x.innerHTML="<br> Discount! Best Price!!"
}
else {
x="<br> Only Few Cakes Left!!"
}
console.log(x)
}, 3000)
}
So far, the innerHTML of the only toggles once, and then it doesn't change again.
I can't make it work and I don't understand why.
The rest of the code is the following:
for (let idx in categProducts){
if (categProducts[idx].category==="cakes") {
const parentElement=document.getElementById("divCakes")
const myDiv=document.createElement("div")
parentElement.appendChild(myDiv)
myDiv.className="product"
const myImg=document.createElement("img")
myImg.src=categProducts[idx].imageURI
myImg.alt=categProducts[idx].alt
myDiv.appendChild(myImg)
myDiv.id="myDiv"
const myP=document.createElement("p")
myP.innerHTML=categProducts[idx].name
myDiv.appendChild(myP)
mySpan=document.createElement("span")
myP.appendChild(mySpan)
mySpan.id="mySpan"
IMO, you should define your desired classes and content inside arrays. Works for two, and more.
const changeContent = (() => {
const classes = ['first-class', 'second-class'];
const spanText = ['first text', 'second text'];
let index = 0;
return function() {
document.getElementById('mySpan').innerHTML = "";
document.getElementById('myDiv').classList = "";
document.getElementById('mySpan').innerHTML = spanText[index];
document.getElementById('myDiv').classList = classes[index];
index++;
if(index === classes.length) {
index = 0;
}
}
})();
setInterval(changeContent, 3000);
This functions uses closures to define global variables.

How can I set timers in slideshow to show as selected?

I have to create a slideshow, using an array of images and have that set on a timer. There is a drop-down menu with slow, medium, and fast options and the pictures need to transition with accordance to the drop down option selected. Whenever I execute this code in a web browser the code repeats itself, while doubling, as I read the value of i in the console.
I have tried using a while and a do-while loop to have the images on a rotation.
I have also tried putting the if-statements outside and below/above the function.
<script>
var i = 0;
function changeImg(){
if (x == 'slow'){
setInterval("changeImg()", 5000);
} else if (x == 'medium'){
setInterval("changeImg()", 3000);
} else if (x == 'fast') {
setInterval("changeImg()", 1000);
} else {}
while (i < 3){
console.log(i);
document.slide.src = sportsArray[i];
i++;
}
console.log(i);
console.log(sportsArray);
}
</sctipt>
First, I would read up on MDN's docs on setInterval() and clearInterval to fill in the knowledge gaps that lead you to approach the problem this way.
You are recursively calling changeImg() in your code which I believe is causing the issue you describe as:
the code repeats itself, while doubling, as I read the value of i in the console
Also, your while loop will run immediately when calling changeImg() which also does not appear to be desired in this situation.
setInterval() mimics a while loop by nature. There is no need for a while loop in this code. Below is a solution that I hope you can use as a reference. I separated the code to determine the interval into a function the getIntervalSpeed.
function changeImg(x) {
var getIntervalSpeed = function(x) {
if (x === 'slow') {
return 5000;
} else if (x === 'medium') {
return 3000;
} else if (x === 'fast') {
return 1000;
} else {
return 3000;
// return a default interval if x is not defined
}
};
var i = 0;
var slideShow = setInterval(function() {
if (i >= sportsArray.length) {
i = 0; // reset index
}
document.slide.src = sportsArray[i]; // set the slide.src to the current index
i++; // increment index
}, getIntervalSpeed(x));
// on click of ANY button on the page, stop the slideshow
document.querySelector('button').addEventListener('click', function() {
clearInterval(slideShow);
});
}

Reset function that will reset fields to what they were based on which of two functions was last run

I'm making a simple browser game to practice JS where you kill a bad guy. There are 2 modes, easy and hard. I am trying to set up a reset button that will reset information fields depending on which of the modes the game is in.
example
playing easy, click reset and the game resets by running easyMode function
playing hard, click reset and the game resets by running hardMode function
apologies if this is simple, this is why I'm making practice games
I've tried to make the function that currently has a specific class selected run when running reset function
var resetButton = document.querySelector("#new");
var easy = document.querySelector("#easy");
var hard = document.querySelector("#hard");
var playerHealth = document.querySelector("#php");
var playerFocus = document.querySelector("#pfocus");
var bossHealth = document.querySelector("#bhp");
var attack = document.querySelector("#attack");
var strong = document.querySelector("#strong");
var regenerate = document.querySelector("#regen");
var modeButtons = document.querySelectorAll(".mode");
var defenseLog = document.querySelector("#defenselog");
var offenseLog = document.querySelector("#offensivelog")
var boss = {}
var player = {}
setupModeButtons();
easyMode();
reset();
function hardMode(){
player.health = 12;
player.focus = 15;
boss.health = 25;
update()
};
function easyMode(){
player.health = 10;
player.focus = 10;
boss.health = 12;
update();
}
function update (){
playerFocus.textContent = player.focus;
playerHealth.textContent = player.health;
bossHealth.textContent = boss.health;
};
function setupModeButtons(){
for(var i = 0; i < modeButtons.length; i++) {
modeButtons[i].addEventListener("click", function(){
modeButtons[0].classList.remove("selected");
modeButtons[1].classList.remove("selected");
this.classList.add("selected");
});
}
}
function reset (){
if(easyMode.classList=="selected"){
easyMode();
} else if(hardMode.classList=="selected") {
hardMode();
}
}
The reset button works but always resets with function easyMode no matter which has had the class "selected" applied with function setupModeButtons
element.classList is a DomTokenList (https://developer.mozilla.org/en-US/docs/Web/API/Element/classList), so it never be "selected". Use the contains method instead:
function reset (){
if(easyMode.classList.contains("selected")){
easyMode();
} else if(hardMode.classList.contains("selected")) {
hardMode();
}
}
I hope this will help!
I am assuming you have a DOM tree that containing something like this
<button class='mode'>Easy</button>
<button class='mode'>Hard</button>
The code might be more readable if you explicitly named the buttons, rather than using an implicit array modeButtons[i] for your difficulty scale.
<button class='mode mode-easy'>Easy</button>
<button class='mode mode-hard'>Hard</button>
Your reset() function is trying to reference the prototype object chain of the functions easyMode.__proto__.classList and hardMode.__proto__.classList rather than the state of the DOM button. Also note that .classList is an array and not a string, so needs .contains()
function reset(){
if( modeButtons[0].classList.contains("selected") ) {
easyMode();
} else if( modeButtons[1].classList.contains("selected") ) {
hardMode();
}
}

Check whether function has run fully before, based on variable

I have a function which "types" out a header title as though it is being typed on the screen.
The typer only starts typing once a particular section of my site is "active" or is seen on the screen.
At present, it takes the outputID aka the area where this text will be typed into. There are two instances of this function being run, each with different outputIDs - I only want the function to run once per outputID.
This is how the function is initially called.
<h2 id="typer-get-in-touch" class="typer" data-text="Get in Toche^^^^^ Touch"></h2>
if(anchorLink == 'contact'){
var outputID = $("#typer-get-in-touch");
textTyping(outputID);
}else if(anchorLink == 'expertise'){
var outputID = $("#typer-expertise");
textTyping(outputID);
}
This is the textTyping function
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
var textArray = textString.split("");
var texttypeing = setInterval(
function() {
typeOutText(outputID,textArray);
}, 170);
function typeOutText(outputID,textArray) {
if (textArray[0] == "^"){
outputID.text(function(index, text){
return text.replace(/(\s+)?.$/, '');
});
textArray.shift();
}else {
if (textArray.length > 0) {
outputID.append(textArray.shift());
} else {
clearTimeout(texttypeing);
}
}
}
}
My issue at present is that the function runs multiple types, and continues to type each time the original anchorLink trigger is achieved. The result is that is writes the title many times e.g:
Get In TouchGet In TouchGet In Touch
Each time the section is navigated to, the typing starts again.
How can I run this function only ONCE per outputID? So once the outputID has been used, the function can no longer run for that data?
JSFiddle of non-working example: https://jsfiddle.net/qLez8zeq/
JSFiddle of mplungjan's solution: https://jsfiddle.net/qLez8zeq/1/
Change
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
to
function textTyping(outputID){
var textString = $(outputID).data("text");
if (textString=="") return;
$(outputID).data("text","");
$(outputID).show();
FIDDLE
What you need to do is to bind the event handler for each ID and then unbind it after it's been triggered the first time. Since you're already using jQuery, you can use the "one" method to do exactly this for each outputID:
$( "#typer-get-in-touch" ).one( "click", function() {
textTyping(outputID);
});
I suppose you could store your processed outputIds into an array and then check if the given outputId is present in the array before starting?
Define your array, check for the existence, if not found, do code example:
var processedIds = [];
function textTyping(outputID) {
var foundItem = false;
for (var i = 0; i < processedIds.length; i++)
{
if (processedIds[i] == outputID) {
foundItem = true;
break;
}
}
if (!foundItem) {
//the rest of your code goes here
}
}
You can add some check at the beginning of your function:
var called = {};
function textTyping(outputID) {
if (called[outputID]) {
return;
}
called[outputID] = true;
// your code
}

simplifying a multi-function in javascript

Hey I'm trying to figure out a way I might be able to simplify my code so that I will not have to have 38 of these functions but only have one that can run 38 different id's at separate times. This is a randomized script that tells the id element to land on a specific letter.
var randlet = 0;
var timesrun = 0;
function randomizer() {
randlet = Math.floor(Math.random() * 26);
timesrun += 1;
if (master[randlet] == letter[0]) {
$('#L1').css('background-position', master[randlet]);
clearInterval(interval);
} else {
if (timesrun == 100) {
master[randlet] = letter[0];
$('#L1').css('background-position', master[randlet]);
clearInterval(interval);
} else {
$('#L1').css('background-position', master[randlet]);
}
}
}
var interval = setInterval(function() {
randomizer();
}, 10);
For each element, set a class called 'randomise'. In the function, use the jquery .each method to iterate over each randomised element. If that element needs to have its value fixed, simp,y remove the 'randomise' class. When no more elements have the randomise class anymore, clear the timer.

Categories

Resources