Search code examples
javascriptnode.jstypescriptdiscord.js

Disable a button after clicking using ActionRowBuilder Discord.Js v14


I'm facing a strange problem, I can't disable a button after it's been clicked. Actually, the disable option doesn't appear. For deffing button I use this function

const row = new ActionRowBuilder()
    .addComponents(
        new ButtonBuilder()
            .setCustomId(
)
            .setLabel('Test 2')
            .setStyle(ButtonStyle.Primary),

        new ButtonBuilder()
            .setCustomId('test_2')
            .setLabel('Test 2')
            .setStyle(ButtonStyle.Danger),
    );

I am sending this code as a follow up

await interaction.followUp(
            {
                content: `Test`,
                ephemeral: true,
                components: [row],
                fetchReply: true
            }
        );

I tried this way too

row[0].components[0].setDisabled(true)

I also tried with foreach.. and the same thing

Should I specify that I use typescript, is it because of this?


Solution

  • When you receive a button interaction, you receive the ActionRow as the first component of the message (i.e. interaction.message.components[0]). This contains your buttons inside its component property.

    You could update this row by iterating over this array of buttons and checking if the current interaction's customId is the same as the current button's customId. If it's the same, you will need to use the ButtonBuilder.from() method to update the button (as Components received from the API are not directly mutable in v14 of discord.js). Then, you can use .setDisabled(true) on this.

    Once the button is updated, you can edit the original message and send the now updated ActionRow. You can find an example below:

    client.on('messageCreate', (message: Message) => {
      if (message.author.bot) return;
    
      const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
        new ButtonBuilder()
          .setCustomId('test_1')
          .setLabel('Test 1')
          .setStyle(ButtonStyle.Primary),
    
        new ButtonBuilder()
          .setCustomId('test_2')
          .setLabel('Test 2')
          .setStyle(ButtonStyle.Danger),
      );
    
      message.channel.send({ components: [row] });
    });
    
    client.on('interactionCreate', async (interaction: Interaction) => {
      if (!interaction.isButton()) return;
    
      let { customId } = interaction;
      let row = interaction.message.components[0];
    
      // TS complains about components being read-only without "as any"
      (row.components as any) = row.components.map((button) =>
        button.customId === customId
          ? ButtonBuilder.from(button as APIButtonComponent).setDisabled(true)
          : button,
      );
    
      await interaction.message.edit({ components: [row] });
    
      interaction.reply({
        content: `Button with ${customId} is disabled`,
        ephemeral: true,
      });
    });
    

    enter image description here