oTree Forum >

How to configure live_method to retrieve the history of the game from the database

#1 by jrm0094

Hi, I have a fully functioning live page but if a player decides to refresh the page, the updates to the pages html all go away. I am creating an Anagram game where if a player types in the correct answer that anagram turns green and they cant keep getting points for writing that answer over and over again. But, if a player hits refresh, the game resets entirely. The only thing that actually stays after a refresh is the chat box.

Here is my code for the init py file:
from otree.api import *


doc = """
Your app description
"""


class C(BaseConstants):
    NAME_IN_URL = 'single_multi'
    PLAYERS_PER_GROUP = None
    NUM_ROUNDS = 1


class Subsession(BaseSubsession):
    pass


class Group(BaseGroup):
    pass


class Player(BasePlayer):
    # Self Identification
    gender = models.BooleanField(
        choices=[
            [False, "Male"],
            [True, "Female"],
        ],
        label="Please select your gender."
    )


# PAGES
class SingleAnagramRound1(Page):
    @staticmethod
    def live_method(player: Player, data):
        if data['type'] == 'correctAnagram':
            return {player.id_in_group: {'type': 'correctAnagram', 'value': data['value'], 'id': data['id']}}


class ResultsWaitPage(WaitPage):
    pass


class Results(Page):
    pass


page_sequence = [SingleAnagramRound1, ResultsWaitPage, Results]


Here is my Single Anagram Round 1 html file:
{{block title}}
Single player Anagram Round 1
{{ endblock }}
{{ block content }}

<body>
    <table id = "exp_table" class = "table table-bordered table-sm">
        <thread>
            <tr class = "table-info table-sm">
                <th class="col-sm-1" scope="col">Put solution in chat</th>
                <th id="a1" class="border-3 col-sm-1" scope="col">azhle</th>
                <th id="a2" class="border-3 col-sm-1" scope="col">lwahe</th>
                <th id="a3" class="border-3 col-sm-1" scope="col">htiwd</th>
                <th id="a4" class="border-3 col-sm-1" scope="col">rnowf</th>
                <th id="a5" class="border-3 col-sm-1" scope="col">nadts</th>
                <th id="a6" class="border-3 col-sm-1" scope="col">augrd</th>
                <th id="a7" class="border-3 col-sm-1" scope="col">nrtai</th>
                <th id="a8" class="border-3 col-sm-1" scope="col">yqeru</th>
                <th id="a9" class="border-3 col-sm-1" scope="col">ivper</th>
                <th id="a10" class="border-3 col-sm-1" scope="col">hcoir</th>
            </tr>
        </thread>
    </table>
</body>
{{ chat channel=player.id_in_group nickname=participant.nickname }}

<script>
    const input = document.getElementsByClassName('otree-chat__input')
    const send = document.getElementsByClassName('otree-chat__btn-send')
    const solutions = [ ["hazel", "a1"], ["whale", "a2"], ["width", "a3"], ["frown", "a4"], ["stand", "a5"], ["guard", "a6"], ["train", "a7"], ["query", "a8"], ["viper", "a9"], ["choir", "a10"]]

    // Add an event listener for the Enter key press on the text box
    input[0].addEventListener('keydown', function(event) {
        if (event.key === 'Enter') {
            send[0].click();   // Trigger the button's onclick event
        }
    });

    function liveRecv(data) {
        document.getElementById(data['id']).className = "border-3 col-sm-1 bg-success";
        document.getElementById(data['id']).innerHTML = data['value'];
        for (let i = solutions.length - 1; i >= 0; i--) {
            if (data['value'] === solutions[i][1]) {
                solutions.splice(i,1);
            }
        }
    }

    // Define the onclick event for the button
    function sendValue() {
        var attempt = input[0].value
        console.log('Button clicked! You entered: ' + attempt);
        for (let i = solutions.length - 1; i >= 0; i--) {
            if (attempt === solutions[i][0]) {
                console.log('Solved anagram ' + solutions[i][1] + '!');
                document.getElementById(solutions[i][1]).className = "border-3 col-sm-1 bg-success";
                liveSend({'type': 'correctAnagram', 'value': solutions[i][0], 'id': solutions[i][1]})
                solutions.splice(i, 1);
            }
        }
    };

    // Define the onclick event for the button
    send[0].onclick = sendValue;
</script>

{{ endblock}}


Any help would be greatly appreciated thank you.

#2 by Daniel_Frey

I think you're not saving anything into the database: Your live_method just returns the inputs back to the page and marks the solutions green.
With this setup, you don't even need the liveSend, you could just turn the box green directly.

However, you can use live_method to save a value into the database (in a participant field for example):

def live_method(player: Player, data):
    # assuming you created an empty set player.participant.solutions_found somewhere and referenced it in PARTICIPANT_FIELDS
    player.participant.solutions_found.add(data['value'])
    return ...

You can pass this list to your JavaScript by js_vars:

def js_vars(player: Player)
    return dict(solutions_found=player.participant.solutions_found)
    
Now you can check this list with a DOMContentLoaded eventlistener and turn the already found answers green.

I haven't tested that code, but I hope it gives you an idea on how to solve your problem!

#3 by jrm0094

That fixed some problems but now i realized that the players arent all synchronized. I will explain with an example. Player one enters the game before player 2 and player 3. Player one solves an anagram. Player 2 and player 3 then dont see that this was solved. Even if all the players are inside the game, if one player answers an anagram the others dont see it. This is a very big problem.

Write a reply

Set forum username