0

I am trying to display a modal with the name and the description of an image that was clicked by the user. Currently I only get the last image's name and no description (bad loop).

Please have a look at my code and please let me know how I can fix this issue. I am looking at this loop and I feel that it's not right, but I just can't figure it out how to fix it. Been trying for a while... Many thanks, guys.

Found an issue - myName[i].innerHTML, I cant reach variable i, I get error (Cannot read property 'innerHTML' of undefined), if I enter number manually then it prints name correctly.

// Get modal
let modal = document.getElementById("myModal");
let i;

// Get image
let img = document.getElementsByClassName("myImg");
let myName = document.getElementsByClassName("myName");
let myDesc = document.getElementsByClassName("myDesc");
let modalImg = document.getElementById("showImg");
let modalName = document.getElementById("imgName");
let modalDesc = document.getElementById("imgDesc");

// Loop through images
for (i = 0; i < img.length; i++) {
    img[i].onclick = function () {
        modal.style.display = "block";
        modalImg.src = this.src;
        modalName.innerHTML = myName[i].innerHTML;
        modalDesc.innerHTML = myDesc[i].innerHTML;
    }
}
 // Images
<div>
    <img class="myImg" src="images/1.png" alt="">
    <h5 class="myName">Image name1</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>

<div>
    <img class="myImg" src="images/2.png" alt="">
    <h5 class="myName">Image name2</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>

<div>
    <img class="myImg" src="images/3.png" alt="">
    <h5 class="myName">Image name3</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium, debitis, provident.</p>
</div>

// Modal
<div id="myModal" class="modal">
    <span class="close">&times;</span>
    <img class="modal-content" id="showImg">
    <div id="imgName"></div>
    <div id="imgDesc"></div>
</div>

5 Answers 5

1

The problem lies in your onClick event listener. You are using the variable i in your listener. By the time anyone clicks on an image, the loop has finished executing and the value of i becomes 3 and does not change and since there are only 3 elements in your myName and myDesc, it throws an error and stops executing.

You can use the following code:

  let modal = document.getElementById("myModal");
  let i;
  let j;
  let k;

  // Get image
  let img = document.getElementsByClassName("myImg");
  let myName = document.getElementsByClassName("myName");
  let myDesc = document.getElementsByClassName("myDesc");
  let modalImg = document.getElementById("showImg");
  let modalName = document.getElementById("imgName");
  let modalDesc = document.getElementById("imgDesc");

  // Loop through images
  for (i = 0; i < img.length; i++) {
    img[i].onclick = function () {
      modal.style.display = "block";
      modalImg.src = this.src;
      modalName.innerHTML = this.parentElement.getElementsByClassName('myName')[0].innerHTML;
      modalDesc.innerHTML = this.parentElement.getElementsByClassName('myDesc')[0].innerHTML;
    }
  }
// Images
<div>
  <img class="myImg" src="images/1.png" alt="">
  <h5 class="myName">Image name1</h5>
  <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>

<div>
  <img class="myImg" src="images/2.png" alt="">
  <h5 class="myName">Image name2</h5>
  <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>

<div>
  <img class="myImg" src="images/3.png" alt="">
  <h5 class="myName">Image name3</h5>
  <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium, debitis, provident.</p>
</div>

// Modal
<div id="myModal" class="modal">
  <span class="close">&times;</span>
  <img class="modal-content" id="showImg">
  <div id="imgName"></div>
  <div id="imgDesc"></div>
</div>

this keyword will always point to the image clicked and thus, using this.parentElement.getElementsByClassName('myName')[0] will give you your desired element.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this is Great.
0

I have added place holder images in your example and it works fine.

<div>
    <img class="myImg" src="http://via.placeholder.com/350x50" alt="">
    <h5 class="myName">Image name1</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>

<div>
    <img class="myImg" src="http://via.placeholder.com/350x100" alt="">
    <h5 class="myName">Image name2</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
</div>


<div>
    <img class="myImg" src="http://via.placeholder.com/350x150" alt="">
    <h5 class="myName">Image name3</h5>
    <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium, debitis, provident.</p>
</div>

<script>
let img = document.getElementsByClassName("myImg");
let myName = document.getElementsByClassName("myName");
let myDesc = document.getElementsByClassName("myDesc");
let modalImg = document.getElementById("showImg");
let modalName = document.getElementById("imgName");
let modalDesc = document.getElementById("imgDesc");

for(i=0; i < img.length; i++) {
  img[i].onclick = function() {
    modal.style.display = "block";
    modalImg.src = this.src;
    modalName.innerHTML = myName[i].innerHTML;
    modalDesc.innerHTML = myDesc[i].innerHTML;
  }
}
</script>

Check the Fiddle

The image which you click upon gets expanded in the bottom section. As in the example there is not Bootstrap or other modal support was present but the code should work. Let me know if any help needed.

Comments

0
Thanks for your effort guys, I fixed it with adding id to each image, I know it's hard coded... But oh well, I will get better.



 // Loop through images
       for(i=0; i < img.length; i++){
          img[i].onclick = function(){
            modal.style.display = "block";
            modalImg.src = this.src;
            modalName.innerHTML = myName[this.id-1].innerHTML;
            modalDesc.innerHTML = myDesc[this.id-1].innerHTML;
          }
        }



          <div>
            <img class="myImg" src="images/2.png" alt="" id="1">
            <h5 class="myName">Image name1</h5>
            <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
          </div>
          <div>
            <img class="myImg" src="images/3.png" alt="" id="2">
            <h5 class="myName">Image name2</h5>
            <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, quaerat, aut.</p>
          </div>
          <div>
            <img class="myImg" src="images/4.png" alt="" id="3">
            <h5 class="myName">Image name3</h5>
            <p class="myDesc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laudantium, debitis, provident.</p>
          </div>

Comments

0

I think its better to use data attributes for holding values,any how try this.

let wrapper = document.querySelector('.wrapper div');

wrapper.addEventListener('click', function() {

  let img = this.querySelector('.myImg');
  console.log(img);
});

complete link https://jsfiddle.net/gcvex46o/30/

Comments

0

You are defining the loop variables outside the loop. These variables are inside the click handler's closure. What happens is the following:

  • You loop over all images and add the click handler
  • Each click handler has a reference to the same loop variables
  • The loop finishes, all loop variables are at their maximum
  • When a click happens, the click handler accesses the maxed loop variables, so always the last entry is selected

To prevent this from happening, you can create different functions with their own indexes:

function createaHandler(src, j, k) {
    return function (src, j, k) {
        modal.style.display = "block";
        modalImg.src = src;
        modalName.innerHTML = myName[j].innerHTML;
        modalDesc.innerHTML = myDesc[k].innerHTML;
    }
}

for (i = 0, j = 0, k = 0; i < img.length, j < myName.length, k < myDesc.length; i++ , j++ , k++) {
    img[i].onclick = createHandler(img[i].src, j, k);
}

A simpler method would be to define the relevant variables on each loop new, so that they are reset and contain the right values:

for (i = 0; i < img.length; i++) {
    let src = img[i].src;
    let nameHTML = myName[i].innerHTML;
    let descHTML = myDesc[i].innerHTML;
    img[i].onclick = function () {
        modal.style.display = "block";
        modalImg.src = src;
        modalName.innerHTML = nameHTML;
        modalDesc.innerHTML = descHTML;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.