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

Enhancing Win8 apps with AppendTo/jquery-win8

Recently, I've been intrigued by the ToDoMVC samples and decided to try porting them into a Windows 8 JS app. I thought it would be as simple as copying and pasting the code while making sure to reference the necessary WinJS libraries. However, I soo ...

Use JQuery to reverse the most recent button click

Here is the code snippet I am working with: <button class="btn">New York</button> <button class="btn">Amsterdam</button> <button class="btn">New Jersey</button> <button class="btn&qu ...

Using JavaScript, aim for a specific element by its anchor headline

I'm looking to make some changes to my navigation menu, specifically hiding the home menu item unless the mobile navigation menu is toggled. Is there a way for me to target the "home" anchor title and apply the active class to it when toggled, similar ...

Creating dual permission menus for two different roles in Vue JS 3

This is my router file checking which role is logged in: router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAdmin)) { if(VueJwtDecode.decode(localStorage.getItem('accessToken')).sub == &quo ...

Tips for steering clear of getting caught in the initial focus trap

I have implemented Focus-trap (https://www.npmjs.com/package/focus-trap) in my modal to enhance keyboard accessibility. Here is a snippet of my code: <FocusTrap focusTrapOptions={{onDeactivate: onClose}} > <div> ... </div> <Focu ...

When the button is clicked, (ngSubmit) will be triggered

In my Angular2 Form Component, I have implemented two buttons with different functionalities. Button Submit: This button submits all the values to the API. Button Add: This button adds an object to an array. Here are the two methods: onSubmit() { this. ...

Tips for avoiding html entities in a string

To prevent any user-entered content from being interpreted as HTML, I need to escape it so that special characters like < become < in the markup. However, I still want to wrap the escaped content with actual HTML tags. The goal is to ensure that the ...

"Troubleshooting ReactionRole Functionality in Discord using JavaScript with Discord

I'm currently working on setting up a reaction role feature for my Discord bot using JavaScript. I've encountered an issue where the embed message is sent successfully, but nothing happens when someone reacts to the emoji. I've tried trouble ...

Enhance your slideshows with React-slick: Integrate captivating animations

I recently built a slider using react slick, and now there is a need to adjust the transition and animation of slides when the previous and next buttons are clicked. I received some advice to add a class to the currently active slide while changing slide ...

displaying information in table cells with jquery

Is there a way to display a table inside a td element with an on-click function without showing all tables in the same column when the function is triggered? I want the table to be shown only for the specific td that was clicked. $(document).ready(funct ...

Initiate the countdown when the button is pushed

Recently ran into an issue where a button triggers a command to a Perl script, causing the page to continuously load for 60 seconds. To provide users with transparency on when the Perl script will be finished running, I implemented a JavaScript countdown t ...

Need to obtain the stack trace from the catch block in a request-p

Currently, I am utilizing the 'request-promise' library in my node-js application for making API calls. However, I am facing challenges in obtaining the correct call stack from the 'catch' function. Upon experimenting with it, I discove ...

Leverage the TypeScript compiler's output from a .NET library within a Blazor application by referencing it

I am currently facing an issue with three different levels: Main Issue: I have developed a Blazor WebAssembly (WASM) application that requires JavaScript, but I prefer to use TypeScript. To address this, I have added a tsconfig file and the TypeScript cod ...

Issues with functionality of React/NextJS audio player buttons arise following implementation of a state

I am currently customizing an Audio Player component in a NextJs application using the ReactAudioPlayer package. However, the standard Import Next/Audio and using just <Audio> without props did not yield the expected results. The player functions as ...

Is the value incorrect when using angular's ng-repeat?

Currently iterating through an array nested within an array of objects like this: <div ng-repeat="benefit in oe.oeBenefits"> <div class="oeInfo" style="clear: both;"> <div class="col-md-2 oeCol"> <img style="he ...

Transform JSON String into Object using jQuery

Recently, I came across a JSON String in this format. {"label":"label","label1":"67041","label2":"745","label3":"45191","label4":"11‌​464"} I needed to convert it into an object structure like this [{"label":"label","label1":"67041","label2":"745"," ...

Is there a method in TypeScript to make an enum more dynamic by parameterizing it?

I've defined this enum in our codebase. enum EventDesc { EVENT1 = 'event 1', EVENT2 = 'event 2', EVENT3 = 'event 3' } The backend has EVENT1, EVENT2, EVENT3 as event types. On the UI, we display event 1, event 2, a ...

Executing JavaScript Code Through Links Created Dynamically

I am currently developing a website with a blog-style layout that retrieves information from a database to generate each post dynamically. After all posts are created, the header of each post will trigger an overlaid div displaying the full article for tha ...

What is the proper way to implement parameters and dependency injection within a service?

My objective is to achieve the following: (function(){angular.module('app').factory("loadDataForStep",ls); ls.$inject = ['$scope','stepIndex'] function ls ($scope, stepIndex) { if ($routeParams ...

Is there a way to include multiple parameters in message.content?

Seeking assistance with my code. Today, I delved into coding my inaugural Discord bot using Node.JS and the Discord.JS library, among others. For guidance, I am currently following a YouTube video on Node.JS. Here's my query. Presented below is my ex ...