I'm using Inquirer.js to create a CLI's prompter which allows users to enter/reply to some input/questions. In the last question, I want to add a feature that if the user replies no to Are you done? question, then the prompter will restart asking the questions until the user replies yes. I'm almost there with the functionality.
It's working, but only on the first time when I enter no. The second time I enter no, the prompter stops.
How can I run this on a loop to accomplish the desired behavior? What I'm doing wrong?
This is what I have some far:
import inquirer from 'inquirer';
inquirer
.prompt([
// { bunch of other questions previously },
{
type: 'confirm',
name: 'repeat_questions',
message: 'Are you done?',
},
])
.then((answers) => {
if (answers.repeat_questions) {
return inquirer.prompt([
// { bunch of other questions previously },
{
type: 'confirm',
name: 'repeat_questions',
message: 'Are you done?',
},
]);
}
})
.catch((error) => {
if (error.isTtyError) {
throw new Error(`Prompt couldn't be render in current environment`);
}
});
One way is a recursive function:
import inquirer from "inquirer";
const questions = [
{
type: "number",
name: "children_count",
message: "How many children do you have?",
},
{
type: "input",
name: "first_child_name",
message: "What is the eldest child's name?",
},
{
type: "confirm",
name: "is_finished",
message: "Are you done?",
},
];
function getAnswers() {
return inquirer.prompt(questions).then((answers) => {
if (answers.is_finished) {
return answers;
} else {
return getAnswers();
}
});
}
getAnswers()
.then(console.log)
.catch((error) => {});
The variable repeat_questions doesn't make sense, if the user says no to if they are done, repeat_questions is also no. So instead I renamed it to is_finished.
Related
I am not very experienced in javascript and I have a problem to display my attached image.
when someone type #1 bot send an embed with caracteristics and i want post the image too !
I don't know if I formatted it wrong or if I should load the image first. So the image is my local folder in the same directory as my index.js file
I had problems with color too! I didn't manage to modify it! I didn't manage to modify it
I would have liked to be able to change the color of the name title or description but I don't know if it's possible my tests were unsuccessful
Could you help me a little bit please? Here is my code. Thanks in advance.
const { token, prefix } = require('../config.json');
const Discord = require('discord.js');
const client = new Discord.Client();
// Listen to the Bot being ready
client.once('ready', () => onClientReady());
function onClientReady()
{
// Listen to Messages in the channel
client.on('message', (message) => onMessageReceived(message));
}
// Upon a message being received, handle how we interact
function onMessageReceived(message)
{
if(message.author.bot) return;
if (message.content.toLowerCase().includes('#1'))
message.channel.send({ embed: {
color: 3447003,
title: "SpaceShips #1 New_York",
url: "http://google.com",
description: "RANK: 74 / SCORE: 121",
Thumbnail: (url="attachment://000793.jpg"),
fields: [{
name: "__**POWER**__",
value: "A-G 0: **39**",
"inline": true
},
{
name: "__**POWER**__",
value: "E-W: **76**",
"inline": true
},
{
name: "__**AUTONOMY**__",
value: "EY-W Nrg: **74**",
"inline": true
},
{
name: "__**AUTONOMY**__",
value: "B-P 0 Nrg: **73**",
"inline": true
},
{
name: "__**DISPLACEMENT**__",
value: "L-A: **79**",
"inline": true
},
{
name: "__**DISPLACEMENT**__",
value: "3D-V: **67**",
"inline": true
},
{
name: "__**SPECIALS**__",
value: "EM-W: **34**",
"inline": true
},
{
name: "__**SPECIALS**__",
value: "3D-W: **42**",
"inline": true
}
],
}
});
}
client.login(token);
If your working with python, and just want to send an image, try this:
await channel.send(file=discord.File('my_image.png'))
You may simply add an image value to the embed object you're sending like so:
message.channel.send({ embed: {
color: 3447003,
title: "SpaceShips #1 New_York",
url: "http://google.com",
description: "RANK: 74 / SCORE: 121",
thumbnail: {
url: "attachment://000793.jpg"
},
}
}); // Removed fields to clear up the clutter, you may add them like before!
As far as color is concerned it's a RGB value you may Google up the value for the colour you like and replace it!
If you want only send the image then here i suppose (Node.Js)
const path = require('path');
const Discord = require('discord.js');
let pic = path.resolve('test.jpg')
// the picture, if you console.log it will send the path of the file for example mine /src/image/test.jpg
message.channel.send(new Discord.MessageAttachment(pic))
In fact it isn't possible in local to put an image in a embed... we only can put attach file...
Si I used an web link and hosted my images on a server and it works!
Thanks for your help.
I've been looking around for a way to make embed pages with discord.js but all of the tutorials I've seen are for a MessageEmbed. I would like to have some way to react to the embed and have it switch to the next.
This is my original code:
client.on('message', (message) => {
if (message.content.toLowerCase() == prefix + "help") {
const Embed = {
color: 0x91A6A6,
title: 'Help Menu. Page 1.',
author: {
name: 'KLSB',
icon_url: bot.user.avatarURL()
},
description: '\n How to use KLSB. \n',
fields: [
{
name: '!-help',
value: 'Opens a help menu.',
inline: true,
},
{
name: '!-cat',
value: 'Grabs a random cat picture from the internet.',
inline: true,
},
{
name: '!-dog',
value: 'Grabs a random dog picture from the internet.',
inline: true,
},
{
name: '!-panda',
value: 'Grabs a random panda picture from the internet.',
inline: true,
},
{
name: '!-bird',
value: 'Grabs a random panda picture from the internet.',
inline: true,
},
{
name: '!-meme',
value: 'Finds a meme from Reddit.',
inline: true,
},
{
name: '!-animememe',
value: 'Finds a anime meme from Reddit.',
inline: true,
},
{
name: '!-animalmeme',
value: 'Finds a animal meme from Reddit.',
inline: true,
},
{
name: '!-hug',
value: "Sends a hug through the internet!",
inline: true,
},
{
name: '!-8ball',
value: "As they say, it sees the future!",
inline: true,
},
],
};
message.channel.send({ embed: Embed });
}})
If anyone has some examples, please share them with me (and it would help if you could explain what's happening :D)
Yes, it is possible. The one I'm going to show you uses reaction collectors to control which page to go to. You can modify it accordingly to fit with your pages needs, but this is the basic gist.
I first set up an array called Pages that would be what you wrote in the description, you can add additional arrays accordingly for your titles and whatnot. I also have page set to one since that's the default page and it will be the counter of which page the user is currently on.
There's multiple steps to show how this works:
Create initial embed + send embed (which I see you have already done, but you'll need to modify it accordingly to fit with the pages array.
Then add the reactions (I chose :rewind: and :fast_forward:. Note: Do not simply just copy them from the Discord channel, as I have learned here.)
Then create two separate filters, one for each ReactionCollector. I've labeled mine isBackwards and isForwards accordingly.
Create a ReactionCollector for both forwards and backwards.
I've labeled mine backwards and forwards
Then inside of each event handler, I just shifted the page and the descriptions and whatnot, and edited the embed accordingly.
Note: The second reaction takes a while to load. I haven't found a function where you can put both embeds at the same time... so it might take a while for the second embed to pop up.
Code:
//pages is very flexible, as long as you change the array at the top you're set
let pages = ["Page one", "Page two", "Page three", "Page four"];
let page = 1;
if (message.content.startsWith("!embed")) {
const embed = new Discord.MessageEmbed()
.setColor(0xffffff) //sets color here
.setFooter(`Page ${page} of ${pages.length}`)
.setDescription(pages[page - 1])
message.channel.send(embed).then(msg => {
msg.react('⏪').then(r => {
msg.react('⏩');
//filters
const isBackwards = (reaction, user) => reaction.emoji.name === '⏪' && user.id === message.author.id;
const isForwards = (reaction, user) => reaction.emoji.name === '⏩' && user.id === message.author.id;
const backwards = msg.createReactionCollector(isBackwards);
const forwards = msg.createReactionCollector(isForwards);
backwards.on("collect", r => {
if (page === 1) return;
page--;
embed.setDescription(pages[page - 1]);
embed.setFooter(`Page ${page} of ${pages.length}`);
msg.edit(embed)
});
forwards.on("collect", r => {
if (page === pages.length) return;
page++;
embed.setDescription(pages[page - 1]);
embed.setFooter(`Page ${page} of ${pages.length}`);
msg.edit(embed)
});
});
});
}
const employeeQuestion = [
{
type: "list",
name: "employeeTitle",
message: "What's the employee's title",
choices: ["Engineer", "Intern"]
},
//when role is engineer is true, ask this question
{
when: input => {
return input.role == "Engineer"
},
type: "input",
name: "github",
message: "Enter your github username:",
},
//when role is intern is true, ask this question
{
when: input => {
return input.role == "Intern"
},
type: "input",
name: "school",
message: "What's the school you enrolled in ?",
},
]
The idea is I want to utilize inquirer's when method so the question whether to ask about the user's github or school is dependent on the answer on the employee's title. But when i run node on the command line, the question asking for github / school never appeared. I wonder if I used the method wrong or if there are other alternatives.
inquirer's when method is definitely the correct one for this situation!
There are two possible reasons:
You are using input.role but never defining a role value in the answers hash. You need to refer to the name value from the earlier question, in this case, input.employeeTitle.
If reason 1 does not fix it, try expanding your function a bit. when needs to take in the answers hash as an input, then apply the conditional to that and explicitly return a Boolean. Ex.
{
type: "input",
name: "github",
message: "Enter your github username:",
when: (answers) => {
if (answers.employeeTitle === "Engineer") {
return true;
}
}
so i'm developing a personality quiz app using one of the tutorials i found on the internet //mitchgavan.com/react-quiz/, I have a quizQuestions.js file for api where i fetch the answer and the question from, like so
{
question: "I am task oriented in order to achieve certain goals",
answers: [
{
type: "Brown",
content: "Hell Ya!"
},
{
type: " ",
content: "Nah"
}
]
},
it has type and content, so this is the initial state of the app, every time the user click on Hell YA button it will increment that type +1, for example Brown: 1 etc.. but the problem is, when user select Nah it will give me this :null , I have a AnswerOption.js component like so
function AnswerOption(props) {
return (
<AnswerOptionLi>
<Input
checked={props.answerType === props.answer}
id={props.answerType}
value={props.answerType}
disabled={props.answer}
onChange={props.onAnswerSelected}
/>
<Label className="radioCustomLabel" htmlFor={props.answerType}>
{props.answerContent}
</Label>
</AnswerOptionLi>
);
}
AnswerOption.PropTypes = {
answerType: PropTypes.string.isRequired,
answerContent: PropTypes.string.isRequired,
answer: PropTypes.string.isRequired,
onAnswerSelected: PropTypes.func.isRequired
};
and my setUserAnswer function like so
setUserAnswer(answer) {
const updatedAnswersCount = update(this.state.answersCount, {
[answer]: {$apply: (currentValue) => currentValue + 1}
});
this.setState({
answersCount: updatedAnswersCount,
answer: answer
});
}
my question is, how can i let react ignore that white space, so when user click Nah it will not do anything with it, and if there is different approach to the problem i will be gladly accept it, thanks in advance.
Simple solution to your problem is to check if answer is empty :
if(answer.trim()) {
const updatedAnswersCount = update(this.state.answersCount, {
[answer]: {$apply: (currentValue) => currentValue + 1}
});
this.setState({
answersCount: updatedAnswersCount,
answer: answer
});
}
im doing the "Intermediate Meteor Tutorial #8 - Insert Permissions, Publishing & Meteor Toys" by LevelUpTuts and my problem is that i cant submit the form i checked the code 5 times but in my opinion everything is right im running meteor 1.4 here is my code
my Recipes.js file
Recipes = new Meteor.Collection('recipes');
Recipes.allow({
insert: function(userId, doc) {
return !!userId;
}
});
RecipeSchema = new SimpleSchema ({
name: {
type: String,
label: "Name"
},
desc: {
type: String,
label: "Description"
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userID
},
autoform: {
type: "hidden"
},
},
createdAt: {
type: Date,
label: "CreatedAt",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden"
},
},
});
Recipes.attachSchema( RecipeSchema);
my recipes.js
Meteor.subscribe('recipes');
my NewRecipe.js
<template name="NewRecipe">
<div class="new-recipe-container">
{{> quickForm collection="Recipes" id="insertRecipeForm" type="insert" class="new-recipe-form"}}
</div>
</template>
and the publis.js file
Meteor.publish('recipes', function(){
return Recipes.find({author: this.userId});
});
Please help me i dont know what i am doing wrong
i don't have the answer for you (at least not yet), but i'm posting this as an answer so i can provide some formatted code.
you posted some code under NewRecipe.js, but i assume that view code is in NewRecipe.html. Try 2 things:
first, put this code in NewRecipe.js onCreated():
SimpleSchema.debug = true;
AutoForm.addHooks(null, {
onError: function(name, error, template) {
console.log(name + " error:", error);
}
});
that will enable some debugging for the quickform.
second, in the schema definition, comment out the Recipes.allow() block to see if that's what's blocking saving your data.
then report back on how that goes.