Joe Moore
Joe Moore

Reputation: 2023

How would I iterate an awaitMessages collector to collect multiple inputs as the loop increments?

I am trying to create a setup command, where the user enters values which are then saved in an SQL db. However I am having trouble getting the awaitMessages method to wait within a for loop.

let input = []; // declare input as empty array
    let setupQ = ['Please enter the role ID of admin', 'Please enter the role ID of mod', 'Please enter the ID of your log channel', 'Please enter the ID of your join/leave channel'];
    for (i = 0; i < 4; i++) {
        message.channel.send(setupQ[i])   

        const filter = (user) => {
            return user.author.id === message.author.id 
        };
  
        message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] })
          .then(async collected =>  {
            input[i] = collected.first().content //takes user input and saves it
        }).catch(collected => {
            message.channel.send(`:x: Setup cancelled - 0 messages were collected in the time limit, please try again`).then(m => m.delete({ timeout: 4000 }));
        });            
};

What currently happens, is that the bot immediately outputs the questions, without waiting for a user to reply. I have previously got this command to work, but by using 4 awaitMessages methods which were ugly and slow. (not to mention a formatting nightmare).

Can anyone see what I have to do to make it wait?

Upvotes: 3

Views: 530

Answers (1)

Lakshya Thakur
Lakshya Thakur

Reputation: 8316

To wait for each instruction execution use await inside an async function like processStuff.

This is actually a workaround to get a kind of synchronous execution (by the looks of it) in JS by leveraging it's async paradigms.

In the earlier code, creation of each of your Promise was not dependent on the previous one to be fully evaluated. But in this case, we're awaiting that promise creation.

let input = []; // declare input as empty array
    let setupQ = ['Please enter the role ID of admin', 'Please enter the role ID of mod', 'Please enter the ID of your log channel', 'Please enter the ID of your join/leave channel'];

async function processStuff(){
    for (i = 0; i < 4; i++) {
        message.channel.send(setupQ[i])   

        const filter = (user) => {
            return user.author.id === message.author.id 
        };
        try{
        let collected = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
           input[i] = collected.first().content; //takes user input and saves it
         } 
        catch(e)
         {
            message.channel.send(`:x: Setup cancelled - 0 messages were collected in the time limit, please try again`).then(m => m.delete({ timeout: 4000 }));
         }              
};
}

processStuff();

Conceptually this is equivalent to all of your 4 promises chained together (like promise.then(...).then(...).then(...)....) so that the creation of next promise (inside then callback of previous one) can only begin after the previous one got fully evaluated and returned a new promise.

Upvotes: 2

Related Questions