Iterate focus components in javascript - javascript

I have some links and want to pass the focus one by one automatically.
I'm using the code below. Works fine passing the focus but only once.
The first time the focus pass, the link change the color, then pass to the next. The one before gets black again and the next is painted red. No problem.
But when its reach the final link doesn't restart.
var i = 0;
var letras = document.getElementsByTagName("a");
function pasaLink() {
if (i == 0) {
letras[letras.length-1].style.color = "black";
} else {
letras[i-1].style.color = "black";
}
letras[i].style.color = "red";
letras[i].focus();
i++;
if (i > letras.length) {
i= 0;
}
setTimeout("pasaLink()",2000);
}
With the final if and i=0; I'm trying to get back to the initial index when reach the final element, and then restart to iterate the entire collection of links in letras.
This function is called in the body.onload().
Any ideas why its not working?

Change your if to:
if (i >= letras.length) {
i= 0;
}
Working example:
http://jsfiddle.net/nivas/Nn62Q/
(click the Orig Button to see the behavior of your code and the New button to see the behavior of the new one. I have added a try...catch to show the error)
Explanation:
Let us say there are five a tags.
You make i = 0 when i > 6 (i.e., 6). But when i becomes 5, letras[i].style.color = "red"; at the beginning of the function fails and an exception is throws a exception. The flow stops here so the if (i > letras.length) will never be reached.

Shouldn't your condition be
if (i == letras.length) {
i= 0;
}
instead?
Once i is equal to the length of your array, reset.

Related

'CSS display: none' will work just fine, but 'document.body.removeChild(child);' will break my code

people that love programming.
Before I explain my issue, I need you to understand what I am doing here. It is a very simple game.
Do you remember that console video game "Guitar Hero"? Or if you are a little younger, "Piano Tiles"?
If you don't know what I'm talking about, click on this link to get an idea of what it is = https://www.youtube.com/watch?v=nWLKlEg0VMs&ab_channel=MattSterner
Well, that is exactly what I am doing with this website (on a more basic level of course).
In other words, there are musical notes falling from the top and the player has to press a button when that note hits the bottom of the screen.
Finally, what is my issue?
Well, when the note gets to the button, I am able to recognize it, which was actually hard and took me quite a while. And when I recognize it (inside the for loop below), and when I press the key E or keycode 69, the note disappears, which is exactly what I want.
So what's wrong?
Well, as you can see, I am setting the div's display property to none but the div is not actually being eliminated, this results in every div/musical note in the game to accumulate at the bottom with a display property of none, making the game slow.
So what do I want?
I want the div/musical note to be eliminated from the website entirely, gone, finito... not just setting its display property to none.
So what have I tried myself?
I tried document.body.removeChild(child) but this actually broke the game, notes stopped coming from the top, so it was not a fix (I have no clue of why this happened by the way).
You can see the part of the code I am having trouble with here:
document.body.addEventListener("keydown", event => {
if (event.keyCode === 69 /* E */) {
for (let i = 0; i < leftSquares.length; i++){
if (leftSquares[i].style.top > "740.5px" && leftSquares[i].style.top < "790.5px"){
console.log('correctin');
leftSquares[i].style.display = "none";
// document.body.removeChild(leftSquares[i]);
}
}
}
})
Or you can play around with the full game here: https://codepen.io/xavi-font/pen/MWeRdwr
Sticks and stones won't break my code, but document.body.removeChild(child) does (for a reason I don't know).
When you are doing document.body.removeChild(leftSquares[i]);
You remove the element from the page (DOM), but you do not remove the id from idArray = [];
So on the next loop of your code you get to:
for (let i = 0; i < idArray.length; i++) {
let element = document.getElementById(i.toString());
animateFunction(element);
}
and now the element does not exist, so you can't animate it, and you get an error that breaks the game.
A simple solution (not necessarily the best) could be:
for (let i = 0; i < idArray.length; i++) {
let element = document.getElementById(i.toString());
if (element) {
animateFunction(element);
}
}
Another option would be to keep specific id's in the array idArray, then when you delete an element, remove it's ID from the array, and where you previously have for (let i = 0; i < idArray.length; i++) { you can now use
idArray.forEach((id) => {
let element = document.getElementById(id.toString());
...
});
Your game also slows down, and if you console.log the element.style.top from within animateFunction you will see that if you don't press E at the correct time, then the element just keeps animating down the page forever.
So I would also suggest a garbage collect function within the animateFunction
maybe something like this?
function animateFunction(element) {
if (element.style.top == "-100px") {
const interval = setInterval(function() {
element.style.top = eval(parseInt(element.style.top) + 1).toString() + "px";
let currentNotePosition = element.getBoundingClientRect();
// Garbage Collect
if (currentNotePosition.top > window.innerHeight) {
document.body.removeChild(element);
}
}, speed);
}
}

Getting previous element in for loop

EDIT 2 (to make the problem more understandable)
The effect I am trying to achieve is the following: everytime an element enters the viewport an 'is-visible' class is added to it and the same 'is-visible' class is removed from the previous element.
Now I've managed to make it work but I run a for loop to remove all is-visible classes before adding the is-visible class to the element in viewport.
It works but in terms of performance I think it would be better to just remove the class from element[i -1]. And this were I can't get it working.
Here is a simplified fiddle were I try to make the element[i-1] solution work: https://jsfiddle.net/epigeyre/vm36fpuo/11/.
EDIT 1 (to answer some of the questions asked)
I have corrected an issue raised by #Catalin Iancu (thanks a lot for your precious help) by using a modulus operator ((i+len-1)%len).
ORIGINAL QUESTION (not really clear)
I am trying to get the previous element in a for loop (to change its class) with following code :
for (var i = 0; i < array.length; i++) {
if(array[i-1] && my other conditions) {
array[i-1].classList.remove('is-visible');
array[i].classList.add('is-visible');
}
}
But it's not removing the class for [i-1] element.
Here is a more complete piece of code of my module (this is running within a scroll eventlistener):
var services = document.getElementsByClassName('services'),
contRect = servicesContainer.getBoundingClientRect();
for (var i = 0; i < services.length; i++) {
var serviceRect = services[i].getBoundingClientRect();
if ( !services[i].classList.contains('active') && Math.round(serviceRect.left) < contRect.right && services[i-1]) {
services[i-1].classList.remove('is-visible');
services[i].classList.add('is-visible');
}
}
Thanks for your help!
Your if(array[i-1] && my other conditions) is always true, except for the very first case where array[-1] doesn't exist. Therefore, it will remove and then add the active class for each element, which will make it seem as only the first element's class has been removed.
What you need is a better if condition or a break statement, when the loop is not needed anymore
for (var i = 0; i < array.length; i++) {
if(array[i] && i != array.length - 1) {
array[i].classList.remove('active');
}
}
array[array.length - 1].classList.add('active');
The problem probably is that based on your code: services[i-1].classList.remove('active'); and services[i].classList.add('active'); the 'active' class you add in current iteration will be removed in next iteration!
So your code has logical errors, array index does not return all prev items!
What if you create a variable that contain the previous element?
var previous = array[0];
for (var i = 0; i < array.length; i++) {
if(previous && my other conditions) {
previous.classList.remove('active');
array[i].classList.add('active');
break;
}
previous = array[i];
}

JQuery alert on TD click

My project doesn't alert "Test" when I click on any of the "td" Elements.
I will use it for something more useful later but I'm just trying to get it to alert on click, Thank you!
link: http://jsfiddle.net/gk5c9z2z/
$("td").click(function () {
alert("Test");
});
for (var i = 0; i <= Cards.length; 0) { line is the culprit. The last iteration fails as Cards[i] returns undefined and undefined doesn't have setAttribute method. JavaScript interpreter throws an error and subsequent lines are not executed. Change it to:
for (var i = 0; i < Cards.length; 0) {
Also note that you could use i++ instead of 0 as the final-expression of the for loop and remove the i = i + 1; line.
I think you should use
$("td image")
as you are really clicking on the image.

How to create and display result one at a time in an infinite loop in javascript?

I'm fairly new to HTML and Javascript. I want to know how to create an infinite loop from, let's say, myArray, list, or whatever and then display result one at a time. Can you please give me an example, hints, or anything with detailed explanation of how it works? I just want to understand on how things work. Thanks!
A very basic loop is a while loop:
while (condition) {
//code block to be executed
}
Typically you would use it like so:
var i = 0;
while (i < 10) {
//code block to be executed
i++;
//This block of code will continue until i >= 10
//adding 1 to the value of I each iteration
}
Easiest way to do a endless loop:
while (true) {
code block to be executed
}
//true will always be true so this will continue until it
//hits a return; statement, the end of time, or the software
//or hardware gives up
A common mistake that end up in an endless loop:
var i = 0;
while (i < 10) {
code block to be executed
//In this example i is never being increased so
//i will always be less than 10
}
A very practical way to do a while loop correctly:
var array = ['a','b','c'];
var i = 0;
while (i < array.length) {
alert(array[i]);
i++;
}
//This will alert a, alert b, then alert c
Another way to do the above is using a for loop:
var array = ['a','b','c'];
for (var i = 0; i < array.length; i++) {
alert(array[i];
}
//for loops are a good practice because you are less
//likely to leave out steps like defining the iterator,
//or increasing the iterator
OP
I'm trying to create something using HTML/Javascript that everytime I press a button called next item (I created one using <form></form>) it would display an item, or an image. The trick is I don't know how to keep displaying the item after the last position. After the last position it should go back to the first position. For example, for the array that you provide in your example you have [a, b, c], after I displayed c and press the button again I want to display a again and so forth. Can you give me hints or any other valuable info on how to do this?
Answer
JSFiddle Example:
http://jsfiddle.net/d2809p6z/
HTML
<button id="button">click me</div>
JS
var array = ['a','b','c'];
var index = 0;
document.getElementById('button').onclick=function(){
if (index >= array.length) {
index = 0;
}
alert(array[index]);
index++;
};

How do I correctly use an iteration value in JavaScript?

I am creating a 'simple' javaScript function which basically displays new information on the page when a user clicks next or previous.
The information is taken from an array and I want to use either i++ or i-- to call an element of the array.
Heres my JavaScript:
var titles = ["Dundalk", "Navan", "Drogheda", "Dublin"];
var i = 0;
function next()
{
i++;
if (i == titles.length)
{
i = 0;
}
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
function prev()
{
if (i == 0)
{
i = titles.length;
}
i--;
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
The problem is, when I run this code in my HTML page, I get an 'UNDEFINED' result. The JavaScript is not recognizing that i has been initialized as 0 in the beginning.
If i change titles[i] to titles[2], for example, the correct text is displayed in HTML.
What am I forgetting or how can I overcome this?
Thanks
The fact that you're seeing undefined indicates that you're accessing an array index which hasn't been set. Your code looks fine at a glance, so I would guess that there's some more code you're not showing which also uses i as a loop variable and leaves it set to a value > titles.length after the code above has run.

Categories