Can't use modal after button
const { ActionRowBuilder,PermissionFlagsBits,PermissionsBitField, ModalBuilder, TextInputBuilder, TextInputStyle, ButtonBuilder, ButtonStyle, SlashCommandBuilder,EmbedBuilder, } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ticketmessinit')
.setDescription('add')
.setDMPermission(false),
async execute(interaction) {
await interaction.deferReply();
await interaction.deleteReply();
const eventtic = new EmbedBuilder()
···
const create = new ButtonBuilder()
.setCustomId('ticketinit')
.setLabel('Create a ticket')
.setStyle(ButtonStyle.Primary);
const cancel = new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary);
const row = new ActionRowBuilder()
.addComponents(create,cancel);
const msg = await interaction.channel.send({
embeds:[eventtic],
components: [row],
});
const collector = msg.createMessageComponentCollector();
collector.on('collect',async i =>{
interaction.deferReply();
if (i.customId=='ticketinit'){
// Create the modal
const modal = new ModalBuilder()
.setCustomId('myModal')
.setTitle('My Modal');
// Add components to modal
// Create the text input components
const favoriteColorInput = new TextInputBuilder()
.setCustomId('Eventid')
// The label is the prompt the user sees for this input
.setLabel("What's the ID of your VTC's event?")
// Short means only a single line of text
.setStyle(TextInputStyle.Short);
// An action row only holds one text input,
// so you need one action row per text input.
const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);
// Add inputs to the modal
modal.addComponents(firstActionRow);
// Show the modal to the user
await interaction.showModal(modal);
const filter = (o) => o.customId === 'myModal';
interaction.awaitModalSubmit({ time: 50_000, filter })
.then(async(interaction) => {···
if (data.error == false){···
} else {
interaction.channel.send({content:'Can\'t find the event!',ephemeral:true});
}
})
.catch(err => console.log('No modal submit interaction was collected'));
} else if(i.customId=='cancel'){
interaction.update();
}
});
},
};
const { ActionRowBuilder,PermissionFlagsBits,PermissionsBitField, ModalBuilder, TextInputBuilder, TextInputStyle, ButtonBuilder, ButtonStyle, SlashCommandBuilder,EmbedBuilder, } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ticketmessinit')
.setDescription('add')
.setDMPermission(false),
async execute(interaction) {
await interaction.deferReply();
await interaction.deleteReply();
const eventtic = new EmbedBuilder()
···
const create = new ButtonBuilder()
.setCustomId('ticketinit')
.setLabel('Create a ticket')
.setStyle(ButtonStyle.Primary);
const cancel = new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary);
const row = new ActionRowBuilder()
.addComponents(create,cancel);
const msg = await interaction.channel.send({
embeds:[eventtic],
components: [row],
});
const collector = msg.createMessageComponentCollector();
collector.on('collect',async i =>{
interaction.deferReply();
if (i.customId=='ticketinit'){
// Create the modal
const modal = new ModalBuilder()
.setCustomId('myModal')
.setTitle('My Modal');
// Add components to modal
// Create the text input components
const favoriteColorInput = new TextInputBuilder()
.setCustomId('Eventid')
// The label is the prompt the user sees for this input
.setLabel("What's the ID of your VTC's event?")
// Short means only a single line of text
.setStyle(TextInputStyle.Short);
// An action row only holds one text input,
// so you need one action row per text input.
const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);
// Add inputs to the modal
modal.addComponents(firstActionRow);
// Show the modal to the user
await interaction.showModal(modal);
const filter = (o) => o.customId === 'myModal';
interaction.awaitModalSubmit({ time: 50_000, filter })
.then(async(interaction) => {···
if (data.error == false){···
} else {
interaction.channel.send({content:'Can\'t find the event!',ephemeral:true});
}
})
.catch(err => console.log('No modal submit interaction was collected'));
} else if(i.customId=='cancel'){
interaction.update();
}
});
},
};
16 Replies
- What's your exact discord.js
npm list discord.js
and node node -v
version?
- Not a discord.js issue? Check out #other-js-ts.
- Consider reading #how-to-get-help to improve your question!
- Explain what exactly your issue is.
- Post the full error stack trace, not just the top part!
- Show your code!
- Issue solved? Press the button!
- ✅
Marked as resolved by OPYou can't show a modal after using deferReply()
if i use interaciton.update it shows it's not a function
if i didn't use deferReply() it will shows replied when i click the button
why are you not just using interaction.reply() to send the buttons and then i.showModal() in the collector
your current approach will not work
i used as this
it shows
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
^
Error [InteractionAlreadyReplied]: The reply to this interaction has already been sent or deferred.
at ChatInputCommandInteraction.showModal (E:\htcqqcom\桌面\bot\marking main\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:255:46)
at InteractionCollector.<anonymous> (E:\htcqqcom\桌面\bot\marking main\commands\slash\ticketmessinit.js:49:29)
at InteractionCollector.emit (node:events:526:35)
at InteractionCollector.handleCollect (E:\htcqqcom\桌面\bot\marking main\node_modules\discord.js\src\structures\interfaces\Collector.js:133:14)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'InteractionAlreadyReplied'
}
Node.js v18.17.1
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
^
Error [InteractionAlreadyReplied]: The reply to this interaction has already been sent or deferred.
at ChatInputCommandInteraction.showModal (E:\htcqqcom\桌面\bot\marking main\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:255:46)
at InteractionCollector.<anonymous> (E:\htcqqcom\桌面\bot\marking main\commands\slash\ticketmessinit.js:49:29)
at InteractionCollector.emit (node:events:526:35)
at InteractionCollector.handleCollect (E:\htcqqcom\桌面\bot\marking main\node_modules\discord.js\src\structures\interfaces\Collector.js:133:14)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'InteractionAlreadyReplied'
}
Node.js v18.17.1
Show the new code
const { ActionRowBuilder,PermissionFlagsBits,PermissionsBitField, ModalBuilder, TextInputBuilder, TextInputStyle, ButtonBuilder, ButtonStyle, SlashCommandBuilder,EmbedBuilder, } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ticketmessinit')
.setDescription('add')
.setDMPermission(false),
async execute(interaction) {
await interaction.reply({content:'test' , ephemeral:true});
const eventtic = new EmbedBuilder()
···;
const create = new ButtonBuilder()
.setCustomId('ticketinit')
.setLabel('Create a ticket')
.setStyle(ButtonStyle.Primary);
const cancel = new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary);
const row = new ActionRowBuilder()
.addComponents(create,cancel);
const msg = await interaction.channel.send({
embeds:[eventtic],
components: [row],
});
const collector = msg.createMessageComponentCollector();
collector.on('collect',async i =>{
if (i.customId=='ticketinit'){
// Create the modal
const modal = new ModalBuilder()
.setCustomId('myModal')
.setTitle('My Modal');
// Add components to modal
// Create the text input components
const favoriteColorInput = new TextInputBuilder()
.setCustomId('Eventid')
// The label is the prompt the user sees for this input
.setLabel("What's the ID of your VTC's event?")
// Short means only a single line of text
.setStyle(TextInputStyle.Short);
// An action row only holds one text input,
// so you need one action row per text input.
const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);
// Add inputs to the modal
modal.addComponents(firstActionRow);
// Show the modal to the user
await interaction.showModal(modal);
const filter = (o) => o.customId === 'myModal';
interaction.awaitModalSubmit({ time: 50_000, filter })
.then(async(interaction) => {
···
if (data.error == false){
···
return;
} else {
interaction.channel.send({content:'Can\'t find the event!',ephemeral:true});
}
})
.catch(err => console.log('No modal submit interaction was collected'));
} else if(i.customId=='cancel'){
interaction.channel.send({content:'canceled',ephemeral:true})
}
});
},
};
const { ActionRowBuilder,PermissionFlagsBits,PermissionsBitField, ModalBuilder, TextInputBuilder, TextInputStyle, ButtonBuilder, ButtonStyle, SlashCommandBuilder,EmbedBuilder, } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ticketmessinit')
.setDescription('add')
.setDMPermission(false),
async execute(interaction) {
await interaction.reply({content:'test' , ephemeral:true});
const eventtic = new EmbedBuilder()
···;
const create = new ButtonBuilder()
.setCustomId('ticketinit')
.setLabel('Create a ticket')
.setStyle(ButtonStyle.Primary);
const cancel = new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Secondary);
const row = new ActionRowBuilder()
.addComponents(create,cancel);
const msg = await interaction.channel.send({
embeds:[eventtic],
components: [row],
});
const collector = msg.createMessageComponentCollector();
collector.on('collect',async i =>{
if (i.customId=='ticketinit'){
// Create the modal
const modal = new ModalBuilder()
.setCustomId('myModal')
.setTitle('My Modal');
// Add components to modal
// Create the text input components
const favoriteColorInput = new TextInputBuilder()
.setCustomId('Eventid')
// The label is the prompt the user sees for this input
.setLabel("What's the ID of your VTC's event?")
// Short means only a single line of text
.setStyle(TextInputStyle.Short);
// An action row only holds one text input,
// so you need one action row per text input.
const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);
// Add inputs to the modal
modal.addComponents(firstActionRow);
// Show the modal to the user
await interaction.showModal(modal);
const filter = (o) => o.customId === 'myModal';
interaction.awaitModalSubmit({ time: 50_000, filter })
.then(async(interaction) => {
···
if (data.error == false){
···
return;
} else {
interaction.channel.send({content:'Can\'t find the event!',ephemeral:true});
}
})
.catch(err => console.log('No modal submit interaction was collected'));
} else if(i.customId=='cancel'){
interaction.channel.send({content:'canceled',ephemeral:true})
}
});
},
};
i.showModal()
not interaction.showModal()
Also once again, why are you not sending the buttons in the interaction.reply
due to i want to let it as all could using
interaciton will has a command row

i want to let it as this
oh i get it
if i used interaciton.show Modal it will has the promise of main not the modal

it did the work but modal replies error
then you didn't reply to the modal
also you should change the name of your interaction inside awaitModalSubmit
thx:huge: :huge: :huge: :huge: :huge: :huge:
:blobreachReverse: :blobreachReverse: :blobreachReverse:
it done