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}"> </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>