PennController for IBEX › Forums › Support › Filled TextInput
Tagged: TextInput Element
- This topic has 29 replies, 6 voices, and was last updated 3 years ago by apspj.
-
AuthorPosts
-
May 4, 2020 at 1:19 pm #5189LynnParticipant
Hello Jeremy,
I have been trying to find some settings for the TextInput Elements in my code below :
1) How can I make sure that the “Continue” button doesn’t take effect if some of the TextInput Elements are not filled ?
2) Is there some way to adjust the TextInput answers to be strictly between 2 certain numbers ? i.e. : in the “age” TextInput below, if the number written is less than 18, it’s not validated.newText("age", "<p></p>Age (years):") .print() , newTextInput("age") .settings.length(2) .print() .log() , newText("height", "<p></p>Height (cm):") .print() , newTextInput("height") .settings.length(3) .print() .log() , newText("weight", "<p></p>Weight (kg):") .print() , newTextInput("weight") .settings.length(3) .print() .log() , newText("<p></p>") .print() , newButton("Continue") .color("green") .print() .wait()
Thank you so much in advance for your help.
Sincerely,May 4, 2020 at 4:36 pm #5194JeremyKeymasterHello,
Yes, you can use .test.text to check the content of a TextInput element, and doing so in the wait command will only validate the click if the test is successful. In your case, you can use regular expressions to check for appropriate numbers, just replace your very last .wait() line with this:
.wait( getTextInput("age").test.text( /^(\d|1[0-8])$/ ) .failure( newText("Age should be a number between 0 and 18").print() ) .and( getTextInput("weight").test.text( /^\d+$/ ) .failure( newText("Weight should be a numeric value").print() ) ).and( getTextInput("height").test.text( /^\d+$/ ) .failure( newText("Height should be a numeric value").print() ) ) )
Jeremy
May 5, 2020 at 4:29 am #5196LynnParticipantThank you so much for your fast reply !
September 14, 2020 at 8:07 am #6079danielaParticipantHi Jeremy,
is there a way to adapt test.text() to test whether or not the textInput element isn’t empty? It seems like the most standard test for a textInput element, but I can’t seem to find the solution anywhere!
Best,
DanielaSeptember 14, 2020 at 11:28 am #6080JeremyKeymasterHi Daniela,
You can take two approaches: either use a negative test
testNot.text("")
or a positive test using a regextest.text(/[^\s]+/)
. The latter is more powerful, as it will only validate non-empty text, whereas the former would succeed even if the text only consists of spaces, for exampleJeremy
September 16, 2020 at 5:28 am #6126danielaParticipantHi Jeremy,
that’s great, thank you again!
– Daniela
March 22, 2021 at 4:25 am #6747kathyParticipantHi Jeremy,
I added a TextInput (for age) to the demographics page of my experiment, restricted it to two characters and managed to add an error message if left empty. Now there are a few issues, though:
1. None of the error messages on the page (including the ones of the DropDowns I had before) will disappear once options are selected / the TextInput is filled.
2. The continue (“Weiter”) button doesn’t work anymore.
3. I am also unsure where to add the restriction of numerical values for age to the TextInput.Here is the code:
(I’m unsure about .wait(“first”) at the end – I actually prefer participants having to click continue once everything has been filled out, so I might change that still).//// DEMOGRAPHICS ============================================================== PennController("demographics", newText("DemographicsText", "<p>Bevor es losgeht, brauchen wir einige Angaben zu Deiner Person. Diese werden anonymisiert gespeichert und eine spätere Zuordnung zu Dir wird nicht möglich sein. Bitte nimm Dir beim Ausfüllen der Felder Zeit.<p>") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.italic() , newCanvas("infocanvas", 1000, 70) .settings.add(0, 0, getText("DemographicsText") ) .print() , newTextInput("age") .settings.length(2) .settings.log() , newText("Alter", "1. Alter:") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newCanvas("agecanvas", 1000, 45) .settings.add(0,10, getText("Alter")) .settings.add(80,8, getTextInput("age")) .settings.log() .print() , /// newText("Geschlecht", "2. Geschlecht: ") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newDropDown("sex","") .settings.add("Weiblich","Männlich", "Divers") .settings.log() , newCanvas("sexcanvas", 1000, 40) .settings.add(0,0, getText("Geschlecht")) .settings.add(120,3, getDropDown("sex")) .print() , /// newText("Muttersprache", "3. Ist Deutsch Deine Muttersprache?") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newDropDown("german", "") .settings.add("Ja", "Nein") .settings.log() , newCanvas("Nativelangcanvas", 1000, 40) .settings.add(0,0, getText("Muttersprache")) .settings.add(295,3, getDropDown("german")) .print() , /// newText("Nationality", "4. Was ist Deine Nationalität?") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newDropDown("nationality", "") .settings.add("Deutschland","Österreich", "Schweiz", "Italien", "Andere") .settings.log() , newCanvas("nationalcanvas", 1000, 40) .settings.add(0,0, getText("Nationality")) .settings.add(240,2, getDropDown("nationality")) .print() , /// newText("Bildungsabschluss", "5. Was ist Dein höchster Bildungsabschluss?") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newDropDown("bildung", "") .settings.add("(Pflicht-)Schulabschluss","Abitur / Matura oder gleichwertiger Abschluss", "Hochschulabschluss", "Ausbildung", "Sonstige") .settings.log() , newCanvas("bildungcanvas", 1000, 40) .settings.add(0,0, getText("Bildungsabschluss")) .settings.add(350,2, getDropDown("bildung")) .print() , /// newText("Hauptbeschäftigung", "6. Was ist Deine derzeitige Hauptbeschäftigung?") .settings.css("font-family","times new roman") .settings.css("font-size", "18px") .settings.bold() , newDropDown("job", "") .settings.add("Keine","Studium","Anstellung", "Selbstständigkeit", "Sonstige") .settings.log() , newCanvas("jobcanvas", 1000, 40) .settings.add(0,0, getText("Hauptbeschäftigung")) .settings.add(380,2, getDropDown("job")) .print() , /// newButton("okay", "Weiter") .print() .wait() , getTextInput("age") .test.text(/[^\s]/) .failure( newText("Bitte gib Dein Alter an.") .settings.color("red") .print()) , getDropDown("sex") .test.selected() .success() .failure( newText("Bitte gib Dein Geschlecht an.") .settings.color("red") .print()) , getDropDown("german") .test.selected() .success() .failure( newText("Bitte gib an, ob Deutsch Deine Muttersprache ist.") .settings.color("red") .print()) , getDropDown("nationality") .test.selected() .success() .failure( newText("Bitte gib Deine Nationalität an.") .settings.color("red") .print()) , getDropDown("bildung") .test.selected() .success() .failure( newText("Bitte gib Deinen Bildungsstand an.") .settings.color("red") .print()) , getDropDown("job") .test.selected() .success() .failure( newText("Bitte gib Deine Hauptbeschäftigung an.") .settings.color("red") .print()) , getTextInput("age").wait("first") , getDropDown("sex").wait("first") , getDropDown("german").wait("first") , getDropDown("nationality").wait("first") , getDropDown("bildung").wait("first") , getDropDown("job").wait("first") , getButton("okay") .print() )
Sorry it’s a bit long! Thanks for your help in advance.
Best,
KathyMarch 22, 2021 at 1:15 pm #6750JeremyKeymasterHi Kathy,
Remember that the script is read and executed in a straightforward top-down fashion by PennController, and it will only pause on
wait
commands. So in your code above, all the elements are printed onto the page and then PennController stays on the Button element’swait
command until your participant clicks it. Once the button is clicked, all thetest
commands below are read and executed in a split second, and the nextwait
command that PennController reads is the TextInput’swait
command: if your participant did not pressEnter
while typing in the input box, they will have to pressEnter
while typing in that box so that PennController can continue reading the rest of the code. Then it will move on and read the nextwait
command, the one called on the “sex” DropDown element, and your participant will need to select an option from that list if they haven’t done so yet. Then the nextwait
command, and so on. (The lastprint
command on the Button element will have no effect practically speaking, because the script will move on to the next trial immediately after it)I don’t think this is what you want. What you want is for PennController to read everything, stay on the Button element’s
wait
command and only validate it if some conditions are met, but stay on it if those conditions are not met. You do that by insertingtest
commands inside thewait
command, just like I illustrated above.Regarding the restriction to numerical values, you simply replace the regular expression in your test with one that tests for numbers only, eg
/^\d+$/
.Regarding the disappearance of the error messages, this is something you’ll need to code yourself. DropDown elements have a
callback
command that you can use to execute commands whenever an option is selected. So if you give unique names to your error messages, you could usecallback
on each of your DropDown elements toremove
the corresponding error Text element. There is nocallback
command on the TextInput element that can detect keypresses, so you’d have to find a workaround. One option would be to usecallback
on a Key element to detect any keypress (including outside the input box) and remove the error message: it would overgenerate but it wouldn’t be too bad.Here is a link to a project where I rearranged your code along those lines: https://farm.pcibex.net/r/SsqEZD/
Let me know if you have any questions
Jeremy
March 23, 2021 at 8:19 am #6756kathyParticipantHi Jeremy,
thanks so much for your explanation and help! I adapted the code you used in your project and it works for me now.
Two minor (aesthetic) details: Ideally, I’d like to have the “age” error message to be displayed on top of the other ones, given that that’s the first piece of information that’s required. Not a big deal, but I was wondering whether / how that could be implemented (if it’s not too much of an effort).
And secondly, is there a way to add some space with the
before
code? On my screen, the TextInput box and DropDown menus are pretty much glued to the text that precedes them…Thanks again!
KathyMarch 23, 2021 at 12:12 pm #6757JeremyKeymasterHi Kathy,
1. This is due to how complex conditionals (
and
/or
) are processed: the parent (first) one actually takes effect last. So make the “job” test the parent (first) one, and make the “age” test its first childand
test, this way the “job” error message will be displayed at the bottom and the “age” error message will be displayed at the top2. Simply add a
margin-right
CSS rule to your Text element. Given the content of your trial, you can even make it part of the defaultcss
commandI have updated the project at https://farm.pcibex.net/r/SsqEZD/ along those lines
Jeremy
March 23, 2021 at 1:33 pm #6759kathyParticipantThank you so much!!
– KathyMarch 29, 2021 at 3:43 am #6774kathyParticipantHi Jeremy,
sorry to bother you again – I added a few options (a drop-down and a text input) to this page and now I get error messages for “job” and “country” (TextInput) even if correctly filled out, which prevent me from continuing. I’m guessing I’ll have to rearrange the order of the code, but I’m not sure how:
newButton("okay", "Weiter") .print() .wait( // job getDropDown("job").test.selected() .failure( newText('errorjob', "Bitte gib Deine Hauptbeschäftigung an.").color("red").print() ) // age .and( getTextInput("age").test.text(/^\d+$/) .failure( newText('errorage', "Bitte gib Dein Alter an.").color("red").print() ) // sex ).and( getDropDown("sex").test.selected() .failure( newText('errorsex', "Bitte gib Dein Geschlecht an.").color("red").print() ) // mother tongue ).and( getDropDown("german").test.selected() .failure( newText('errorgerman', "Bitte gib an, ob Deutsch Deine Muttersprache ist.").color("red").print() ) // bilingualism ).and( getDropDown("bilingual").test.selected() .failure( newText('errorbilingual', "Bitte gib an, ob Du bilingual aufgewachsen bist.").color("red").print() ) // nationality ).and( getDropDown("nationality").test.selected() .failure( newText('errornationality', "Bitte gib Deine Nationalität an.").color("red").print() ) // education ).and( getDropDown("bildung") .test.selected() .failure( newText('errorbildung', "Bitte gib Deinen Bildungsstand an.").color("red").print() ) // country ).and( getTextInput("country").test.text() .failure( newText('errorcountry', "Bitte gib an, in welchem Land Du in letzten 5 Jahren gewohnt hast.").color("red").print() ) ) )
Any chance you could have another look? Thanks a lot!
Best,
KathyMarch 29, 2021 at 11:27 am #6775JeremyKeymasterHi Kathy,
This is because you’re testing that the content of your “country” TextInput should be empty: whenever you click the button and there is at least one character in that input box, your last test will fail and accordingly print the ‘errorcountry’ Text element. Because all the
and
s are attached to the first test on “job,” whenever one test fails it systematically triggers failure for that first one too (the “parent”), hence the printing of the “errorjob” Text element.So the solution is to make your test on ‘country’ check that there’s at least one character in the input box (see this message above) and, if you want to make each test’s failure independent from one another, you can insert a dummy test as the parent and make all the other ones children of that test:
newFunction('dummy', ()=>true).test.is(true) // age .and( getTextInput("age").test.text(/^\d+$/) // ...
(Note that you no longer need to move the last test up to the top of the stack in order for the error messages to show in the correct order, now that we’re using a dummy test as the parent)
I have updated the code at the project whose demonstration link I shared in my previous post
Jeremy
March 29, 2021 at 5:26 pm #6779kathyParticipantThank you!!
March 30, 2021 at 4:40 am #6780AnnaParticipantHi Jeremy and Kathy,
just a heads up about your code: if a participant enters a string instead of a number in the age input field (e.g. “AP” instead of “99”), they are shown the error message but they cannot correct their input to a number (or otherwise).
Best,
Anna -
AuthorPosts
- You must be logged in to reply to this topic.