0

I have a web page that is displaying a set of images using a table for simple layout. What I'd like to do is allow a user to click the image and have that image appear magnified in a modal.

The html row holding a graphic:

<tr>
    <td>Graphic One</td>
    <td><img class="graph" src="/chart1.jpg">
        <div class="modal">
        <div class="modal-content">
            <span class="close-btn">&times;</span>
                <img src="/chart1.jpg">
        </div>
    </div>
    </td>
</tr>

This is repeated to create more rows with graphics. Here's the script:

<script>
let modalBtn = document.querySelector(".graph")
let modal = document.querySelector(".modal")
let closeBtn = document.querySelector(".close-btn")
    modalBtn.onclick = function(){
    modal.style.display = "block"
    }
closeBtn.onclick = function(){
    modal.style.display = "none"
    }
    window.onclick = function(e){
    if(e.target == modal){
        modal.style.display = "none"
    }
}
</script>

This only seems to activate the first graphic on the page, though, so I'm assuming that the querySelector() stops at the first instance found.

How can I apply this to every row with an image in the table?

1
  • 1
    .querySelector() will return the first matching element. Try using .querySelectorAll() to return all matching elements then loop through them as needed. MDN docs Commented Apr 2, 2020 at 14:09

1 Answer 1

1

If you want to apply it to every table row, all you need is to select all the <td> and then iteratively apply the same logic as you have above to the elements found inside it.

To access the individual elements, you can simply use Element.querySelector() instead, assuming Element refers to the <td>. It helps to give this <td> element that contains all these elements a class, so you can narrow down the selection, e.g. <td class="action">:

<tr>
    <td>Graphic One</td>
    <td class="action">
        <img class="graph" src="/chart1.jpg">
        <div class="modal">
        <div class="modal-content">
            <span class="close-btn">&times;</span>
                <img src="/chart1.jpg">
        </div>
    </div>
    </td>
</tr>

...then you can do this:

document.querySelectorAll('.action').forEach(el => {
    let modalBtn = el.querySelector(".graph");
    let modal = el.querySelector(".modal");
    let closeBtn = el.querySelector(".close-btn");

    modalBtn.addEventListener('click', e => {
        // Stop click event from bubbling up
        e.stopPropagation();

        modal.style.display = 'block';
    });

    closeBtn.addEventListener('click', e => {
        // Stop click event from bubbling up
        e.stopPropagation();

        modal.style.display = 'none';
    });
});

// Listen to click event on the window ONCE, outside the forEach loop
window.addEventListener('click', () => {
    document.querySelectorAll(".modal").forEach(el => {
        el.style.display = 'none';
    });
});

You can see that I have left out the window click event listener in the for each loop. The reason is that you can simply rely on event.stopPropagation to stop the click event from bubbling to the window object. That means, you simply have to bind the click event once on the window.

Also, I would not suggest using Element.onclick = Function to add event listeners, because that means you can only assign one handler this way. Use Element.addEventListener instead.

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

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.