如何在ASP.NET局部视图间传递用户ID参数
解决ASP.NET中循环传递用户ID到模态框的问题
问题说明
在ASP.NET项目的店铺详情页员工列表局部视图中,添加了标记员工病假的模态框局部视图。尝试用ViewBag传递循环中的用户ID(u.Id),但循环结束后ViewBag仅保留最后一个用户的ID,导致模态框内的表单无法将正确的用户ID传递给AddSicknessTimeCard控制器操作。
原代码分析
员工列表局部视图
@model Shop <div class="mb-3 d-flex border-bottom align-items-center justify-content-between"> <h3 class="text-secondary">Employees in @Model.Name</h3> <a asp-condition=@User.IsInRole("admin") asp-controller="User" asp-action="Register" asp-route-id="@Model.Id" class="btn-add-employee" title="Add a new user"><i class="bi bi-person-fill-add" ></i></a> </div> <table class="table table-sm"> <thead> <tr> <th>Name</th> <th>Surname</th> <th>Role</th> <th>Edit Clock In-Out and Add Holiday Leave</th> <th>Sickness</th> <th></th> </tr> </thead> <tbody> @if (Model.Users.Count == 0) { <tr> <td colspan="4">No Employees...</td> </tr> } else { @foreach (var u in Model.Users) { var rowClass = "table-danger"; // Default to red // Get today's timecard for the user var todayTimeCard = u.TimeCards.Where(tc => tc.ClockIn.Date == DateTime.Today).OrderByDescending(tc => tc.ClockIn).FirstOrDefault(); if (todayTimeCard != null) { if (todayTimeCard.Holiday) { rowClass = "table-primary"; // Blue row for holiday } else if (todayTimeCard.Sickness) { rowClass = "table-warning"; // Yellow row for sickness } else { rowClass = "table-success"; // Green row for regular time card } } <tr class="@rowClass"> <td>@u.Name</td> <td>@u.LastName</td> <td>@u.Role</td> <td>@u.ShopId</td> <td> <a asp-condition=@User.HasOneOfRoles("manager,admin") asp-controller="User" asp-action="TimeCardLog" asp-route-id="@u.Id" class="btn"><i class="bi bi-pencil-fill"></i></a> </td> <td> @{ViewBag.UserId = u.Id;} <button asp-condition=@User.HasOneOfRoles("manager,admin") data-bs-toggle="modal" data-bs-target="#AddSicknessTimeCardModal" class="btn btn-sm btn-outline-warning"><i class="bi bi-emoji-frown" title="mark as sick"></i>Mark as Sick</button> </td> <td class="text-end"> <a asp-condition=@User.IsInRole("admin") asp-controller="User" asp-action="Edit" asp-route-id="@u.Id" class="btn btn-sm btn-outline-dark">Edit employee details</a> <br> <a asp-condition=@User.IsInRole("admin") asp-controller="User" asp-action="Delete" asp-route-id="@u.Id" class="buttondelete btn-sm btn-outline-danger"> <i class="bi bi-trash" title="Delete User"></i>Remove employee</a> <br> <a asp-condition=@User.IsInRole("admin") asp-controller="User" asp-action="ReassignShop" asp-route-id="@u.Id" class="buttondelete btn-sm btn-outline-danger"> <i class="bi bi-arrow-right" title="Reassign User"></i>Re-assign employee</a> </td> </tr> } } </tbody> </table> <!-- Mark as sickness Modal Confirmation --> <partial name="_AddSicknessTimeCardModal" />
模态框局部视图
<!-- Modal --> <div class="modal fade" id="AddSicknessTimeCardModal" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalLabel">Mark Absence</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="alert alert-warning"> <h3>Are you sure you want to mark this person as being sick today?</h3> </div> <div class="modal-footer"> <form asp-action="AddSicknessTimeCard" method="post" asp-route-id="@ViewBag.UserId"> <button type="submit" class="btn btn-primary" aria-label="add">Yes</button> <button type="button" class="btn btn-danger" data-bs-dismiss="modal">Cancel</button> </form> </div> </div> </div> </div> </div>
问题根源:ViewBag是服务器端全局对象,循环中每次赋值都会覆盖之前的值,而模态框是在循环结束后渲染的,因此只能获取到最后一次赋值的用户ID。
解决方案
方法一:用JavaScript动态设置表单参数
这种方法只保留一个模态框,通过按钮的自定义属性存储用户ID,在模态框显示时动态修改表单的参数。
- 修改员工列表中的按钮,添加
data-user-id属性存储当前用户ID:
<button asp-condition=@User.HasOneOfRoles("manager,admin") data-bs-toggle="modal" data-bs-target="#AddSicknessTimeCardModal" data-user-id="@u.Id" class="btn btn-sm btn-outline-warning"> <i class="bi bi-emoji-frown" title="mark as sick"></i>Mark as Sick </button>
- 修改模态框的表单,添加隐藏域用于存储用户ID:
<form id="sicknessForm" asp-action="AddSicknessTimeCard" method="post"> <input type="hidden" id="userIdInput" name="id" value=""> <button type="submit" class="btn btn-primary" aria-label="add">Yes</button> <button type="button" class="btn btn-danger" data-bs-dismiss="modal">Cancel</button> </form>
- 添加JavaScript监听模态框显示事件,动态设置隐藏域的值:
const sicknessModal = document.getElementById('AddSicknessTimeCardModal'); sicknessModal.addEventListener('show.bs.modal', function (event) { // 获取触发模态框的按钮 const triggerBtn = event.relatedTarget; // 获取按钮上存储的用户ID const userId = triggerBtn.getAttribute('data-user-id'); // 设置表单隐藏域的值 document.getElementById('userIdInput').value = userId; });
方法二:为每个员工生成独立模态框
这种方法在循环内为每个员工渲染专属的模态框,每个模态框使用唯一ID,直接绑定当前用户ID,无需额外JS。
- 修改员工列表中的按钮,将
data-bs-target设置为唯一的模态框ID:
<button asp-condition=@User.HasOneOfRoles("manager,admin") data-bs-toggle="modal" data-bs-target="#AddSicknessTimeCardModal-@u.Id" class="btn btn-sm btn-outline-warning"> <i class="bi bi-emoji-frown" title="mark as sick"></i>Mark as Sick </button>
- 在循环内部渲染模态框局部视图,传递当前用户ID作为模型:
<partial name="_AddSicknessTimeCardModal" model="@u.Id" />
- 修改模态框局部视图,接收用户ID并设置唯一ID和路由参数:
@model int <div class="modal fade" id="AddSicknessTimeCardModal-@Model" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalLabel">Mark Absence</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="alert alert-warning"> <h3>Are you sure you want to mark this person as being sick today?</h3> </div> <div class="modal-footer"> <form asp-action="AddSicknessTimeCard" method="post" asp-route-id="@Model"> <button type="submit" class="btn btn-primary" aria-label="add">Yes</button> <button type="button" class="btn btn-danger" data-bs-dismiss="modal">Cancel</button> </form> </div> </div> </div> </div> </div>
方法对比
- 方法一:仅渲染一个模态框,减少DOM元素数量,适合员工数量较多的场景,需要少量JS逻辑。
- 方法二:逻辑直观,无需JavaScript,适合员工数量较少的场景,每个员工对应一个模态框,DOM元素会随员工数量增加而增多。
内容的提问来源于stack exchange,提问作者molly1312
相关产品推荐
相关产品推荐

