Razor Pages:更新数据后Partial View刷新页面及事件重绑定问题
问题描述
已实现Razor Pages中通过Partial View更新数据后刷新页面的功能,但表格列表中的Update按钮仅能生效一次。由于重新加载表格内容会导致Update事件绑定失效,请问该如何重新绑定该事件?
index.cshtml页面
@page @model RazorPagesCollection.Pages.PopUp.IndexModel @using Northwind_EF.Models @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> <script type="text/javascript"> $(function () { $("#CustomerGrid .details").click(function () { var customerId = $(this).closest("tr").find("td").eq(0).html(); $.ajax({ type: "POST", url: "Index?handler=GetDetails", headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, data: { "customerId": customerId }, success: function (response) { $("#partialModal").find(".modal-body").html(response); $("#partialModal").modal('show'); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); }); $("#CustomerGrid .updatePopup").click(function () { var customerId = $(this).closest("tr").find("td").eq(0).html(); $.ajax({ type: "POST", url: "Index?handler=UpdateRecordView", headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, data: { "customerId": customerId }, success: function (response) { $("#partialModal").find(".modal-body").html(response); $("#partialModal").modal('show'); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); }); $("#divCustomer .updatePost").on("click", function (e) { console.log("Posting Form Data...."); var customerId = $(this).closest("tr").find("td").eq(0).html(); var data = $("#form1").serialize(); $.ajax({ type: "POST", url: "Index?handler=UpdateRecord", data: data, headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, success: function (response) { console.log(response); $("#partialModal").modal('hide'); $("#CustomerGrid").load("index #CustomerGrid"); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); }); }); function PostProcessFormID(id) { //check valid if you have client side validation... valid = $('#' + id).valid(); console.log("id: " + valid); if (valid) { thisForm = document.getElementById(id); var data = new FormData(thisForm); $.ajax({ type: "POST", url: "Index?handler=UpdateRecord", data: data, headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, success: function (response) { console.log(response); $("#partialModal").modal('hide'); $("#CustomerGrid").load("index #CustomerGrid"); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); } } </script> </head> <body> <h4>Customers</h4> <hr /> <div id="divCustomer"> <table cellpadding="0" cellspacing="0" class="table table-striped table-condensed table-responsive" id="CustomerGrid"> <tr> <th>CustomerID</th> <th>Company Name</th> <th>City</th> <th>Country</th> <th></th> <th></th> </tr> @foreach (Customer customer in Model.Customers) { <tr> <td>@customer.CustomerID</td> <td>@customer.CompanyName</td> <td>@customer.City</td> <td>@customer.Country</td> <td><a class="details" href="javascript:;">View</a></td> <td><a class="updatePopup" href="javascript:;">Update</a></td> </tr> } </table> @Html.AntiForgeryToken() <div id="partialModal" class="modal" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Customer Details Form</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" id="btnEdit" data-toggle="modal" class="btn btn-primary updatePost">Update</button> </div> </div> </div> </div> </div> </body> </html>
Index.cshtml.cs后台代码
using EF_DBContext; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Northwind_EF.Models; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace RazorPagesCollection.Pages.PopUp { public class IndexModel : PageModel { private NorthwinDbContext Context { get; } public IndexModel(NorthwinDbContext _context) { this.Context = _context; } public List<Customer> Customers { get; set; } public void OnGet() { this.Customers = (from customer in this.Context.Customers.Take(10) select customer).ToList(); } public PartialViewResult OnPostGetDetails(string customerId) { return new PartialViewResult { ViewName = "Details", ViewData = new ViewDataDictionary<Customer>(ViewData, this.Context.Customers.Find(customerId)) }; } public PartialViewResult OnPostUpdateRecordView(string customerId) { return new PartialViewResult { ViewName = "Update", ViewData = new ViewDataDictionary<Customer>(ViewData, this.Context.Customers.Find(customerId)) }; } public IActionResult OnPostUpdateRecord(Customer customer) { Customer updatedCustomer = (from c in this.Context.Customers where c.CustomerID == customer.CustomerID select c).FirstOrDefault(); if (updatedCustomer != null) { updatedCustomer.CompanyName = customer.CompanyName ; updatedCustomer.Country = customer.Country; this.Context.SaveChanges(); return Content("Updated Successfully"); } else { return Content("Updated Failed"); } } } }
Partial View更新页面
@model Northwind_EF.Models.Customer @{ Layout = null; } <form id="form1" method="POST" onsubmit="PostProcessFormID('form1'); return false;"> <table cellpadding="0" cellspacing="0" border="0"> <tr> <th>Name</th> <td><input asp-for="CompanyName" class="form-control" /></td> </tr> <tr> <th>Address</th> <td><input asp-for="Address" class="form-control" /></td> </tr> <tr> <th>City</th> <td><input asp-for="City" class="form-control" /></td> </tr> <tr> <th>Country</th> <td><input asp-for="Country" class="form-control" /></td> </tr> <tr> <th>PostalCode</th> <td><input asp-for="PostalCode" class="form-control" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="Update" class="btn btn-primary" /></td> <td colspan="2"><input type="button" value="Cancel" class="btn btn-dark" /></td> </tr> </table> <input type="hidden" name="CustomerID" asp-for="CustomerID" value="@Model.CustomerID" /> </form>
解决方案
问题出在你直接把事件绑定到了动态生成的DOM元素上,当表格通过$("#CustomerGrid").load()重新加载后,原来的按钮元素被替换,之前绑定的事件也跟着失效了。解决办法是用事件委托,把事件绑定到一个始终存在的父元素上,让父元素监听子元素的事件。
具体修改步骤
把原来的.click()事件绑定改成用.on()绑定到父元素#CustomerGrid:
// 替换原来的 $("#CustomerGrid .details").click(...) $("#CustomerGrid").on("click", ".details", function () { var customerId = $(this).closest("tr").find("td").eq(0).html(); $.ajax({ type: "POST", url: "Index?handler=GetDetails", headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, data: { "customerId": customerId }, success: function (response) { $("#partialModal").find(".modal-body").html(response); $("#partialModal").modal('show'); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); }); // 替换原来的 $("#CustomerGrid .updatePopup").click(...) $("#CustomerGrid").on("click", ".updatePopup", function () { var customerId = $(this).closest("tr").find("td").eq(0).html(); $.ajax({ type: "POST", url: "Index?handler=UpdateRecordView", headers: { "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val() }, data: { "customerId": customerId }, success: function (response) { $("#partialModal").find(".modal-body").html(response); $("#partialModal").modal('show'); }, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); } }); });
原理说明
事件委托利用了DOM的事件冒泡机制:当子元素触发点击事件时,事件会向上冒泡到父元素。通过在父元素上监听事件,并指定目标子元素的选择器,就能确保即使子元素是动态生成的,事件依然能被正常触发。
额外优化建议
- 可以把重复的AJAX逻辑封装成通用函数,减少代码冗余,比如提取获取CustomerID、发送POST请求的公共方法。
- 注意
PostProcessFormID函数里的表单验证,如果没引入jQuery Validation插件,$('#' + id).valid()会报错,需要确保相关脚本已正确引入。
内容的提问来源于stack exchange,提问作者Milacay
相关产品推荐
相关产品推荐

