-1

When I do a search for images it loads images from Pixabay, which are added to a container via fetch without a page reload, I need to click on the newly generated images to get the ID of the image, which then converts the image ID to an URL, and gets added into the input.

My workaround is to find dom elements with the class ".dePixaImage" using the click, and mouseover event and then remove those events with removeEventListener which works fine to a certain point, but then when I apply a new search nothing happens because the new dom elements are being loaded and the event listener has been stopped.

If I do not remove the removeEventListener, then the for each loop keeps on multiplying, which results in a lot of fetch requests when the mouse is moved, or if a click occurs, which is completely unnecessary and uses up all the API requests.

window.addEventListener("click", deViewImage);
window.addEventListener("mouseover", deViewImage);

function deViewImage() {
  let deViewImageAttr = "";
  let dePixaImage = document.querySelectorAll(".dePixaImage");
  if (dePixaImage) {
    dePixaImage.forEach((e) => {
      e.addEventListener("click", function () {
        // id of the image from Pixabay, added via fetch
        deViewImageAttr = e.getAttribute("id");
        // call fetch function and pass ID
        pixabayImageUrlFromId(deViewImageAttr);
      });
      window.removeEventListener("click", deViewImage);
      window.removeEventListener("mouseover", deViewImage);
    });
  }
}

Maybe there is a better solution to listen for the dom elements when they get changed frequently?

Artur B
  • 45
  • 6
  • 1
    You didn't tell us what you want to achieve ! – ThS Sep 19 '22 at 21:42
  • 2
    Does this answer your question? [Detect changes in the DOM](https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom) – imvain2 Sep 19 '22 at 21:45
  • @ths I have added a better description at the top, thanks. – Artur B Sep 19 '22 at 21:54
  • Could you share a working snippet of your code? It'll be useful to understand what the problem is and what you're trying to achieve. – aghashamim Sep 19 '22 at 22:04
  • As @imvain2 mentioned, I think you are looking for MutationObserver – user3252327 Sep 19 '22 at 22:06
  • You can prevent the window click from being triggered by a dePixaImage click by using `e.stopPropagation()` inside the dePixaImage handler. That means you shouldn't need to remove the window event listener, at least for click. – James Sep 19 '22 at 22:07
  • @aghashamim It's part of an application and the code probably would be too big to share up here, basically once the new images get loaded via fetch, it has a unique ID attached to them, so after images are reloaded I need to click on the image and again select the ID from there which gets passed on to another field to register that specific image. Stopping the event listener will prevent the clicks on the new images once they are clicked. Not having the 'removeEventListener' will multiply the function. – Artur B Sep 19 '22 at 22:11
  • I didn't understand the question at all, and I am not entirely sure you actually want to listen for DOM element changes (which `MutationObserver` helps you do). – Armen Michaeli Sep 20 '22 at 08:33

2 Answers2

1

I see from your comment what you are really looking for is attaching a click handler to dynamically added elements.

That is rather easy with event delegation and not having a click handler inside another click handler. This will work with objects in the DOM and new objects added to the DOM later. You only need to add the code once, and it won't be duplicated.

function pixabayImageUrlFromId(id) {
  console.log(id)
}

document.body.addEventListener("click", deViewImage);
document.body.addEventListener("mouseover", deViewImage);

function deViewImage(e) {
  let obj = e.target;
  if (obj.classList.contains("dePixaImage")) {
    pixabayImageUrlFromId(obj.dataset.id);
  }
}
<div class="dePixaImage" data-id="1111111">ssss</div>
imvain2
  • 15,480
  • 1
  • 16
  • 21
  • Thank you, this actually worked perfectly. I posted a few small tweaks below in case someone else will find this useful. – Artur B Sep 20 '22 at 08:30
0

Thanks, @imvain, with little modification I no longer needed mouseover, here is the solution now with the above help.

function pixabayImageUrlFromId(id) {
  let imageUrlInput = document.querySelector(
    '[data-test-id="control-attributes-de_image_img_url"] input'
  );
  let URL = "https://pixabay.com/api/?key=" + API_KEY + "&id=" + id;
  fetch(URL)
    .then(function (resp) {
      return resp.json();
    })
    .then(function (data) {
      let imgUrl = data.hits[0].largeImageURL;
      imageUrlInput.value = imgUrl;
      imageUrlInput.dispatchEvent(new Event("input"));
    });
}

document.addEventListener("click", deViewImage);

function deViewImage(e) {
  let obj = e.target;
  if (obj.classList.contains("dePixaImage")) {
    pixabayImageUrlFromId(obj.getAttribute("id"));
  }
}
Artur B
  • 45
  • 6