I am trying to implement a "Back" button that will return to the previous dropdown. I am using Pycord.
I have a dropdown with options to pick different food categories, after you pick a category, the dropdown menu changes to a new dropdown where see items in that category. In addition, you have a "Back" button that should get you to the previous dropdown.
At the moment I get In components.0.components.0.options.1: The specified option value is already used
Error, after I click the back button and click the same category again.
Here is where I recreate the issue, first I run the slash command /shop
and I click the "Meats" category
Then I get to a new dropdown and I click the "Back" Button:
I get to the original dropdown. and if I click the "Meats" cateogry again it crushes.
main.py
import discord
from example1 import CategoryView
bot = discord.Bot()
@bot.command()
async def shop(ctx):
await ctx.respond("Choose a category from the dropdown below! ✨", view=CategoryView())
@bot.event
async def on_ready():
print("Ready!")
bot.run("TOKEN")
example1.py
import discord
from example2 import CategoryPriceView
class CategoryView(discord.ui.View):
def __init__(self):
super().__init__()
@discord.ui.select(
placeholder = "Choose a food category!",
min_values = 1,
max_values = 1,
options = [
discord.SelectOption(
label="Meats",
emoji='🍖'
),
discord.SelectOption(
label="Salads",
emoji='🥗'
)
]
)
async def select_callback(self, select, interaction):
category = select.values[0]
await interaction.response.edit_message(content="Choose your item!", view=CategoryPriceView(category, self))
example2.py
import discord
options = []
class CategoryPriceView(discord.ui.View):
def __init__(self, category, father):
super().__init__()
global options
self.category = category
self.father = father
if self.category == 'Meats':
options.append(discord.SelectOption(label='Steak', description="Price: 40$"))
elif self.category == 'Salads':
options.append(discord.SelectOption(label='Greek Salad', description="Price: 30$"))
@discord.ui.button(label="Back", row=1, style=discord.ButtonStyle.blurple)
async def button_callback(self, button, interaction):
await interaction.response.edit_message(content="Choose a category from the dropdown below! ✨", view=self.father)
@discord.ui.select(
placeholder = "Choose an item!",
min_values = 1,
max_values = 1,
options = options
)
async def select_callback(self, select, interaction):
item = select.values[0]
await interaction.response.edit_message(content=f"You chose {item}! ", view=None)
EDIT: My answer was completely wrong. Edited to provide actual answer.
The issue is the global options
. Every time you select an option from the original CategoryView
, you're creating a new instance of CategoryPriceView
and adding to options
. As options
is global and never gets cleared - there are duplicates in there - hence the duplicate value error. You can resolve this by subclassing Select
and creating a custom CategoryPriceSelect
that has the options logic you want. See below.
# example2.py
import discord
class CategoryPriceSelect(discord.ui.Select):
def __init__(self, category: str) -> None:
options = []
if category == 'Meats':
options.append(discord.SelectOption(label='Steak', description="Price: 40$"))
elif category == 'Salads':
options.append(discord.SelectOption(label='Greek Salad', description="Price: 30$"))
super().__init__(
placeholder="Choose an item!",
min_values=1,
max_values=1,
options=options
)
async def callback(self, interaction: discord.Interaction):
item = self.values[0]
await interaction.response.edit_message(content=f"You chose {item}! ", view=None)
class CategoryPriceView(discord.ui.View):
def __init__(self, category, father):
super().__init__()
self.category = category
self.father = father
select = CategoryPriceSelect(self.category)
self.add_item(select)
@discord.ui.button(label="Back", row=1, style=discord.ButtonStyle.blurple)
async def button_callback(self, button, interaction):
await interaction.response.edit_message(content="Choose a category from the dropdown below! ✨", view=self.father)
I've tested this and this works now without throwing the error and I believe this has your desired functionality.