4

I have five buttons in my HTML file.

Seeing as they are five, I would like to be able to print the index of the specific button that has been clicked in the HTML collection. i.e on tapping btn 4 I should see 3 printed. I tried putting together some javascript lines that I thought would do it but in vain. The JS code is:

if (document.readyState == 'loading') {
        document.addEventListener('DOMContentLoaded',execute);
    }else{
        execute()
    }
    function execute() {
        var btns = document.getElementsByClassName('item');
        for (var i = 0; i < btns.length; i++) {
            btns[i].addEventListener('click',btnClicked);
        }       
    }
    function btnClicked(event,btns) {
        var btn = event.currentTarget;
        var btnIndex = btns.indexOf(btn)
        console.log(btnIndex)
    }
<body>
        <div class="btn-items">
            <button class="item">btn 1 </button>
            <button class="item">btn 2 </button>
            <button class="item">btn 3</button>
            <button class="item">btn 4</button>
            <button class="item">btn 5</button> 
        </div>
    </body>

What is the way to go?

ATP
  • 2,939
  • 4
  • 13
  • 34
The_Ogre
  • 97
  • 1
  • 9
  • 1
    Remove the fluff around `DOMContentLoaded` event, just attach the event without any checks. Don't iterate a live HTMLCollection, use an array instead (`btns = Array.from(document.querySelectorAll('.item'));`). That would also resolve your issue with `indexOf`. – Teemu Jan 10 '21 at 12:26
  • Check out [this answer](https://stackoverflow.com/a/37566648/989920). Even though it's about `classList` it applies to the result of `querySelectorAll` – evolutionxbox Jan 10 '21 at 12:50

6 Answers6

3

You can get the desired output with this solution

function execute() {
    var btns = document.querySelectorAll('.item');
    btns.forEach(btnClicked);
  
}
function btnClicked(btn,index) {
    btn.addEventListener('click',()=>{
       console.log(index)
    });
}

This is a cleaner way of achieving that.

3

why not use

if (document.readyState == 'loading') {
    document.addEventListener('DOMContentLoaded',execute);
}else{
    execute();
}
function execute() {
    const btns = document.getElementsByClassName('item');
    for(let i = 0; i < btns.length; i++){
        btns[i].addEventListener('click',function(){
            console.log('button index : '+i);
        });
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button class="item">button 1</button>
    <button class="item">button 2</button>
    <button class="item">button 3</button>
    <script src="script.js"></script>
</body>
</html>
wwwikla
  • 31
  • 3
3

Often when you want to apply the same event to multiple elements, try and use event delegation.

Basically what you do is listen for the event on the parent btn-items, this works because Browser bubble events up.

Below is an example, notice because you listen for all clicks on the parent, if you click on the gap between buttons you will get -1, in a real example you will likely want to handle this.

But the advantage with this approach, there is a single event listener, and a single event callback. And a really nice advantage is that if you later dynamically add .item, it will automatically work for these too.

const btns = document.querySelector('.btn-items');
btns.addEventListener('click', e => {
  console.log([...btns.children].
    indexOf(e.target));
});
<div class="btn-items">
    <button class="item">btn 1 </button>
    <button class="item">btn 2 </button>
    <button class="item">btn 3</button>
    <button class="item">btn 4</button>
    <button class="item">btn 5</button> 
</div>
Keith
  • 22,005
  • 2
  • 27
  • 44
2

You could give every button a custom attribute by using the setAttribute function on the HTML element. Then you just need to retrieve the value of this attribute by using the getAttribute function. See code example below:

var btns = document.getElementsByClassName('item')

for (var i = 0; i < btns.length; i++) {
    btns[i].addEventListener('click', btnClicked)
    btns[i].setAttribute('data-index', i)
}

function btnClicked(event) {
   var btn = event.currentTarget;
   console.log(btn.getAttribute('data-index'))
}
<div class="btn-items">
    <button class="item">btn 1 </button>
    <button class="item">btn 2 </button>
    <button class="item">btn 3</button>
    <button class="item">btn 4</button>
    <button class="item">btn 5</button> 
</div>
niklhs
  • 166
  • 9
2

document.getElementsByClassName() returns a node list that doesn't have indexOf() function. (see this question)

You can just pass i as parameter to btnClicked().

var btns;
if (document.readyState == 'loading') {
        document.addEventListener('DOMContentLoaded',execute);
    }else{
        execute()
    }
    function execute() {
        btns = document.getElementsByClassName('item');
        for (let i = 0; i < btns.length; i++) {
            btns[i].addEventListener('click',(e)=> btnClicked(e,i));
        }       
    }
    function btnClicked(event,i) {
        
        console.log(i)
    }
ATP
  • 2,939
  • 4
  • 13
  • 34
0

var trows = document.getElementById("myTable").querySelector('tbody').rows;

Array.from(trows).map((trow, index) => {
  trow.onclick = () => {
    console.log(index)
  }
})
table{
    border-collapse: collapse;
    border-spacing: 0;
    min-width: max-content;
}

th, td {
    border: 1px solid black;
}

tbody tr{
    cursor: pointer;
}
        <div id="results" class="scrollingdatagrid">
            <table id="myTable">
                <thead>
                    <tr>
                        <th>File Number</th>
                        <th>Date1</th>
                        <th>Date2</th>
                        <th>Status</th>
                        <th>Num.</th>                        
                    </tr>
                </thead>
                <tbody>
                    <tr> 
                        <td>KABC</td>
                        <td>09/12/2002</td>
                        <td>09/12/2002</td>
                        <td>Submitted</td>
                        <td>1</td>
                 
                      </tr>
                      <tr> 
                        <td>KCBS</td>
                        <td>09/11/2002</td>
                        <td>09/11/2002</td>
                        <td>Lockdown</td>
                        <td>2</td>
                      </tr>
                 
                      <tr> 
                        <td>WFLA</td>
                        <td>09/11/2002</td>
                        <td>09/11/2002</td>
                        <td>Submitted</td>
                        <td>3</td>
                      </tr>
                      <tr> 
                        <td>WTSP</td>
                        <td>09/15/2002</td>
                        <td>09/15/2002</td>
                        <td>In-Progress</td>
                        <td>4</td>
                      </tr>                    
                </tbody>
            </table>
        </div>
edwDev
  • 11
  • 2