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

ASP.NET foreach循环中asp-route因JS对话框始终传首个ID的问题求助

问题:删除列表项时自定义模态框始终传递首个ID

在Razor页面中通过foreach循环渲染后端数据列表,点击删除按钮弹出自定义<dialog>确认后,后端始终收到第一个列表项的ID,无法正确传递当前点击项的ID。需保留自定义模态框,不使用浏览器默认弹窗。


现有代码

HTML代码

<form method="post">
    <table class="table table-striped">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var experiment in Model.MainExperimentsTests)
        {
            <tr>
                <td>@experiment.Id</td>
                <td>@experiment.ExperimentTestName</td>
                <td>
                    <a class="btn permissionRead permissionWrite"
                       onclick="showDeleteDialog()">
                        <i class="bi-bucket"></i>
                    </a>
                    <dialog id="deleteDialog">
                        Do you really want to delete?
                        <button asp-page-handler="Delete" asp-route-experimentId="@experiment.Id"
                        value="confirm">Ok</button>
                        <button onclick="closeDeleteDialog()" type="reset">Cancel</button>
                    </dialog> </td>

            </tr>
        }

        </tbody>
    </table>
</form>

JavaScript代码

<script>
    function showDeleteDialog() {
        document.getElementById("deleteDialog").showModal();
    }
    function closeDeleteDialog() {
        document.getElementById("deleteDialog").close();
    }
</script>

问题根源

  • 所有循环生成的<dialog>都使用了同一个id="deleteDialog",getElementById只会返回页面中第一个匹配的元素,因此无论点击哪个删除按钮,打开的都是第一个列表项的对话框,提交时自然传递首个ID。
  • 删除按钮与对应对话框无关联,无法定位到当前点击项的弹窗。

解决方案

方案1:给每个对话框生成唯一ID(非AJAX方式)

通过为每个对话框生成带ID后缀的唯一标识,让删除按钮精准打开对应弹窗:

修改后的HTML

<form method="post">
    <table class="table table-striped">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var experiment in Model.MainExperimentsTests)
        {
            var dialogId = $"deleteDialog-{experiment.Id}";
            <tr>
                <td>@experiment.Id</td>
                <td>@experiment.ExperimentTestName</td>
                <td>
                    <a class="btn permissionRead permissionWrite"
                       onclick="showDeleteDialog('@dialogId')">
                        <i class="bi-bucket"></i>
                    </a>
                    <dialog id="@dialogId">
                        Do you really want to delete?
                        <button asp-page-handler="Delete" asp-route-experimentId="@experiment.Id"
                                value="confirm">Ok</button>
                        <button onclick="closeDeleteDialog('@dialogId')" type="reset">Cancel</button>
                    </dialog> 
                </td>
            </tr>
        }
        </tbody>
    </table>
</form>

修改后的JavaScript

<script>
    function showDeleteDialog(dialogId) {
        document.getElementById(dialogId).showModal();
    }
    function closeDeleteDialog(dialogId) {
        document.getElementById(dialogId).close();
    }
</script>

方案2:使用单个共享对话框+AJAX(无刷新删除)

若不想生成多个对话框,可使用全局弹窗,点击按钮时暂存当前ID,确认后通过AJAX提交:

修改后的HTML

<form method="post">
    <table class="table table-striped">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var experiment in Model.MainExperimentsTests)
        {
            <tr data-id="@experiment.Id">
                <td>@experiment.Id</td>
                <td>@experiment.ExperimentTestName</td>
                <td>
                    <a class="btn permissionRead permissionWrite delete-btn"
                       data-experiment-id="@experiment.Id">
                        <i class="bi-bucket"></i>
                    </a>
                </td>
            </tr>
        }
        </tbody>
    </table>
</form>

<!-- 单个共享对话框 -->
<dialog id="deleteDialog">
    Do you really want to delete?
    <button id="confirmDelete">Ok</button>
    <button onclick="closeDeleteDialog()" type="reset">Cancel</button>
</dialog>

修改后的JavaScript

<script>
    let currentDeleteId = null;
    const deleteBtnList = document.querySelectorAll('.delete-btn');
    const deleteDialog = document.getElementById('deleteDialog');
    const confirmBtn = document.getElementById('confirmDelete');

    // 绑定删除按钮点击事件
    deleteBtnList.forEach(btn => {
        btn.addEventListener('click', () => {
            currentDeleteId = btn.dataset.experimentId;
            deleteDialog.showModal();
        });
    });

    // 确认删除并AJAX提交
    confirmBtn.addEventListener('click', async () => {
        if (!currentDeleteId) return;

        try {
            // 构造Delete handler请求URL,带上防CSRF令牌
            const token = document.querySelector('input[name="__RequestVerificationToken"]').value;
            const response = await fetch(`?handler=Delete&experimentId=${currentDeleteId}`, {
                method: 'POST',
                headers: {
                    'RequestVerificationToken': token
                }
            });

            if (response.ok) {
                // 删除成功后移除对应行或刷新页面
                document.querySelector(`tr[data-id="${currentDeleteId}"]`).remove();
            } else {
                alert('删除失败');
            }
        } catch (error) {
            console.error(error);
            alert('删除出错');
        } finally {
            deleteDialog.close();
            currentDeleteId = null;
        }
    });

    function closeDeleteDialog() {
        deleteDialog.close();
        currentDeleteId = null;
    }
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:27:53