Search code examples
javascriptgoogle-apps-scripttimersetinterval

Clearing a javascript timer when new starting point is input


yes I'm new, and don't worry about making me sound dumb. :) This is a web app written in Google Script and it's taking info from Google Sheets.

I adopted a code from a comment here: Javascript timer to use multiple times in a page . Current code is below. I'm running several different timers thru this whole thing and they all go down by 1 second every second - great. My question is because the value on the google sheet that the first code grabs, is changing every few minutes. I WANT it to be counting down from the most recent data, and make the "old" counter STOP. From reading several related threads I think I need another clearInterval somewhere but I can't figure out where to put it.

Google Apps Script that grabs Google sheets values and puts them into a variable. the "getdata" values are dates in the future, and then "data" is how many seconds until that date:

    function getfivecoins(){
      var livesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Live");
      var getdata = livesheet.getRange("D42").getValue().getTime();
      var now = new Date().getTime();
      var data = (getdata-now)/1000; // how many seconds in the future this date is
      return data;
    }


function gettencoins(){
  var livesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Live");
  var getdata = livesheet.getRange("D43").getValue().getTime();
  var now = new Date().getTime();
  var data = (getdata-now)/1000;  // how many seconds in the future this date is
  return data;
}

then in html page:

<span id="timer1"></span>
    <br>
<span id="timer2"></span>
    <br>

lower down inside of script tags:

// every 10 seconds, gets new values from google sheets. Countdown should continue as normal (with some milliseconds difference, whatever) if values are the same, but trying to get countdown to start again if the value has changed. If its easier, clearing all the countdowns and then starting them again should have the same result.

  document.addEventListener('DOMContentLoaded', function(){
        setInterval(function(){
        google.script.run.withSuccessHandler(generatefivecoins).getfivecoins();
        google.script.run.withSuccessHandler(generatetencoins).gettencoins();
}, 10000);
        });


const clearStack = []; //Added
   function generatefivecoins(result) {
   clearStack.forEach(clearInterval); //Added
   var timer = document.getElementById('timer1');
   var t = new timerObject();
   clearStack.push(t.startTimer(result, timer)); //Modified
   }

    function generatetencoins(result){
    clearStack.forEach(clearInterval); //Added
    var timer =  document.getElementById("timer2");
    var t = new timerObject();
    clearStack.push(t.startTimer(result, timer)); //Modified
    } 





     var timerObject = function(){
    return this;
};

timerObject.prototype.startTimer = function(duration, display) {
  var me = this, 
      timer = duration,
      STYLETEST, hours, minutes, seconds, ENDSTYLETEST; 
var intervalLoop = setInterval(() => { // modified this line

    //fancy colours and formatting stuff goes here

  display.innerHTML = STYLETEST + " " + hours + ":" + minutes + ":" + seconds + ENDSTYLETEST;

    if (--timer < 0) {
      clearInterval(intervalLoop);
    }    
  }, 1000);
    return intervalLoop; //Added  
};

Solution

  • Flow:

    • Instead of multiple functions, We use a single function with variable arguments.
    • coinBucket holds the different coins that can be generated
    • After generateCoins is called from server side, We use Map to store timerObject instance of class . During the next call, We use the same timerObject instead of creating a new one.

    code.gs

    function doGet(e) {
      return HtmlService.createHtmlOutputFromFile('index');
    }
    
    const getCoins = coin => {
      const map = { 5: 'D42', 10: 'D43', 20: 'D48', 60: 'D49', 90: 'D50' };//fivecoin range = D42 and so on
      var livesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Live');
      var getdata = livesheet
        .getRange(map[coin])
        .getValue()
        .getTime();
      var now = new Date().getTime();
      var data = getdata - now; // how many milliseconds in the future this date is
      return data;
    };
    

    Client side:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title></title>
      </head>
      <body>
        <h1>Coins!!</h1>
        <span id="timer1"></span>
        <span id="timer2"></span>
        <span id="timer3"></span>
        <span id="timer4"></span>
        <span id="timer5"></span>
      </body>
      <script>
        const coinBucket = [5, 10, 20, 60, 90];//number of coin buckets 
        const GSR = (func, ...args) =>// google.script.run to promise
          new Promise((resolve, reject) =>
            google.script.run
              .withSuccessHandler(resolve)
              .withFailureHandler(reject)
              [func](...args)
          );
    
        const clearStack = new Map();//map to store timerObjects
        function generateCoins(result, i) {
          const timer = clearStack.get(i) || new timerObject(i);
          clearStack.set(i, timer);
          timer.stopTimer();
          timer.startTimer(result);
        }
        class timerObject {
          constructor(id) {
            this.elementId = 'timer' + (id + 1);
            this.timerIds = [];
          }
          startTimer(duration) {
            const display = document.getElementById(this.elementId);
            this.timerIds.push(
              setInterval(() => {
                const hours = parseInt(duration / 1000 / 60 / 60, 10),
                  minutes = parseInt((duration / 1000 / 60) % 60, 10),
                  seconds = parseInt((duration / 1000) % 60, 10);
                display.innerHTML = [hours, minutes, seconds]
                  .map((e) => ('0' + e).slice(-2))
                  .join(':');
                duration = duration - 1000;
                if (duration < 0) this.stopTimer();
              }, 1000)
            );
          }
          stopTimer() {
            this.timerIds.forEach(clearInterval);
            this.timerIds = [];
          }
        }
    
        document.addEventListener('DOMContentLoaded', function () {
          setInterval(function () {
            Promise.all(
              coinBucket.map((bucket) => GSR('getCoins', bucket))
            ).then((values) => values.forEach(generateCoins));
          }, 10000);
        });
      </script>
    </html>