21

I am creating a program to take input of two numbers from the command line and then showing there sum in node.js. I am using readline module to take stdin. Below is my code.

const readline = require('readline');

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

const r2 = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question('Please enter the first number', (answer1) => {
    r2.question('Please enter the second number', (answer2) => {
        var result = (+answer1) + (+answer2);
        console.log(`The sum of above two numbers is ${result}`);
    });
    rl.close();
});

This program just show me "Please enter the first number" and when i enter a number like 5, it takes 5 for second input also and shows the answer 10

It don't ask second question at all. Please check this and tell me what is the problem. And if there is any better way to take multiple input please tell that.

I am a novice user in node.js

Puneet Singh
  • 211
  • 1
  • 2
  • 4

11 Answers11

47

Nested code/callback are terrible to read and maintain, here's a more elegant way to use Promise for asking multiple questions

node 8+

'use strict'

const readline = require('readline')

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

const question1 = () => {
  return new Promise((resolve, reject) => {
    rl.question('q1 What do you think of Node.js? ', (answer) => {
      console.log(`Thank you for your valuable feedback: ${answer}`)
      resolve()
    })
  })
}

const question2 = () => {
  return new Promise((resolve, reject) => {
    rl.question('q2 What do you think of Node.js? ', (answer) => {
      console.log(`Thank you for your valuable feedback: ${answer}`)
      resolve()
    })
  })
}

const main = async () => {
  await question1()
  await question2()
  rl.close()
}

main()
jc1
  • 591
  • 5
  • 5
  • 2
    Code only answers arent encouraged as they dont provide much information for future readers please provide some explanation to what you have written – WhatsThePoint Feb 14 '18 at 15:50
  • what if you want the second to keep taking user input, lets say the first prompt is just to happen once in a game to gather some initial info like name, etc. and then you want another stdin to run the the rest of the game separate from that first prompt? – PositiveGuy Jul 05 '18 at 20:34
  • resolve(answer) – Jacob Nelson Aug 17 '22 at 06:12
25

No need another variable, just use like this:

const readline = require('readline');

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

rl.question('Please enter the first number : ', (answer1) => {
    rl.question('Please enter the second number : ', (answer2) => {
        var result = (+answer1) + (+answer2);
        console.log(`The sum of above two numbers is ${result}`);
        rl.close();
    });
});
Thamilhan
  • 13,040
  • 5
  • 37
  • 59
  • 12
    Why is console input so overly complex in node. Why can't they have a one line command. What is preventing this? – Andrew S Jan 21 '18 at 05:47
  • Am I getting this correct? Waiting on user input locks up javascript, since it is single threaded. While javascript is locked, javascript can't check to see if a user has entered any input... – TamusJRoyce Oct 04 '18 at 03:06
  • @TamusJRoyce Did you happen to try this first? – Thamilhan Oct 04 '18 at 04:35
  • Yes. But that not flattened. var answer = null; rl.question('Please enter the first number : ', (answer1) => { answer = answer1; }); while(answer == null) { } console.log(answer); // You have to queue up your questions. Or the javascript thread gets locked. And there is only one thread. Javascript = Lots of boiler plate. : ( – TamusJRoyce Oct 09 '18 at 00:43
8

I would ask the questions in an async function and wrap readline similarly to how Jason did it above. Although with slightly less code :)

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

function question(theQuestion) {
    return new Promise(resolve => rl.question(theQuestion, answ => resolve(answ)))
}

async function askQuestions(){
    var answer = await question("A great question")
    console.log(answer);
}
user3032538
  • 81
  • 1
  • 1
3

For those interested I put together this little module that takes an array of questions and returns a promise that resolves to an array of answers:

const readline = require('readline');

const AskQuestion = (rl, question) => {
    return new Promise(resolve => {
        rl.question(question, (answer) => {
            resolve(answer);
        });
    });
}

const Ask = function(questions) {
    return new Promise(async resolve => {
        let rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        let results = [];
        for(let i=0;i < questions.length;i++) {
            const result = await AskQuestion(rl, questions[i]);
            results.push(result);
        }
        rl.close();
        resolve(results);
    })
}

module.exports = {
    askQuestions: Ask 
}

Save that in a file called ask.js (or whatever you like) and use like this:

const { askQuestions } = require('./ask');

askQuestions([
   'What is question 1?',
   'What is question 2?',
   'What is question 3?'
])
    .then(answers => {
        // Do whatever you like with the array of answers
    });

Note: Will need a transpiler or recent version of Node as it uses a lot of ES6 features.

Jason
  • 2,455
  • 4
  • 37
  • 48
1

you could use recursion :

var fs = require('fs')
var readline = require('readline')


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

 var keys = []
function gen(rank){
  if(rank > 3)
    {
        //do whatever u want
        var sum_avg = 0
        for (i in keys)
             {
                sum_avg+=Number(keys[i])
             }
         console.log(sum_avg/3); 
         return -1;     
    }
    else 
    { 
        var place = rank>1 ? "th" : "st"
        var total = rank+place 
        rl.question("Please enter the "+total+ " number :",function(answer){
            keys.push(answer)
            //this is where the recursion works
             gen(rank+1)
        })
     }
  }

//pass the value from where you want to start
  gen(1)
serious_luffy
  • 419
  • 1
  • 6
  • 17
1
const readline = require("readline")

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

var questions = [
 "Input first number",
 "Input second number",
 "Input third number",
 "Input fourth number",
 "Input fifth number",
];

const askQuestion = (theQuestion) => {
    return new Promise((resolve, reject) => {
        try {
          rl.question(theQuestion + ": ", theAnswer => resolve(theAnswer));
        } catch {
          reject("No Answer");
        }
    })
}

async function start(){
    const answers = [];
    for (question of questions){
        answers.push(await askQuestion(question));
    }
    
    const total = answers.reduce((a, b) => {return Number(a) + Number(b)}); 
    console.log( `The sum of array ${answers} is ${total}`);
    rl.close();
}

start();
 
troydo42
  • 129
  • 2
  • 8
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 12 '21 at 04:13
1
const readline = require('readline')

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

const question = (question) => {
  return new Promise((resolve, reject) => {
    rl.question(question, (answer) => {
      resolve(answer)
    })
  })
}

const main = async () => {
  const username = await question('Please enter a username: ');
  const password = await question('Please enter a password: ');
  console.log("result: ", {
      "username" : username,
      "password" : password
  });
  rl.close()
}

main()

I have decided to simplify the code which @jc have written for developers that want to get an output out from the question.

0
const readline = require('readline');

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

const q0 = 'What\'s your name? Nicknames are also acceptable :)';
const q1 = 'What\'s an activity you like doing?';
const q2 = 'What do you listen to while doing that?';
const q3 = 'Which meal is your favourite (eg: dinner, brunch, etc.)';
const q4 = 'What\'s your favourite thing to eat for that meal?';
const q5 = 'Which sport is your absolute favourite?';
const q6 = 'What is your superpower? In a few words, tell us what you are amazing at!';

const arr = [q0, q1, q2, q3, q4, q5, q6];
let res = '';
const askQ = i => {
  if (i < arr.length) {
    rl.question(arr[i], (answer) => {
      res += '\n' + answer;
      askQ(i + 1);
    });
  } else {
      console.log(`Thank you for your valuable feedback: ${res}`);
      rl.close();
  }
};
askQ(0);
0

For more optimizing code I found a package node-quick-cli

its not support require() to support change file name .js to .mjs

import readline from 'node-quick-cli';
var readlineq = new readline();
(async () => {
    console.log(await readlineq.question('Question 1 : '));
    console.log(await readlineq.question('question 3 : ',{color:"blue"}));
    console.log(await readlineq.question('Question 2 : ',{bgcolor:"bgBlue"}));
    readlineq.close();
})();
0
import readline from 'readline'

const CLI = readline.createInterface( { input: process.stdin , output: process.stdout } )

multiLineCI()

async function multiLineCI() {

     const credentials = {
         server: await new Promise( rsl => CLI.question( 'enter server: ' , ans => rsl( ans ) ) ),
         port: await new Promise( rsl => CLI.question( 'enter port: ' , ans => rsl( ans ) ) ),
         username: await new Promise( rsl => CLI.question( 'enter username: ' , ans => rsl( ans ) ) ),
         password: await new Promise( rsl => CLI.question( 'enter password: ' , ans => rsl( ans ) ) )
     }
     
     console.log( credentials )
     
     CLI.close()

}
sonen
  • 11
  • 3
  • Code only answers arent encouraged as they dont provide much information for future readers please provide some explanation to what you have written – chrslg Dec 13 '22 at 23:35
0

Similar to Hari's solution but using the standard readline instead of a special package. Also agree with jc1 that use of async (well, just a top-level await) helps avoid unnecessary "clutter" of callbacks or Promises/then(), and a big bonus for avoiding recursion (yuck!).

import * as readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';

const rl = readline.createInterface({ input, output });
console.log(await rl.question('Enter something: '));
console.log(await rl.question('Something else: '));
rl.close();

Sample output:

$ node repl2.mjs
Enter something: one
one
Something else: two
two
$

Note that the OP specifically asked for getting exactly 2 pieces of input from the end-user. A more general question where I posted a similar answer is this one asking how to do an infinite loop asking the user for more data until they quit.

wescpy
  • 10,689
  • 3
  • 54
  • 53