🔢 Pagination Session
It's recommended that you first read the ️👤 Session documentation, since this is an extension of it.
A PaginationSession
is a special type of session made to be paginated (have pages).
From a manager's perspective, a pagination session is just a regular session. The pagination logic happens inside the session itself.
For the case of AbstractPaginationSession
, it does it by implementing #update()
, which does the following:
- It attempts to extract a referred page, depending on the interaction type:
Buttons
: Extracts from#customId
.SelectMenu
: Extracts from#customId
. If no page is present there, it's aStringSelectMenu
and only one value was selected, it extracts from the selected value.Modal
: Extracts from#customId
. If no page is present there, it iterates through the modal's components, searching for a component whosecustomId
is the session'scustomId
. If there is one, the page is extracted from said component's value.
- If there's no referred page, it uses
super.update()
, which will call#handleButton()
,#handleSelectMenu()
or#handleModal()
(like a regularAbstractSession
). - If there's a referred page, it updates its
currentPage
and calls#updatePage()
.
You can change the page resolving behavior by overriding #update()
, #extractPageFromInteraction()
,
#extractPageFromButton()
, #extractPageFromSelectMenu()
or #extractPageFromModal()
.
👷 Creation
You can create a paginated session by either:
- Extending
AbstractPaginationSession
from@framework
(recommended). - Implementing the
PaginationSession
interface from@core
.
After creating it, start it via SessionManager#start()
.
- Extending AbstractPaginationSession
- Implementing PaginationSession
import { AbstractPaginationSession, SessionUpdateInteraction } from '@nyx-discord/framework';
class MyPaginationSession extends AbstractPaginationSession {
public async handleStart() {
const page = this.createPage();
await this.startInteraction.reply(page);
}
protected async updatePage(interaction: SessionUpdateInteraction) {
const newPage = this.createPage();
await interaction.editReply(newPage);
return true;
}
protected createPage() {
const randomPage = Math.floor(Math.random() * 10);
const customIdBuilder = this.customId.clone();
const customId = customIdBuilder.setPage(randomPage).build();
const button = new ButtonBuilder()
.setCustomId(customId)
.setLabel('Go to a random page!')
.setStyle(ButtonStyle.Primary);
const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(button);
const pageRow = this.buildDefaultPageRow();
return {
content: `You're on page ${this.currentPage}`,
components: [buttonRow, pageRow]
};
}
}
// Somewhere in your code, like inside a command...
const sessionId = 'mySessionId'; // Ideally randomly generated
const session = new MyPaginationSession(bot, sessionId, interaction);
await bot.getSessionManager().start(session);
import { PaginationSession } from '@nyx-discord/core';
class MyPaginationSession implements PaginationSession {
// ...
}
const session = new MyPaginationSession(/** ... */);
await bot.getSessionManager().start(session);
💬 Pagination Custom Ids
When using a pagination session the SessionCustomIdCodec
can generate a PaginationCustomIdBuilder
, an extension of
CustomIdBuilder
that supports adding a page reference to the customId being built.
const codec = bot.getSessionManager().getCustomIdCodec();
const builder = codec.createPageCustomIdBuilder(session);
builder.push('foo').push('bar').setPage(1);
const customId = builder.build();
For AbstractPaginationSession
:
- A customId not referring to a page is handled by
AbstractSession#update()
(see 👤 Session (📝 Updating)). - A customId referring to a page is handled by
AbstractPaginationSession#updatePage()
.
✨ Component Examples
- Button
- Select Menu
- Modal
const buttonId = builder.cloneSetPage(3).build();
const button = new ButtonBuilder()
.setCustomId(buttonId)
.setLabel('Go to page 3')
.setStyle(ButtonStyle.Primary);
You can either:
- Put the pagination custom id in the select menu itself, making it switch to that page regardless of selection (useful for 🔀 Stage Pagination Sessions).
const selectId = builder.cloneSetPage(3).build();
const select = new SelectMenuBuilder()
.setCustomId(selectId)
.setPlaceholder('Switch to page 3')
.addOptions([
new StringSelectMenuOptionBuilder()
.setLabel('Option 1')
.setValue('option1'),
new StringSelectMenuOptionBuilder()
.setLabel('Option 2')
.setValue('option2'),
]);
- Put the pagination custom id in the select menu's options, making it switch to that page only when the option is selected. Note that you still need to put the pagination custom id in the select menu itself.
If a received interaction has more than 1 value, the AbstractPaginationSession
won't try to parse its values as
pagination indexes.
const selectId = builder.build();
const selectMenu = new StringSelectMenuBuilder()
.setCustomId(selectId)
.setMaxValues(1)
.setPlaceholder('Select a page');
const options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.map((page: number) => {
const customId = this.customId.cloneSetPage(page);
return new StringSelectMenuOptionBuilder()
.setLabel(`Go to page ${page}`)
.setValue(customId)
});
selectMenu.addOptions(options);
You can either:
- Put the pagination custom id in the modal itself, making it switch to that page regardless of values (useful for 🔀 Stage Pagination Sessions).
const modalId = builder.cloneSetPage(3).build();
const textInput = new TextInputBuilder()
.setCustomId('textInput')
.setLabel('Text input')
.setStyle(TextInputStyle.Short);
const modalRow = new ActionRowBuilder<ModalActionRowComponentBuilder>()
.addComponents(textInput);
const modal = new ModalBuilder()
.setCustomId(modalId)
.setTitle('A session modal that switches to page 3')
.addComponents(modalRow);
- Put the pagination custom id in the modal's components, making it switch to that component's value (if it's a number). Note that you still need to put the pagination custom id in the modal itself.
If the component's value cannot be parsed to a number, it will be handled as a regular update (#handleModal()
).
const modalId = builder.build();
const modal = new ModalBuilder()
.setTitle('Pagination')
.setCustomId(modalId)
const textInput = new TextInputBuilder()
.setLabel('New page?')
.setCustomId(modalId)
.setStyle(TextInputStyle.Short);
const modalRow = new ActionRowBuilder<ModalActionRowComponentBuilder>()
.addComponents(textInput);
modal.addComponents(modalRow);
🧩 Utility methods
The AbstractPaginationSession
provides the following protected
utility methods:
#buildDefaultPageRow()
: Builds a component row with default "next"/"previous" buttons.#buildCustomIdForPage(page: number)
: Builds a customId for a specific page.