Line-By-Line Node JS prompting for Input not functioning

1k Views Asked by At

I have started working with node js and am working with the line-by-line dependency. I have properly installed line-by-line and it is within the folder. Currently, my application will run but will not prompt the user to input an answer. My code is as follows:

var rlname;
var rlage;
var rlcolor;

// Create reading interface
const readline = require('readline');

const rl = readline.createInterface ({
    input: process.stdin,
    output: process.stdout,
    prompt: '>'
});

// Ask a question
function getUserInput()
{
    rl.question("What is your name? \n", (name) => {
        console.log(name);
        rlname = name;
        // Log answer in JSON
    })

    rl.question("What is your age? \n", (age) => {
        console.log(age);
        rlage = age;
        // Log answer in JSON
    })

    rl.question("What is your favorite color? \n", (color) => {
        console.log(color);
        rlcolor = color;
        // Log answer in JSON
    })

    console.log("Hello " + rlname + ", you are " + rlage + " years old and your favorite color is " + rlcolor + ".");
}

getUserInput();
rl.close();

This is the produced result:

What is your name?
Hello undefined, you are undefined years old and your favorite color is undefined.
3

There are 3 best solutions below

3
On BEST ANSWER

The problem here is caused by the fact that this code should be asynchronous, but it is written as if it was synchronous.

To be more clear: you ask for the name, but the code is not waiting for the input, as it is asynchronous. It continues down to the console.log statement and proceed to close the input with rl.close().

You should put each question inside the callback of the previous one, and the closing statement in the last callback:

var rlname;
var rlage;
var rlcolor;

// Create reading interface
const readline = require('readline');

const rl = readline.createInterface ({
    input: process.stdin,
    output: process.stdout,
    prompt: '>'
});

// Ask a question
function getUserInput()
{
    // FIRST QUESTION
    rl.question("What is your name? \n", (name) => {
        console.log(name);
        rlname = name;
        
        // SECOND QUESTION
        rl.question("What is your age? \n", (age) => {
            console.log(age);
            rlage = age;
            
            // THIRD QUESTION
            rl.question("What is your favorite color? \n", (color) => {
                console.log(color);
                rlcolor = color;

                // LOG DATA
                console.log("Hello " + rlname + ", you are " + rlage + " years old and your favorite color is " + rlcolor + ".");
                
                // CLOSE CONNECTION
                rl.close();
            })
        })
    })
}

getUserInput();
0
On

The problem here is that readline.question is asynchronous and you need to wait for each callback to return, before you (a) can use the input and (b) create the next question. You are executing the console.log statement, however, directly after the question call. It's probably the easiest way to wrap the question into a promise, so that you can await the response.

Here is an example using promises: https://stackoverflow.com/a/47999168/3233827

0
On

Like many modules in Node.js, readline works on the basis of callbacks. The callback functions you are passing to rl.question don't run immediately; they are called only when input has been received from the user. So your program is trying to ask three questions all at once and then immediately log your "Hello" line before any of the answers have been received. (You are probably not seeing the second or third question because readline has some internal buffer for them.)

With callbacks, the correct approach is nesting like this:

var rlname;
var rlage;
var rlcolor;

// Create reading interface
const readline = require('readline');

const rl = readline.createInterface ({
    input: process.stdin,
    output: process.stdout,
    prompt: '>'
});

// Ask a question
function getUserInput()
{
    rl.question("What is your name? \n", (name) => {
        console.log(name);
        rlname = name;

        rl.question("What is your age? \n", (age) => {
            console.log(age);
            rlage = age;

            rl.question("What is your favorite color? \n", (color) => {
                console.log(color);
                rlcolor = color;

                console.log("Hello " + rlname + ", you are " + rlage + " years old and your favorite color is " + rlcolor + ".");

                rl.close();
            })
        })
    })
}

getUserInput();

(Note that rl.close can't be called until all the questions have been asked, so within the innermost callback.)

Using an async function with promises would make this easier to follow, without the nested functions and deep indents.