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

如何触发for循环中对应独立表单?解决按钮仅首个生效问题

解决Razor循环渲染多表单时按钮触发异常的问题

问题场景

我正在设计一个支持用户间发送好友请求的页面,搜索结果中的每个用户对应一个按钮,点击按钮即可向该用户发送连接请求。但使用for循环渲染表单时,点击首个按钮以外的按钮会返回null,需要实现每个按钮仅触发所在的表单提交。

原有代码

Razor视图代码

@model IList<UserViewModel>

@for (int i = 0; i < Model.Count; i++)
{
    <form id="@i" method="post">
        <table>
            <tr>
                <td>@Model[i].Name</td>
                <td>@Model[i].Surname</td>
            </tr>
            <tr>
                <td colspan="2"><input asp-for="@Model[i].UserName">@Model[i].UserName</td>
            </tr>
        </table>
        <button onclick="btn(@i)" asp-controller="Connection" asp-action="AddConnection" formmethod="post" >Add</button>
    </form>
}

JavaScript代码

<script>
function btn(iteration) {
    let formDOM = document.querySelector(`#${iteration}`)
    formDOM.addEventListener('submit', formSubmit)
}
function formSubmit(event) {
    event.preventDefault()
}
</script>

问题原因

  1. Razor循环闭包问题:for循环中的变量i是共享的,渲染完成后所有表单绑定的Model[i]都会指向最后一个元素,导致后端接收的数据异常。
  2. 事件绑定混乱:通过按钮onclick动态绑定submit事件,会重复绑定事件,且无法确保事件正确关联到目标表单。
  3. 表单元素属性冲突:asp-for生成的input name属性重复,后端无法区分不同表单提交的数据。

修复方案

修改后的Razor视图代码

@model IList<UserViewModel>

@for (int i = 0; i < Model.Count; i++)
{
    // 捕获当前循环索引,避免闭包共享变量问题
    var currentIndex = i;
    <!-- 给表单设置唯一ID,同时指定提交的控制器和动作 -->
    <form id="connection-form-@currentIndex" method="post" 
          asp-controller="Connection" asp-action="AddConnection">
        <table>
            <tr>
                <td>@Model[currentIndex].Name</td>
                <td>@Model[currentIndex].Surname</td>
            </tr>
            <tr>
                <td colspan="2">
                    <!-- 使用hidden类型传递UserName,避免重复可视输入框 -->
                    <input type="hidden" asp-for="@Model[currentIndex].UserName" />
                    @Model[currentIndex].UserName
                </td>
            </tr>
        </table>
        <!-- 按钮默认type为submit,点击自动提交所在表单,无需额外onclick -->
        <button type="submit">Add</button>
    </form>
}

优化后的JavaScript代码(如需异步提交)

<script>
// 使用事件委托统一处理所有表单提交,避免重复绑定
document.addEventListener('submit', function(event) {
    const form = event.target;
    // 仅处理我们的连接请求表单
    if (form.id.startsWith('connection-form-')) {
        event.preventDefault();
        
        // 异步提交表单数据
        fetch(form.action, {
            method: form.method,
            body: new FormData(form)
        })
        .then(response => {
            if (response.ok) {
                console.log('好友请求已发送');
                // 可添加成功后的UI更新,比如隐藏按钮
                form.querySelector('button').disabled = true;
                form.querySelector('button').textContent = '已发送';
            }
        })
        .catch(error => {
            console.error('发送请求失败:', error);
        });
    }
});
</script>

修改说明

  1. 捕获循环索引:通过var currentIndex = i保存当前循环的索引,确保每个表单绑定的是当前用户的数据,解决Razor闭包导致的变量共享问题。
  2. 唯一表单ID:给每个表单设置以connection-form-为前缀的唯一ID,方便后续事件处理区分。
  3. 隐藏输入传递数据:将asp-for的input改为hidden类型,既保留数据传递功能,又避免重复的可视输入框。
  4. 简化按钮逻辑:移除按钮的onclick和formmethod属性,利用按钮默认的submit行为自动提交所在表单。
  5. 事件委托处理提交:使用事件委托监听全局submit事件,统一处理所有表单的提交,避免重复绑定事件,同时确保能正确获取触发提交的表单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:39:22