How to use AutoComplete in Discord.js v13? - node.js

How do you use the Discord autocomplete feature using Discord.js v13.6, #Discord.js/builders v0.11.0?
I couldn't find a guide or tutorial anywhere
Here is what I have so far:
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageEmbed } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('autocomplete')
.setDescription('Test command')
async execute(interaction) {
await interaction.replay({ content: "Hello World" })
},
};

Basically, autocomplete is a way for bots to suggest values for integer and string options for command interactions.
When a user uses a slash command (lets call it help) and this command takes a string argument of which command to describe, it might be annoying for the user to know every single command. Autocomplete fixes this by suggesting values (in this case commands).
You can set an option as autocompetable when you use the slash command builder:
import { SlashCommandBuilder } from '#discordjs/builders';
const command = new SlashCommandBuilder()
.setName('help')
.setDescription('command help')
.addStringOption((option) =>
option
.setName('command')
.setDescription('The command to get help for.')
.setRequired(true)
// Enable autocomplete using the `setAutocomplete` method
.setAutocomplete(true)
);
When autocomplete is set to true, every time a user starts using an option, Discord will send a request to your bot (as an interaction) to see what should be suggested. You can handle the response as such:
client.on('interactionCreate', async (interaction) => {
// check if the interaction is a request for autocomplete
if (interaction.isAutocomplete()) {
// respond to the request
interaction.respond([
{
// What is shown to the user
name: 'Command Help',
// What is actually used as the option.
value: 'help'
}
]);
}
});

Related

Edit variables with command discord.js v13

I'm working on a discord.js v13 bot, and I want to make a command that add the channel Id where the command executed in an existing variable and, another command that works only with the channels in the variable
This is the variable
const ch = ["1068584484473143386","1068570010756337705","","","",]
The command that works with the channels stored
client.on("message", async (message) => {
if(message.author.bot) return;
if(ch.includes(message.channel.id)) {
const prompt = message.content
message.channel.sendTyping(60)
const answer = await ask(prompt);
message.channel.send(answer);
}});
Edit : I used array.push() in an command but it didn't work it didn't do anything
client.on('messageCreate', message => {
if (message.content === '..auto-on') {
if(!message.member.permissions.has("ADMINISTRATOR")) {
message.channel.reply("**You don't have permissions**")};
ch.push(`${message.channel.id}`)
message.channel.reply(`**Added ${message.channel} to auto-reply**`);
}});
Edit 2 : it worked but it get reset after restarting
If I understood you correctly you want to insert a new channel Id to an existing array, you can do that using the Array.push() method.
Example:
const arrayofItems = ["Flour", "Milk", "Sugar"]
console.log(arrayofItems) // ["Flour", "Milk", "Sugar"]
arrayofItems.push("Coffee")
console.log(arrayofItems) // ["Flour", "Milk", "Sugar", "Coffee"]
Make sure to learn the basics of JS before starting out with libraries such as Discord.JS.

DiscordJS v13 send to specific channel

So I am trying to send an embed to a different channel than the command was used in as a log channel how ever I have tried a few different methods however where I am at now is the error i get is qChann.send is not a function it is yelling at the .send part.
This is the part referenced in index.js Yes I know it is bad practice to reference and export from main file but I am desperate for a solution
client.on('ready', async () => {
console.log('Online');
const qChann = client.channels.cache.get('960425106964885535');
console.log(qChann);
})
The second part is in a command file call deposit.js
It uses a 2 part collector ignore date and time stuff thats from express
I am also using mongoDB and it works completely fine how ever that last little statement is giving me a hard time qChann.send({embed: steelEmbed}); also qChann is included as const qChann = require('../index');
if (collected.content.toLowerCase() === 'steel') {
message.reply('Enter the amount youd like to deposit');
collector.stop('user entered steel');
const steelCollector = message.channel.createMessageCollector({
filter,
max: 1,
time: 1000 * 20,
});
steelCollector.on('collect', async (collected) => {
const steelAmount = collected.content;
await steelSchema.findOneAndUpdate({
$inc: {
steel: +steelAmount,
}
})
steelNewCount = await steelSchema.findOne({steelSchema}, {_id: 0});
const steelEmbed = new MessageEmbed()
.setColor('#4278f5')
.setTitle(`Ammo11 Stash Update`)
.setDescription(`Steel Count Updated`)
.addField(`Stash Updated`, `by <#${message.author.id}>`, true)
.addField(`Date Log`, `${date} / ${month} / ${year}`, true)
.addField(`Steel Deposited`, `${steelAmount}`, true)
.addField(`New Steel Count`, `${steelNewCount}`, true )
.setTimestamp()
.setFooter({text:'THIS MESSAGE IS NOT TO BE DELETED'});
qChann.send({embed: steelEmbed});
})
}
You need to define channel and then export it. You didn't export so you can't take it from another file as i know.
// outside of events
const qChann = client.channels.cache.get("960425106964885535")
module.exports = { qChann }
After this edit on your main file, you can access your channel with importing it with require in your command files.

DiscordJS Error, Embed Message Within Command Handler

I am trying to make my bot use an embed message however it will not work because i keep getting the Message not defined error
I have tried just using the author.bot but then it comes up with Author not defined, Something important to mention, I am using the command handler provided by the DiscordJS Guide and then i tried using the DiscordJS Guide for Embeds and it didnt work, thats basically how i ended up here
Code Below
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageEmbed } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('embed')
.setDescription('A W.I.P Embed'),
async execute(interaction) {
const Embed1 = new MessageEmbed().setTitle('Some title');
if (message.author.bot) {
Embed1.setColor('#7289da');
}
}
};```
This is because you are using a message object when the exported item is: interaction.
Change:
if (message.author.bot) {
Embed1.setColor('#7289da');
}
to:
if (interaction.user.bot) {
Embed1.setColor('#7289da');
}
There is no interaction.author and only a interaction.user, therefore is the only way to check if it's a bot.

Microsoft Teams Bot-Framework Skill Dialog: endDialog() does not work

I am implementing a dialogRootBot that will call a skillDialogBot.
My dialogRootBot is able to invoke the skillDialogBot. The conversation can progress until the point where the skillDialogBot is supposed to return the results to the dialogRootBot.
The skillDialogBot has the following setup
this.addDialog(new TextPrompt(TEXT_PROMPT))
.addDialog(new ConfirmPrompt(CONFIRM_PROMPT))
.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
this.processStep.bind(this)
]));
The processStep is laid out like this
async processStep(stepContext) {
const details = stepContext.options;
details.result = {
status: 'success'
};
return await stepContext.endDialog(stepContext.options);
}
I was expecting the dialogRootBot to get the result from the skillDialogBot after processStep has called endDialog, but that never happens. Instead, the user is stuck with the skillDialogBot until the user manually types in "abort", which is the command the dialogRootBot is monitoring to cancel all dialogs in its onContinueDialog() implementation
Here is how the onContinueDialog() looks like
async onContinueDialog(innerDc) {
const activeSkill = await this.activeSkillProperty.get(innerDc.context, () => null);
const activity = innerDc.context.activity;
if (activeSkill != null && activity.type === ActivityTypes.Message && activity.text) {
if (activity.text.toLocaleLowerCase() === 'abort') {
// Cancel all dialogs when the user says abort.
// The SkillDialog automatically sends an EndOfConversation message to the skill to let the
// skill know that it needs to end its current dialogs, too.
await innerDc.cancelAllDialogs();
return await innerDc.replaceDialog(this.initialDialogId, { text: 'Request canceled!' });
}
}
return await super.onContinueDialog(innerDc);
}
I modeled this after the botbuilder-samples\samples\javascript_nodejs\81.skills-skilldialog sample. If I were to change the skillDialogBot and have it do a ConfirmPrompt() before the finalStep()'s endDialog(), then the conversation ends correctly with the skillDialogBot() posting the dialog's results to the rootDialogBot.
For the sake of clarity, this is how the bookingDialog in the skills-skilldialog sample looks like
/**
* Confirm the information the user has provided.
*/
async confirmStep(stepContext) {
const bookingDetails = stepContext.options;
// Capture the results of the previous step.
bookingDetails.travelDate = stepContext.result;
const messageText = `Please confirm, I have you traveling to: ${ bookingDetails.destination } from: ${ bookingDetails.origin } on: ${ bookingDetails.travelDate }. Is this correct?`;
const msg = MessageFactory.text(messageText, messageText, InputHints.ExpectingInput);
// Offer a YES/NO prompt.
return await stepContext.prompt(CONFIRM_PROMPT, { prompt: msg });
}
/**
* Complete the interaction and end the dialog.
*/
async finalStep(stepContext) {
if (stepContext.result === true) {
const bookingDetails = stepContext.options;
return await stepContext.endDialog(bookingDetails);
}
return await stepContext.endDialog();
}
Is it not possible to endDialog() without a prompt? Why is my skillDialogBot unable to endDialog and pass the results to the rootDialogBot?
Thank You
For the sake of reference, when using stepContext.beginDialog(), it appears that we cannot reliably endDialog() if the waterfall dialog does not have a prompt step added. If there is a use case where we want to use a skillDialogBot and call a specific dialog in the skillDialogBot via stepContext.beginDialog(), and the called dialog is only doing processing (eg. call REST APIs) without the need to prompt users for further information, at the end of the processing, we can opt to end the conversation instead.
Hence, assuming we have finalStep() bound to the waterfall dialog as the last step, just use the following in finalStep()
return await stepContext.context.sendActivity({
type: ActivityTypes.EndOfConversation,
code: EndOfConversationCodes.CompletedSuccessfully,
value: stepContext.options
});
At least for my use case, I was able to terminate the dialog without needing a user prompt and got the results back to the rootDialog.

How to split my chat commands into differents files?

I'm creating a basic nodejs based chatbot for discord using discordjs.
In my main script, when a 'message' event is sent, the bot checks if the message match with a specific command and, in this case call it. The functions corresponding to these commands are in methods in a "TextCommand" class, inported in the main script, but the TextCommand file is getting too big I think...
I tried to split each command in one file and export it, but I can't import it as methods into TextCommand class.
index.js
const TextCommand = require('./src/commands.js');
client.on('message', (msg) => {
if (!msg.author.bot) {
let command;
let reg;
let prefix;
if (msg.guild != undefined){ // Guild commands
db.query(`SELECT prefix FROM guilds WHERE discord_id=${msg.guild.id};`, (err, result) => {
if (err) throw err;
prefix = result[0].prefix
command = new TextCommand(prefix, msg)
reg = new RegExp('^' + prefix, 'i')
if (msg.content.startsWith(prefix + 'help')) {
command.help();
} else if (msg.content.startsWith(prefix + 'ping')) {
command.ping();
} else if (msg.content.startsWith(prefix + 'search')) {
command.search();
TextCommand file
module.exports = class TextCommand {
constructor(prefix, msg){
this.message = msg;
this.prefix = prefix;
}
ping(){
this.message.channel.send('pong !');
}
search(){
let search = this.message.content.slice(this.prefix.length + 'search '.length).replace(/ /g, '+');
this.message.channel.send(`http://google.com/search?q=${search}`);
}
I do not understand how to use class extands... but maybe it's a part of the solution, I would include my functions into TextCommands just wrinting them somewhere else (and export it)
Instead of using a class to hold every command you own, try exporting commands.
For instance, in the ready event, you'll want to search the commands folder for command files, which may follow the format of <command name>.js, so a command !foo would be foo.js in the folder commands.
To find all the files in the commands folder:
const { promisify } = require('util');
const readdir = promisify(require('fs').readdir);
client.commands = new Map();
client.on('ready', async () => {
readdir('./commands/', (error, files) => {
if (error) throw error;
files.forEach(file => {
if (!file.endsWith('.js')) return; // make sure the file is what you are looking for
try {
const properties = require(`./commands/${file}`);
client.commands.set(properties.help.name, properties);
} catch (err) {
throw err;
}
});
}
});
This basically defines a Map, extended from the client object called client.commands. This map will contain the command properties, which is used to run the command later. The readdir reads the directory of ./commands/ for any file (using the module fs), and tries to filter them so they are only javascript files (ending with .js), and then adds the commands to the map with its properties.
Later, on the message event, you'll want to test to see if the message content is the command that you have coded:
client.on('message', async (message) => {
if (!message.guild) return; // exit if the message does not have a guild
if (message.author.bot) return; // exit if the message author is a bot
// ... your database code to get the prefix ...
const args = message.content.slice(prefix.length).trim().split(/ +/g).call(Function.prototype.call, String.prototype.trim);
const command = args.shift().toLowerCase();
const cmd = client.commands.get(command);
if (!cmd) return; // the message is not a command we know of
cmd.run(client, message, args); // run the command with client object, message object and args array
});
This code does the basic checks, to make sure the bot is only responding to a user in a guild channel (you may also want to check if the message is from Discord: message.system).
After, it'll separate the content after the prefix into an array, splitting on a space, and then trimming every element of leading and trailing white space.
It'll then assign the first element of the args array to the constant command, to then be checked if that command exists in our map.
If it does, it'll run the command (apart of the module.exports), passing along the client object, message object, and the arguments array.
Finally, in a command file, such as foo.js, you'll need to have some important code to make sure the bot registers said the file is a command we want to run. This is:
module.exports.run = async (client, message, args) => {
// ... command logic
message.channel.send('Hello!');
};
module.exports.help = {
name: 'foo'
};
This is the basic layout of the command file the system is able to read. The first line exports the run process of the command, which is an async function. It also exports the help object, which includes the name of the command. It's best that this is the same as the file name since this name is what the command is responding to.
In my opinion, this is a better method than creating the class holding all the commands, but I'll keep an open mind!

Resources