Solution 1 :

You could do something like this:

from flask import Flask, render_template, jsonify

app = Flask(__name__)


class Timer:
    def __init__(self, current_time):
        self.current_time = current_time

    def decrement(self):
        if self.current_time > 0:
            self.current_time = self.current_time - 1
        return self.current_time


t = Timer(current_time=60)


@app.route("/", methods=["GET"])
def index():
    return render_template("index.html")


@app.route("/_timer", methods=["GET", "POST"])
def timer():
    new_time = t.decrement()
    return jsonify({"result": new_time})


if __name__ == "__main__":
    app.run()

and this:

<body>
   <span id="result"></span>
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
   <script>window.jQuery || document.write('<script src="{{ url_for('static', filename='jquery.js') }}">x3C/script>')</script>
   <script type="text/javascript">
      const root_url = {{request.root_url|tojson|safe}};
      const intervalID = setInterval(update_values, 1000);
      function update_values() {
        $.getJSON(
          root_url + "_timer",
          data => {
            $("#result").text(data.result);
            if (data.result == 0) {
              clearInterval(intervalID);
            }
          }
        )
      }
   </script>
</body>

When I logged request.script_root I got an empty string back, making the request fail, so that might also be a problem on your end. I used request.root_url instead. request.root_url does have a trailing slash so you need to be aware of that when you’re trying to call endpoints with it.

The idea here is to create a class where an instance of this class can be passsed an initial time which can be decremented and returned.

In your code you use both setInterval(update_values, 1000) and time.sleep(1). I removed the time.sleep(1) call since we’re already only calling the _timer endpoint every second so we don’t need to wait an extra second.

I only decrement the time if the time is more than 0. In the template if data.result (i.e. the time received from Flask) is 0 we don’t decrement anymore and clear the interval.

Also be aware that since we’re decrementing the time based on setInterval something like a refresh won’t reset the timer. That might be desired behavior, but either way something to keep in mind.

Problem :

I am building a game using Flask where every round has a countdown time to complete the round. I want the time value to decrease by 1 every second and to update without reloading the page. The countdown itself uses a time.sleep to wait 1 second before setting the next value of a generator to a global variable, which is passed through jsonify to my HTML. However it is not working. Any help would be appreciated!

python:

def countdownGen(t):
    return (t-i for i in range(t))

def countdown(t):
    gen = countdownGen(t)
    while t > 0:
        try:
            globaltimer = next(gen)
            time.sleep(1)
        except StopIteration:
            globaltimer = 0

@app.route('/_timer', methods=['GET'])
def timer():
    global globaltimer
    globaltimer = 60
    countdown(globaltimer)
    return jsonify(result=globaltimer)

HTML / JS:

<script type="text/javascript">
  var intervalID = setInterval(update_values,1000);
  $SCRIPT_ROOT = {{request.script_root|tojson|safe}};
  function update_values() {
    $.getJSON($SCRIPT_ROOT + '/_timer',
    function(data) {
      $('#result').text(data.result);
    });
  };
</script>

<body onload="update_values();">
  <span id="result">?</span>
<script>
document.getElementById("result").innerHTML;
</script>
</body>

Comments

Comment posted by Bruno Monteiro

Have you tried moving your

Comment posted by rmd_po

@BrunoMonteiro that doesn’t seem to work either

Comment posted by jot240

This code pretty much worked for me, thanks. However I was getting a null being returned from the get request instead of the value from t. I don’t know if this is the best way to improve it, but instead of:

By

Leave a Reply

Your email address will not be published. Required fields are marked *