Reputation:
I am trying to list out all the channels from the server and put them all into a Select Menu but I get the following error:
data.components[0].components[0].options: Must be between 1 and 25 in length.
Code:
run: async (interaction) => {
const embed = new MessageEmbed()
.setColor('#4ccdea')
.setTitle('Select a channel below.')
.setTimestamp()
let selectmenu = new MessageActionRow()
.addComponents(
new MessageSelectMenu()
.setCustomId('channel')
.setPlaceholder('Nothing selected')
.addOptions([{
label: `Cancel`,
description: 'Cancel the channel selection',
value: 'cancel',
}])
)
interaction.guild.channels.cache.forEach(channel => {
selectmenu.components[0].addOptions([{
label: `${channel.name}`,
description: `${channel.name}`,
value: `${channel.id}`,
}]);
})
await interaction.reply({ embeds: [embed], components: [selectmenu] });
}
Upvotes: 1
Views: 2049
Reputation: 23189
The error means that you can't have more than 25 options in a select menu. As you have already an option (cancel
), you can only add 24 channels at a time.
A quick and dirty solution is to just send the first 24 channels, like this:
let selectmenu = new MessageActionRow().addComponents(
new MessageSelectMenu()
.setCustomId('channel')
.setPlaceholder('Nothing selected')
.addOptions([
{
label: `Cancel`,
description: 'Cancel the channel selection',
value: 'cancel',
},
]),
);
interaction.guild.channels.cache.first(24).forEach((channel) => {
selectmenu.components[0].addOptions([
{
label: `${channel.name}`,
description: `${channel.name}`,
value: `${channel.id}`,
},
]);
});
await interaction.reply({ embeds: [embed], components: [selectmenu] });
You could also send more than one select menu. You will need to create an options array using map()
, create an action row for every 24 channels, and add the menu with the 24 options.
You can also create a helper function to chunkify your array:
// helper function to slice arrays
function chunkify(arr, len) {
let chunks = [];
let i = 0;
let n = arr.length;
while (i < n)
chunks.push(arr.slice(i, (i += len)));
return chunks;
}
And then you can use it like this:
async (interaction) => {
const embed = new MessageEmbed()
.setColor('#4ccdea')
.setTitle('Select a channel below.')
.setTimestamp();
let selectMenus = [
new MessageActionRow().addComponents(
new MessageSelectMenu()
.setCustomId('channel')
.setPlaceholder('Nothing selected')
.addOptions([
{
label: `Cancel`,
description: 'Cancel the channel selection',
value: 'cancel',
},
]),
),
];
await interaction.guild.channels.fetch();
// iterate over the channels and create menu option objects
let options = interaction.guild.channels.cache.map((channel) => ({
label: channel.name,
description: channel.name,
value: channel.id,
}));
// if there is less than 24 fields, you can safely send the menu
// in a single message
if (options.length <= 24) {
selectMenus[0].components[0].addOptions(options);
await interaction.reply({ embeds: [embed], components: selectMenus });
}
// if there are more, you need to create chunks w/ max 24 fields
// you can use the helper function created above
const chunks = chunkify(options, 24);
chunks.forEach((options, i) => {
// if this is the first row, append the options
if (i === 0)
selectMenus[0].components[0].addOptions(options);
// else just create a new action row with a new menu for each 24 fields
else
selectMenus.push(
new MessageActionRow().addComponents(
new MessageSelectMenu()
.setCustomId(`channel-${i}`)
.setPlaceholder('Nothing selected')
.addOptions(options),
),
);
});
await interaction.reply({ embeds: [embed], components: selectmenus });
}
One drawback of this is that the customId
is not channel
, but channel
, channel-1
, channel-2
, etc. It means, you will need to make sure that when you handle the interaction, you check if the interaction.customId.startsWith('channel')
.
Upvotes: 2
Reputation: 14
You can use .slice(0,25)
to only keep 25 first channels and put them in the select.
Upvotes: -1