skip to Main Content

The problem I have is a bit more complicated, so I have made a video that shows the behavior I am talking about.

Problem video

As you can see what I want to achieve is to open a photo on a larger size upon clicking on it. As you can see it works … well … kind of.
It behaves kind of weird because it seems to be lagging and not recording the onclick event very well. Sometimes it can record it faster sometimes slower, but not even once would it open the image on a single click as I would want it to. It takes at least two clicks. And I tried the code on a page that has no XML requests and it works on a single click (with a slight delay between the two console log calls though .. around 0.3 sec). And it also works on the chat page if I have a huge delay in refreshing the chat. But I would want to have it work with a single click on a refresh rate of 1 second.

The XML request is the following:

  
     table2 = function(url, callback) 
{
    var request = new XMLHttpRequest();
    request.onreadystatechange = function()
    {
        if (request.readyState == 4 && request.status == 200)
        {
            callback(request.responseText); 
             document.getElementById("scrollchat").innerHTML = this.responseText;
        }
    }; 
    request.open('GET', url);
    request.send();
    
    
}

function mycallback(data) {
   //alert(data);
}

table2('load_chat.php', mycallback);

setInterval(function(){
       table2('load_chat.php', mycallback);
      }, 1700);

The items within the XML request file load_chat.php look like this:

<img src="image1.jpg" class="responsive" onclick="fullimagetry()">
<img src="image2.jpg" class="responsive" onclick="fullimagetry()">
<img src="image3.jpg" class="responsive" onclick="fullimagetry()">
<!-- And the list goes on as more images are being loaded. -->

My JS function that handles this is the following:

function fullimagetry() {

    let photonameval = document.getElementsByClassName('responsive');   
    console.log("click");

document.querySelectorAll('.responsive').forEach((element, index) => {
  element.addEventListener('click', function(event) {
    console.log('Clicked element index:', index, 'Image path:',photonameval[index].src);
    
    const fullPage = document.querySelector('#fullpage');
    
fullPage.style.backgroundImage = 'url(' + photonameval[index].src + ')';
    fullPage.style.display = 'block';
    
  });
});
    

}

Is there a better way to handle this? Maybe modify the fullimagetry() function and make it more efficient, or change something in the XML request itself? As you can see the request is made at 1.7s which is already too slow, but it makes things work at least on a double click. And I would want it to load at 1 second so that the user won’t feel like the server is lagging. Looking forward to your response.

EDIT: I have to specify that I use XML for this because I don’t know any other way to load elements on page without refreshing it. If you could provide me with an alternate way that is more efficient, I am keen to try it. I am still learning, and I go by what I can find on Youtube or W3Schools. Also that 1.7 delay is just set to make the opening of the photo more likely, the lower the value is the more click it needs to open (I know it’s weird).

2

Answers


  1. I can only give you a partial answer due to missing information. You should use some kind of an event delegation.
    You should not add an addEventListener to every image but simply to the chat container and check if the clicked element was an image. That way you will be more time efficient and you can execute the script from the start on. You can add images dynamically without having to re-execute the function.

    You’re using:

    function fullimagetry() {
      let photonameval = document.getElementsByClassName('responsive');   
      document.querySelectorAll('.responsive').forEach((element, index) => {
        element.addEventListener('click', function(event) {
          //...
        )}
      })
    }
    

    that is highly inefficient. Every time you click on an image, you create a List (HTML Collection Object) and then create an (almost) identical list (Node List) of all images.
    After that, you attach an event listener to every image. There is no reason for all of that the function fullimagetry already can be referenced to a single image. Next, you set up 2 lists when one would be sufficient. All of that cost unnecessary time!

    So you should optimize your code by not adding an event listener to every image but simply only getting the image you clicked on. For that, you don’t even need any kind of list as you already have the exact element you want to work with!

    ChatContainer.addEventListener('click', function(element) {
      if (element.target.tagName === 'IMG') {
        FullPage.style.backgroundImage = `url(${element.target.src})`;
        FullPage.classList.add('d-block');
      }
    })
    
    FullPage.addEventListener('click', function() {
      this.classList.remove('d-block');
    })
    #FullPage {
      position: fixed;
      inset: 0;
      z-index: 100;
      display: none;
      background-repeat: no-repeat;
      background-attachment: fixed;
      background-position: center;
      background-size: contain;
      background-color: black;
      &.d-block {
        display: block;
      }
    }
    <div id="ChatContainer">
      <img src="https://placehold.co/600x400/FF0000/FFFFFF/png">
      <img src="https://placehold.co/600x400/00FF00/FFFFFF/png">
      <img src="https://placehold.co/600x400/0000FF/FFFFFF/png">
    </div>
    
    <div id="FullPage"></div>

    For Optimizing your XML request into a fetch and reducing the loading times on that part, I would need to know exactly what your data package looks like. But I’m already pretty confident that with the optimized code you don’t even need the 1.7sec delay anymore!

    Login or Signup to reply.
  2. I think there are a lot of problems with your approaches in general. I highly recommend you to research more on "WebSockets" (you can just use this keyword for search). It will definetly help your chat better.

    But I will give you an approach for your actual problem. Try the snippet below.

    // There's actually no need for indexing, but it can be done.
    
    function amplifyImage ( myImageElement, myFullImageSource )
    {
      // Directly get the original thumbnail source.
      const myImageSource = myImageElement.src;
      
      // Make sure this element is last in the DOM or make it have the
      // highest z-index for it to overlay everything else.
      const myFullPageOverlay = document.getElementById('fullpage');
      
      // You can use can use some element attribute to host your index.
      const myImageIndex1 = myImageElement.getAttribute('alt');
      
      // Or you can create your custom element attribute to host your index.
      const myImageIndex2 = myImageElement.getAttribute('myIndex');
      
      // Displays the overlay.
      myFullPageOverlay.style.display = 'block';
      
      // Replace the overlay background image.
      myFullPageOverlay.style.backgroundImage = `url('${myFullImageSource ?? myImageSource}')`;
      
      // Debug:
      {
        console.log('Image in Thumbnail:', myImageSource);
        console.log('Image in Background:', myFullImageSource ?? myImageSource);
        console.log('Thumbnail Alternate Text:', myImageIndex1);
        console.log('Image Custom Index:', myImageIndex2);
        console.log('Click on the overlay to close.');
      }
    }
    #fullpage
    {
      position: fixed;
      top: 0;
      left: 0;
      
      margin: 0px;
      
      display: none;
      
      width: 100%;
      height: 100%;
      
      background-image: url('https://placehold.co/30x30/000000/FFFFFF/png');
      background-attachment: fixed;
      background-position: center;
      background-repeat: no-repeat;
      background-color: black;
      background-size: contain;
    }
    
    .responsive
    {
      border: 2px solid blue;
      cursor: pointer;
      width: 20%;
      height: 20%;
    }
    <img src="https://placehold.co/300x200/FF0000/FFFFFF/png" alt="Index1" myIndex=1 class="responsive" onclick="amplifyImage(this, 'https://placehold.co/600x400/FF0000/FFFFFF/png')">
    <img src="https://placehold.co/300x200/00FF00/FFFFFF/png" alt="Index2" myIndex=2 class="responsive" onclick="amplifyImage(this, 'https://placehold.co/600x400/00FF00/FFFFFF/png')">
    <img src="https://placehold.co/300x200/0000FF/FFFFFF/png" alt="Index3" myIndex=3 class="responsive" onclick="amplifyImage(this, 'https://placehold.co/600x400/0000FF/FFFFFF/png')">
    
    <p>Click on any image placeholder to open the overlay. Click on the overlay to close it.</p>
    
    <div id="fullpage" onclick="this.style.display = 'none'; console.clear();"></div>

    NOTE: You can also add more parameters in the function to provide more customization to your overlay or extract the attributes from the <img> element.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search