#1 by aarumardi
What can I do if I find this message? Results.is_displayed line 1: undefined name 'get_timeout_seconds'
#2 by Chris_oTree
It’s saying that in is_displayed you used get_timeout_seconds which is not defined.
#3 by aarumardi
where should I define get_timeout_seconds?
#4 by BonnEconLab
Reading the documentation helps: https://otree.readthedocs.io/en/latest/timeouts.html#get-timeout-seconds. In your case, it should be something like the following: class Results(Page): @staticmethod def get_timeout_seconds(player): return <THE VALUE THAT YOU WANT THE TIMEOUT TO HAVE IN SECONDS>
#5 by aarumardi (edited )
I'm trying to create multiple rounds with a timeout with otree studio, however the timer stop when it is going to the next round, is there any specific code I should do?
#6 by BonnEconLab
If I understand you correctly, you would like the timeout to span multiple rounds. Again, reading the documentation helps. There is an example for the code that does what you desire on the very page that I linked to: https://otree.readthedocs.io/en/latest/timeouts.html#timeouts-that-span-multiple-pages. Following the documentation, let’s assume that you have two HTML templates, Start.html and Page1.html. For instance, Start.html: {{ block title }} Ready? {{ endblock }} {{ block content }} <p>Press the button when you’re ready to start.</p> {{ next_button }} {{ endblock }} Page1.html: {{ block title }} Round No. {{ player.round_number }} {{ endblock }} {{ block content }} {{ formfields }} {{ next_button }} {{ endblock }} In the settings.py file, include PARTICIPANT_FIELDS = [ 'expiry', ] An __init__.py file like the following does the job: from otree.api import * import time doc = """ An app to illustrate a countdown that spans multiple rounds. """ class C(BaseConstants): NAME_IN_URL = 'multiround_timeout' PLAYERS_PER_GROUP = None NUM_ROUNDS = 10 # Set to the desired number of rounds TIMEOUT_SECONDS_TOTAL = 42 # Set to the desired total timeout, e.g., 30 * 60 for 30 minutes class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): pass # FUNCTIONS def get_timeout_seconds(player): return player.participant.expiry - time.time() # PAGES class Start(Page): @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def before_next_page(player, timeout_happened): player.participant.expiry = C.TIMEOUT_SECONDS_TOTAL + time.time() # Remember to add 'expiry' to PARTICIPANT_FIELDS in settings.py class Page1(Page): timer_text = 'Time left to complete this section:' get_timeout_seconds = get_timeout_seconds @staticmethod def is_displayed(player): return get_timeout_seconds(player) > 0 page_sequence = [ Start, Page1, ]
#7 by aarumardi
<p> Your income pre-tax in: </p> <p> <tr> Round 1 <input type="text" id="income_pre_tax1" oninput="recalc()"> {{ formfield "income_pre_tax1" }} </p> <p> <tr> Round 2 <input type="text" id="income_pre_tax2" oninput="recalc()"> {{ formfield "income_pre_tax2" }} </p> <p> <tr> Round 3 <input type="text" id="income_pre_tax3" oninput="recalc()"> {{ formfield "income_pre_tax3" }} </p> <p> <tr> Round 4 <input type="text" id="income_pre_tax4" oninput="recalc()"> {{ formfield "income_pre_tax4" }} </p> <p> <tr> Round 5 <input type="text" id="income_pre_tax5" oninput="recalc()"> {{ formfield "income_pre_tax5" }} </p> <p>Total income: <span id="totalincome"></span> <small>Dollars</small></p> <p>Tax rate: {{ C.TAX_RATE }}</p> <br> <p>Your tax payable is:</p> <h2><span id="taxpayable"></span> <small>Dollars</small></h2> <style> .red-text { color: red; } </style> <p> Your income after tax is:</p> <h2><span id="incomeaftertax" class="red-text"></span> <small class="red-text">Dollars</small></h2> <button name="Submit Tax Returns" value="True" class="blue-text">Submit Tax Returns</button> <script> let taxpayableEle = document.getElementById('taxpayable'); let incomeaftertaxEle = document.getElementById('incomeaftertax'); let totalincomeEle = document.getElementById('totalincome'); function recalc() { let income_pre_tax1 = parseInt(document.getElementById('income_pre_tax1').value); let income_pre_tax2 = parseInt(document.getElementById('income_pre_tax2').value); let income_pre_tax3 = parseInt(document.getElementById('income_pre_tax3').value); let income_pre_tax4 = parseInt(document.getElementById('income_pre_tax4').value); let income_pre_tax5 = parseInt(document.getElementById('income_pre_tax5').value); let totalincome = income_pre_tax1 + income_pre_tax2 + income_pre_tax3 + income_pre_tax4 + income_pre_tax5; totalincomeEle.innerText = totalincome; // Check if totalincome is a valid number if (isNaN(totalincome)) { taxpayableEle.innerText = ''; incomeaftertaxEle.innerText = ''; } else { let taxRate = parseFloat('{{ C.TAX_RATE }}'); // Access tax rate directly from your template let taxpayable = totalincome * taxRate; taxpayableEle.innerText = taxpayable; let incomeaftertax = totalincome - taxpayable; incomeaftertaxEle.innerText = incomeaftertax; } } // Attach event listeners to input fields document.getElementById('income_pre_tax1').oninput = recalc; document.getElementById('income_pre_tax2').oninput = recalc; document.getElementById('income_pre_tax3').oninput = recalc; document.getElementById('income_pre_tax4').oninput = recalc; document.getElementById('income_pre_tax5').oninput = recalc; </script> I'm trying to create inputs from round1 to round5 as form fields not just a live method of authomatic calculation, however, it creates two different boxes.