Select Menus
note
This page is a continuation of the Interactions (Reference) which dives into what Interactions are.
#
Creating Select MenusCreating Select Menus is extremely easy with Discord4J. You can add select menus to any message the bot sends, including responses to application commands or other interactions!
#
Creating and sending select menus for a regular message// Whatever channel you want the message inSnowflake channelId = Snowflake.of(0);
SelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2"), SelectMenu.Option.of("label3", "value2"));
client.getChannelById(channelId) .ofType(GuildMessageChannel.class) .flatMap(channel -> channel.createMessage( MessageCreateSpec.builder() .content("Select Something!") // Select Menus must be in action rows .addComponent(ActionRow.of(select)) .build() )).subscribe();
#
Select menus in a component responseSelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2"), SelectMenu.Option.of("label3", "value2"));
client.on(ChatInputInteractionEvent.class, event -> { if (event.getCommandName().equals("ping")) { return event.reply("Pong!") .withComponents(ActionRow.of(select)); }}).subscribe();
#
Setting how many values a user may pickSometimes you may want to have a select menu where a user can pick multiple values rather than just one.
To set a minimum amount of values a user must pick: .withMinValues(AMOUNT)
And to set a maximum amount of values a user can pick: .withMaxValues(AMOUNT)
These methods can be used together to enable more complex select menu actions:
SelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.ofDefault("default-label", "Default Value!"), SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2")).withMaxValues(3).withMinValues(1);
#
Disabled select menusIf you want to prevent a select menu from being used, you can easily set it to being disabled.
SelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.ofDefault("default-label", "Default Value!"), SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2")).disabled();
#
Placeholder textPlaceholder text can be used when you don't wish to have a default selected value. This text will appear when no value is selected and can easily be done like so:
SelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2")).withPlaceholder("Please select an option <3");
#
Default selected valueYou may want to have a default value selected for the user, luckily discord supports this and D4J implements this cleanly. All you need to do is create an option as follows:
SelectMenu.Option.ofDefault("default-label", "Default Value!")
#
Adding descriptions to optionsHelping users understand the options they are picking is important. Sometimes, the context is clear and a description is unneeded, but if there needs to be a description, this can easily be achieved.
SelectMenu.Option option = SelectMenu.Option.of("Label", "value").withDescription("My Description");
#
Emoji optionsIf you want an emoji displayed rather than a text label we would use the following code:
// Custom non-animated emoteReactionEmoji customEmoji = ReactionEmoji.of(546687597246939136L, "d4j", false);SelectMenu.Option customEmoteOption = SelectMenu.Option.of("label", "value").withEmoji(customEmoji);
// Unicode emoteReactionEmoji unicodeEmoji = ReactionEmoji.unicode("\u2764");SelectMenu.Option unicodeEmoteOption = SelectMenu.Option.of("label", "value").withEmoji(unicodeEmoji);
#
Using a Temporary Listener To Respondnote
If you would like to always respond to select menu interactions, you can easily do so by creating a custom listener just as we showed in
Application Commands - Receiving, using the SelectMenuInteractionEvent
class.
Like Application Commands, select menus are always valid, no matter how much time has passed since the message was created. Responding to a select menu days, or weeks after its creation may not always be feasible. To counteract this, we can create a temporary listener that automatically times out.
// Whatever channel you want the message inSnowflake channelId = Snowflake.of(0);
SelectMenu select = SelectMenu.of("custom-id", SelectMenu.Option.of("label", "value"), SelectMenu.Option.of("label2", "value2")).withPlaceholder("Please select an option <3");
client.getChannelById(channelId) .ofType(GuildMessageChannel.class) .flatMap(channel -> { Mono<Message> createMessageMono = channel.createMessage(MessageCreateSpec.builder() .addComponent(ActionRow.of(select)) .build());
Mono<Void> tempListener = client.on(SelectMenuInteractionEvent.class, event -> { if (event.getCustomId().equals("custom-id")) { //Get all selected values String values = event.getValues().toString().replace("[", "").replace("]", ""); return event.reply("You selected these values: " + values).withEphemeral(true); } else { // Ignore it return Mono.empty(); } }).timeout(Duration.ofMinutes(30)) // Timeout after 30 minutes // Handle TimeoutException that will be thrown when the above times out .onErrorResume(TimeoutException.class, ignore -> Mono.empty()) .then(); //Transform the flux to a mono
//Return both of the monos together return createMessageMono.then(tempListener); }).subscribe();