Home > front end >  document.querySelectorAll didn't get call from generated html element
document.querySelectorAll didn't get call from generated html element

Time:06-30

I'm displaying list of div element that generated from .html function whenever users click a button. The code look like below

array

const obj = [{"id":"1","section":"delivery","label":"Self-Pick up"},{"id":"2","section":"delivery","label":"Delivery"}]

javascript

createFilterBubblesTemplate = (obj) => {
  let bubbles = ''
  obj.forEach(e => {
    bubbles  = `<div >
    <span>${e.label}</span>
    <span  id="bubbles-close" data-filter-id="${e.id}" data-filter-section="${e.section}"></span>
    </div>`
  })
  $("#filtered-items").html(bubbles);
}

html element after generated by createFilterBubblesTemplate function

<div  id="filtered-items">
    <div >
    <span>Self-Pick up</span>
    <span  id="bubbles-close" data-filter-id="1" data-filter-section="delivery"></span>
    </div><div >
    <span>Delivery</span>
    <span  id="bubbles-close" data-filter-id="2" data-filter-section="delivery"></span>
    </div>
</div>

But when I tried to attach click eventlistener on span with , its seems not working. Need help to solve this issue

document.querySelectorAll('.icon-xmark').forEach(item => {
  item.addEventListener('click', (event) => {
    console.log(event)
  })
})

CodePudding user response:

maybe you are attach the event BEFORE you added the element to the DOM. Try to delegate the event

document.addEventListener('click', (event) => {
  const target = event.target;
  if (target.classList.contains('icon-xmark')) {
    console.log(event);
  }
});

but it's better to use the date attribute

<span  data-close id="bubbles-close" data-filter-id="2" data-filter-section="delivery"></span>
  ...
document.addEventListener('click', (event) => {
  const target = event.target;
  if ('close' in target.dataset) {
    console.log(event);
  }
});

CodePudding user response:

The problem is fixed by using answer from Arm144. Attaching onclick attribute into the span

createFilterBubblesTemplate = async (obj) => {
  let bubbles = ''
  obj.forEach(e => {
    bubbles  = `<div >
    <span>${e.label}</span>
    <span  onclick="closeFiltersBubbles(${e.id},'${e.section}')" data-filter-id="${e.id}" data-filter-section="${e.section}"></span>
    </div>`
  })
  $("#filtered-items").html(bubbles);
}

CodePudding user response:

The spans you assign the click handler to are empty, thus they are rendered with 0 width and you cannot click them.

The following corrects this by adding content (non-breaking spaces).

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type"   content="text/html;charset=utf-8">
        <meta http-equiv="expires"        content="0">
        <meta http-equiv="cache-control"  content="private">
        <meta http-equiv="pragma"         content="no-cache">
        <title>SO - Bitmap (svg)</title>
        <!--
        -->
        <style type="text/css">
            body {
                background-color:   #eee;
            }
            
            .icon-xmark {
                background-color:   lime;
                cursor:             pointer;
            }
        </style>
        <script>
            const obj = [{"id":"1","section":"delivery","label":"Self-Pick up"},{"id":"2","section":"delivery","label":"Delivery"}];
            
            let createFilterBubblesTemplate = (obj) => {
              let bubbles = '';
              obj.forEach(e => {
                bubbles  = `<div >
                <span>${e.label}</span>
                <span  id="bubbles-close" data-filter-id="${e.id}" data-filter-section="${e.section}">&nbsp;&nbsp;&nbsp;&nbsp;</span>
                </div>`;
              });
              document.querySelector("#filtered-items").innerHTML = bubbles;
            }; //   createFilterBubblesTemplate
                              
            document.addEventListener('DOMContentLoaded', () => {
                setTimeout ( () => {
                        createFilterBubblesTemplate(obj);
                        setTimeout ( () => {
                                document.querySelectorAll('.icon-xmark').forEach(item => {
                                    item.addEventListener('click', (event) => {
                                        console.log('Here we go...');
                                    });
                                });
                            } 
                          , 1000
                        );
                    }
                  , 1000
                );
            });
        </script>
    </head>
    <body>
        <div  id="filtered-items"></div>
    </body>
</html>

CodePudding user response:

Delegate click event with jQuery method .on(). Bind the click event to a static element (an element that's been there since the page loaded, like #filtered-items) and then delegate the click event to the .icon-xmark the user clicked ($(this)). This indirect way of event handling is called event delegation. This is necessary since you cannot bind event handlers to dynamically added elements.

Details are commented in example

const obj = [{
  "id": "1",
  "section": "delivery",
  "label": "Self-Pick up"
}, {
  "id": "2",
  "section": "delivery",
  "label": "Delivery"
}]

/*
A proper arrow function should begin with a const or let
`.html()` method is like `.innerHTML` in that it it's destructive
Use `.append()`
*/
const createFilterBubblesTemplate = (obj) => {
  obj.forEach(e => {
    let html =`<div >
    <span>${e.label}</span>
    <span  data-filter-id="${e.id}" data-filter-section="${e.section}"></span>
    </div>`;
    $("#filtered-items").append(html);
  });
}

/*
Delegate click events to each ".icon-xmark" by binding the click event to
the parent tag "#filtered-items"
Note the second parameter ".icon-xmark" -- that designates "this" as ".icon-xmark"
console.log(event) does nothing
*/
$("#filtered-items").on('click', ".icon-xmark", function(e) {
  const x = $(this).data('filter-id');
  console.log(x);
});

createFilterBubblesTemplate(obj);
.icon-xmark {
  display: inline-block;
  padding: 5px;
  outline: 1px red dashed
}
<div  id="filtered-items"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  • Related