0

I have a product list (li elements) with custom titles and buttons. In addition there is also a popup form which is triggered by clicking any of the buttons.

There are as many Click me! buttons, as many titles, but all of them trigger the same pop-up.

What I want to achieve is that form input element's value of the popup form is taken from a specific title according to the position of the button. So, if I click the Click me! under the button Second title, the input element value will be filled with Second title.

This is what I figured out, but somehow it won't work. I get the same value. Could someone help me to find the problem?

Thanks in advance!

var title = document.getElementsByClassName('title');
var titleText;
var i;      
for (i = 0; i < title.length; i++) {
  titleText = title[i].innerText;
  console.log("Name: " + titleText + ", position: " + i);
}
document.getElementById('inserthere').value = titleText; 
<ul class="products-list">
<li class="product">
<h2 class="title">First title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Second title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Third title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Fourth title</h2>
<a class="button" href="#">Click me!</a>
</li>
</ul>
<div class="popup">
<input type="text" id="inserthere" value="">
</div>
walacky
  • 35
  • 10

3 Answers3

1

You can retrieve the text by taking the clicked element, retrieve the sibling (via the parent element), pick up its text and then display that:

// We use event delegation, by picking up the bubbled-up click event 
//   in the container element. This way we only to bind only one click handler 
document.querySelector(".products-list").addEventListener("click", function (e) {
    if (e.target.classList.contains("button")) { // The click was on a button class
        // Go to the button's parent and find the title underneath it:
        document.getElementById("inserthere").value = 
            e.target.parentNode.querySelector(".title").textContent;
    }
});
<ul class="products-list">
    <li class="product">
        <h2 class="title">First title</h2>
        <a class="button" href="#">Click me!</a>
    </li>
    <li class="product">
        <h2 class="title">Second title</h2>
        <a class="button" href="#">Click me!</a>
    </li>
    <li class="product">
        <h2 class="title">Third title</h2>
        <a class="button" href="#">Click me!</a>
    </li>
    <li class="product">
        <h2 class="title">Fourth title</h2>
        <a class="button" href="#">Click me!</a>
    </li>
</ul>

<div class="popup">
    <input type="text" id="inserthere" value="">
</div>
trincot
  • 317,000
  • 35
  • 244
  • 286
1

First, don't use .getElementsByClassName() - ever. And, in this case you don't even need to get all the elements. Just handle the click event at the ul level because all events will "bubble" up to their ancestor. Handling events this way is called "event delegation".

But, you are also using HTML incorrectly.

  • a elements are for navigation, not for something that can trigger JavaScript. Nearly all elements support a click event, so use a span and style it to look like a hyperlink.
  • Don't use headings (h1...h6) because of how they look. They are meant to denote the beginning of a section or sub-section. Again, choose a better element and style it the way you'd like.
  • Don't use an input element for output. Use a placeholder like a span instead.

See comments inline:

let output = document.getElementById("out");

// Set up the event handler on the common ancestor of all the elements that will
// be clicked and handle the click event there ("event delegation")
document.querySelector(".products-list").addEventListener("click", function(event){
  
  // You can get a reference to the actual element that the event was triggered on
  // through the event object reference that was passed into the event handler
  if(event.target.classList.contains("button")){
    // Now just get the text of the previous sibling that is an element
    output.textContent = event.target.previousElementSibling.textContent;
  }

});
.title { font-weight:bold; font-size:1.1em; }
.button { color:blue; cursor:pointer; text-decoration:underline; }
#out { width:10em; height:1em; border:1px solid #808080; }
<ul class="products-list">
  <li class="product">
    <div class="title">First title</div>
    <span class="button">Click me!</span>
  </li>
  <li class="product">
    <div class="title">Second title</div>
    <span class="button">Click me!</span>
  </li>
  <li class="product">
    <div class="title">Third title</div>
    <span class="button">Click me!</span>
  </li>
  <li class="product">
    <div class="title">Fourth title</div>
    <span class="button">Click me!</span>
  </li>
</ul>
<div class="popup">
  <div id="out"></div>
</div>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
0

If in case you are interested with the order of the texts, as you used i in your code, you may use forEach( (value, index) => {...} ):

const inserthere = document.getElementById('inserthere');

[...document.getElementsByClassName('button')].forEach( (button, i) => 
    button.addEventListener('click', function() {
       let titleText = event.target.previousElementSibling.innerText;
       inserthere.value = titleText;
       console.log("Name: " + titleText + ", position: " + i);
    })
)
<ul class="products-list">
<li class="product">
<h2 class="title">First title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Second title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Third title</h2>
<a class="button" href="#">Click me!</a>
</li>
<li class="product">
<h2 class="title">Fourth title</h2>
<a class="button" href="#">Click me!</a>
</li>
</ul>
<div class="popup">
<input type="text" id="inserthere" value="">
</div>
<br><br>
Addis
  • 2,480
  • 2
  • 13
  • 21