2

I'm trying to create a modal(dialog box) that is hidden by default for multiple images in a page. Whenever clicked on modal it will trigger to display image. I found this example in w3school code is as below

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial, Helvetica, sans-serif;}

#myImg {
  border-radius: 5px;
  cursor: pointer;
  transition: 0.3s;
}

#myImg:hover {opacity: 0.7;}

/* The Modal (background) */
.modal {
  display: none; /* Hidden by default */
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  padding-top: 100px; /* Location of the box */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
}

/* Modal Content (image) */
.modal-content {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
}

/* Caption of Modal Image */
#caption {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
  text-align: center;
  color: #ccc;
  padding: 10px 0;
  height: 150px;
}

/* Add Animation */
.modal-content, #caption {  
  -webkit-animation-name: zoom;
  -webkit-animation-duration: 0.6s;
  animation-name: zoom;
  animation-duration: 0.6s;
}

@-webkit-keyframes zoom {
  from {-webkit-transform:scale(0)} 
  to {-webkit-transform:scale(1)}
}

@keyframes zoom {
  from {transform:scale(0)} 
  to {transform:scale(1)}
}

/* The Close Button */
.close {
  position: absolute;
  top: 15px;
  right: 35px;
  color: #f1f1f1;
  font-size: 40px;
  font-weight: bold;
  transition: 0.3s;
}

.close:hover,
.close:focus {
  color: #bbb;
  text-decoration: none;
  cursor: pointer;
}

/* 100% Image Width on Smaller Screens */
@media only screen and (max-width: 700px){
  .modal-content {
    width: 100%;
  }
}
</style>
</head>
<body>

<h2>Image Modal</h2>
<p>In this example, we use CSS to create a modal (dialog box) that is hidden by default.</p>
<p>We use JavaScript to trigger the modal and to display the current image inside the modal when it is clicked on. Also note that we use the value from the image's "alt" attribute as an image caption text inside the modal.</p>

<img id="myImg" src="img_snow.jpg" alt="Snow" style="width:100%;max-width:300px">

<!-- The Modal -->
<div id="myModal" class="modal">
  <span class="close">&times;</span>
  <img class="modal-content" id="img01">
  <div id="caption"></div>
</div>

<script>
// Get the modal
var modal = document.getElementById('myModal');

// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementById('myImg');
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
img.onclick = function(){
  modal.style.display = "block";
  modalImg.src = this.src;
  captionText.innerHTML = this.alt;
}

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks on <span> (x), close the modal
span.onclick = function() { 
  modal.style.display = "none";
}
</script>

</body>
</html>

it is applicable only for one image. Suppose if I want to do this for multiple images present in a page how can I achieve this? In my html file I'm displaying list of images in single page using for loop like below

  {% for item in itemslist %}
      <img src="{{url_for('image', path=item.thumb)}}" id="img{{loop.index}}" class="img-thumbnail" alt=""width="100" height="100"/>
{% endfor %}

how can i do modal image for all images.like in this image

i found this example modal image but this didn't help it was giving console error, may be I was doing wrong. Help me to fix this issue. Let me know if you need any more to ask

Tried based on answers

{% extends "base.html" %}
{% block content %}

<ul class="list-group">
  {% for item in listitems %}
  <li class="list-group-item d-flex justify-content-between align-items-center">

    <a href="/browse/{{item.href}}" id="item{{loop.index}}">{{item.name}}</a>
    <!--below hyperlink is just a hack for creating a clickable space-->
    <a href="/browse/{{item.href}}" id="blahh{{loop.index}}" style="color:white">{{item.name}}</a>
    {% if item.thumb != "" %}
      <!-- <img src="{{url_for('image', fpath=item.thumb)}}" id="img{{loop.index}}" class="img-thumbnail" alt=""width="300" height="300"/> -->
      <img src="{{url_for('image', fpath=item.thumb)}}" id="img{{loop.index}}" class="clickable" alt=""width="300" height="300"/>
      <div id="myModal" class="modal">
  <span class="close">&times;</span>
  <img class="modal-content" id="img01">
  <div id="caption"></div>
</div>
    {% endif %}   
  </li>
  {% endfor %}
</ul>
<script>
/* JavaScript */

// define variables to hold the 'modal' Elements
var modal, modalImg, captionText, close;

// Event Handler
function imageClicked(e) {
   // set modal Elements on first click
   !modal && (
        modal = document.getElementById("modal"),
        modalImg = document.getElementById("img01"),
        captionText = document.getElementById("caption"),
        // find the 'close' button and add an event listener
        close = document.getElementsByClassName("close")[0],
        close.addEventListener("click", closeModal, !1)
    );

    // the clicked image
    var clickedImage = e.target;

    // set the Elements in the 'modal' box
    modalImg.src = clickedImage.src;
    captionText.innerHTML = clickedImage.title;
    modal.style.display = "block";
}

// Event Handler
function closeModal(e) {
    modal.style.display = "none";
}

// Finally, add an event listener to
// every image with a class .clickable
[].slice.call(
    document.getElementsByClassName("clickable")
).forEach(function(im) {
    im.addEventListener("click", imageClicked, !1);
});
</script>
{% endblock %}

I ended up getting console error as this

can I fix it
  • 73
  • 2
  • 10

2 Answers2

1

I would go with something like this. You have to bind the onclick event to all your images. As of your TWIG code I took the img-thumbnail class as selector to bind the onclick event on all your images. As you didn't provide a full-demonstrating example I couldn't test it (and I'm a bit lazy TBH). But this is the way it should work. Only replace the existing code. I'm pretty sure this should already do the job.

// Get the images and bind an onclick event on each to insert it inside the modal
// use its "alt" text as a caption
var images = document.querySelectorAll(".img-thumbnail");
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
for(let i = 0; i < images.length; i++){
  images[i].onclick = function(){
    modal.style.display = "block";
    modalImg.src = this.src;
    captionText.innerHTML = this.alt;
  }
}

Full working example:

// Get the modal
var modal = document.getElementById('myModal');

// Get the images and bind an onclick event on each to insert it inside the modal
// use its "alt" text as a caption
var images = document.querySelectorAll(".img-thumbnail");
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
for(let i = 0; i < images.length; i++){
  images[i].onclick = function(){
    modal.style.display = "block";
    modalImg.src = this.src;
    captionText.innerHTML = this.alt;
  }
}

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks on <span> (x), close the modal
span.onclick = function() {
  modal.style.display = "none";
} 
 /* Style the Image Used to Trigger the Modal */
.img-thumbnail{
  border-radius: 5px;
  cursor: pointer;
  transition: 0.3s;
}

.img-thumbnail:hover {opacity: 0.7;}

/* The Modal (background) */
.modal {
  display: none; /* Hidden by default */
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  padding-top: 100px; /* Location of the box */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
}

/* Modal Content (Image) */
.modal-content {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
}

/* Caption of Modal Image (Image Text) - Same Width as the Image */
#caption {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
  text-align: center;
  color: #ccc;
  padding: 10px 0;
  height: 150px;
}

/* Add Animation - Zoom in the Modal */
.modal-content, #caption {
  animation-name: zoom;
  animation-duration: 0.6s;
}

@keyframes zoom {
  from {transform:scale(0)}
  to {transform:scale(1)}
}

/* The Close Button */
.close {
  position: absolute;
  top: 15px;
  right: 35px;
  color: #f1f1f1;
  font-size: 40px;
  font-weight: bold;
  transition: 0.3s;
}

.close:hover,
.close:focus {
  color: #bbb;
  text-decoration: none;
  cursor: pointer;
}

/* 100% Image Width on Smaller Screens */
@media only screen and (max-width: 700px){
  .modal-content {
    width: 100%;
  }
} 
 <!-- Trigger the Modal -->
<img id="myImg1" src="//i.stack.imgur.com/bpLjl.png" class="img-thumbnail" alt="Angular" style="width:100%;max-width:50px">
<img id="myImg2" src="https://cdn.sstatic.net/Sites/stackoverflow/img/apple-touch-icon.png?v=c78bd457575a" class="img-thumbnail" alt="Stacky" style="width:100%;max-width:50px">

<!-- The Modal -->
<div id="myModal" class="modal">

  <!-- The Close Button -->
  <span class="close">&times;</span>

  <!-- Modal Content (The Image) -->
  <img class="modal-content" id="img01">

  <!-- Modal Caption (Image Text) -->
  <div id="caption"></div>
</div> 

Update: Added full working example based on the original answer.

thex
  • 590
  • 2
  • 12
  • I tried your answer ,no changes was happening when I click on the image, page gets hanged . I have made changes to my question please have a look – can I fix it Mar 27 '19 at 03:55
  • @canIfixit It does work I have added a complete example with the W3C tutorial provided in your link. And it works fantastic I just added my lines of code instead of the original ones. See the full working example I now added. I didn't change anything on my code I just added it to the W3C example. Additionally I modified the `img-thumbnail` class name like in your TWIG code. But this isn't essential. – thex Mar 27 '19 at 11:14
  • @canIfixit You should learn some basics on what you are doing. Just asking "solve this one for me"! Doesn't bring you further also in the future you need to narrow down the error you're getting to solve it yourself. We are here to help you of course but keep in mind that you can inspect your JS code with your browser and take a look where the error you are getting occurs. – thex Mar 27 '19 at 11:20
  • 1
    @thex Thank you so much for posting this, it was awesome! – Adrian Nesta Apr 01 '20 at 02:18
  • @AdrianNesta You're welcome, glad to hear that my answer helped! :-) – thex Apr 02 '20 at 05:16
0

This can be achieved by attaching an Element.addEventListener to all the clickable images on the page. For example...

<!-- HTML -->
<div id="modal">
    <span id="close">&times;</span>
    <img id="modalImg">
    <div id="captionText"></div>
</div>
<div id="clickbox">
    <img class="clickable" src="img1.jpg" title=" Image 1 ">
    <img class="clickable" src="img2.jpg" title=" Image 2 ">
    <img class="clickable" src="img3.jpg" title=" Image 3 ">
    ... etc ...
</div>

...

/* JavaScript */

// dirty selection
function $(a) {
    switch (a.slice(0,1)) {
        case "#":
            return document.getElementById(a.slice(1));
        default:
            return [].slice.call(document.getElementsByClassName(a.slice(1)));
    }
}
//////////////////////////////////////

// define variables to hold the 'modal' Elements
var modal, modalImg, captionText, close;

// Event Handler
function imageClicked(e) {
   // set modal Elements on first click
   !modal && (
        modal = $("#modal"),
        modalImg = $("#modalImg"),
        captionText = $("#captionText"),
        // find the 'close' button and 
        // add an event listener
        close = $("#close"),
        close.addEventListener("click", closeModal, !1)
    );

    // the clicked image
    var clickedImage = e.target;

    // set the Elements in the 'modal' box
    modalImg.src = clickedImage.src;
    captionText.textContent = clickedImage.title;
    modal.style.display = "block";
}

// Event Handler
function closeModal(e) {
    modal.style.display = "none";
}

// Finally, add an event listener to
// every image with a class .clickable
$(".clickable").forEach(function(im) {
    im.addEventListener("click", imageClicked, !1);
});

Setting event listeners on each image will mean that each time an img.clickable is clicked the event handling function imageClicked() will be called.

In that function, if the variable 'modal' is not set (on the first click) it and all the other modal box Elements are assigned to their own variables. Additionally the 'close' button gets an Element.addEventListener attaching it to the function closeModal().

The imageClicked() function takes its information from the clicked image (e.target), which it then uses to populate the contents of the modal box as in the W3Schools example.

You'll find a working example @ JSFIDDLE.COM

Hope that helped ;)

See Also:

Brian Peacock
  • 1,801
  • 16
  • 24
  • thanks for the answer, I'm getting console error after doing changes to code based on your answer . I have mentioned this code in edited question please have a look – can I fix it Mar 27 '19 at 03:54
  • @canIfixit I've added a Fiddle link and reformatted the code to make it easier to read. – Brian Peacock Mar 27 '19 at 06:03