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

如何通过AJAX为多个表单内的相同下拉框正确填充选项

问题场景
  • 多个独立项目表单放置在Bootstrap手风琴(accordion)折叠组件中,每个表单包含一个经理选择下拉框
  • 期望通过接口拉取全局经理列表,为所有下拉框统一填充选项
  • 实际表现:仅第一个下拉框成功加载选项,其余下拉框无选项

现有代码

HTML(Razor视图)

@foreach (Project project in Model.Projects)
{
    <div class="accordion-item">
        <h2 class="accordion-header" id="@($"heading{project.Key}")">
            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" aria-expanded="false">
                <b> @project.Number- </b>: @project.Name
            </button>
        </h2>
        <div class="accordion-body">
            <form>
                <div class="mb-3 row">
                    <label for="manager" class="col-sm-1 col-form-label">Manager</label>
                    <div class="col-sm-3">
                        <select class="form-control capManager" asp-for="@project.Manager"></select>
                    </div>
                    <label for="budgetYear" class="col-sm-2 col-form-label" style="text-align: right">Budget Year</label>
                    <div class="col-sm-1">
                        <input type="text" class="form-control" asp-for="@project.BudgetYear">
                    </div>
                    <label for="budgetQuarter" class="col-sm-1 col-form-label">Quarter</label>
                    <div class="col-sm-1">
                        <input type="text" class="form-control" asp-for="@project.BudgetQuarter">
                    </div>
                    <div class="col-sm-3"></div>
                </div>
            </form>
        </div>
    </div>
}

Javascript

function populateManagerOptions() {
    //Populate Manager options
    $.ajax({
        url: '/Lookup/GetProjManagerData/',
        type: 'GET',
        data: {
            'reason': 'dropdown'
        },
        dataType: 'json',
        success: function (json) {
            const collection = document.getElementsByClassName("capManager");
            for (let i = 0; i < collection.length; i++) {
                $.each(json, function (i, value) {
                    collection[i].append($('<option>').text(value.mgrname).attr('value', value.projmgr));
                });
            }
        }
    });
}

后端Controller

[HttpGet]
public IActionResult GetProjManagerData(string reason)
{
   try
   {
       IEnumerable<TblProjmgr> codes = _context.TblProjmgr.AsEnumerable();
       if (reason == "dropdown")
           return Json(codes);
       else
           return Json(new { data = codes });
   }
   catch (Exception ex)
   {
       _logger.LogError(ex, DateTime.Now + "- Error occured during GetCauseData()");
       return Json(new { error = ex.Message.ToString() });
   }
}

问题根因

核心问题是两层循环的索引变量重名导致逻辑错乱:

  1. 外层for循环用变量i作为下拉框集合的遍历索引
  2. 内层$.each遍历经理列表时,回调函数的第一个参数也命名为i,根据作用域规则,内层的i会遮蔽外层的下拉框索引
  3. 内层执行collection[i].append()时,实际取的是经理项的索引来定位下拉框,导致选项错位追加、索引越界,最终只有第一个下拉框能拿到选项,其余下拉框无法正常填充

次要问题:

  • getElementsByClassName返回的是动态DOM集合,遍历过程中如果DOM变动会影响遍历结果,稳定性不足
  • Razor循环生成的labelfor属性和selectid重复,不符合HTML规范,影响无障碍访问

修复方案

1. 修复JS逻辑(必改)

重命名内层循环的索引变量避免冲突,同时优化DOM遍历方式,使用jQuery选择器获取静态元素集合,提前拼接选项字符串减少DOM操作,逻辑更稳定:

function populateManagerOptions() {
    $.ajax({
        url: '/Lookup/GetProjManagerData/',
        type: 'GET',
        data: { reason: 'dropdown' },
        dataType: 'json',
        success: function (managerList) {
            // 统一生成所有option字符串,减少重复DOM操作
            const optionHtml = managerList.map(mgr => 
                `<option value="${mgr.projmgr}">${mgr.mgrname}</option>`
            ).join('');
            // 批量给所有经理下拉框追加选项
            $('.capManager').append(optionHtml);
        }
    });
}

注意:请确保在DOM加载完成后再调用该函数,比如放在$(function() { populateManagerOptions() })中,或者放在页面底部脚本位置。Bootstrap手风琴折叠状态下的元素依然存在于DOM中,不需要等面板展开再填充。

2. 优化HTML规范(可选,建议修改)

给循环生成的select和对应label添加唯一标识,补全手风琴组件缺失的目标绑定属性,避免id/for属性重复,保证组件功能正常:

@foreach (Project project in Model.Projects)
{
    // 生成当前表单唯一前缀
    var formId = $"projectForm_{project.Key}";
    var collapseId = $"collapse{project.Key}";
    <div class="accordion-item">
        <h2 class="accordion-header" id="@($"heading{project.Key}")">
            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#@collapseId" aria-expanded="false" aria-controls="@collapseId">
                <b> @project.Number- </b>: @project.Name
            </button>
        </h2>
        <div id="@collapseId" class="accordion-collapse collapse" aria-labelledby="@($"heading{project.Key}")">
            <div class="accordion-body">
                <form>
                    <div class="mb-3 row">
                        <!-- 绑定唯一for/id -->
                        <label for="@($"{formId}_manager")" class="col-sm-1 col-form-label">Manager</label>
                        <div class="col-sm-3">
                            <select class="form-control capManager" id="@($"{formId}_manager")" asp-for="@project.Manager"></select>
                        </div>
                        <label for="@($"{formId}_budgetYear")" class="col-sm-2 col-form-label" style="text-align: right">Budget Year</label>
                        <div class="col-sm-1">
                            <input type="text" class="form-control" id="@($"{formId}_budgetYear")" asp-for="@project.BudgetYear">
                        </div>
                        <label for="@($"{formId}_budgetQuarter")" class="col-sm-1 col-form-label">Quarter</label>
                        <div class="col-sm-1">
                            <input type="text" class="form-control" id="@($"{formId}_budgetQuarter")" asp-for="@project.BudgetQuarter">
                        </div>
                        <div class="col-sm-3"></div>
                    </div>
                </form>
            </div>
        </div>
    </div>
}

3. 后端代码无需修改

现有Controller接口逻辑正常,可以正确返回经理列表数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 12:36:26