You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js 14.22.1含选择菜单的模态组件提交报错排查

问题原因与解决方案

错误根源

你遇到的cannot read properties of undefined (reading 'forEach')错误,核心原因是手动构建的Modal组件结构完全不符合Discord API规范,导致Discord.js解析提交后的交互数据时出现异常。具体问题包括:

  • 错误使用了不存在的组件类型type:18,模态中的行组件类型应为1(即ActionRow);
  • 错误用component字段包裹子组件,正确结构是将子组件放在ActionRow的components数组中;
  • 未遵循模态组件规则:每个ActionRow只能包含一个组件(文本输入或选择菜单)。

修正后的代码

使用Discord.js官方推荐的Builder类构建模态组件,避免手动拼写字段出错:

const {
  SlashCommandBuilder,
  ModalBuilder,
  ActionRowBuilder,
  TextInputBuilder,
  TextInputStyle,
  StringSelectMenuBuilder,
  UserSelectMenuBuilder,
  ChannelSelectMenuBuilder,
  ComponentType
} = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('testmodal')
    .setDescription('Opens a modal with all supported input types'),

  async execute(interaction) {
    // 构建模态
    const modal = new ModalBuilder()
      .setCustomId('test_modal_inputs')
      .setTitle('Test Modal Inputs')
      // 添加各类组件行
      .addComponents(
        new ActionRowBuilder().addComponents(
          new TextInputBuilder()
            .setCustomId('construction_speed')
            .setLabel('Construction Speed (%)')
            .setStyle(TextInputStyle.Short)
            .setPlaceholder('e.g. 0 or 15')
            .setRequired(false)
        ),
        new ActionRowBuilder().addComponents(
          new TextInputBuilder()
            .setCustomId('notes')
            .setLabel('Notes or Comments')
            .setStyle(TextInputStyle.Paragraph)
            .setPlaceholder('Optional notes...')
            .setRequired(false)
        ),
        new ActionRowBuilder().addComponents(
          new StringSelectMenuBuilder()
            .setCustomId('buffs_select')
            .setPlaceholder('Select all that apply')
            .setMinValues(0)
            .setMaxValues(3)
            .setOptions([
              { label: 'VP Buff', value: 'vp' },
              { label: 'Mercantilism Buff', value: 'merc' },
              { label: 'Double Time Buff', value: 'double' }
            ])
        ),
        new ActionRowBuilder().addComponents(
          new UserSelectMenuBuilder()
            .setCustomId('user_select')
            .setPlaceholder('Pick a user')
        ),
        new ActionRowBuilder().addComponents(
          new ChannelSelectMenuBuilder()
            .setCustomId('channel_select')
            .setPlaceholder('Pick a channel')
        )
      );

    await interaction.showModal(modal);
  },

  async handleModalSubmit(interaction) {
    const fields = getModalFieldValues(interaction);

    const speed = fields.construction_speed || '0';
    const notes = fields.notes || 'None';
    const buffs = fields.buffs_select?.join(', ') || 'None';
    const user = fields.user_select?.map(u => `<@${u}>`).join(', ') || 'None';
    const channel = fields.channel_select?.map(c => `<#${c}>`).join(', ') || 'None';

    await interaction.reply({
      content: `**Construction Speed:** ${speed}%\n**Notes:** ${notes}\n**Buffs Applied:** ${buffs}\n**Selected User:** ${user}\n**Selected Channel:** ${channel}`,
      flags: 64
    });
  }
};

function getModalFieldValues(interaction) {
  const values = {};

  for (const row of interaction.components ?? []) {
    for (const comp of row.components ?? []) {
      const id = comp.customId;
      if (!id) continue;

      if (comp.type === ComponentType.TextInput) {
        values[id] = comp.value ?? '';
      } else if (
        [
          ComponentType.StringSelect,
          ComponentType.UserSelect,
          ComponentType.ChannelSelect,
          ComponentType.RoleSelect,
          ComponentType.MentionableSelect
        ].includes(comp.type)
      ) {
        values[id] = comp.values ?? [];
      }
    }
  }

  return values;
}

额外说明

  1. Discord.js 14.22.1确实支持模态中的选择菜单组件,但必须严格遵循API结构规范;
  2. Builder类会自动处理字段名转换(如customId转custom_id)和结构验证,大幅降低手动构建的出错概率;
  3. 确保机器人已正确注册模态提交事件监听器,例如在主文件中添加:
client.on('interactionCreate', async interaction => {
  if (interaction.isModalSubmit()) {
    const command = interaction.client.commands.get('testmodal');
    if (command?.handleModalSubmit) {
      await command.handleModalSubmit(interaction);
    }
  }
});

内容的提问来源于stack exchange,提问作者UnsureCoding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 08:29:50