A more efficient method for refreshing Discord Message Embeds using a MessageComponentInteraction collector to streamline updates

Currently, I am working on developing a horse race command for my discord bot using TypeScript. The code is functioning properly; however, there is an issue with updating an embed that displays the race and the participants. To ensure the update works correctly, I have to set its description every time the collector.on("collect") event occurs. I would like to inquire if there is a more efficient and cleaner method to handle this. Thank you!
code:

    const bet = interaction.options.get("bet").value;

    class Horse {
      name: string;
      owner: User;
      speed: number;
      position: Array<string>;
      constructor(name: string) {
        this.name = name;
        this.owner = null;
        this.speed = 0;
        this.position = ["🐴"];
      }
    }

    const horses = [
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: true })),
      new Horse(aimless.pick(names, { remove: false })),
    ];
    const hasJoined: Array<Horse["owner"]> = [];

    const row = new MessageActionRow();
    for (const horse of horses) {
      row.addComponents(
        new MessageButton()
          .setCustomId(horse.name)
          .setLabel(horse.name)
          .setStyle("SECONDARY")
      );
    }
    const embed = new MessageEmbed()
      .setTitle("Place your bets!")
      .setDescription(
        `**${horses[0].name} - ${
          horses[0].owner !== null ? horses[0].owner.username : "Nobody"
        } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
          horses[1].owner !== null ? horses[1].owner.username : "Nobody"
        }
        ${horses[1].position}
        
        ${horses[2].name} - ${
          horses[2].owner !== null ? horses[2].owner.username : "Nobody"
        }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
          horses[3].owner !== null ? horses[3].owner.username : "Nobody"
        }
        ${horses[3].position}**`
      );
    await interaction.editReply({
      embeds: [embed],
      components: [row],
    });
    const filter = async (i: MessageComponentInteraction) => {
      let profile: any;
      try {
        profile = await profileModel.findOne({ userID: i.user.id });
        if (!profile) {
          await profileModel.create({
            userID: i.user.id,
            serverID: i.guild?.id,
            username: i.user.username,
            bananas: 100,
            deposit: 0,
          });
          profile.save();
        }
      } catch (e) {
        await i.editReply("Something went wrong! :( Please retry.");
      } finally {
        if (hasJoined.includes(i.user)) {
          return false;
        }
        if (profile.bananas < bet) {
          interaction.editReply(`${i.user} you don't have enough bananas!`);
        }
        return profile.bananas >= bet;
      }
    };
    const collector = interaction.channel.createMessageComponentCollector({
      filter,
      time: 60000,
    });
    collector.on("collect", async (int) => {
      await int.deferUpdate();
      for (const btn of row.components) {
        if (btn.customId === (int.component as MessageButton).customId) {
          (btn as MessageButton).setDisabled(true).setStyle("SUCCESS");
          hasJoined.push(int.user);
          horses.find((h) => h.name === btn.customId).owner = int.user;
          console.log(horses);
        }
      }

      embed.setDescription(
        `**${horses[0].name} - ${
          horses[0].owner !== null ? horses[0].owner.username : "Nobody"
        } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
          horses[1].owner !== null ? horses[1].owner.username : "Nobody"
        }
        ${horses[1].position}
        
        ${horses[2].name} - ${
          horses[2].owner !== null ? horses[2].owner.username : "Nobody"
        }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
          horses[3].owner !== null ? horses[3].owner.username : "Nobody"
        }
        ${horses[3].position}**`
      );

      await int.editReply({
        embeds: [embed],
        components: [row],
      });
    });
  },
});`

Answer №1

One way to simplify this code is by turning it into a function:

const displayHorses = (horses: Array<Horse>) => {
  return `**${horses[0].name} - ${
    horses[0].owner !== null ? horses[0].owner.username : "Nobody"
  } 
        ${horses[0].position}
        
        ${horses[1].name} - ${
    horses[1].owner !== null ? horses[1].owner.username : "Nobody"
  }
        ${horses[1].position}
        
        ${horses[2].name} - ${
    horses[2].owner !== null ? horses[2].owner.username : "Nobody"
  }
        ${horses[2].position} 
        
        ${horses[3].name} - ${
    horses[3].owner !== null ? horses[3].owner.username : "Nobody"
  }
        ${horses[3].position}**`;
};

Then, you can simply use this function each time like so:

embed.setDescription(displayHorses(horses));

To further condense the code, you can map through the horse array:

const displayHorses = (horses: Array<Horse>) => {
  return horses.map(
    ({ name, owner, position }) =>
      `**${name}** - ${owner !== null ? owner.username : "Nobody"}
     ${position}`
  );
};

Lastly, for those using version 14 and above, you can make it even more concise:

const displayHorses = (horses: Array<Horse>) => {
  return horses.map(
    ({ name, owner, position }) =>
    `**${name}** - ${owner?.username ?? "Nobody"}
     ${position}`
  );
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Conceal div elements and retain their status when the page is reloaded or switched

I currently have 3 div elements displayed on a webpage: header-div fixed_menu_div page_cont Each of these divs are styled with the following CSS properties: #header-div { top:0; left:0; display:inline; float:left; } #page_cont { mar ...

Node.js Request Encoding Using Google Translate

I have developed a node.js module to use the Google Translate API. module.exports = function(sourceText, sourceLang, targetLang, callback) { var qst = qs.stringify({ client: 'gtx', sl: sourceLang, tl: targetLang, ...

Ionic ion-view missing title issue

I'm having trouble getting the Ionic title to display on my page: http://codepen.io/hawkphil/pen/oXqgrZ?editors=101 While my code isn't an exact match with the Ionic example, I don't want to complicate things by adding multiple layers of st ...

regex execution and testing exhibiting inconsistent behavior

The regex I am using has some named groups and it seems to match perfectly fine when tested in isolation, but for some reason, it does not work as expected within my running application environment. Below is the regex code that works everywhere except in ...

Mastering the art of constraining TypeScript function parameters using interface properties

Hey there, I've been exploring ways to restrict a function parameter so that it only accepts "strings" related to interface properties, similar to what I achieved in the validate fields function: Please note: The TypeScript code provided here is simp ...

Are you experiencing a clash among various JS files in your WordPress installation?

I'm in a bit of a bind here. I've been tasked with working on a Wordpress website for a friend, using a free theme that he provided. Naturally, he wants some modifications made, so I've been editing the theme accordingly. The theme relies on ...

Issue with handsontable numbro library occurs exclusively in the production build

Encountering an error while attempting to add a row to my handsontable instance: core.js.pre-build-optimizer.js:15724 ERROR RangeError: toFixed() digits argument must be between 0 and 100 at Number.toFixed () at h (numbro.min.js.pre-build-op ...

Transmit a data element from the user interface to the server side without relying on the

I have developed a MEAN stack application. The backend of the application includes a file named api.js: var express = require('express') var router = express.Router(); var body = 'response.send("hello fixed")'; var F = new Function (" ...

Issue with the Z-Index property not functioning as expected on unordered lists within a dropdown menu

I have a dropdown menu that opens to the left, but it is displaying underneath the content. I attempted adjusting the z-index of the content to 1 and the dropdown to 2, however, this did not resolve the issue. Here is a sample in jsFiddle: https://jsfiddl ...

Get the contents inside the window.open using Javascript

First and foremost, I want to acknowledge that I understand the likelihood of this failing due to cross-domain restrictions - just seeking confirmation on that. Here's my approach: I have a window that I open using JavaScript. Subsequently, I make an ...

Refresh the content with an embedded iframe

I am attempting to update the body content by removing all existing content and inserting an iframe: function create_custom_iframe(target){ var iframe = document.createElement('iframe'); iframe.setAttribute('id', 'target_u ...

Tips for dynamically updating the id value while iterating through a class

Here's the HTML snippet I am working with: <div class="info"> <div class="form-group"> <label class="control-label col-sm-2">Title</label> <div class="col-xs-10 col-sm-8"> <inpu ...

Is there a way to consistently substitute a specific path parameter with a different value within node.js?

Snippet of my coding: router.get('/name/:name/height', (req,res) => { ... } router.get('/name/:name/weight', (req,res) => { ... } router.get('/age/:age/height', (req,res) => { ... } router.get('/ag ...

enable jQuery timer to persist even after page refresh

code: <div class="readTiming"> <time>00:00:00</time><br/> </div> <input type="hidden" name="readTime" id="readTime"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script&g ...

Struggling to get Ajax to function on IE8 with dropdowns, while other browsers are working perfectly fine

My AJAX code functions properly in most browsers, however, it is not performing well in IE. While it successfully creates an XMLHTTPRequest object, the data retrieved from my PHP script is only returning an empty list! Check out my JavaScript code: < ...

Tips for soothing the TypeScript compiler

It seems like TypeScript is heavily influenced by Microsoft's interpretation of the DOM and JavaScript. But what if I'm not concerned with Internet Explorer and Edge? Unfortunately, I'm encountering issues with TypeScript... For instance, w ...

Tips for keeping the most recently opened accordion in a group by using the is-open attribute to call a function

I have a dynamically populated accordion that updates every 15 seconds. I need to keep track of the last opened accordion group as the dataList can be very large and parsing it for each update is not feasible. Below is the code snippet from my HTML file: ...

Avoiding the capturing of events on $( document ).mousemove

Each time the browser detects a $( document ).mousemove event, my function is invoked. The performance is smooth with an empty page, but once I introduce a div element and hover over it, the function gets executed twice: first on the document and then agai ...

The appearance of an unforeseen * symbol caused a

Having issues with this particular line of code, import * as posenet from '@tensorflow-models/posenet' The error 'Uncaught SyntaxError: Unexpected token *' keeps popping up, I have the latest version of Chrome installed and I've ...

Error with object props in React using Typescript

Here's a scenario; I have a list of 'Reviews' that I am trying to render. The Proptype for these reviews is as follows: export interface Props { title: string; name: string; reviewdesc: string; rating: number; } In the pare ...