0

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>

2
  • Delegate to the main static container and use e.target and relative addressing: e.target.closest('.popupPriceContainer') Commented Sep 19, 2021 at 13:44
  • 1
    dont use getElementsByClassName anymore. In 2021 you should use querySelector or querySelectorAll instead. Commented Sep 19, 2021 at 16:06

3 Answers 3

2

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Please delegate
Thank you so much for your time and for your great answer and for already incorporating the price Submit! @MisterJojo
1

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>

1 Comment

Thank you very much for this clean and short approach! Wish I could accept two answers.
0

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">.

  1. Declare an event paramenter for the click listener
  2. Get a reference to the clicked price button using event.currentTarget
  3. Get a reference to the corresponding .position using closest method
  4. Find the .popupPriceContainer inside the div.position using querySelector
  5. Show the .popupPriceContainer using display block.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.