Reputation: 37
I am brand new to using discord buttons. This command is just a test command to see how everything works. My problem is that the buttons work but I can only press them once. after I press them once and then press them again I get the error at the bottom of the button saying "This interaction failed". how could I have the buttons be pressed as much as the user wants to? My Code is below. Any help would be great!
Code:
@commands.command()
async def button(self, ctx):
await ctx.send("This is a button test", components=[Button(style=ButtonStyle.blue, label="Btn1"), Button(style=ButtonStyle.red, label="Btn2"), Button(style=ButtonStyle.grey, label="Btn3")])
res = await self.client.wait_for("button_click")
if res.channel == ctx.channel:
await res.respond(type=InteractionType.ChannelMessageWithSource, content=f"{res.component.label} has been clicked! this is button 1")
res2 = await self.client.wait_for("button_click")
if res2.channel == ctx.channel:
await res2.respond(type=InteractionType.ChannelMessageWithSource, content=f"{res2.component.label} has been clicked! this is button 2")
res3 = await self.client.wait_for("button_click")
if res3.channel == ctx.channel:
await res3.respond(type=InteractionType.ChannelMessageWithSource, content=f"{res3.component.label} has been clicked! this is button 3")
Upvotes: 1
Views: 5459
Reputation: 66
It's possible to create an on_button_click listener.
The following code gives an example how to get it working
import discord
import settings
from discord_components import DiscordComponents, Button
class MyClient(discord.Client):
async def on_ready(self):
buttons = [Button(label="button 1", custom_id="1"), Button(label="button 2", custom_id="2"),
Button(label="button 3", custom_id="3")]
channel = self.get_channel(settings.DISCORD_ROLEBOT_SETTINGS_CHANNEL)
await channel.send("test", components=buttons)
async def on_button_click(self, interaction):
await interaction.respond(content=f"you clicked button {interaction.component.custom_id}")
if __name__ == "__main__":
client = MyClient()
DiscordComponents(client)
client.run(settings.DISCORD_TOKEN)
Upvotes: 4
Reputation: 423
It seems like you used this code example.
It looks like you have a misconception on how wait_for
operates.
The method wait_for
will return, once the bot has received an event specified in the arguments. It will not return before this event was received.
This means your code will not return from your first statement until you click a button. You can observe this behaviour by clicking your buttons out of order.
You will e.g. receive the chat message Btn3 has been clicked! this is button 1
From this explanation you see why that your 3 wait_for
statements (in series) only allow you to press any buttons 3 times before the method returns, resulting in failed interactions for further button presses.
As the wait_for
method does not differentiate between the different buttons, you can simply call a single wait_for
method within a (infinite) while-loop
and detect the pressed button by accessing res.component.label
.
while True:
res = await bot.wait_for("button_click")
if res.channel == ctx.channel:
await res.respond(type=InteractionType.ChannelMessageWithSource, content=f"{res.component.label} has been clicked!")
# do more stuff
# maybe break
As described in the linked wiki, you should use the check=
argument when using wait_for
. This allows you to filter for specific labelled Buttons which will get usefull for big bots running mutliple components at the same time.
You can aswell add the timeout=
argument to wait_for
in order to return if the user didn't press any buttons after a certain time. If the timeout is reached, an exception is raised.
Upvotes: 1