Been working on this bot for a bit, but I seem to be stumped. every time I run it, it says
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'createReactionCollector' of undefined
This is caused by
const collector = message.createReactionCollector(filter, { time: 15000 });
and i dont know how else to do this. Most of the other examples are either outdated or made for a particular purpose, making it hard to implement them into my code. I really appreciate any help you can provide!
if (command === 'ping') {
const pingEmbed = new Discord.MessageEmbed()
.setColor('#03cffc')
.setTitle('Ping!')
.setDescription(`${message.author.username} is playing a game! \n \n Playing With: \n ` + isPlaying);
message.channel.send(pingEmbed)
.then(sentEmbed => {
sentEmbed.react("👍")
}).then( async message => {
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
})}
You do not need to use two then methods. Simply one would be enough for your case. Instead of having to use another then method and passing in message, you can just replace message with sentEmbed.
Code:
if (command === 'ping') {
const pingEmbed = new Discord.MessageEmbed()
.setColor('#03cffc')
.setTitle('Ping!')
.setDescription(`${message.author.username} is playing a game! \n \n Playing With: \n ` + isPlaying);
message.channel.send(pingEmbed)
.then(sentEmbed => {
sentEmbed.react("👍")
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
})
}
Related
How to make clicks non-repeatable?
If i click an emotion multiple times, i can launch the max value of collection even though it is removed at 'messageReactionRemove'.
setTimeout(() => {
message.channel.send({ embeds: [messageRollWin] })
.then(async function (message) {
await message.react("👎");
const filter = (reaction, user) => {
return reaction.emoji.name === '👎';
};
const collector = message.createReactionCollector({ filter, max: 4, errors: ['time'] });
client.on('messageReactionAdd', (reaction, user) => {
console.log(reaction.count)
});
client.on('messageReactionRemove', (reaction, user) => {
console.log(reaction.count)
console.log(user.username)
});
collector.on('end', collected => {
message.channel.send({ embeds: [messageCountDislike] })
});
})
.catch("err");
}, 5000);
Thanks for the help, I forgot to make them asynchronous, and add await to reaction add / remove.
await client.on('messageReactionAdd')
Firstly you are using client.on incorrectly.
You will need to change the 2 client.on collector values to collector.on which is what you did on the end collector.
You will also need to change messageReactionAdd to collect and messageReactionRemove to `remove.
Correct code:
setTimeout(() => {
message.channel.send({ embeds: [messageRollWin] })
.then(async function (message) {
await message.react("👎");
const filter = (reaction, user) => {
return reaction.emoji.name === '👎';
};
const collector = message.createReactionCollector({ filter, max: 4, errors: ['time'] });
collector.on('collect', (reaction, user) => {
console.log(reaction.count)
});
collector.on('remove', (reaction, user) => {
console.log(reaction.count)
console.log(user.username)
});
collector.on('end', collected => {
message.channel.send({ embeds: [messageCountDislike] })
});
})
.catch("err");
}, 5000);
You can find more information about collectors here - https://discordjs.guide/popular-topics/collectors.html#message-collectors
I have written this code in my Bot and it doesn't work properly. The function awaitReactions() is always timing out:
message.channel.send({ embed: hEmbed }).then(embedreacted => {
embedreacted.react('👍').then(() => embedreacted.react('👎'));
const filter = (reaction, user) => {
console.log("user \n" + user)
return ['👍', '👎'].includes(reaction.emoji.name) && user.id === message.author.id;
};
embedreacted.awaitReactions(filter, { max: 1, time: 20000, errors: ['time'] })
.then(collected => {
console.log("col" + collected)
const reaction = collected.first();
if (reaction.emoji.name == '👍') {
let hlembed = new Discord.MessageEmbed()
Embed
embedreacted.edit({ embed: hlembed });
} else if (reaction.emoji.name === '👎') {
let hfEmbed = new Discord.MessageEmbed()
Embed
embedreacted.edit({ embed: hfEmbed });
}
for (const [key, value] of Object.entries(reaction)) {
console.log(key, value);
}
})
.catch(collected => {
console.log("collected \n" + collected.keys())
});
In your filter function:
const filter = (reaction, user) => {
console.log("user \n" + user)
return ['👍', '👎'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.author.id is the bot's user ID, because the message to which the reactions are being "awaited" was created by the bot. So the condition user.id === message.author.id will only trigger when the bot's user reacts to it.
I'm not sure if this is what you want but if you want it to only trigger when a user reacts to it (and not the bot itself) just do user.id !== <Client>.user.id or even user.id !== message.author.id as a shortcut.
If you wish to receive a reaction only from the user that created a prior message to this one, you need to set that <Message> object to a variable and then use user.id === variable.author.id
I am trying to make it so when you get to a certain amount of reactions my bot will send a message and if somebody can help here is my code
.then(function(sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.')).message.reactions.cache.get('👍').count;
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
message.awaitReactions(filter, { max: 2, time: 00, errors: ['time'] })
.then(collected => console.log(collected.size))
.catch(collected => {
console.log(`After a minute, only ${collected.size} out of 4 reacted.`);
});
});
})
Instead of awaitReactions, you could also use createReactionCollector which is probably easier to use and its collector.on() listeners are more readable than awaitReactions's then() and catch() methods.
You won't need to use message.reactions.cache.get('👍').count to check the number of reactions, as the end event fires when you reached the maximum and you can send a message inside that.
Also, in your filter, you don't need to check if user.id === message.author.id as you will want to accept reactions from other users. However, you can check if !user.bot to make sure that you won't count the bot's reaction. You can also remove the time option if you don't want to limit the time your bot collects reactions.
Another error was that you called .awaitReactions() on the message itself not the sentMessage.
Check out the working code below:
// v12
client.on('message', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector(filter, {
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
If you're using discord.js v13, there are a couple of changes:
you'll need to add the GUILD_MESSAGE_REACTIONS intents
the message event is now messageCreate
the collector's filter is inside the options object
// v13
const { Client, Intents } = require('discord.js');
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
],
});
const prefix = '!';
client.on('messageCreate', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector({
filter,
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
And the result:
You want to check the collected.size with an if statement like so:
let amount = 4; // any integer
if (collected.size /* returns an integer */ === amount) {
console.log(`Got ${amount} reactions`)
}
Hope I got the issue right.
If I understand it correctly, then you can just change the parameters for the awaitMessage method. You can remove the time: 00, errors: ['time'] arguments since they're optional and keep the max: 2. That way, the function will only finish once there are 2 reactions (in this case).
I would recommend removing the user.id === message.author.id; from the filter since it seems like you want multiple users to react to the message.
For more information, you can check the discord.js guide or the documentation for awaitReactions.
Code:
message.channel.send("Message reacting to.").then(function (sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.'));
const filter = (reaction, user) => {
return reaction.emoji.name === '👍';
};
message.awaitReactions(filter, { max: 2 })
.then(collected => console.log(collected.size))
});
I made a bot where if you type a command it will send a message and if you react to that message it will send another message but if i run the command again and react to the first message it will send the message two times how can i fix that?
client.on('messageReactionAdd', async (reaction, user)=>{
if(user.bot) return;
if (reaction.emoji.name === '⛔') {
clearInterval(my_interval);
clearTimeout(my_timeout);
const exampleEmbed1 = new Discord.MessageEmbed()
.setColor('#fefefe')
.setTitle(`Your record was ${index}s!`)
.setAuthor(message.author.tag, message.author.avatarURL())
.setDescription('Bot made by tempacc')
if(run){
message.channel.send(exampleEmbed1);
index = 0;
message.member.voice.channel.leave();
run = false;
}else if(!run){
message.channel.send('You must start a speedrun before running this command!');
}
}
})
I suggested that you should use a reaction collector instead, but I will include an example here along with docs for anyone else wondering.
const filter = (reaction, user) => {
return reaction.emoji.name === '👍'; // Check reaction was a 👍 and not anything else
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
However where time is, you can also pass max, maxUsers or maxEmojis into this data object, for example:
const collector = message.createReactionCollector(filter, { maxUsers: 1 });
You can find more about the reaction collector here and more about the options here
I wanted to remove the user's reaction when he reacts, leaving only one, the bot's own
I've already seen some tutorials on this, but I haven't found this method
const test = new Discord.MessageEmbed()
.setColor("random")
.setTitle("help")
.setDescription(`**this a test**`)
message.channel.send(test).then(msg => {
msg.react('📚').then(r => {
msg.react('📌').then(r => {
})
})
const hiFilter = (reaction, user) => reaction.emoji.name === '📚' && user.id === message.author.id;
const hi2Filter = (reaction, user) => reaction.emoji.name === '📌' && user.id === message.author.id;
const edit = msg.createReactionCollector(hiFilter);
const edit2 = msg.createReactionCollector(hi2Filter);
edit.on('collect', r2 => {
test.setTitle("test edited")
test.setDescription("edited")
msg.edit(test)
})
})
This code removes the reaction if the ID of the user that added the reaction is not your bot's ID. Replace <Client> with whatever you've declared your Discord client as.
edit.on('collect', (r2, user) => {
if (user.id !== <Client>.user.id) r2.remove().catch(console.log);
test.setTitle("test edited");
test.setDescription("edited");
msg.edit(test);
});