oTree Forum >

Text input is not saved

#1 by sried

Hi everyone!
I have a text input field that I do display through CSS in the beginning. After a certain answer given to a previous question, the text input pops up. However, when you enter something and submit the page, the text is not saved.
Here is a MWE:

________________
__init.py:
...
class Player(BasePlayer):
    first_q = models.IntegerField()
    other_q = models.StringField()


class MyPage(Page):
    form_model = 'player'
    form_fields = ['first_q']        ## note here that I do not include other_q because it does not necessarily pop up

...
________________
MyPage.html:
...
<style>
    #other_quest {
            display: none;
        }
</style>

<label for="first_q">Please type in some number.</label>
<br>
<input name="first_q" id="first_q" type="number" oninput="show_other_q()"/>
{ formfield_errors "first_q"}}

<div id="other_quest">
    <label for="other_q">Why is this number greater 0?</label>
    <br>
    <input name="other_q" id="other_q" type="text"/>
</div>

<script>
    function show_inc_other_spec (e) {
        let first_quest = document.getElementById('first_q').value;
        if (parseInt(first_quest)>0) {
            document.getElementById('other_quest').style.display = 'block';
        } else {
            document.getElementById('other_quest').style.display = 'none';
        }
    }
</script>


The first variable first_q is saved properly. The second one, other_q, is not saved, even when it is displayed and an answer is entered. Do you have any idea what to do with this?

#2 by BonnEconLab

I’m pretty sure that you have to include 'other_q' in your form_fields definition for participants’ input to be recorded in the oTree database:

form_fields = ['first_q', 'other_q']

To allow it to be empty, make it “optional”, as described in https://otree.readthedocs.io/en/latest/forms.html#optional-fields:

other_q = models.StringField(blank=True)

#3 by BonnEconLab

PS: If you would like to force your participants to provide an answer in the case that the “other_q” input is displayed, you could add the following to the “if” branch of your JavaScript code:

document.getElementById('other_q').required = true;

#4 by sried

Hello Holger!
Thanks for the solution, that worked very smooth and even allows me to use the {{ formfield 'other_q' }} option. That works smoothly.
What does not work, however, is to use the models.StringField(blank=True)-option and then use forminputs.other_q.required=true. Thus, the following code does not prevent the field of other_q to be blank.

...
<label for="first_q">Please type in some number.</label>
<br>
<input name="first_q" id="first_q" type="number" oninput="show_other_q()"/>
{ formfield_errors "first_q"}}

<div id="other_quest">
    {{ formfield "other_q" }}
    {{ formfield_errors "other_q"}}
</div>

<script>
    function show_inc_other_spec (e) {
        let first_quest = document.getElementById('first_q').value;
        if (parseInt(first_quest)>0) {
            document.getElementById('other_quest').style.display = 'block';
            forminputs.other_q.required = true;
        } else {
            document.getElementById('other_quest').style.display = 'none';
        }
    }
</script>

#5 by BonnEconLab

The code you posted contains a couple of typos – for instance, a missing “{”, and you renamed the JavaScript function but did not change the “oninput” attribute accordingly.

Im my testing, the following works flawlessly:

In __init__.py:

class Player(BasePlayer):

    first_q = models.IntegerField()
    other_q = models.StringField(blank=True)

class Test(Page):

    form_model = 'player'
    form_fields = ['first_q', 'other_q']

In Test.html:

<label for="first_q">Please type in some number.</label>
<br>
<input name="first_q" id="first_q" type="number" oninput="show_other_q()"/>
{{ formfield_errors "first_q"}}

<div id="other_quest" style="display: none;">
   {{ formfield "other_q" }}
   {{ formfield_errors "other_q"}}
</div>
{{ next_button }}

<script>
   function show_other_q() {
       let first_quest = document.getElementById('first_q').value;
       if (parseInt(first_quest)>0) {
           document.getElementById('other_quest').style.display = 'block';
           forminputs.other_q.required = true;
       } else {
           document.getElementById('other_quest').style.display = 'none';
           forminputs.other_q.required = false;
       }
   }
</script>

• If I type in a number > 0 into the first input field, the second input field appears and also has to be filled for the next_button to work.
• If I type in a number <= 0, then the second input field is now shown and also not required for the next_button to work.

#6 by sried

Sorry for the typos, I wrote the code from scratch since it is of course only a dummy example of my problem in the real code. Interestingly, when I set up a testapp with your code exactly, the problem still remains. Leaving other_q blank after it pops up due to a number > 0, I can still press the next_button without any error_message.

My otree version was updated today to 5.8.4

I don't know where the problem could be. Do you have any other idea? I run otree in a virtual environment using Python 3.9.6 on Windows 10 Enterprise.

#7 by BonnEconLab

Can you send me a ZIP archive of your test app/attach it to a post in this forum?

#8 by sried

Of course, here is the otreezip of the very basic dummy problem. Thanks again for your help! I am very grateful!

#9 by BonnEconLab

Hmmmmmm, maybe there has been a misunderstanding.

The code you sent works perfectly on my computer (macOS 12.5, oTree 5.8.5, Python 3.8.2). I have tested it with three browsers: Firefox, Chrome, and Safari. By “it works perfectly,” I mean that I cannot press the “Next” button unless I fill in the “q_other” field.

Of course, this does not produce an oTree-generated error message, because the field is never submitted if it is left empty and required is set to true. The only “error” message I get is “Please fill out this field.”

#10 by sried

That really is interesting. I tested it on Firefox, Chrome, and Edge, and it doesn't work. I even updated it to otree 5.9.0 now and it still doesn't work. I can resume to the next page without any issues.

#11 by BonnEconLab

Well, then the solution is obvious: Get a Mac. ;-)

Kidding aside, I can only think of one reason: The “forminputs.other_q.required = true;” part of your JavaScript code is not executed by your browser.

#12 by sried

That is probably the only reasonable explanation. The interesting question would now be: What happens on the participants' PCs when this is set up online? It would be a pity if it works for some, but not for all..

#13 by BonnEconLab

I’m really puzzled. I just tested the code that you attached previously on a Windows machine in Firefox, Chrome, and Edge, and none of the three browsers lets me advance to the next page if I leave “Other Q” empty.

I have an idea for an alternative, though ...

#14 by BonnEconLab

... and the alternative idea is:

Let both fields be mandatory in __init__.py:

class Player(BasePlayer):

    first_q = models.IntegerField()
    other_q = models.StringField()

In Test.html, include the following:

{{ block content }}

<label for="first_q">Please type in some number.</label>
<br>
<input name="first_q" id="first_q" type="number" oninput="show_other_q()"/>
{{ formfield_errors "first_q"}}

<div id="other_quest" style="display: none;">
   {{ formfield "other_q" }}
</div>

<p>{{ next_button }}</p>

<script>
   function show_other_q() {
       let first_quest = document.getElementById('first_q').value;
       if (parseInt(first_quest) > 0) {
           document.getElementById('other_quest').style.display = 'block';
           if (document.getElementById('id_other_q').value == "N/A") {
             document.getElementById('id_other_q').value = "";
           };
       } else {
           document.getElementById('other_quest').style.display = 'none';
           if (document.getElementById('id_other_q').value == "") {
             document.getElementById('id_other_q').value = "N/A";
           };
       }
   }
</script>

{{ endblock }}

This way, you get an “N/A” entry for “other_q” when the answer to the first question is ≤ 0 (on the first attempt). If the entry for the first question is > 0, the “other_q” input field is initially empty, and the form cannot be submitted if the field is left empty.

Does this help?

#15 by Chris_oTree

forminputs is a new feature, so make sure you are updated to the latest otree version (currently 5.9): https://otree.readthedocs.io/en/latest/forms.html#javascript-access-to-form-inputs

#16 by sried

Hi Chris, I did update it yesterday to 5.9.0, but it still did not work. I don't know why, especially since it worked for Holger.

Write a reply

Set forum username