Search code examples
javascriptfunctiontimerreset

How to apply a JavaScript function to different elements by assigning the function to different buttons


I am trying to build a reset function for a timer. I do understand how to reset the value of one button, but I cannot figure out how I can assign the same function to different buttons with each their own timer.

Currently I use the code below, but it specifically targets one element, while it should work on different ones.

<html>
<head>
    <script>
    function resettimer() {
        var x = document.getElementsByClassName("timer");
        x[0].innerHTML = "Hello World!";
    }
    </script>
</head>
<body>
    <table> 
        <tr>
            <p class="timer">Timer 1</p>
            <button onclick="resettimer()">Reset timer 1</button>
        </tr>
        <tr>
            <p class="timer">Timer 2</p>
            <button onclick="resettimer()">Reset timer 2</button>
        </tr>
        <tr>
            <p class="timer">Timer 3</p>
            <button onclick="resettimer()">Reset timer 3</button>
        </tr>
        <tr>
            <p class="timer">Timer 4</p>
            <button onclick="resettimer()">Reset timer 4</button>
        </tr>
    <table>
</body>
</html>

Solution

  • By placing all the buttons into an array and all the timers into an "array-like" object, you can simply set the timer who's index matches the index of the button that was clicked (for example, if button 0 is clicked, update timer 0).

    Next, you need to move your script so that it is just prior to the closing body tag so that by the time is is encountered, all the HTML will have been read into memory and you can successfully access the elements.

    You should also not be using inline HTML event handling attributes (i.e. onclick) as this is a 20+ year old technique that has many reasons to not use them. Instead separate your JavaScript from your HTML completely.

    Also, you have some HTML validity issues (no closing table tag).

    Lastly, don't use .innerHTML when the value you are setting/getting does not contain any HTML - that's a waste of processing. Use .textContent when there is no HTML to set/get.

    <!doctype html>
    <html>
    <head></head>
    <body>
    <table>
      <tr>
        <p class="timer">Timer 1</p>
        <button class="reset">Reset timer 1</button>
      </tr>
    
      <tr>
        <p class="timer">Timer 2</p>
        <button class="reset">Reset timer 2</button>
      </tr>
    
      <tr>
        <p class="timer">Timer 3</p>
        <button class="reset">Reset timer 3</button>
      </tr>
    
      <tr>
        <p class="timer">Timer 4</p>
        <button class="reset">Reset timer 4</button>
      </tr>
    
    </table>
      <script>
        // Get all the buttons into an array and loop through the array
        var btns = Array.prototype.slice.call(document.querySelectorAll("button.reset"));
        btns.forEach(function(btn){
          btn.addEventListener("click", resettimer);
        });
        
        // Get all the timer elements into a collection
        var timers = document.querySelectorAll("p.timer");
      
        function resettimer() {
          // Access the timer with the same index as the index of the button that was clicked
          timers[btns.indexOf(this)].textContent = "Hello World!";
        }
      </script>
    </body>
    </html>