Search code examples
node.jsdiscorddiscord.js

Different choices for each guild slash command using discord js


I am building a discord bot that is going to be used on multiple guilds (a.k.a servers). The bot has a command called 'send' that has a set of choices inside an option:

const { SlashCommandBuilder } = require('@discordjs/builders');

module.exports = {

    data: new SlashCommandBuilder()
        .setName('send')
        .setDescription('Do stuff')
        .addStringOption(option =>
            option.setName('choices') // setting the choices
                .setDescription('users will chose one of the options bellow')
                .setRequired(true)
                .addChoice('choice1', 'potato')
                .addChoice('choice2', 'tomato')
                .setRequired(true))
        

    async execute(interaction) {

       //do stuff

        }; }};

All of the other application commands are global, but this specific command must have custom choices for each different guild. All this choices are stored on a mongo db, with the respective guild id.

The DB querying is ok to do, but I'm struggling with finding a solution to 'deploy' automatically this commands with different choices for each server. This is my goal with this question, to find a solution to deploy the commands with different choices for each guild.

If needed, I can provide my deploy-commands.js code ( it follows this tutorial ) and also more detail.

Appreciate the help


Solution

  • As mentioned on the comments, using choices with data from the DB is not possible. The workaround is to use the 'autocomplete' option.

    To do that, inside the builder, we add a .setAutocomplete(true) . Now, we need to handle the autocomplete interaction, and fill it with the values that we want form the Database.

    It is important to 'filter' the type of interaction that we are handling. Using if statements, we need to verify if the interaction is an autocomplete or a command. Below is the resulting code:

    const { SlashCommandBuilder } = require('@discordjs/builders');
        const mongo = require('../structures/mongo')
    
    module.exports = {
        data: new SlashCommandBuilder()
            .setName('send')
            .setDescription('items list')
            .addStringOption((option) =>
                option
                    .setName('items')
                    .setDescription('Select your item from the list')
                    .setRequired(true)
                    .setAutocomplete(true)),
    
        async execute(interaction) {
    
            const guildID = interaction.member.guild.id;
            //query DB for the options 
    
            let guild = await mongo.getGuild(guildID)
    
            //loop through guild token and set to autocomplete 
    
            for (let i = 0; i < guild.guild_tokens.length; i++) {
                choices.push({
                    name: `${guild.guild_tokens[i].name}`,
                    value: `${i}`,
                })
                tokens.push(`${guild.guild_tokens[i].name}`)
            }
    
            if (interaction.isAutocomplete()) {
                interaction.respond(choices)
                    .catch(console.error);
            }
    
            // Must handle interactions (command ones) inside the if statement
            if (interaction.isCommand()) {
    
               //  do stuff 
    
        }
    };
    

    On a side note, I had an issue with the interactions at first, because on my 'interactionCreate' file I was returning if the interaction was not a command. It's also important to change that file to not return if the interaction is an 'autocomplete' type:

    module.exports = { name: "interactionCreate", async execute(interaction) {

        if (!(interaction.isCommand() || (interaction.type == 'APPLICATION_COMMAND_AUTOCOMPLETE'))) {
            console.log('fuck')
            return;
    
        }
    
        const command = interaction.client.commands.get(interaction.commandName);
    
    
        if (!command) return;
    
        try {
            await command.execute(interaction)
    
        } catch (err) {
            if (err) console.error(err);
    
        }
    }
    

    }