Razor Page中JS实现下拉联动填充面板费用及计算欠款
问题描述
我正在开发一个包含Client表、Attendance表和Panel表的ASP.NET应用,在Attendance创建页面需要实现两个功能:
- 选择Panel下拉选单后,自动从Panel表获取对应
PanelFee填充至只读的PanelCost字段; - 输入
AmountPaid后,自动计算并填充AmountOutstanding(公式:PanelCost - AmountPaid)。
目前编写的JavaScript完全不生效:选择Panel后PanelCost无填充,输入AmountPaid后欠款字段也没有计算结果,需要排查并修正。
当前代码片段
Create.cshtml
@model AttendanceCreateModel <form asp-action="Create"> <div class="form-group"> <label asp-for="PanelId" class="control-label"></label> <select asp-for="PanelId" asp-items="Model.PanelList" class="form-control"></select> <span asp-validation-for="PanelId" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="PanelCost" class="control-label"></label> <input asp-for="PanelCost" class="form-control" readonly /> <span asp-validation-for="PanelCost" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="AmountPaid" class="control-label"></label> <input asp-for="AmountPaid" class="form-control" /> <span asp-validation-for="AmountPaid" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="AmountOutstanding" class="control-label"></label> <input asp-for="AmountOutstanding" class="form-control" readonly /> <span asp-validation-for="AmountOutstanding" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} <script> $(document).ready(function () { $('#PanelId').change(function () { var panelId = $(this).val(); $.get('/Attendance/GetPanelFee/' + panelId, function (data) { $('#PanelCost').val(data); }); }); $('#AmountPaid').on('input', function () { var panelCost = parseFloat($('#PanelCost').val()) || 0; var amountPaid = parseFloat($(this).val()) || 0; var outstanding = panelCost - amountPaid; $('#AmountOutstanding').val(outstanding.toFixed(2)); }); }); </script> }
CreateModel.cs
public class AttendanceCreateModel : PageModel { private readonly ApplicationDbContext _context; public AttendanceCreateModel(ApplicationDbContext context) { _context = context; } [BindProperty] public Attendance Attendance { get; set; } public SelectList PanelList { get; set; } public async Task<IActionResult> OnGetAsync() { var panels = await _context.Panel.Select(p => new { p.Id, p.PanelName }).ToListAsync(); PanelList = new SelectList(panels, "Id", "PanelName"); return Page(); } public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } _context.Attendance.Add(Attendance); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); } public async Task<IActionResult> OnGetGetPanelFee(int id) { var panel = await _context.Panel.FindAsync(id); if (panel == null) { return NotFound(); } return new JsonResult(panel.PanelFee); } }
Panel实体类
public class Panel { public int Id { get; set; } public string PanelName { get; set; } public decimal PanelFee { get; set; } // 其他属性... }
排查与修正方案
1. 核心问题:DOM选择器不匹配
ASP.NET Core Tag Helper会根据模型层级生成元素ID,你的PanelId、PanelCost等属性属于Attendance绑定对象,实际渲染的ID是Attendance_PanelId、Attendance_PanelCost,而非你JS中写的PanelId。
验证方式:F12打开开发者工具,查看对应元素的ID即可确认。
2. 路由匹配错误
Razor Pages的Handler方法默认路由格式是/页面名?handler=方法名&参数=值,你写的/Attendance/GetPanelFee/xxx无法匹配OnGetGetPanelFee方法。
3. 修正后的完整代码
Create.cshtml 脚本部分
@section Scripts { <script src="~/lib/jquery/dist/jquery.min.js"></script> @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} <script> $(document).ready(function () { // 用实际渲染的ID选择元素 const panelSelect = $('#Attendance_PanelId'); const panelCostInput = $('#Attendance_PanelCost'); const amountPaidInput = $('#Attendance_AmountPaid'); const outstandingInput = $('#Attendance_AmountOutstanding'); panelSelect.change(function () { const panelId = $(this).val(); if (!panelId) { panelCostInput.val(''); outstandingInput.val(''); return; } // 用Razor Pages标准路由格式请求 $.get('/Attendance', { handler: 'GetPanelFee', id: panelId }, function (fee) { panelCostInput.val(fee); // 自动触发欠款计算 amountPaidInput.trigger('input'); }).fail(function() { alert('获取Panel费用失败,请重试'); panelCostInput.val(''); }); }); amountPaidInput.on('input', function () { const panelCost = parseFloat(panelCostInput.val()) || 0; const amountPaid = parseFloat($(this).val()) || 0; // 避免欠款出现负数 const outstanding = Math.max(panelCost - amountPaid, 0); outstandingInput.val(outstanding.toFixed(2)); }); }); </script> }
CreateModel.cs Handler优化(可选)
为避免decimal精度丢失,返回时格式化字符串:
public async Task<IActionResult> OnGetGetPanelFee(int id) { var panel = await _context.Panel.FindAsync(id); if (panel == null) { return NotFound("Panel不存在"); } return new JsonResult(panel.PanelFee.ToString("F2")); }
4. 额外边界处理
- 下拉框清空时,同步清空费用和欠款字段;
- 付款金额为空/非数字时,按0计算;
- 付款超过费用时,欠款显示0而非负数;
- 添加请求失败的提示,提升用户体验。
内容的提问来源于stack exchange,提问作者MelB
相关产品推荐
相关产品推荐

