Reputation: 59
Beginner here.
I have a small image gallery, with two classes declared in CSS:
imagem: selected image, with border
imagem-activa: all the others, without border
How can i use JavaScript to add/remove the classes when the user clicks one image? I already know how to do it in jQuery, but want to learn also pure JS.
HTML
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="img/imagem1.jpg" class="imagem imagem-activa" />
<img src="img/imagem2.jpg" class="imagem" />
<img src="img/imagem3.jpg" class="imagem" />
<img src="img/imagem4.jpg" class="imagem" />
</div>
CSS
.imagem{border:5px solid #000;opacity:0.5;cursor: pointer;}
.imagem-activa{border:5px solid #ff0066;opacity:1;}
JS
This part i can't make it work. Can someone help me?
var imagens = document.getElementsByClassName("imagem");
var imagemActual = 0;
for(var i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function() {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = i;
});
}
This is my working jQuery solution
$(".imagem").click(function() {
$(".imagem").removeClass("imagem-activa");
$(this).addClass("imagem-activa");
});
Upvotes: 0
Views: 1044
Reputation: 387
So, what is happening here is that anytime any of your click handlers is invoked, your variable imageActual
gets set to the current value of i
which will always be 4 because this is the final value of i
after the for loop. For the first click, you might not run into any errors and you might get the expected result. But as soon as any of your event listeners has run, the value of imagemActual
will be 4 and that will cause an error on any future invocation of your event listeners because imagens[4]
will be undefined.
There are a few ways to solve this.
1) bind
You can bind the (temporary) value of i
inside the loop to the event listener function:
var imagens = document.getElementsByClassName("imagem");
var imagemActual = 0;
for(var i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function(index) {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = index;
}.bind(imagens[i], i));
}
.imagem {
width: 20px;
height: 20px;
background-color: blue;
}
.imagem.imagem-activa {
background-color: red;
}
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="" class="imagem imagem-activa" />
<img src="" class="imagem" />
<img src="" class="imagem" />
<img src="" class="imagem" />
</div>
2) let
If you can use ES6, you can use let
which will make sure that your counting variable is a unique instance for every value that is applied:
const imagens = document.getElementsByClassName("imagem");
let imagemActual = 0;
for(let i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function() {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = i;
});
}
.imagem {
width: 20px;
height: 20px;
background-color: blue;
}
.imagem.imagem-activa {
background-color: red;
}
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="" class="imagem imagem-activa" />
<img src="" class="imagem" />
<img src="" class="imagem" />
<img src="" class="imagem" />
</div>
Upvotes: 1