The event listener function is not functioning properly on images generated by JavaScript

I'm currently working on placing multiple images on a grid in the center of the page and would like to include a function that triggers when each individual image is clicked. The images are dynamically created using JavaScript and inserted into the document. Could the issue be that these images are not yet fully 'ready' or something else?

function placePieces() {
  for (var i = 0; i < setup.length; i++) {
    if ((setup[i]+'' == "undefined")) {continue;}
    var element = document.createElement("img");
    element.src = "Images/" + pieces[Object.keys(pieces)[setup[i]]] + ".png";
    element.style.width = "10vh";
    element.style.height = "10vh";
    element.style.marginTop = (Math.floor(i/8) * 10) + "vh";
    element.style.marginLeft = "calc(((100vw - 80vh)/2) + " + (10 * (i%8) - 1) + "vh)";
    element.style.zIndex = 10;
    element.style.position = "absolute";
    element.id = i+1;
    document.body.innerHTML = "\n" + element.outerHTML + document.body.innerHTML;
    console.log(element.outerHTML)
    var nelement = document.getElementById(i+1);
    console.log(nelement)
    nelement.addEventListener("click",highlight);
  }
}
placePieces()

function highlight(n) {
  console.log(n)
  n = n.currentTarget.myParam;
  if (setup[n] == 0 || setup[n] == 6) {
    var moves = [];
    var m = n
    while (True) {
      if (!(Math.floor((m-9)/8)<=0)) {
        console.log("test")
      }
    }
  }
}

The second function is still a work in progress but it isn't producing the expected results.

Answer №1

Instead of retrieving the element again, you have the option to directly attach the listener.

const block = document.createElement('div')
block.style.background = 'blue'
block.style.width = '150px'
block.style.height = '150px'
block.addEventListener('click', () => console.log('clicked'))
document.body.appendChild(block)

The following code demonstrates how this can be achieved:

function addBlocks() {
  for (var x = 0; x < grid.length; x++) {
    if ((grid[x]+'' == "undefined")) {continue;}
    var block = document.createElement("div");
    // ...
    block.addEventListener("click", showDetails);
  }
}

Answer №2

Event Handling

When it comes to event handling, you have two options:

Method Pros Cons
A Bind (or register) the "click" event to each <img>. Easier to write Any dynamically added <img> must be registered to the "click" event.
B Bind the "click" event to an ancestor tag in which all <img>'s reside within. Write the event handler so that it only reacts when an <img> is clicked. This concept is known as event delegation Only needs to register to the event on one tag once and any dynamically added <img> do not require any additional binding Creating the event handler is more complex.

Here are some steps to take while reviewing the example:

  1. Click on some <img> in Area A and B. A blue outline should appear around them.
  2. Next, click both ADD buttons.
  3. Click on some of the new <img>s. The new <img> in Area A won't trigger the action.
  4. Click the BIND button.
  5. Now, try clicking on any of the new <img> in Area A.

Feel free to explore the details provided in the example below:

// File names of all images
const images = ["Fqsw6v8/2s", "Qb6N0dG/3s", "qnGtC68/4s", "nDFmjJB/5s", "sPtNDGm/6s", "HpmggvF/7s", "dKfcwxQ/8s", "K7HbrWp/9s", "9ys8PXt/as", "HVK2zvw/bs", "7SgXHz2/cs", "StdB11X/ds", "cN9CnV5/es"];
// List of first 3 image file names that will be initially added to the DOM
const init = [images[0], images[1], images[2]];

/**
 * Generate one or more <img>s from a given array/
 * @param {Array} array - An array of file names
 * @param {String|Object} node - Selector string or DOM object used as the target to append the <img>s to.
 * @param {String} css - Class name for each generated <img>, defaults to "img"
 * @returns {array} - An array of <img>
 */
function genImg(array, node, css = "img") {
  let root = typeof node === "string" ? 
    document.querySelector(node) : node ? 
    node : document.body;
  let offset = root.childElementCount;
  const pix = array.flatMap((img, idx) => {
    if (idx >= offset) { 
      const image = new Image();
      const frame = document.createElement("figure");
      image.src = `https://i.ibb.co/${img}.png`;
      image.className = css;
      image.dataset.idx = offset + idx;
      root.append(frame.appendChild(image));
      return image;
    } 
    return [];
  });
  return pix;
}

const main = document.forms.gallery;
const io = main.elements;
const areas = Array.from(io.area);

const imgsA = genImg(init, areas[0]);
const imgsB = genImg(init, areas[1]);

imgsA.forEach(img => img.onclick = highlightA);

function highlightA(event) {
  this.classList.toggle("highlight");
}

areas[1].onclick = highlightB;

function highlightB(event) {
  const clk = event.target;
  if (clk.matches("img")) {
    clk.classList.toggle("highlight");
  }
}

const btns = Array.from(io.add);
btns.forEach(btn => btn.onclick = addImg);

function addImg(event) {
  const clk = event.target;
  if (clk.matches("button")) {
    let idx = btns.indexOf(clk);
    genImg(images, areas[idx]);
  }
}

const bind = io.bind;
bind.onclick = bindImg;

function bindImg(event) {
  Array.from(document.querySelectorAll("#A img"))
  .forEach(img => img.onclick = highlightA);
}
html {font: 300 4vmin/1.15 "Segoe UI"}
form {display: flex; flex-flow: column nowrap; justify-content: center; 
margin: 15px auto; padding: 0 10px;}
fieldset {margin: 0.5rem 0}
fieldset fieldset {display: flex; justify-content: space-evenly; align-items: center;}
legend {font-size: 1.25rem}
button {font: inherit; float: right; cursor: pointer;}
figure {display: inline-flex; justify-content: center; align-items: center; 
margin: 0.5rem 0.5rem 0; padding: 0.5rem;}
.img {display:inline-block; max-width: 5rem}
.highlight {outline: 5px groove cyan;}
<form id="gallery">
  <fieldset>
    <legend>Area A</legend>
    <fieldset id="A" name="area"></fieldset>
    <button name="add" type="button">ADD</button>
    <button name="bind" type="button">BIND</button>
  </fieldset>
  
  <hr>
  
  <fieldset>
    <legend>Area B</legend>
    <fieldset id="B" name="area"></fieldset>
    <button name="add" type="button">ADD</button>
  </fieldset>
</form>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Enhance Your Website with Slider Swipe Effects using CSS3 and

After scouring the internet for various types of sliders, including swipe sliders, I am interested in creating a responsive swipe slider specifically for mobile phones. This would be a full page swipe slider where users can swipe left and right seamlessly. ...

Contrast the objects in views.py between two distinct model objects in Django

I am currently working on a feature that compares the skills required for different job postings (such as web development, marketing, etc) with the skills of a user who is logged in. If there is a match, the job posting will be displayed to the user. The ...

What could be causing WidgEditor, the JavaScript text editor, to fail to submit any values?

After clicking submit and attempting to retrieve text from the textarea, I am encountering a problem where the text appears blank. The reason for this issue eludes me. function textSubmit() { var text = $("#noise").val(); console.log(text); consol ...

Adjust the background to scroll to the bottom of the image first and then change it to be fixed

Here is the code I have written: body{ margin:0; padding:0; line-height: 1.5em; background-image: url(http://fehlbelichtet.stefanwensing.de/wp-content/uploads/sites/6/2016/04/alte-strasse-endlos.jpg); background-repeat:no-repeat; background-attachment: ...

What are some solutions for repairing unresponsive buttons on a webpage?

My task is to troubleshoot this webpage as the buttons are not functioning correctly. Here’s a snippet of the source code: <!DOCTYPE html> <html lang="en"> <head> ... </head> <body> <div id="container" ...

The outline none property on the Material UI IconButton is malfunctioning

Attempting to style with CSS as shown in the following example: <CustomColorIconButton> <DeleteForeverIcon /> </CustomColorIconButton> const CustomColorIconButton = withStyles({ root: { color: "#ff8833", ...

Error in jQuery Ajax post request caused by a keyword in the posted data

I understand why the post is failing, but I'm at a loss on how to fix it and I haven't been able to find any solutions online. I am removing references to jEditable in an attempt to simplify things, as this issue occurs even without the jEditable ...

Retrieve webpage content using an ajax request in JavaScript

I'm working on an HTML page with an Ajax call to load table content. <html> .... <script sec:haspermission="VIEW_NOTE" th:inline='javascript'> require(['app/agent/viewGlobalAgent'], function (){ ...

"Terminate the current window that is open within the handler for the XMLHttpRequest

Currently, my approach involves using Javascript and Ajax to retrieve data and display it in a new window. I am encountering an issue where I am trying to close the window in the OpenFileWindow() function before opening a new one, but I am facing a permiss ...

Using Ajax and jQuery to redirect a page with values in ASP.NET

I have two pages: Default.aspx and DetailView.aspx. My goal is to redirect from Default.aspx to DetailView.aspx using an AJAX call and pass a value as well. Although I have tried something, the function defined in the class is not being called. The functi ...

Ensure all fields are valid prior to performing an update

I'm currently faced with the challenge of validating my form data before executing an AJAX update. Essentially, what I want to achieve is to validate the input data in the form before triggering the ajax update function. I'm unsure about where to ...

Is it possible to fill dropdown menus on a webpage using jQuery or JavaScript without the need for an ajax call?

Currently, I am looking to populate multiple dropdown lists using jQuery when the page loads rather than relying on ajax responses to events. My Controller is responsible for creating several List objects that will be used for these dropdowns. Right now, I ...

Creating registration and login forms using an express server

Currently, I'm in the process of creating a basic website on my localhost that incorporates a signup form along with other essential HTML elements. The setup for the signup procedure went smoothly as planned. When a user completes the form and submits ...

adjust the dimensions of the clickable icon's background

Is there a way to expand the pressable area of a close icon without altering its size? For example, if the icon is 19X19 pixels, can the pressable area be increased to 39X39 pixels? The concern lies with the div element containing the close button and the ...

What is the best way to align the main navigation at the center of

Even though I have utilized text-align: center, the style of .main-nav did not change. What is the most effective way to center this navigation menu? /***** Navigation *****/ .main-nav { font-family: 'Lato', Helvetica, Arial, sans-serif; f ...

Tips for dividing echo output from PHP into two separate divs using jQuery AJAX

I am trying to display two different echoes from PHP in separate divs within my AJAX success function. $.ajax({ url: 'counter.php', type: 'POST', data: { some_data:some_data ...

When using Next.js getServerSideProps(), cookies are not accessible on the initial render after a redirect, but they become available upon refreshing the page

Within my Next.js application, I am serving cookies from the server-side API like this: res.setHeader('Set-Cookie', AJWT) res.redirect(302, '/') Now, in my index.js file, I am attempting to retrieve the cookie before the page is render ...

When working with NextJs, you may encounter a ValidationError indicating that the configuration object is invalid. This error occurs when Webpack has been initialized with a configuration object that doesn't

After upgrading from Next v12 to v12.2.3, I encountered a problem when running "yarn dev" with a new middleware.js file in the root directory: ValidationError: Invalid configuration object. Webpack initialization error due to mismatched API schema. - Deta ...

Tips for adjusting the size and positioning the ng bootstrap carousel in the center

My Angular project is using ng bootstrap, but I'm facing a styling issue. The content doesn't display in the center, rather it appears in the upper left corner: example I would like the content to be centered and wide under the blue headbar. W ...

What is the best method for incorporating a JavaScript redirect into an Android WebView?

My issue involves loading a page into a webview. Typically, when I use the code webview.loadUrl(url); it functions as expected. The url contains a javascript code that redirects the page. Here is the javascript code: <script type="text/javascript"> ...