Reputation: 64
I am wondering how to target a specific element, knowing only its class.
I want to click the .editPrice
button and only showing the .popupPriceContainer
next to the button and not all of them.
The close button works fine since it is a child of the element I want to hide and I can easily target it with parentNode
.
Here is a fiddle: https://jsfiddle.net/jwLf4smu/1/
And Here a runnable snippet:
//CLOSE POPUP PRICE CONTAINER
//create variable from pop up close buttons
const popupClose = document.getElementsByClassName('popupClose');
//set price edit container to display none
Array.from(popupClose).forEach((popupClose) => {
popupClose.addEventListener('click', () => {
// 2x .parentNode to select the outer wrapper
popupClose.parentNode.parentNode.style.display = "none";
});
});
//OPEN POPUP PRICE CONTAINER
//create variable for all edit price buttons and price edit pop up container
const popupEditPrice = document.getElementsByClassName('editPrice');
const priceContainer = document.getElementsByClassName('popupPriceContainer');
//show price edit box
Array.from(popupEditPrice).forEach((popupEditPrice) => {
popupEditPrice.addEventListener('click', () => {
Array.from(priceContainer).forEach((priceContainer) => {
priceContainer.style.display = "block";
});
});
});
#serviceList .position {
margin-top: 16px;
}
.popupPriceContainer {
display: none;
}
<section id="serviceList" class="items">
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 1
</div>
<div class="price">
<span class="amount" id="priceElement">100</span>
</div>
<div class="popupPriceContainer">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 2
</div>
<div class="price">
<span class="amount">1000</span>
</div>
<div class="popupPriceContainer">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 3
</div>
<div class="price">
<span class="amount">240</span>
</div>
<div class="popupPriceContainer">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
</section>
Upvotes: 0
Views: 99
Reputation: 22320
prefer to use a class:
.noDisplay {
display: none;
}
then use [element].classList
/ .add()
or .remove()
methods
full code:
const
editBtns = document.querySelectorAll('button.editPrice')
, closeBtns = document.querySelectorAll('button.popupClose')
;
editBtns.forEach(btn=>
{
btn.onclick = ({target}) => // get only target object in event
{
target.closest('div.position').querySelector('.popupPriceContainer').classList.remove('noDisplay')
}
})
closeBtns.forEach(btn=>
{
btn.onclick = ({target}) => // get only target object in event
{
let
div_position = target.closest('div.position')
box_popupPriceContainer = div_position.querySelector('.popupPriceContainer')
, price_El = box_popupPriceContainer.querySelector('input.priceInput')
, actual_amount_el = div_position.querySelector('span.amount')
;
if (target.matches('.submbitPrice'))
{
// do submit price stuff
let priceVal = parseInt( price_El.value.replace(/\D/g, ''),10) || 0; // otherwise use parseFloat()
price_El.value = priceVal;
actual_amount_el.textContent = priceVal
// do submit price other stuff
}
// else price_El.value = actual_amount_el.textContent
box_popupPriceContainer.classList.add('noDisplay')
}
})
#serviceList .position {
margin-top: 16px;
}
.noDisplay {
display: none;
}
<section id="serviceList" class="items">
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 1
</div>
<div class="price">
<span class="amount" id="priceElement">100</span>
</div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 2
</div>
<div class="price">
<span class="amount">1000</span>
</div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 3
</div>
<div class="price">
<span class="amount">240</span>
</div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
</section>
but it should be better to use a delegate method way (get the global click over the section, then determine wich button is clicked) I also changed your Edit price / Close Price method, to put them on the same button, it is more ergonomic
code:
document.querySelector('#serviceList').onclick = ({target}) => // get only target object in event
{
if (!target.matches('button.editPrice, button.submbitPrice')) return // ignore click elsewhere
let
div_position = target.closest('div.position')
, price_El = div_position.querySelector('input.priceInput')
, actual_amount_el = div_position.querySelector('span.amount')
;
if (target.matches('button.editPrice'))
{
target.textContent = div_position.classList.toggle('noPriceEdit') ? 'Edit price' : 'Close edit'
}
else // button.submbitPrice stuff
{
let priceVal = parseFloat( price_El.value) || 0;
price_El.value = actual_amount_el.textContent = priceVal.toFixed(2)
div_position.classList.add('noPriceEdit')
div_position.querySelector('button.editPrice').textContent = 'Edit price'
}
}
#serviceList .position {
margin-top: 16px;
}
div.position.noPriceEdit > div.popupPriceContainer {
display: none;
}
<section id="serviceList" class="items">
<div class="position noPriceEdit">
<button type="button" class="editPrice">Edit price</button>
<div class="item">Service 1</div>
<div class="price"><span class="amount" id="priceElement">100</span></div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice">Submit</button>
</div>
</div>
</div>
<div class="position noPriceEdit">
<button type="button" class="editPrice">Edit price</button>
<div class="item">Service 2</div>
<div class="price"><span class="amount">1000</span></div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice">Submit</button>
</div>
</div>
</div>
<div class="position noPriceEdit">
<button type="button" class="editPrice">Edit price</button>
<div class="item">Service 3</div>
<div class="price"><span class="amount">240</span></div>
<div class="popupPriceContainer noDisplay">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice">Submit</button>
</div>
</div>
</div>
</section>
Upvotes: 2
Reputation: 178011
Delegate to the main static container and use e.target and relative addressing: e.target.closest('.popupPriceContainer')
Note I add and remove a class .hide
document.getElementById('serviceList').addEventListener('click', function(e) {
const tgt = e.target;
if (tgt.classList.contains('popupClose')) {
const parent = tgt.closest('.popupPriceContainer')
parent.classList.add('hide')
}
if (tgt.classList.contains('editPrice')) {
const parent = tgt.closest('.position')
parent.querySelector('.popupPriceContainer').classList.remove('hide')
}
})
#serviceList .position {
margin-top: 16px;
}
.hide {
display: none;
}
<section id="serviceList" class="items">
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 1
</div>
<div class="price">
<span class="amount" id="priceElement">100</span>
</div>
<div class="popupPriceContainer hide">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 2
</div>
<div class="price">
<span class="amount">1000</span>
</div>
<div class="popupPriceContainer hide">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
<div class="position">
<button type="button" class="editPrice">Edit price</button>
<div class="item">
Service 3
</div>
<div class="price">
<span class="amount">240</span>
</div>
<div class="popupPriceContainer hide">
<div class="popupPriceInner">
<input type="number" placeholder="100,00" class="priceInput">
<button value="Set Value" class="submbitPrice popupClose">Submit</button>
<button class="popupClose">Close</button>
</div>
</div>
</div>
</section>
Upvotes: 1
Reputation: 1861
The problem is in the following code:
popupEditPrice.addEventListener('click', () => {
Array.from(priceContainer).forEach((priceContainer) => {
priceContainer.style.display = "block";
});
});
When the "edit price" button is clicked the forEach
in the above code searches for all price containers & shows them.
Each "edit price" button & its corresponding "price container" is inside a <div class="position">
.
event.currentTarget
.position
using closest method.popupPriceContainer
inside the div.position
using querySelector.popupPriceContainer
using display block
.Upvotes: 0