I have some cards like this:
And I draw them with this function:
let createCard = (header, price, category, size, type, show, img) => {
let card = document.createElement('div')
card.className = 'card drk'
document.querySelector('.container').appendChild(card)
card.innerHTML = `
<img src="${img}" alt="">
<div >
<h3>${header}</h3>
<ul>
<li>Price: ${price}</li>
<li>Category: ${category}</li>
<li>Size: ${size}</li>
<li>Type: ${type}</li>
<li>Show: ${show}</li>
</ul>
<div >
<button >More</button>
<i class='bx bx-bookmark-alt'></i>
</div>
</div>
`
let menuBtn = document.querySelectorAll('.MoreBtn')
menuBtn.forEach (item => item.addEventListener('click', () => {
createMoreInfoCard(img, header, category, type, show, price)
}))
return card
}
And I want to trigger
<- this function on specific button click. As you can see I tried forEach but on click, it triggers all the buttons. So I want to get one specific button.
CodePudding user response:
try this way:
let createCard = (header, price, category, size, type, show, img) => {
let card = document.createElement('div')
card.className = 'card drk'
document.querySelector('.container').appendChild(card)
card.innerHTML = `
<img src="${img}" alt="">
<div >
<h3>${header}</h3>
<ul>
<li>Price: ${price}</li>
<li>Category: ${category}</li>
<li>Size: ${size}</li>
<li>Type: ${type}</li>
<li>Show: ${show}</li>
</ul>
<div >
<button >More</button>
<i class='bx bx-bookmark-alt'></i>
</div>
</div>
`
card.addEventListener('click', (event) => {
if (event.target.classList.contains('.MoreBtn'))
createMoreInfoCard(img, header, category, type, show, price);
});
return card
}
CodePudding user response:
You don't have to keep track of how many buttons you have or will have in the future, and you just need one event handler bound to an ancestor element, you don't even need #ids.
In the example below there's only one clickhandler on a <section> -- any clicks within the section will invoke the event handler more(e). Because more(e) passes the event object (all event handlers do by default), e.target points to the element the user actually clicked. With that knowledge you can design the event handler to delegate the event by determining what reacts and what ignores the click event. In the example, only the elements with .more class can react and nothing else.
const sec = document.querySelector('section');
let data = [{
img: `https://cdn.shopify.com/s/files/1/0268/7480/6357/products/cw7356-002_256x.jpg?v=1636057508`,
name: 'Shoe',
prc: '$90',
cat: 'Apparal',
desc: 'They go on your feet',
mfg: 'Nike',
pn: '256D8J'
}, {
img: `https://cdn.shopify.com/s/files/1/0268/7480/6357/products/gm8646_1_400x.jpg?v=1614728158`,
name: 'Hoodie',
prc: '$50',
cat: 'Apparal',
desc: 'Keeps you warm',
mfg: 'Adidas',
pn: '881V9A'
}, {
img: `https://cdn.shopify.com/s/files/1/0268/7480/6357/products/cw7356-002_256x.jpg?v=1636057508`,
name: 'Shoe',
prc: '$90',
cat: 'Apparal',
desc: 'They go on your feet',
mfg: 'Nike',
pn: '256D8J'
}, {
img: `https://cdn.shopify.com/s/files/1/0268/7480/6357/products/gm8646_1_400x.jpg?v=1614728158`,
name: 'Hoodie',
prc: '$50',
cat: 'Apparal',
desc: 'Keeps you warm',
mfg: 'Adidas',
pn: '881V9A'
}];
const createDeck = (node, data) => {
data.forEach((c, i) => {
let card = `
<article data-idx='${i}'>
<img src="${c.img}">
<fieldset><legend><h3>${c.name} <br>${c.prc}</h3></legend><ul class='list'><li>Category: ${c.cat}</li>
<li>Size: ${c.desc}</li> <li>Manufacturer: ${c.mfg}</li> <li>Part No.: ${c.pn}</li> </ul><button >More</button></fieldset></article>`;
node.insertAdjacentHTML('beforeEnd', card);
});
};
const more = e => {
const btn = e.target;
if (btn.matches('.more')) {
let list = btn.previousElementSibling;
list.classList.toggle('open');
}
};
createDeck(sec, data);
sec.onclick = more;
:root {
font: 1ch/1.5 'Segoe UI'
}
body {
font: 2ch
}
main {
width: 100vw;
height: 100vh;
margin: 10px auto;
}
section {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
width: 100%;
height: max-content;
padding: 5px 10px;
}
.card {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 30vw;
height: 100%;
overflow-x: hidden
}
img {
display: block;
width: 30vw;
}
fieldset {}
legend {}
.list {
display: none;
font-size: 1rem;
margin-left: -30px
}
.more {
display: block;
margin-left: 10vw;
font: inherit;
}
.open {
display: block
}
<main>
<section></section>
</main>
