javascripthtmlduplicates

How to duplicate a Javascript on the same page


I have some code for a stopwatch here: https://github.com/Aerodyll/Stopwatch

As you can see the counter changes the html of 4 tags for hours, minutes, seconds and milliseconds. And it ties to 3 buttons, start, stop and clear.

This works fine when there is just one counter on screen but how would I alter this code to make it work for multiple counters on the screen at once (that all work independently)? It just breaks when I duplicate it at the moment. I understand why it breaks because it is pointing to the same html objects but how would I go about duplicating the counters on the page without writing a whole new script for each one?

(I have found a couple of examples of other users doing this but their code is very difficult for me to understand.)


Solution

  • works fine when there is just one counter on screen but how would I alter this code to make it work for multiple counters on the screen at once ...

    1. Wrap your HTML elements into a div to create multiple blocks. Give this wrapper an id if you want to target those individually. Alternatively, just give it a same class if you want to target them all.
    2. Wrap your entire code into a function. This will encapsulate your logic.
    3. Call that function with the element id or element itself.
    4. Within the function get references to your spans within the element. This could be done via class or nth-child selector.

    Example:

    The example below is your original code, just refactored as per the above points.

    var allWatches = document.getElementsByClassName('stopwatch'), 
        firstWatch = document.getElementById('sw1')
    ;
    
    // One way to call stopwatch on individual blocks
    //stopWatch('sw1'); // pass id to the function
    
    // Another way to call stopwatch on individual blocks
    //stopWatch(firstWatch); // pass the element ref to the function
    
    // One way to call stopwatch on all blocks
    for(i=0; i < allWatches.length; i++) {
      stopWatch(allWatches[i]);
    }
    
    function stopWatch(element) {
      /* Declaring the html objects that will contain the time */
      var hrs, mins, secs;
      /* Declaring the html buttons */
      var start, stop, clear;
      /* Other variables */
      var seconds = 0, minutes = 0, hours = 0, t;
      // check if id is passed or the actual element reference
      if (typeof element === 'string') {
        element = document.getElementById(element);
      }
      // get reference to component elements inside
      hrs = element.querySelector('.hours');
      mins = element.querySelector('.minutes');
      secs = element.querySelector('.seconds');
      start = element.querySelector('.start');
      stop = element.querySelector('.stop');
      clear = element.querySelector('.clear');
    
      function runWatch() {
        seconds++;
        if (seconds >= 60) {
          seconds = 0; minutes++;
          if (minutes >= 60) {
            minutes = 0; hours++;
          }
        }
    
        /* Hours */
        if (hours == null) {
          hrs.textContent = "00";
        } else {
          hrs.textContent = hours > 9 ? hours : "0" + hours;
        }
    
        /* Minutes */
        if (minutes == null) {
          mins.textContent = "00";
        } else { 
          mins.textContent  = minutes > 9 ? minutes : "0" + minutes;
        }
    
        /* Seconds */
        if (seconds == null) {
          secs.textContent = "00";
        } else { 
          secs.textContent  = seconds > 9 ? seconds : "0" + seconds;
        }
    
        t = setTimeout(runWatch, 1000);
    
      } // End of runWatch
    	
      runWatch();
    	
      /* Start button */
      start.onclick = runWatch;
    
      /* Stop button */
      stop.onclick = function() { clearTimeout(t); }
    
      /* Clear button */
      clear.onclick = function() {
        hrs.textContentL = "00"; mins.textContent = "00"; secs.textContent = "00";
        clearTimeout(t);
        seconds = 0; minutes = 0; hours = 0;
      }	
    }
    * { box-sizing: border-box; margin: 0; padding: 0; }
    div.stopwatch {
      width: 180px; border: 1px solid #999;
      margin: 8px; display: inline-block;
    }
    div.stopwatch > div { display: flex; margin: 8px; } 
    div.stopwatch > div > * { flex: 1 1 auto; }
    div.stopwatch > div > span { 
      text-align: center; 
      font-family: sans-serif; font-size: 1.7em;
    }
    div.stopwatch > div > button { 
      padding: 2px 4px;
    }
    <div id="sw1" class="stopwatch">
      <div>
        <span class="hours">00</span>
        <span class="minutes">00</span>
        <span class="seconds">00</span>
      </div>
      <div>
        <button class="start">start</button>
        <button class="stop">stop</button>
        <button class="clear">clear</button>	
      </div>
    </div>
    
    <div id="sw2" class="stopwatch">
      <div>
        <span class="hours">00</span>
        <span class="minutes">00</span>
        <span class="seconds">00</span>
      </div>
      <div>
        <button class="start">start</button>
        <button class="stop">stop</button>
        <button class="clear">clear</button>	
      </div>
    </div>