Closed tonylukasavage closed 4 months ago
There's a lot of way this can be done manually by the user in pretty easy way (build/filter the question array) - or even using parts of inquirer api like when
functions.
It is actually a pretty common use case in a lot of yeoman-generators.
Thanks for the suggestion, but I don't think this functionality would add real benefits over filtering the array you pass to inquirer manually.
can we reopen this?
I'll try to illustrate a good use case:
var inquirer = require('inquirer');
inquirer.registerPrompt(
'autocomplete',
require('inquirer-autocomplete-prompt')
);
...
inquirer.prompt([{
type: 'autocomplete',
name: 'from',
message: 'Select a state to travel from',
source: function(answersSoFar, input) {
return myApi.searchStates(input);
}
}]).then(function(answers) {
//etc
});
If we filter the questions, you will see that answersSoFar
will be missing what could be useful for narrowing down a search result, for example. I understand there are hacks around it, but I agree with @tonylukasavage that this is an important missing feature.
Okay, I'll reopen. That's been a feature asked many times.
I'm still unsure how this could cleanly fit in the codebase - and it needs to works properly with plugins.
cool! I took a stab at it here: https://github.com/pyramation/Inquirer.js/pull/1/files
I think I have something that works, but 3 tests are broken, maybe you can see what I did wrong! The test case I wrote passes---it's something around async fetching of property defaults that broke (error messages at bottom of this post)
My approach was to return an always-resolving answer from the overrides before asking the user anything.
PromptUI.prototype.fetchAnswer = function (question) {
if (question.name && _.has(this.overrides, question.name)) {
return rx.Observable.defer(
function () {
return rx.Observable.fromPromise(
new Promise(resolve => {
resolve({
name: question.name,
answer: this.overrides[question.name]
});
})
);
}.bind(this)
);
}
var Prompt = this.prompts[question.type];
this.activePrompt = new Prompt(question, this.rl, this.answers);
return rx.Observable.defer(function () {
return rx.Observable.fromPromise(this.activePrompt.run().then(function (answer) {
return {name: question.name, answer: answer};
}));
}.bind(this));
};
For providing overrides, I passed them into the prompt
constructor:
var overrides = {
q1: false
};
var prompts = [
{
type: 'confirm',
name: 'q1',
message: 'message',
default: true
},
{
type: 'confirm',
name: 'q2',
message: 'message',
default: false
}
];
var promise = this.prompt(prompts, overrides);
Here were the errors:
1) inquirer.prompt should run asynchronous `message`:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
2) inquirer.prompt should parse `default` if passed as a function:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
3) inquirer.prompt should parse `choices` if passed as a function:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
finally got around to it - but ended up just making a wrapper. If anyone is interested in this https://github.com/pyramation/inquirerer
What is the current state of this? @pyramation gave a solution by creating another package. Do we expect to implement this feature in this package as well? Should we close it?
@tonylukasavage you are the one who opened the issue. What is your opinion?
I believe this use case is covered with the following:
const answers = require('./answers'); // This could be from a file, or from some business logic.
const questions = require('./questions');
inquirer
.prompt(questions, answers) // provide `answers` as an argument, and inquirer skips those questions
.then((_answers) => {
// Use user feedback for... whatever!!
preFlightChecks(_answers);
})
.catch(handleError);
answers.js
module.exports = {
description: "Default answer, or something specific",
.
.
.
}
Answers will contain objects whose answers are known. When this is passed as args into Inquirer
it skips those questions.
questions.js
module.exports = [
{
type: "input",
name: "title",
message: "Title",
default: "Random Title",
},
{
type: "input",
name: "description",
message: "Description",
when: function (answers) {
return answers.title;
},
}
One bit of functionality missing from
inquirer
that I found indispensable in prompt is the ability to provide anoverride
to the prompting process. So in the case ofinquirer
, if I have 2 questions I want to ask, but in previous code I've already determined the value of 1 of them, I'd love it if I could do something like this:In the above case, only the
value
question would be asked sincename
is already available in the override. The resultinganswers
object would include the input answer forvalue
and the value from the override forname
.I didn't see this functionality in the docs nor did I see any means to do it in a very quick check of the source.