ASP.NET MVC3 中 dropdown 的 jQuery change 事件无响应
结论
问题一般不在 change(),而是页面没有生成 id="PaymentType" 的 <select> 元素,或者 JavaScript 没有写在 <script> 标签内。这样一来,$("#PaymentType") 就匹配不到元素。jQuery 不会报错,但也无法绑定事件。
Ajax 地址也不要直接使用相对路径 "Order/PaymentChanged"。建议通过 Url.Action() 生成地址,避免当前页面路径变化后,请求被发送到错误的位置。
正确生成 dropdown
先确认最终 HTML 中存在 id="PaymentType" 的 <select>:
@using (Html.BeginForm())
{
@Html.Label("PaymentType", "Select payment method")
@Html.DropDownList(
"PaymentType",
new SelectList(
new[]
{
new { Value = "CreditCard", Text = "Credit Card" },
new { Value = "Cash", Text = "Cash" },
new { Value = "Check", Text = "Check" }
},
"Value",
"Text"
),
"-- Select --"
)
<div id="payment"></div>
}
生成的 HTML 类似这样:
<select id="PaymentType" name="PaymentType">
<option value="">-- Select --</option>
<option value="CreditCard">Credit Card</option>
<option value="Cash">Cash</option>
<option value="Check">Check</option>
</select>
绑定事件并调用 Controller
<script type="text/javascript">
$(function () {
$("#PaymentType").change(function () {
var selection = $(this).val();
$.ajax({
url: '@Url.Action("PaymentChanged", "Order")',
type: "GET",
data: {
paymentType: selection
},
dataType: "json",
success: function (data) {
$("#payment").text("server returned: " + data.agent);
},
error: function (xhr, status, error) {
$("#payment").text(
"Request failed: " +
xhr.status +
" " +
error
);
}
});
});
});
</script>
Controller 可以保持下面的写法:
public JsonResult PaymentChanged(string paymentType)
{
return Json(
new
{
agent = "sample html"
},
JsonRequestBehavior.AllowGet
);
}
paymentType 要与 Ajax data 中的属性名一致,否则 MVC 模型绑定器无法把选中的值传给 Action。
如果返回的是 HTML
当前 Action 返回 JSON,所以前端需要读取 data.agent。如果希望 Controller 直接返回一段 HTML,可以改为返回 PartialViewResult:
public PartialViewResult PaymentChanged(string paymentType)
{
var model = GetPaymentModel(paymentType);
return PartialView("_Payment", model);
}
前端再用 .html(data) 填充内容:
success: function (data) {
$("#payment").html(data);
}
.text() 会把 HTML 当作普通文本显示,.html() 则会将返回内容作为 HTML 插入。只有返回内容可信或已经妥善编码时,才应该使用 .html()。
逐步排查
先在浏览器开发者工具的 Console 中执行:
$("#PaymentType").length
正常结果是 1。如果返回 0,说明选择器与页面实际生成的 id 不一致,或者脚本执行时该元素还没有出现。
接着可以临时加入日志:
$(function () {
console.log("document ready");
console.log("PaymentType count:", $("#PaymentType").length);
$("#PaymentType").change(function () {
console.log("changed:", $(this).val());
});
});
根据输出结果排查:
- 没有输出
document ready:检查代码是否写在<script>标签内,并确认前面没有 JavaScript 语法错误。 - 元素数量为
0:查看浏览器中的实际 HTML,确认<select>的id。 - 能输出
changed,但没有发出请求:检查 Ajax 代码和 Console 中的错误。 - 请求已发送但返回
404:通常是 URL 不正确,应使用@Url.Action(...)。 - 返回
500:检查 Controller Action 内部是否发生异常。 - 请求成功但页面没有变化:确认页面中存在
id="payment"的元素,并检查返回数据究竟是 JSON 还是 HTML。
还需要在 Network 面板中核对实际请求地址、HTTP 状态码和响应内容。
其他常见问题
如果 dropdown 是在页面加载后通过 Ajax 动态插入的,初始的直接绑定对它无效。这时可以使用委托绑定:
$(document).on("change", "#PaymentType", function () {
console.log($(this).val());
});
不过 jQuery 1.5.1 还不支持 .on()。如果必须继续使用该版本,需要改用 .delegate():
$(document).delegate("#PaymentType", "change", function () {
console.log($(this).val());
});
如果 dropdown 在初始页面中已经存在,就不需要委托,直接使用 .change() 即可。
还要检查 _Layout.cshtml 是否重复引入了多个 jQuery 版本。脚本必须等 jQuery 加载完成后再执行。如果视图使用脚本 section,也要确认布局中包含相应的 RenderSection。页面引用了 jquery-1.5.1.min.js,并不代表这段代码一定已经执行,也不能说明它成功找到了目标元素。
备注:内容仅供参考。
