Creating Pages from Array using Buttons

2.3k Views Asked by At

I'm having some difficulty creating "next page" and "previous page" buttons using discord-buttons.

What my command so far does is grab role info from an array formatted like:

{ role: 'hot rod red', color: '#fc0000' , price: 25000, roleid: '733373020491481219', id: 'red' }

Then create embeds for each of those roles. The code I have so far sends all of the roles at once with no issues, but I am trying to get them to send one at a time, and when the "next page" button is pressed, the message edits, and it goes to the next role embed in that array, all the way to the end. Since discord buttons are fairly new, there's not that much information on them yet, so any help's appreciated, thanks! (Please let me know I need to provide more code)

1

There are 1 best solutions below

0
theusaf On

Buttons are basically, a kind of alternative to using reactions. For page-like systems, it works almost identically. You send a message with reactions/buttons, wait for reactions, and then edit the message.

There are a few differences:

  • Buttons are immediately applied to the message and do not need to be added on afterward.
  • Buttons need to be responded to within 3 seconds of being pressed to avoid the user getting "This interaction failed" on their screen.
  • When interacted with, the buttons on the message cannot be interacted with again by the same user until acknowledged by the bot or the interaction times out.
  • Buttons cannot be removed by users

This means that buttons are very useful for actions such as editing the message it is on, but not as much for something like toggling a role.

Each message can have 5 ActionRows, and each ActionRow can have 5 Buttons (a total of 25)

Buttons have a label, style, and a custom id (or URL, if it is a 'URL-styled' button).

Since you are using discord-buttons, you can do something like this to send the message with buttons:

const { MessageActionRow, MessageButton } = require("discord-buttons");

// create a row!
const row = new MessageActionRow(),
  backButton = new MessageButton()
    .setLabel("Back")
    // https://discord.com/developers/docs/interactions/message-components#buttons-button-styles
    .setStyle("blurple"),
    // identifies the button, so you can know which button was pressed
    .setID("back"),
  nextButton = new MessageButton()
    .setLabel("Next")
    .setStyle("blurple")
    .setID("next");
row.addComponent(backButton).addComponent(nextButton);

const pages = [
  "Hello",
  "World",
  "Foo",
  "Bar"
];
let index = 0;

const message = await channel.send(pages[index], {
  component: row
});

Then, you can wait for the interactions using either the methods or events that discord-buttons provide:

discord-buttons extends functionalities of regular discord.js classes, so similar options can be used.

function handleInteractions() {
  // originalMessage is the message sent by the user to activate this 'command'
  const filter = (button) => button.clicker.user.id === originalMessage.author.id;
  const clickedButton = (await message.awaitButtons(filter, {
    max: 1, // how many to collect
    time: 60000 // how long to wait in milliseconds
  })).first();

  // check if a button was actually clicked
  if (clickedButton) {

    // IMPORTANT: Respond to the interaction to prevent false errors on the user's side.
    // https://discord-buttons.js.org/events/clickbutton#functions

    // Acknowledges the interaction, doesn't send or edit anything
    // You may find it easier to use a different method to acknowledge and edit/send a new message, but in this example, the message will be edited normally.
    await clickedButton.defer();

    if (clickedButton.id === "back") {
      index--;
    } else {
      index++;
    }
    // constrain the pages
    if (index < 0) index = pages.length - 1;
    if (index >= pages.length) index = 0;

    // edit your message!
    message.edit(pages[index]);

    // re-listen to button clicks
    handleInteractions();

  } else {
    // It may be useful to delete the message or remove the buttons from the 
    // message once you are no longer listening to the events.
    message.edit({components: []});
  }
}
handleInteractions();