Listen to DOM element change

Viewed 49

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?

2 Answers

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>

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"));
  }
}
Related