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
相关产品推荐
相关产品推荐

