#Passing data to next interaction without individual collectors?

43 messages · Page 1 of 1 (latest)

slim field
#

As far as I've understood discord.js you can either use a global event interactionCreate listener or you'd create individual collectors and handle the responses in-function.

Now in theory I quite like the global listener approach, problem is each interaction runs in a vacuum and there's no persistence of data between interactions. It seems I'm forced to create individual collectors if I want to create an interaction chain/ flow.

So my questions are,** is there any way to pass data to the next interaction using a global listener?**

and if there is not, is there any way to run both a global listener and individual collectors without Discord complaining that the interaction failed when the interaction wasn't acknowledged by both approaches?

true fog
#

• What's your exact discord.js npm list discord.js and node node -v version?
• Post the full error stack trace, not just the top part!
• Show your code!
• Explain what exactly your issue is.
• Not a discord.js issue? Check out #useful-servers.

thorn plaza
#

my suggestion is, if you need a flow, lets say the user has to do x amount of steps on the same command / interaction, then you should use collectors / await message components for this, the flow is gonna be easier to follow. On the other hand, if all you do is just reply to some interaction that can be made at any point in time (a button press, a selection menu for lets say roles selection, etc) then you 100% should go with a global interaction handler. As you can already tell, handling a flow only by using the global interactionCreate event is messy and can get complicated easily

slim field
#

Yeah that's kinda the problem I'm running into, I have a lot of both flows and random button presses. Currently I'm doing both and it works (mostly). Except for Discord sometimes saying that the interaction failed, even when it didn't.

Real shame there is no middle ground here. Both approaches are good at different things, but using individual collectors for everything to be able to run flows sounds like a massive headache.

thorn plaza
#

it shouldn't be. Kind of hard to say why you are getting those interaction failed errors, most likely you are either not deferring some interactions and your bot takes some time to process requests, or it is giving you an error somewhere and you are not catching it. Also for interactions that use collectors, if the collector ends or if you don't need to receive more interactions from that message you should edit it and remove all the components or disable them, so nobody can emit more interactions on expired components

slim field
#

I'm not 100% sure, but I'm fairly confident from earlier talks with more knowledgable people than me from this Discord that the reason is because I'm running both.

When I'm in a flow, I use the customId to know whether or not to disregard the interaction in my global listener and it would make sense if the global listener then thought I didn't do anything with the interaction because of the early exit.

Unless there's a way to acknowledge the interaction without deferring, replying or editing anything that I can put in my global listener instead of an early return.

thorn plaza
#

you shouldn't really be needing to filter the interactions by custom id in your global handler if you are already handling the interaction in your command with collectors

#

I mean, it really sounds like you are making it a bit more complicated than it should to be honest... The purpose of collectors or awaiting message components is for short lived interactions, if you want to use info from one interaction in another without the use of collectors, you need some external path to pass this information, can be a database, a file, or a global cache from where you can then retrieve this information by some identifier

slim field
thorn plaza
# slim field Can you force that any interaction coming out of a message will go to a certain ...

No that I am aware of. If you create a collector depending on how you create it, it will only listen for interactions made within the channel or from a specific message, i'm pretty sure it will still be received by your global interactionCreate event handler, and for that reason in your global handler you should only handle those interactions that can be triggered at any time. For example I have some buttons that can be pressed at any time from members to get roles (these buttons are prefixed with role- in their custom id), i'm only listening for those on my global handler, and any other button interaction my bot receives is handled inside that specific command / button handler using collectors, the interactionCreate just ignores it / doesn't do anything with it

slim field
#

when you say you only listen to buttons prefixed role-, does that look like a
if(interaction.customId.startsWith("role-") === false) return or something else?

It's pretty much the same thing I'm doing, but I have had multiple users reaching out and being confused when they get the interaction failed warning in red letters. The only way those come is if you send an interaction to the bot and it's not responded to. But all the interactions are responded to, just not by the global listener.

I can't get it to show consistently, it might be a latency thing.

thorn plaza
#

Okay so if those "interaction failed" messages come from interactions that you are using collectors on, then there is a bunch of ways those can fail. 1st because as you said they are not being handled by the global listener so they are just ignored. second because the collector expired, so when they press the button there is no collector listening for those interactions. And third it can be that you restarted the bot and the collector was destroyed

#

I still dont know if we are talking about components specifically or slash commands

#

also yes, the filter i use looks something like that but i use switch statement instead

#

here is an example

#

I have a lot of other buttons that are part of other commands and I just handle them inside those files using collectors, that is all the interactionCreate handler has related to buttons

slim field
#

They're not ignored, they technically fail in the eyes of either discordjs or Discord, hence the interaction failed.
There will not be a collector expired failure on my part since I remove any buttons when the collector expires.
As for the bot restart, ye that's tough luck I'm not gonna bother with that.

thorn plaza
#

You will have to try and pinpoint the cause of this interactions failing, because if they are not being ignored as you said, then there shouldn't be a reason for them to fail if you are successfully replying / updating them. You need to avoid handling the same interaction in more than 1 place at a time though, if an interaction fails because it expired that is okay though. So you said when these interactions fail you don't receive any errors in your console? that just makes it harder to debug. Some days ago discord had an issue with some update they pushed to the api that made some interactions fail, but I guess that should've been resolved by now

slim field
#

I know why they fail. The interaction failed feedback comes when the users client doesn't get a reply from the bot within a certain time. Seeing as they actually do get a response from the function the collector is in, the only other option is that they don't get a response from the global listener, which makes sense, because they don't.

thorn plaza
#

okay then these seems like you should be deferring the interaction in these commands then, if that doesn't help either, something between discord and the bot is causing the interactions to not reach in time, could be a connection issue, could be your bot process being stuck doing something, etc

slim field
#

deferring every message that has a collector?

thorn plaza
#

deferring every interaction that you know can take more than just 3 seconds to reply

#

the most common example for deferring interactions is when you have to do some fetch calls or your code has to wait for something for some time and you are uncertain if it can take less than 3 seconds everytime

slim field
#

Well, I defer all the initial buttons that are picked up by the global listener, the ones that initiate the flows, but I don't defer anything inside the flows.

thorn plaza
#

so you are saying that they get the interaction failed message after 15 minutes then?, because after you defer/reply to it you can still use that interaction for other things up to 15 minutes

slim field
#

No, it can happen during a flow. While people are filling out information, when both user and bot is replying within 3s.

thorn plaza
#

otherwise if your bot cannot even send the defer signal to discord then there is something else going up there

thorn plaza
#

can you like try and send some of the code you think is causing problems? like where on the flow you think the code is failing

slim field
#

Well, I've already told you 2-3 times why it happens. It's because the global listener isn't replying.

Afaik, the only reason why interaction failed shows is because it cannot get a response from the bot quick enough. But I'm literally seeing the interaction failed flicker (sometimes it stays) while (<500ms) the collector is updating the message from the interaction.

Anyway, it seems like what I originally thought is still true, either do both approaches and accept that this sometimes happens or choose an approach and accept the limitations of that approach.

Thank you for your time though!

thorn plaza
#

yea its kind of difficult to figure out the issue just by talking about it, but i hope you can figure something out later, seems a bit annoying

loud stream
# slim field Well, I've already told you 2-3 times why it happens. It's because the global li...

Your global handler doesn’t need to acknowledge an interaction at all that you have a collector for. The collector is responsible for acknowledging those interactions. Do you defer the reply or update in the collector‘s collect event? What about people using a button or SelectMenu that the collector is meant to collect but they don’t pass the filter? You should acknowledge those interactions too, be it with an empty deferUpdate or an ephemeral reply saying „this component is not meant for you“

#

This is not an issue with having both approaches in your code, it’s just an issue with how you handle the specific one that fails

slim field
#

Is it ok to then have an early return in your global event listener or am I doing something wrong if the event gets triggered there at all?

Right now I'm not deferring any of the ones that have collectors.
It something looks like this

module.exports = {
  data: {
    name: "signup-custom-btn",
  },
  async execute(interaction: ButtonInteraction, client: any) {
    const interactionTimeoutMS = 30000
    try {
      await interaction.deferReply({ ephemeral: true })

      // multiple of these
      const selectLateMsg = (await interaction.editReply({
        content: `Select option:`,
        components: [lateMaxRow],
      })) as Message

      const lateResult = await selectLateMsg
        .awaitMessageComponent({
          filter,
          componentType: ComponentType.SelectMenu,
          time: interactionTimeoutMS,
        })
        .catch((err) => {
          interaction.editReply({
            content: `Interaction timed out.`,
            components: [],
          })
          return null
        })

      // logic based on previous input
      // another message and another msg.awaitMessageComponent

      await interaction.editReply({
        embeds: [],
        content: "✅ done",
        components: []
      })

    } catch (error) {
      console.error(error)

      await interaction.editReply({
        content: "Error message",
        embeds: [],
        components: [],
      })
    }
  },
}
slim field
loud stream
slim field
loud stream
slim field
slim field
#

Ok thanks a lot! will try this, but it's a bit of refactor work

slim field
#

@loud stream
is there any benefit to always using the latest interaction when creating the next prompt?
or is it ok to just .deferUpdate() them and .editReply() on the original interaction?

With the exception of when you want to use modals I guess.