aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord-bots

Discord Autocomplete: dynamische suggesties voor slash-commando's

Discord autocomplete is de functie waarmee je directe, dynamische suggesties kunt tonen voor een optie van een slash-commando terwijl de gebruiker typt. Een statische keuzelijst (choices) is beperkt tot 25 items en volledig vast, terwijl je met autocomplete de suggestielijst bij elke toetsaanslag zelf genereert: een live zoekopdracht in de database, resultaten uit een API, of data die specifiek voor de server van de gebruiker is gefilterd. In dit artikel bouwen we een autocomplete-systeem vanaf nul met discord.js v14, en behandelen we elke stap: autocomplete inschakelen op een commando-optie, de interactie binnen het strikte venster van 3 seconden beantwoorden, en grote datasets slim filteren.

Wanneer heb je autocomplete nodig?

De vaste methode addChoices() van Discord is perfect voor kleine, onveranderlijke lijsten: rood, groen en blauw op een optie "kleur", bijvoorbeeld. Maar ze schiet tekort in deze gevallen:

  • Het aantal opties is groter dan 25 (Discords harde limiet voor statische keuzes).
  • De lijst is dynamisch: de eigen items van de gebruiker, records in een database, live API-resultaten.
  • De lijst is server- of gebruikerspecifiek: elke server heeft andere tags, elke gebruiker een eigen afspeellijst.

Hier komt autocomplete in beeld. Wanneer de gebruiker begint te typen, ontvangt de bot de huidige invoer, voert zijn eigen logica uit en stuurt maximaal 25 suggesties terug. Suggesties zijn puur visueel; de gebruiker kan nog steeds een waarde typen en versturen die niet in de lijst staat, dus je moet de binnenkomende waarde altijd valideren bij het verwerken van het commando.

Autocomplete inschakelen op een commando-optie

De eerste stap is .setAutocomplete(true) toevoegen aan de betreffende optie in je slash-commandodefinitie. Een belangrijke beperking: je kunt niet zowel setChoices als autocomplete op dezelfde optie gebruiken; je moet er één kiezen. Autocomplete werkt alleen op opties van het type string, integer en number.

const { SlashCommandBuilder } = require('discord.js');

const data = new SlashCommandBuilder()
  .setName('zoek')
  .setDescription('Zoek een item op naam')
  .addStringOption(option =>
    option
      .setName('naam')
      .setDescription('De naam van het item dat je zoekt')
      .setRequired(true)
      .setAutocomplete(true));   // dynamische suggesties in plaats van statische keuzes

module.exports = { data, execute };

Zodra je het commando bij Discord registreert (globaal of per guild), schakelt deze optie over naar de autocomplete-modus. Op het moment dat de gebruiker in de optie begint te typen, stuurt Discord je bot een interactie van een ander type dan een normale commando-uitvoering, en die moeten we op een aparte plek opvangen.

De autocomplete-interactie beantwoorden

De gebeurtenis die afgaat terwijl de gebruiker typt, is geen ChatInputCommandInteraction maar een AutocompleteInteraction. In je interactionCreate-listener moet je dus eerst op het type vertakken. Je leest de huidige waarde van de gefocuste optie met interaction.options.getFocused() en stuurt de suggesties terug met interaction.respond():

client.on('interactionCreate', async (interaction) => {
  // Normale commando's
  if (interaction.isChatInputCommand()) {
    const command = client.commands.get(interaction.commandName);
    return command?.execute(interaction);
  }

  // Autocomplete-verzoeken
  if (interaction.isAutocomplete()) {
    const command = client.commands.get(interaction.commandName);
    if (command?.autocomplete) {
      try {
        await command.autocomplete(interaction);
      } catch (err) {
        console.error('Autocomplete-fout:', err);
      }
    }
  }
});

We voegen aan elk commandobestand een autocomplete-functie toe, naast de gebruikelijke execute-functie. Zo houdt elk commando zijn eigen suggestielogica in zichzelf besloten:

async function autocomplete(interaction) {
  const focused = interaction.options.getFocused();   // de tekst die de gebruiker typte (string)

  const items = ['Zwaard', 'Schild', 'Drankje', 'Boog', 'Staf', 'Harnas'];

  const filtered = items
    .filter(item => item.toLowerCase().startsWith(focused.toLowerCase()))
    .slice(0, 25);   // Discord accepteert maximaal 25 suggesties

  await interaction.respond(
    filtered.map(item => ({ name: item, value: item }))
  );
}

Elke suggestie is een object van de vorm { name, value }. name is het label dat de gebruiker ziet (max 100 tekens), terwijl value de werkelijke waarde is die je in execute ontvangt wanneer het commando draait. Het type van value moet overeenkomen met het optietype: een string voor een string-optie, een getal voor een integer-optie. Deze scheiding is erg handig; je kunt "Gebruikersnaam" tonen aan de gebruiker terwijl je op de achtergrond een echte id als waarde verstuurt.

Dynamische suggesties uit een database genereren

De echte kracht van autocomplete is suggesties voeden vanuit een live databron. Stel dat we tags suggereren die de gebruiker zelf heeft aangemaakt. De zoekopdracht aan de SQL-kant doen met LIKE en het resultaat direct tot 25 beperken blijft snel, zelfs bij duizenden records:

async function autocomplete(interaction) {
  const focused = interaction.options.getFocused();

  // better-sqlite3-voorbeeld — alleen de tags van deze server
  const rows = db.prepare(
    `SELECT name, id FROM tags
     WHERE guild_id = ? AND name LIKE ?
     ORDER BY name LIMIT 25`
  ).all(interaction.guildId, `${focused}%`);

  await interaction.respond(
    rows.map(row => ({ name: row.name, value: String(row.id) }))
  );
}

Er zijn hier twee kritieke punten. Ten eerste: laat de database het filteren doen: alle records in het geheugen trekken en in JavaScript zeven is traag bij grote tabellen; LIKE ? en LIMIT 25 geven het werk aan de DB. Ten tweede: toon een leesbare naam (name) aan de gebruiker terwijl je de unieke id (id) als waarde verstuurt; bij het verwerken van het commando vind je het record direct, zonder opnieuw te hoeven zoeken.

De 3-secondenregel, limieten en prestaties

Er zijn strikte regels die je bij autocomplete moet respecteren:

  • De 3-secondenlimiet: je moet de interactie binnen drie seconden met respond() beantwoorden, anders verwerpt Discord het verzoek. deferReply werkt hier niet; uitstellen kan niet. Je suggestie-query moet dus snel zijn.
  • De limiet van 25 items: kort de array altijd in met .slice(0, 25) of SQL LIMIT 25; meer geeft een fout.
  • Lege invoer: als de gebruiker nog niets heeft getypt, is focused een lege string. In dat geval geeft het tonen van de populairste of meest recente items een goede standaardervaring.

Terwijl de gebruiker snel typt, kan Discord bij elke toetsaanslag een nieuw verzoek sturen. Om te voorkomen dat deze verzoeken je bot belasten, helpen twee technieken: een kortlevende cache voor vaak opgevraagde resultaten (bijvoorbeeld een Map die een queryresultaat enkele seconden bewaart) en het beperken van de snelheid van je verzoeken als je een externe API gebruikt. Onthoud toch: validatie van de waarde hoort thuis in execute, want de gebruiker is niet verplicht uit de lijst te kiezen; hij kan het met de hand typen en versturen.

Veelgestelde vragen

Kan ik autocomplete en setChoices samen gebruiken?

Nee. Op één optie gebruik je ofwel statische setChoices() ofwel setAutocomplete(true); de twee kunnen niet samengaan, en de commandoregistratie wordt geweigerd als je het probeert. Als je lijst minder dan 25 items heeft en nooit verandert, is setChoices eenvoudiger. Is de lijst groot, dynamisch of gepersonaliseerd, stap dan over op autocomplete.

Kan ik er zeker van zijn dat de gebruiker een van de suggesties koos?

Nee, dat kun je niet garanderen. Suggesties zijn slechts een gemak; de gebruiker kan elke tekst typen die niet in de suggesties staat en op Enter drukken. Valideer de binnenkomende waarde dus altijd in de echte execute-functie van het commando: controleer of het record werkelijk bestaat en geef anders een vriendelijke foutmelding terug.

Hoe weet ik welke gefocuste optie wordt getypt?

Als een commando meerdere autocomplete-opties heeft, moet je weten welke gefocust is. De aanroep interaction.options.getFocused(true) (met true) geeft niet alleen de waarde terug maar het object { name, value }; uit het veld name lees je welke optie wordt getypt en genereer je de suggesties daarop.

Wil je slimme, snelle autocomplete-commando's voor je bot? Ik kan commando's bouwen met door een database ondersteunde live zoekopdrachten, caching en serverspecifieke suggesties. Neem contact op en laten we bespreken wat je nodig hebt.

Bu kategorideki tüm yazılar →

Devamı için