'I need to create a gallery of images where one image changes opacity on click but reverts back when another is clicked

I've struggled with this one for hours now. I have a gallery of images fed in from an API.

I need an image to change opacity when clicked and revert back to its original opacity when clicked again and/or another image in the gallery is clicked.

I've managed to get it where all images chane upon one being clicked and where each one changes upon being clicked but don't revert the previously clicked ones but I can't seem to combine the two.

I have to use vanilla JS. I've browsed various similar questions on here but none seem to solve the problem I'm having.

Here is my code

var URL = new Array();
URL[0] = "https://www.vam.ac.uk/api/json/museumobject/search?q=a&limit=45";
URL[1] = "https://www.vam.ac.uk/api/json/museumobject/search?q=a&limit=45&offset=45";
URL[2] = "https://www.vam.ac.uk/api/json/museumobject/search?q=a&limit=45&offset=90";
var nRequest = new Array();
for (var i = 0; i < 3; i++) {
  (function(i) {
    nRequest[i] = new XMLHttpRequest();
    nRequest[i].open("GET", URL[i], true);
    nRequest[i].onreadystatechange = function(oEvent) {
      if (nRequest[i].readyState === 4) {
        if (nRequest[i].status === 200) {
          var data = JSON.parse(nRequest[i].responseText);
          var url = 'http://media.vam.ac.uk/media/thira/collection_images/';
          for (let key in data.records) {
            let value = data.records[key];
            let image = value.fields.primary_image_id;
            let res = image.substr(0, 6);
            document.querySelector(".image").innerHTML += '<a class="wallImageLink"><img id="' + value.fields.primary_image_id + ' imagery" class="wallImage" src="' + url + res + '/' + image + '.jpg"></a>';

            document.querySelector(".mypanel").innerHTML += '<div class="' + value.fields.primary_image_id + '"> <p> <span style="font-weight:bold">Title: </span>' + value.fields.title + '</p>' +
              '<p> <span style="font-weight:bold">Artist: </span>' + value.fields.artist + '</p>' +
              '<p> <span style="font-weight:bold">Object Type: </span>' + value.fields.object + '</p>' +
              '<p> <span style="font-weight:bold">Location: </span>' + value.fields.location + '</p>' +
              '<p> <span style="font-weight:bold">Place: </span>' + value.fields.place + '</p>' +
              '<br> </div>';

          }
        } else {
          console.log("Error", nRequest[i].statusText);
        }
      }

      //

    };
    nRequest[i].send(null);
  })(i);

};
.image img {
  height: 215px;
  width: 20%;
  object-fit: cover;
  opacity: 0.5;
}

.image img:hover,
.image img:focus,
.image img:active {
  opacity: 1;
}

.inlineFlex {
  display: inline-flex;
}

.mypanel {
  width: 50%;
}

.mypanel div {
  display: none;
}

.image {
  width: 50%;
  height: 500px;
  overflow-y: auto;
}
<div class="inlineFlex">
  <div class="image" id="image"></div>
  <div class="mypanel"></div>
  <div class="mypanel2"></div>
</div>
<script src="wall.js"></script>


Solution 1:[1]

One way to do this,

  1. First store if the image is already highlighted.
  2. Un-Highlight all of them.
  3. Finally toggle the one you click based on what you stored.

Below is a simple example, that you should be able to modify for your needs.

document.body.addEventListener('click', (e) => {
  const el = e.target;
  if (el.tagName !== 'DIV') return;
  const wasSel = el.classList.contains('selected');
  for (const d of document.querySelectorAll('div'))
    d.classList.remove('selected');
  el.classList.toggle('selected', !wasSel);
});
div {
  padding: 1rem;
  margin: 0.2rem;
  width: 3rem;
  height: 3rem;
  border: 1px solid black;
  display: inline-block; 
  background-color: pink;
  opacity: 0.4;
  user-select: none;
  transition: opacity 0.2s;
}

div.selected {
  opacity: 1;
}
<div>One</div><div>two</div><div>Three</div><div>Four</div><div>Five</div><div>Six</div><div>Seven</div><div>Eight</div><div>Nine</div><div>Ten</div>

A shorter way,. classList.toggle, has 3 options, if the second parameter is undefined it will toggle the class. Alternatively if you pass either true or false, it will toggle on & off.

Using this information the code can be shortened, and the state can be updated in the loop without having to store the previous state of the selected item.

eg.

document.body.addEventListener('click', (e) => {
  const el = e.target;
  if (el.tagName !== 'DIV') return;
  for (const d of document.querySelectorAll('div'))
    d.classList.toggle('selected', d===el ? undefined:false);
});
div {
  padding: 1rem;
  margin: 0.2rem;
  width: 3rem;
  height: 3rem;
  border: 1px solid black;
  display: inline-block; 
  background-color: pink;
  opacity: 0.4;
  user-select: none;
  transition: opacity 0.2s;
}

div.selected {
  opacity: 1;
}
<div>One</div><div>two</div><div>Three</div><div>Four</div><div>Five</div><div>Six</div><div>Seven</div><div>Eight</div><div>Nine</div><div>Ten</div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1