Get element inside "block" relative of user click without IDs

I'm not entirely sure if this is possible, but here is my idea:

I have multiple blocks in my page, all of them are built the same and they have the same classes. Only the content in the blocks is different.

I can't / don't want to assign IDs because these blocks get generated by the backend and it's just not suitable to give each an individual ID.

I want to get relative (in the HTML) to where the user clicks the button another element near the button and store that in a variable.

So if my HTML looks like this:

<div class="this-is-a-block">
  <h3>My first Element 1</h3>
  <p>Some text</p>
  <p>Some text</p>
  <div>
    <div>
      <button class="classButton">Button 1</button>
    </div>
  </div>
</div>
<div class="this-is-a-block">
  <h3>My second Element 2</h3>
  <p>Some other text</p>
  <p>Some other tex</p>
  <div>
    <div>
      <button class="classButton">Button 2</button>
    </div>
  </div>
</div>

I want to get the h3 in a variable, but only in the scope of the block.

So when the user clicks Button 2 the variable would be My second Element 2 but when the user clicks Button 1 the variable would be My first Element 1

I think you get the point.

Is that possible to do without IDs? I assume for JS both blocks look the same. Is there any way to stay in the scope of where the user clicks?

When I select the button with querySelectorAll and loop through the output then I get multiple results for my h3 (so a result for any button on the page).

This is an example with a single block with an ID to show how my other code would work.

document.getElementById("button").addEventListener("click", myScript);

function myScript() {
let result = document.getElementById("button").parentElement.parentElement.parentElement.firstElementChild.innerHTML.trim();
    console.log(result)
}
<div>
  <h3>My first Element 1</h3>
  <p>Some text</p>
  <p>Some text</p>
  <div>
    <div>
      <button id="button" class="classButton">Button 1</button>
    </div>
  </div>
</div>

The only part missing is to only select the button that get's actually clicked and get relative to that the h3, and only a single h3 inside the block and not every h3 on the page.

This is my simplified code of the actual thing without IDs and multiple blocks:

let result;
let button = document.querySelectorAll(".classButton");
button.forEach(click => {
  click.addEventListener("click", myScript);
})


function myScript() {
  button.forEach(i => {
    result = i.parentElement.parentElement.parentElement.firstElementChild.innerHTML.trim();
  })

  console.log(result)
}
<div class="this-is-a-block">
  <h3>My first Element 1</h3>
  <p>Some text</p>
  <p>Some text</p>
  <div>
    <div>
      <button class="classButton">Button 1</button>
    </div>
  </div>
</div>
<div class="this-is-a-block">
  <h3>My second Element 2</h3>
  <p>Some other text</p>
  <p>Some other tex</p>
  <div>
    <div>
      <button class="classButton">Button 2</button>
    </div>
  </div>
</div>

I either only get the last element or if I put the console.log inside the forEach both.

Any way of doing that?

Thanks!

I know the way of getting the content of the h3 might not be the best way, but that's another problem I can work on as soon as the other part works.

2 answers

  • answered 2022-05-04 10:06 Ankit Tiwari

    When you specify a function to handle an event inside a loop then you have access to event and element both so you don't have to loop again

    let result;
    let button = document.querySelectorAll(".classButton");
    button.forEach(click => {
      click.addEventListener("click", getH1);
    })
    
    
    function getH1(e){
      let textValue = e.target.parentNode.parentNode.parentNode.children[0].innerText
      console.log(textValue)
    }
    <div class="this-is-a-block">
      <h3>My first Element 1</h3>
      <p>Some text</p>
      <p>Some text</p>
      <div>
        <div>
          <button class="classButton">Button 1</button>
        </div>
      </div>
    </div>
    
    <div class="this-is-a-block">
      <h3>My second Element 2</h3>
      <p>Some other text</p>
      <p>Some other tex</p>
      <div>
        <div>
          <button class="classButton">Button 2</button>
        </div>
      </div>
    </div>
    
    <div class="this-is-a-block">
      <h3>My second Element 3</h3>
      <p>Some other text</p>
      <p>Some other tex</p>
      <div>
        <div>
          <button class="classButton">Button 3</button>
        </div>
      </div>
    </div>
    
    <div class="this-is-a-block">
      <h3>My second Element 4</h3>
      <p>Some other text</p>
      <p>Some other tex</p>
      <div>
        <div>
          <button class="classButton">Button 4</button>
        </div>
      </div>
    </div>

  • answered 2022-05-04 10:09 jona

    Thanks to @CBroe's comment I got this solution:

    let result;
    let buttonEvent = document.querySelectorAll(".classButton");
    let button = document.querySelector(".classButton");
    buttonEvent.forEach(click => {
      click.addEventListener("click", myScript);
    })
    
    
    function myScript() {
      result = this.parentElement.parentElement.parentElement.firstElementChild.innerHTML.trim()
      console.log(result)
    }
    <div class="this-is-a-block">
      <h3>My first Element 1</h3>
      <p>Some text</p>
      <p>Some text</p>
      <div>
        <div>
          <button class="classButton">Button 1</button>
        </div>
      </div>
    </div>
    <div class="this-is-a-block">
      <h3>My second Element 2</h3>
      <p>Some other text</p>
      <p>Some other tex</p>
      <div>
        <div>
          <button class="classButton">Button 2</button>
        </div>
      </div>
    </div>

    I'm not sure if this is the 100% best way, but it's working.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum