Search code examples
javascriptnode.jsuser-inputwaitsynchronous

Wait for user input in node.js


I just want to mention that I tried a bunch of techniques from blogs for getting user input but the examples were always in the context of a program that only asks for user input... and they always work but there's never any problem of node.js continuing on to the next lines of code because there are none.

I have to get user input and then verify that the input is valid so I created this construct:

while ( designAppealTest(subject) == false ) {
            subject[DESIGN_APPEAL] = ei.errorInput('designAppeal for the subject', iteration, subject[DESIGN_APPEAL])
        }

The function that it calls is this:

module.exports.errorInput =  function (fieldName, iteration, originalValue) {
    originalValue = originalValue || 'false'
    console.log('\n\n' + fieldName + ' for the subject' + ' contains an invalid value in for #' + i)

    if (originalValue !== false)
        console.log('original value of field = ' + originalValue)

    console.log('\nPlease enter a new value for it:\n')

    process.stdin.on('data', function (text) {
        console.log('received data:', text);
        return text;
    });

}

This works except that it keeps going through the while loop before the user has a chance to input a value. So all I see is the prompt asking the user to input a value 40,000 times a second. How can I make node.js wait until a value is entered before continuing the loop? Is the construct itself wrong or is it because I'm not halting it from being asynchronous?

CFrei:

Okay I added a callback to check() itself as well:

checkedSubject = check(subject, function(v) {
            return v;
        });

        console.log('checkedSubject = ' + checkedSubject)

        function check(listing, callback) {
            if (designAppealTest(subject) == false ) {
                ei.errorInput('designAppeal', iteration, listing[DESIGN_APPEAL], function(v) {
                    listing[DESIGN_APPEAL] = v;
                    check(listing)
                    });
            } else {
                callback(listing);
            }
        }

I'm still getting the same problem - it will ask for input but execute everything after it immediately.


Solution

  • Well, the async approach is about "never coming back" to any return value, just give the next callback to the function. Your "loop" should look like that:

    function check() {
        if (designAppealTest(subject) == false ) {
                ei.errorInput('designAppeal for the subject', iteration, subject[DESIGN_APPEAL], function(v) { subject[DESIGN_APPEAL] = v; check() })
        }
    }
    

    (Please note the recursive call to simulate your "while".)

    And instead of

    return text;
    

    you call that function (lets name it cb):

    cb(text)
    

    And yes, libs like async or Promise-Library help to make that look all a bit nicer.