I've been trying to learn javascript by refactoring some Jquery examples in a book into javascript. In the following code I add a click listener to a tab and make it change to active when the user clicks on the tab.
var tabs = document.querySelectorAll(".tabs a span");
var content = document.querySelectorAll("main .content li");
for (var tabNumber = 0; tabNumber <= 2; tabNumber++) {
tabs[tabNumber].addEventListener("click", function (event) {
for (var i = 0; i < tabs.length; i++) {
tabs[i].classList.remove("active");
}
tabs[tabNumber].classList.add("active");
for (var i = 0; i < content.length; i++) {
content[i].innerHTML = "";
}
event.preventDefault();
});
}
This returns an undefined error when I run it. However, I tried replacing tabs[tabNumber].classList.add("active") with this.classList.add("active") and it worked.
Why doesn't the previous code work? As far as I can see they are referring to the same thing, and tabs[tabNumber] should work since at that point in the code it is tabs[0].
2 Answers 2
If use this, I think it's better and a more polished solution. If you still want to use tabNumber, it's probably evaluating to 3 in every click callback, because it's the number after the last iteration, and you don't have a tabs[3] position.
So, you just have to make a closure of the tabNumber variable.
Comments
I guess other answers told you why tabs[tabNumber] does not work (because it comes from the score of the for loop and so, is always equal to the greater value of tabNumber).
That's why I would recommend using a .forEach loop. Careful though because it doesn't work on arrays of DOM nodes produced by document.querySelectorAll(), but you can use:
// ES6
Array.from(document.querySelectorAll('...'))
// ES5
[].slice.call(document.querySelectorAll('...'))
Anyway, I made a simplified working demo of your code.
Note that I save the currently active tab in a variable, to prevent another for loop. You could also do:
document.querySelector('.active').classList.remove('active')
But I like to reduce the amount of DOM reading.
Good luck for your apprentissage, re-writing some jQuery code into Vanilla JS seems like a good method, and you might acquire a far better comprehension of JavaScript.
letfor for loops as much as possible, but the issue can be resolved by closure or the place you reference it in your JS code.