javascript otree:根据前一个问题的答案提出一个问题(在同一页上)

2w3kk1z5  于 2023-02-15  发布在  Java
关注(0)|答案(1)|浏览(182)

我想在Otree中加入一个问题,这个问题可能会被问到,也可能不会被问到,这取决于前面的问题。
问题1:你的主要职业是什么:A.工作B.学生C.失业
问题2(仅在“问题1”的答案为“A.工作”时提问):你从事什么行业?A.运输业B.采矿业C.其他
当问题1和问题2在不同的页面上时,我已经成功地做到了这一点(见下面的代码)。然而,我希望问题1和问题2在同一页上。关于如何做到这一点,有什么见解吗?(我是一个使用otree/javascript的初学者)

from otree.api import *

doc = """
'other' option
"""

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

class Subsession(BaseSubsession):
    pass

class Group(BaseGroup):
    pass

class Player(BasePlayer):
    occupation = models.StringField(label='main occupation?',choices=['Work', 'Student', 'Unemployment'])
    industry = models.StringField(label='what industry do you work on?', choices=['transportation','mining','others'])

# PAGES
class MyPage(Page):
    form_model = 'player'
    form_fields = ['occupation']

class MyPage2(Page):
    @staticmethod
    def is_displayed(player: Player):
        return player.occupation == 'Work'

    form_model = 'player'
    form_fields = ['industry']

page_sequence = [MyPage, MyPage2]
nuypyhwy

nuypyhwy1#

要根据同一页面上另一个问题的答案来显示一个问题,您需要一点javascript(您可能已经猜到了,因为您的问题已经被相应地标记了)。此javascript代码可以直接集成到HTML模板(Page.html)中,例如:

{{ block styles }}
<style>
    .do-not-show {
        display: none;
    }
</style>
{{ endblock }}

{{ block content }}
    {{ formfield "occupation" }}

    <div id="industry-box" class="do-not-show">
        {{ formfield "industry" }}
    </div>

    {{ next_button }}
{{ endblock }}

{{ block scripts }}
<script>
    let industry_box = document.getElementById("industry-box");
    let industry_select = document.getElementById("id_industry");
    let occupation_select = document.getElementById("id_occupation");

    occupation_select.addEventListener("change", function() {
        if (occupation_select.value == "Work") {
            industry_box.classList.remove("do-not-show");
            industry_select.required = true;
        } else {
            industry_box.classList.add("do-not-show");
            industry_select.required = false;
        }
    });
</script>
{{ endblock }}

解释:首先,让我们隐藏第二个问题,方法是将其 Package 在一个框中,并创建一个CSS类来确保该框不显示。然后在javascript块中,我们创建一个事件侦听器,它在每次选择第一个问题的答案时做出React。如果答案是"Work",我们将通过删除CSS类来显示第二个问题。如果答案具有不同的值,我们添加CSS类并隐藏问题(如果它还没有被隐藏)。如果你想让第二个问题是可选的(而不是强制的),你可以删除这两行:industry_select.required = true/false;.
同样重要的是,在player模型中的第二个问题的字段中添加blank=True,否则,otree总是希望得到这个问题的答案,如果问题没有得到回答,就会抛出一条错误消息(例如,因为玩家从来没有看到过它):

class Player(BasePlayer):
    
    occupation = models.StringField(
        label='main occupation?',
        choices=['Work', 'Student', 'Unemployment']
    )
    
    industry = models.StringField(
        label='what industry do you work on?',
        choices=['transportation','mining','others'],
        blank=True
    )

当然,这两个问题都必须作为表单字段包含在页面的类中:

class MyPage(Page):
    form_model = 'player'
    form_fields = ['occupation', 'industry']

相关问题