keijishi32
@keijishi32

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【discord.js】ButtonBuilderで行方を眩ませたinteraction.component

解決したいこと

ボタンを押したらButtonStyleを変え、他のボタンはそのまま保持する。
というコードを書いているのですが問題が発生しました。

(理想
image.png
アセントをタッチ!
image.png

発生している問題・エラー

TypeError: Cannot read properties of undefined (reading 'customId')
at Client.<anonymous> (/app/index.js:117:51)

該当するソースコード

console.logが多いのは初学者なのでデバックの使い方がわからいので...
生暖かい目で見てください。

 for (let i = 0; i < currentComponents.length; i++) {
      console.log("[" + i + "]");
      console.log("iの中", interaction.component.customId);
      for (let j = 0; j < currentComponents[i].components.length; j++) {
        console.log(
          "[" + i + "]" + "[" + j + "]" +
            currentComponents[i].components[j].customId
        );
        console.log("jの中", interaction.component.customId);
        if (
          interaction.component.customId ==
          currentComponents[i].components[j].customId
        ) {
          console.log("ifの中", interaction.component.customId); //ここまで存在する。
          const newButton = new ButtonBuilder()
            .setCustomId(interaction.component.customId) //ここには存在しない。
            .setLabel(interaction.component.label);
         await console.log("ifの中2", interaction.component.customId);
          if (currentStyle === ButtonStyle.Success) {
            console.log("successの中", interaction.component.customId);
            newButton.setStyle(ButtonStyle.Danger); // スタイルを変更
          } else if (currentStyle === ButtonStyle.Danger) {
            newButton.setStyle(ButtonStyle.Success); // スタイルを変更
          }
          await console.log("ifの中3", interaction.component.customId);
          currentComponents[i].components[j] = newButton;
        }
        console.log("jの中2", interaction.component.customId);
      }
      console.log("iの中2", interaction.component.customId);
    }

↓がボタン構造
image.png

3つのActionRowで制御。
下記イメージ

[
  ActionRow {
    components: [ [sunset], [bind], [icebox] ]
  },
  ActionRow {
    components: [ [haven], [split], [lotas] ]
  },
  ActionRow {
    components: [ [pearl], [fracture], [breeze], [ascent] ]
  }
]

「アセント」を押した際のコンソール

[0]
iの中 ascent
[0][0]sunset
jの中 ascent
jの中2 ascent
[0][1]bind
jの中 ascent
jの中2 ascent
[0][2]icebox
jの中 ascent
jの中2 ascent
iの中2 ascent
[1]
iの中 ascent
[1][0]haven
jの中 ascent
jの中2 ascent
[1][1]split
jの中 ascent
jの中2 ascent
[1][2]lotas
jの中 ascent
jの中2 ascent
iの中2 ascent
[2]
iの中 ascent
[2][0]pearl
jの中 ascent
jの中2 ascent
[2][1]fracture
jの中 ascent
jの中2 ascent
[2][2]breeze
jの中 ascent
jの中2 ascent
[2][3]ascent
jの中 ascent
ifの中 ascent
ifの中2 ascent
successの中 ascent
ifの中3 ascent

コンソールを見ると、ifの中には入れてるはずですが、エラー文を見るとif文の条件の interaction.component.customIdがundefindと表示されている状態。

また、if文の中の

const newButton = new ButtonBuilder()
            .setCustomId(interaction.component.customId) //ここには存在しない。
            .setLabel(interaction.component.label);

ここも存在undefindになるが、if文を抜けると颯爽と現れるinteraction.component

エラーの解決したいです、よろしくお願いいたします。

0

1Answer

Comments

  1. @keijishi32

    Questioner

    仰る通りです。

    index.js

    const {
      Client,
      GatewayIntentBits,
      ButtonBuilder,
      ButtonStyle,
    } = require("discord.js");
    
    const client = new Client({
      intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
        GatewayIntentBits.GuildMessageReactions,
        GatewayIntentBits.GuildMembers,
        GatewayIntentBits.GuildVoiceStates,
      ],
    });
    
    client.on("interactionCreate", async (interaction) => {
      if (interaction.isButton()) {
        const currentComponents = interaction.message.components;
        const currentComponent = interaction.component; // 現在のコンポーネントを取得
        console.log(currentComponents.length);
        console.log(currentComponents);
        if (!interaction.component) return; // interaction.componentが存在しない場合はreturn
        const currentStyle = interaction.component.style;
        console.log(currentStyle);
    
        let newComponents;
        for (let i = 0; i < currentComponents.length; i++) {
          console.log("[" + i + "]");
          console.log("iの中", interaction.component.customId);
          for (let j = 0; j < currentComponents[i].components.length; j++) {
            console.log(
              "[" +
                i +
                "]" +
                "[" +
                j +
                "]" +
                currentComponents[i].components[j].customId
            );
            console.log("jの中", interaction.component.customId);
            if (
              interaction.component.customId ==
              currentComponents[i].components[j].customId
            ) {
              console.log("ifの中", interaction.component.customId); //ここまで存在する。
              const newButton = new ButtonBuilder()
                .setCustomId(interaction.component.customId) //ここには存在しない。
                .setLabel(interaction.component.label);
             await console.log("ifの中2", interaction.component.customId);
              if (currentStyle === ButtonStyle.Success) {
                console.log("successの中", interaction.component.customId);
                newButton.setStyle(ButtonStyle.Danger); // スタイルを変更
              } else if (currentStyle === ButtonStyle.Danger) {
                newButton.setStyle(ButtonStyle.Success); // スタイルを変更
              }
              await console.log("ifの中3", interaction.component.customId);
              currentComponents[i].components[j] = newButton;
            }
            console.log("jの中2", interaction.component.customId);
          }
          console.log("iの中2", interaction.component.customId);
        }
        await interaction.update({
          components: currentComponents,
        });
      }
    });
    

    ボタンを作るコード
    maps.js

    const { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');
    
    module.exports = {
    	data: new SlashCommandBuilder()
    		.setName('maps')
    		.setDescription('マップ選択'),
    	async execute(interaction) {
    
    		const mapButtons = [
    			{ customId: 'sunset', label: 'サンセット' },
    			{ customId: 'bind', label: 'バインド' },
    			{ customId: 'icebox', label: 'アイスボックス' },
    			{ customId: 'haven', label: 'ヘイヴン' },
    			{ customId: 'split', label: 'スプリット' },
    			{ customId: 'lotas', label: 'ロータス' },
    			{ customId: 'pearl', label: 'パール' },
    			{ customId: 'fracture', label: 'フラクチャー' },
    			{ customId: 'breeze', label: 'ブリーズ' },
    			{ customId: 'ascent', label: 'アセント' }
    		];
    
    		const actionRows = [];
    
    		const actionRow1 = new ActionRowBuilder()
    			.addComponents(
    				new ButtonBuilder()
    					.setCustomId(mapButtons[0].customId)
    					.setLabel(mapButtons[0].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[1].customId)
    					.setLabel(mapButtons[1].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[2].customId)
    					.setLabel(mapButtons[2].label)
    					.setStyle(ButtonStyle.Success)
    			);
    
    		const actionRow2 = new ActionRowBuilder()
    			.addComponents(
    				new ButtonBuilder()
    					.setCustomId(mapButtons[3].customId)
    					.setLabel(mapButtons[3].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[4].customId)
    					.setLabel(mapButtons[4].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[5].customId)
    					.setLabel(mapButtons[5].label)
    					.setStyle(ButtonStyle.Success)
    			);
    
    		const actionRow3 = new ActionRowBuilder()
    			.addComponents(
    				new ButtonBuilder()
    					.setCustomId(mapButtons[6].customId)
    					.setLabel(mapButtons[6].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[7].customId)
    					.setLabel(mapButtons[7].label)
    					.setStyle(ButtonStyle.Success),
    				new ButtonBuilder()
    					.setCustomId(mapButtons[8].customId)
    					.setLabel(mapButtons[8].label)
    					.setStyle(ButtonStyle.Success),
            				new ButtonBuilder()
    					.setCustomId(mapButtons[9].customId)
    					.setLabel(mapButtons[9].label)
    					.setStyle(ButtonStyle.Success)
    			);
    
    
    		actionRows.push(actionRow1, actionRow2, actionRow3);
    
    		await interaction.reply({
    			content: `マップローテです`,
    			components: actionRows,
    		});
    	},
    };
    
    

    他にも必要な情報があればお申し付けください。

  2. コード見ました。

    client.on("interactionCreate", async (interaction) => {
    
        try {
            if (interaction.isButton()) {
                const currentComponents = interaction.message.components;
                const currentComponent = interaction.component; // 現在のコンポーネントを取得
                if (!interaction.component) return; // interaction.componentが存在しない場合はreturn
                const currentStyle = interaction.component.style;
    
                for (let i = 0; i < currentComponents.length; i++) {
                  for (let j = 0; j < currentComponents[i].components.length; j++) {
                    if (
                        currentComponent.customId == currentComponents[i].components[j].customId
                    ) {
                      const newButton = new ButtonBuilder()
                        .setCustomId(currentComponent.customId) //ここには存在しない。
                        .setLabel(currentComponent.label);
                      if (currentStyle === ButtonStyle.Success) {
                        newButton.setStyle(ButtonStyle.Danger); // スタイルを変更
                      } else if (currentStyle === ButtonStyle.Danger) {
                        newButton.setStyle(ButtonStyle.Success); // スタイルを変更
                      }
    
                      console.log(currentComponent); 
                      currentComponents[i].components[j] = newButton;
                      console.log(currentComponent); 
                    }
                  }
                }
                await interaction.update({
                  components: currentComponents,
                });
              }
        } catch (error) {
            console.log(error) ;
        }
    });
    

    もし、上のコードで行けるか確認できます?

  3. @keijishi32

    Questioner

    天才ですか?
    解決出来ました、ありがとうございます!!!!

    もしお手数でなければ
    どこが悪かったか、(原因)
    それを直す為に、どういう点を加えたか(実際の変更点)
    をご教授いただけると幸いです。

    宜しくお願い致します。

  4. すみません、答えが遅かったです。

    console.log(interaction.message.components);
    currentComponents[i].components[j] = newButton;
    console.log(interaction.message.components); 
    

    該当コードだけですが、こうしてコンソルを見ると結果が下のようになります。

    [
      ActionRow {
        data: { type: 1 },
        components: [ [ButtonComponent], [ButtonComponent], [ButtonComponent] ]
      },
      ActionRow {
        data: { type: 1 },
        components: [ [ButtonComponent], [ButtonComponent], [ButtonComponent] ]
      },
      ActionRow {
        data: { type: 1 },
        components: [
          [ButtonComponent],
          [ButtonComponent],
          [ButtonComponent],
          [ButtonComponent]
        ]
      }
    ]
    [
      ActionRow {
        data: { type: 1 },
        components: [ [ButtonComponent], [ButtonComponent], [ButtonComponent] ]
      },
      ActionRow {
        data: { type: 1 },
        components: [ [ButtonComponent], [ButtonComponent], [ButtonComponent] ]
      },
      ActionRow {
        data: { type: 1 },
        components: [
          [ButtonComponent],
          [ButtonBuilder],
          [ButtonComponent],
          [ButtonComponent]
        ]
      }
    ]
    

    結果を見ると、変わったボタンが「ButtonComponent」ではなくて「ButtonBuilder」になったですよね?
    それで「interaction.component」は該当の部分をShallow Copyしてるので「ButtonComponent」ではなくて「ButtonBuilder」でした。
    For文を回して、「interaction.component.customId」を参照する前に「ButtonComponent」ではなくて「ButtonBuilder」に変わってしまったのが原因です。

Your answer might help someone💌