Search code examples
pythondiscord.pypycord

How to reset Discord.OptionSelect in Python Pycord?


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

enter image description here

Then I get to a new dropdown and I click the "Back" Button:

enter image description here

I get to the original dropdown. and if I click the "Meats" cateogry again it crushes.

enter image description here

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) 

Solution

  • 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.