Enabling a button after text is entered without pressing Enter

PennController for IBEX Forums Support Enabling a button after text is entered without pressing Enter

This topic contains 10 replies, has 2 voices, and was last updated by Jeremy Jeremy 1 month, 1 week ago.

Viewing 11 posts - 1 through 11 (of 11 total)
  • Author
    Posts
  • #6133
    Avatar
    mawilson
    Participant

    I’d like to set up a text input that collects info from participants. This input should be mandatory, so I want to disable the “Next” button until participants have entered text in the field. In order to avoid confusion, I’d ideally like to just disable the button entirely (i.e., make it unclickable) until a participant has entered text, and then enable it. Again, in order to avoid confusion, I’d like to not require participants to press Enter after typing to make this work, but I can’t seem to find a way to do that. Here’s a minimal working example illustrating what I have so far (https://expt.pcibex.net/ibexexps/mawilson/test/experiment.html):

    PennController.ResetPrefix(NULL)
    Sequence('test')
    
    newTrial('test',
        newTextInput('test_input')
             .print()
        ,
        newButton('Next', 'Next')
             .print()
             .disable()
        ,
        getTextInput('test_input')
             .wait()
        ,
        getButton('Next')
             .enable()
             .wait()
    )

    But this still requires participants to press Enter after typing in the text box. Is there a way to allow the button to be enabled upon text entry without participants having to press Enter?

    Edit: I’ve tried using wait(getTextInput('test_input').testNot.text('') before enable() for the button element, but the button never actually gets enabled then.

    • This topic was modified 1 month, 1 week ago by Avatar mawilson.
    • This topic was modified 1 month, 1 week ago by Avatar mawilson.
    • This topic was modified 1 month, 1 week ago by Avatar mawilson.
    #6139
    Jeremy
    Jeremy
    Keymaster

    Hello,

    Since I haven’t implemented a callback command for the TextInput element that would listen to keypresses, the best solution is to use a Key element (for which there is a callback command) to listen to keypresses. Now, it reacts to keypresses so fast that immediately checking the value of the TextInput element in the callback block won’t capture the newly pressed key, so you want to add a slight delay, e.g. 5ms before checking it.

    Here’s how to do it based on the example you give:

    newTrial('test',
        newTextInput('test_input')
             .print()
        ,
        // empty string means any key
        newKey('').callback( 
            newTimer(5).start().wait()
            ,
            getTextInput('test_input').test.text(/\w/)
              .success( getButton('Next').enable() )
              .failure( getButton('Next').disable() )
        )
        ,  
        newButton('Next', 'Next')
             .print()
             .disable()
             .wait()
    )

    Let me know if you have any questions

    Jeremy

    #6140
    Avatar
    mawilson
    Participant

    Thanks! That worked great! This isn’t crucial, but is there a way to disable the button again if they delete the text? It’s not a huge deal if there isn’t.

    #6141
    Jeremy
    Jeremy
    Keymaster

    Isn’t it already the case?

    #6142
    Avatar
    mawilson
    Participant

    Sorry, yeah, I just realized that it does that if you use a separate button press to delete the last character. But if you enter multiple characters and hold down backspace to delete everything, it won’t disable it until you press a key again. If there’s no good way around that edge case it shouldn’t be a problem anyway.

    • This reply was modified 1 month, 1 week ago by Avatar mawilson.
    #6144
    Jeremy
    Jeremy
    Keymaster

    In that case let’s use a good old javascript function:

    newTrial('test',
        newTextInput('testinput')
             .print()
        ,
        newFunction( () =>
            $("textarea.PennController-testinput").bind('keyup', e=>
                getTextInput('testinput').test.text(/\w/)
                  .success( getButton('Next').enable() )
                  .failure( getButton('Next').disable() )
                  ._runPromises()
            )
        ).call()
        ,
        newButton('Next', 'Next')
             .print()
             .disable()
             .wait()
    )

    Jeremy

    • This reply was modified 1 month, 1 week ago by Jeremy Jeremy. Reason: fixed errors in code - see messages below
    #6145
    Avatar
    mawilson
    Participant

    Not sure why, but when I try that I get an error message: [16:20:14] Uncaught SyntaxError: missing ) after argument list (PennController: 0). I’ve been messing around trying to fix it but can’t seem to figure out how.

    Sorry for all the trouble!

    Edit: removing the semicolon after _runPromises() lets the script run, but the function doesn’t appear to work.

    • This reply was modified 1 month, 1 week ago by Avatar mawilson.
    • This reply was modified 1 month, 1 week ago by Avatar mawilson.
    #6149
    Jeremy
    Jeremy
    Keymaster

    I made a few typos after I copy-pasted my code (eg. I had getTextInput("test_input")—gotten rid of _) —things should work now. Sorry about that

    Jeremy

    #6150
    Avatar
    mawilson
    Participant

    No worries! Thank you for all the help!

    #6155
    Avatar
    mawilson
    Participant

    This is probably similar enough to fit in this thread, but is there a way to do this for a checkbox (i.e., only enable the button when the checkbox is selected). This one is more crucial since it’s for an HTML consent form, and I want to make absolutely sure people can’t get past the form unless the box saying they consent is checked.

    #6158
    Jeremy
    Jeremy
    Keymaster

    Hi,

    Since there is no checkbox element natively implemented in PennController yet, you’ll need to code the checkbox element yourself, for example as part of an HTML document. Make sure you give it a unique ID or class, and use the method above. Here’s an example:

    newTrial(
        newHtml("form", `<div>
        <input name='consent' id='consent' type='checkbox'><label for='consent'>I consent</label>
        </div>`).print()
        ,
        newFunction( () => $("#consent").change( e=>{
            if (e.target.checked) getButton("Next").enable()._runPromises();
            else getButton("Next").disable()._runPromises();
        }) ).call()
        ,
        newButton("Next")
            .disable()
            .print()
            .wait()
    )

    Jeremy

Viewing 11 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic.