fields
fields

Reputation: 59

Image Gallery: how to remove and add class when clicking an image


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

Answers (1)

glutengo
glutengo

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

Related Questions