skip to Main Content

Firstly I am very new to javascript. I have a Shopify store and I am planning to have a countdown timer just like Amazon to each of my product pages. I know there are a lot of plugins I can use for Shopify but none of them matches with the theme and style of my Shopify store so I planned to make one myself.

What I want is if User-1 opens my website and navigates to a product page, he should see a timer counting down to a specific time say 12:00:00 (hh:mm:ss). Suppose User-1 sees ‘Deal ends in 11:20:10‘ Now if User-2 opens the same product page at the same time then he should also see ‘Deal ends in 11:20:10‘ The whole point is the timer should not refresh back to 12:00:00 every time the browser loads/reloads the page and every user on the website should see the same time remaining on the countdown timer.

I starting with a bit of research and managed to run a timer on my store. It’s not exactly what I want but here’s the code:

    var interval;
    var minutes = 1;
    var seconds = 5;
    window.onload = function() {
        countdown('countdown');
    }

    function countdown(element) {
        interval = setInterval(function() {
            var el = document.getElementById(element);
            if(seconds == 0) {
                if(minutes == 0) {
                    el.innerHTML = "countdown's over!";                    
                    clearInterval(interval);
                    return;
                } else {
                    minutes--;
                    seconds = 60;
                }
            }
            if(minutes > 0) {
                var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
            } else {
                var minute_text = '';
            }
            var second_text = seconds > 1 ? 'seconds' : 'second';
            el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + ' remaining';
            seconds--;
        }, 1000);
    }
    </script>

And here’s what it looks like:

enter image description here

It does work but has the following problems:

  1. It refreshes with the browser refresh.
  2. It doesn’t have hours.
  3. It does not auto-repeat when the timer reaches zero.
  4. For every user time remaining varies.

As I mentioned I am almost a noob in JavaScript. Can anyone help me build a countdown timer that overcomes the above issues?

2

Answers


  1. I am not sure how Shopify handles plugins, but there must be some way to edit CSS for them, so you could have them match the style of your theme.

    What you’ve done here, in the JS you’ve provided, will always have that behavior because it is client-side code. The script will run after each refresh, and will always refresh the values minutes and seconds to the associated initial values namely 1 and 5. I believe this answers your first question.

    As per your second question, you clearly have not coded hours in that JS script. So hours should not appear, it would be a mystery if they did!

    With respect to your third question, you only call countdown once during the onload function.

    And by the first answer, it is natural that the clock should not be synchronized among users since they would logically be refreshing your page at different times.

    So I think your best bet is to use one of the plugins and just modify the CSS.

    Login or Signup to reply.
  2. Explanation

    Problem 1: It refreshes with the browser refresh.

    Cause: Because you hardcoded the seconds and minutes (var seconds = 5, var minutes = 1), every user that visits the page will see the timer counting down from the exact same value being "1 minute and 5 seconds remaining" again and again.

    Solution: Instead of hardcoding the start value of the countdown, hardcode the deadline. So instead of saying to each visitor of your page "Start counting down from 1 min and 5 sec to 0!", you have to say something like "Count down from whatever time it is now to midnight!". This way, the countdown will always be synced across different users of your website (assuming that their computer clock is set correctly).

    Problem 2: It doesn’t have hours.

    Cause: Your code has only variables to keep track of seconds and minutes, there is no code written to keep track of the hours.

    Solution: Like proposed in the solution for problem 1: don’t keep track of the hours/minutes/seconds remaining, but only keep track of the deadline and then calculate hours/minutes/seconds remaining based on the current client time.

    Problem 3: It does not auto-repeat when the timer reaches zero.

    Cause: The nested ifs (that check seconds == 0 and m == 0) in your code explicitly state to display the text "countdown’s over!" when the countdown is over.

    Solution: Keep a conditional that checks when the countdown is over but instead of displaying "countdown’s over!", reset the deadline to a next deadline.

    Problem 4: For every user time remaining varies.

    Cause: See Problem 1

    Solution: See Problem 1

    Sample code

    here is a piece of code that integrates the solutions mentioned above:

    const span = document.getElementById('countdown')
    
    const deadline = new Date
    deadline.setHours(0)
    deadline.setMinutes(0)
    deadline.setSeconds(0)
    
    function displayRemainingTime() {
      if (deadline < new Date) deadline.setDate(deadline.getDate() + 1)
      const remainingTime = deadline - new Date
      const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
      const seconds = extract(   60000, 1000   ) 
      const minutes = extract( 3600000, 60000  ) 
      const hours   = extract(86400000, 3600000)
      const string = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
      span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
    }
    window.setInterval(displayRemainingTime, 1000)
    displayRemainingTime()
    <h3>
      <span id="countdown"></span>
    </h3>

    Edit: make sure the client time is correct

    If you don’t trust your clients for having their time set up correctly. You can also send a correct timestamp from the server that serves your page. Since I don’t know what kind of server you are using I can’t give an example for your server code. But basically you need to replace the code (from the following example) after const trustedTimestamp = (being (new Date).getTime()) with a correct timestamp that you generate on the server. For the correct formatting of this timestamp refer to Date.prototype.getTime()

    const span = document.getElementById('countdown')
    const trustedTimestamp = (new Date).getTime()
    let timeDrift = trustedTimestamp - (new Date)
    const now = () => new Date(timeDrift + (new Date).getTime())
    
    const deadline = now()
    deadline.setHours(0)
    deadline.setMinutes(0)
    deadline.setSeconds(0)
    
    function displayRemainingTime() {
      if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
      const remainingTime = deadline - now()
      const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
      const seconds = extract(   60000, 1000   ) 
      const minutes = extract( 3600000, 60000  ) 
      const hours   = extract(86400000, 3600000)
      span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
    }
    window.setInterval(displayRemainingTime, 1000)
    displayRemainingTime()
    <h3>
      <span id="countdown"></span>
    </h3>

    Time from google server

    To create a working example I added this experiment where I get the correct time from a Google page. Do not use this code on your website because it is not guaranteed that google will keep hosting this web-page forever.

    const span = document.getElementById('countdown')
    const trustedTimestamp = (new Date).getTime()
    let timeDrift = 0
    const now = () => new Date(timeDrift + (new Date).getTime())
    
    const deadline = now()
    deadline.setHours(0)
    deadline.setMinutes(0)
    deadline.setSeconds(0)
    
    window.setInterval(displayRemainingTime, 1000)
    window.setInterval(syncClock, 3000)
    displayRemainingTime()
    syncClock()
    
    function displayRemainingTime() {
      if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
      const remainingTime = deadline - now()
      const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
      const seconds = extract(   60000, 1000   ) 
      const minutes = extract( 3600000, 60000  ) 
      const hours   = extract(86400000, 3600000)
      span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
    }
    
    function syncClock() {
      const xmlhttp = new XMLHttpRequest();
      xmlhttp.open("HEAD", "http://www.googleapis.com",true);
      xmlhttp.onreadystatechange = function() {
        const referenceTime = new Date
        if (xmlhttp.readyState==4) {
          const correctTime = new Date(xmlhttp.getResponseHeader("Date"))
          timeDrift = correctTime - referenceTime
        }
      }
      xmlhttp.send(null);
    }
    <h3>
      <span id="countdown"></span>
    </h3>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search