I handle a channelDelete event in my discord bot. My original intent was to do the following:
I can typically access channels under a CategoryChannel
through its property called children
anywhere else except during this event...
module.exports = {
name: 'channelDelete',
once: false,
async execute(channel) {
if(channel.type == 'GUILD_CATEGORY')
for(let [child_id, child] of channel.children)
if (child.deletable) child.delete();
},
}
I can confirm the code is being executed, but the problem is that the incoming channel object is in a state where it is already deleted, and I cannot get the children:
deleted: true
children
property is empty, even though I know there were channels in that channel category prior to deletionIs there a way for my bot to collect and handle the children of a CategoryChannel
prior to its deletion?
Unfortunately, this is how CategoryChannels work in discord.js...
When the category is deleted, discord.js sends a request to the API to delete the channel. Only then, Discord sends you the event after the category is deleted.
What happens next is that the children are not located in the category anymore! So you will not be able to get the children inside the CategoryChannel object.
This is the code for the children
property
get children() {
return this.guild.channels.cache.filter(c => c.parentId === this.id);
}
It filters the channels which are in the guild, but those children channels are not located in the category anymore. Which is the reason the property is empty.
This will require caching the channels themselves. As there aren't really any other solutions.
You may cache the channels in different ways.
Just remember... there are instances and references in Javascript, and failure to acknowledge may lead to weird behaviors. The following code only works for small bots without sharding, just so you know.
const cachedChannels = new Map()
client.on('ready', () => {
// Looping thru guilds...
client.guilds.forEach((guild) => {
// Filtering the channels to category channels only and looping thru them...
guild.channels.filter((channel) => channel.type === "GUILD_CATEGORY").forEach((category) => {
// Note on references and instances: Numbers, Strings and Booleans do not have instances like Object, Arrays, etc. do
// We are using an array here to abuse the references
cachedChannels.set(category.id, [])
// Looping thru the children channels...
category.children.forEach((children) => {
// This is the array we've created earlier
const storedChannels = cachedChannels.get(category.id)
// Pushing the ID so we can fetch them later
storedChannels.push(children.id)
})
})
})
})
client.on('channelDelete', (channel) => {
if (channel.type === "GUILD_CATEGORY") {
// Looping thru our cached channel IDs defined earlier
cachedChannels.get(channel.id).forEach((id) => {
const child = channel.guild.channels.get(id)
child.delete()
})
// Delete the cached IDs to save memory
cachedChannels.delete(channel.id)
}
})