讲述怎么使用Unobtrusive Ajax之前,先看在Asp.net MVC传统情况下怎么来实现一个下拉框联动效果:
1. 简单的定义一个model:
{
public string ClientName { get; set; }
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public bool TermsAccepted { get; set; }
}
2. controller和action的实现:
index.cshtml:
@{
ViewBag.Title = "Index";
}
<h4>Appointment List</h4>
@using (Html.BeginForm())
{
<table>
<thead>
<th>
Client Name
</th>
<th>
Appointment Date
</th>
</thead>
<tbody id="tabledata">
@Html.Action("AppointmentData", new { id = Model })
</tbody>
</table>
<p>
@Html.DropDownList("id", new SelectList(new[] { "All", "Joe", "Jane", "Bob" }, (Model ?? "All")))
<input type="submit" value="Submit" />
</p>
}
AppointmentData.cshtml:
@model IEnumerable<UnobtrusiveAjax.Models.Appointment>
@{
Layout = null;
}
@foreach (Appointment appt in Model)
{
<tr>
<td>@Html.DisplayFor(m => appt.ClientName)
</td>
<td>@Html.DisplayFor(m => appt.Date)
</td>
</tr>
}
最终的效果就是:当切换下拉框的选择项时,Appointment list也对应变化,但是页面是通过postback来刷新数据的。现在想实现Ajax切换效果:
4. 启用Unobtrusive Ajax脚本了。
web.config中新增:
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>。
然后在页面中引入:
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
5. 页面中更新form为ajax form:
@{
ViewBag.Title = "Index";
AjaxOptions ajaxOptions = new AjaxOptions
{
UpdateTargetId = "tabledata"
};
}
<h4>Appointment List</h4>
@using(Ajax.BeginForm("AppointmentData", ajaxOptions))
{
<table>
<thead>
<th>
Client Name
</th>
<th>
Appointment Date
</th>
</thead>
<tbody id="tabledata">
@Html.Action("AppointmentData", new { id = Model })
</tbody>
</table>
<p>
@Html.DropDownList("id", new SelectList(new[] { "All", "Joe", "Jane", "Bob" }, (Model ?? "All")))
<input type="submit" value="Submit" />
</p>
}
这时候,基本的Ajax效果已经出来了。如果要继续完善美化,可以从AjaxOptions着手。先看AjaxOptions的属性有:Confirm, HttpMethod, InsertionMode, LoadingElementId, LoadingElementDuration, UpdateTargetId, Url,OnBegin, OnComplete, OnFailure, OnSuccess等。详细的可以参考:http://msdn.microsoft.com/en-us/library/system.web.mvc.ajax.ajaxoptions(v=vs.108).aspx。利用这些属性,我们来一个完美的吧:
@{
ViewBag.Title = "Index";
AjaxOptions ajaxOptions = new AjaxOptions
{
UpdateTargetId = "tabledata",
Url = Url.Action("AppointmentData"),
LoadingElementId = "loading",
LoadingElementDuration = 2000,
Confirm = "Do you wish to request new data?",
OnBegin = "OnBegin",
OnComplete = "OnComplete",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess"
};
}
<h4>Appointment List</h4>
<p>
Loading Data...</p>
</div>
@using (Ajax.BeginForm(ajaxOptions))
{
<table>
<thead>
<th>
Client Name
</th>
<th>
Appointment Date
</th>
</thead>
<tbody id="tabledata">
@Html.Action("AppointmentData", new { id = Model })
</tbody>
</table>
<p>
@Html.DropDownList("id", new SelectList(new[] { "All", "Joe", "Jane", "Bob" }, (Model ?? "All")))
<input type="submit" value="Submit" />
</p>
}
其中标黄部分是为了兼容不支持js的浏览器(原有实现在不支持js的浏览器中直接返回没有html的原始数据)。
6. 增加Ajax Links(支持Ajax的超链接)。在index顶部增加:
{
<div style="margin-right: 5px; float: left">
@Ajax.ActionLink(str, "AppointmentData", new { id = str },
new AjaxOptions
{
UpdateTargetId = "tabledata",
LoadingElementId = "loading",
})
</div>
}
这时,点击它所生成的链接,和切换下拉框选中内容,效果完全一样。
7. 为了让上一步中ajax兼容不支持js的浏览器,并将ajax response回来的html数据改为json原始数据,做一些改进。
controller变为:
{
public ActionResult Index(string id)
{
return View("Index", (object)id);
}
public ActionResult AppointmentData(string id)
{
IEnumerable<Appointment> data = new[]
{
new Appointment
{ClientName = "Joe", Date = DateTime.Parse("1/1/2012")},
new Appointment
{ClientName = "Joe", Date = DateTime.Parse("2/1/2012")},
new Appointment
{ClientName = "Joe", Date = DateTime.Parse("3/1/2012")},
new Appointment
{ClientName = "Jane", Date = DateTime.Parse("1/20/2012")},
new Appointment
{ClientName = "Jane", Date = DateTime.Parse("1/22/2012")},
new Appointment
{ClientName = "Bob", Date = DateTime.Parse("2/25/2012")},
new Appointment
{ClientName = "Bob", Date = DateTime.Parse("2/25/2013")}
};
if (!string.IsNullOrEmpty(id) && id != "All")
{
data = data.Where(e => e.ClientName == id);
}
if (Request.IsAjaxRequest())
{
return Json(data.Select(m => new
{
ClientName = m.ClientName,
Date = m.Date.ToShortDateString()
}),
JsonRequestBehavior.AllowGet);
}
else
{
return View(data);
}
}
}
标黄部分的变更前者是为了兼容get和post2种请求,后者是为了兼容普通请求和ajax请求并分别生成不同类容。其中,Request.IsAjaxRequest()方法可以判断当前请求是否来自Ajax。
view变更为:
@model string
@{
ViewBag.Title = "Index";
AjaxOptions ajaxOptions = new AjaxOptions
{
UpdateTargetId = "tabledata",
//Url = Url.Action("AppointmentData"),
LoadingElementId = "loading",
LoadingElementDuration = 2000,
Confirm = "Do you wish to request new data?",
//OnBegin = "OnBegin",
//OnComplete = "OnComplete",
//OnFailure = "OnFailure",
//OnSuccess = "OnSuccess"
};
}
<h4>Appointment List</h4>
<script type="text/javascript">
function OnSuccess2(data) {
var target = $('#tabledata');
target.empty();
for (var i = 0; i < data.length; i++) {
target.append('<tr><td>' + data[i].ClientName + '</td><td>' + data[i].Date + '</td></tr>');
}
}
</script>
<div id="loading" style="display: none; color: Red; font-weight: bold">
<p>
Loading Data...</p>
</div>
@using (Ajax.BeginForm(ajaxOptions))
{
<table>
<thead>
<th>
Client Name
</th>
<th>
Appointment Date
</th>
</thead>
<tbody id="tabledata">
@Html.Action("AppointmentData", new { id = Model })
</tbody>
</table>
<p>
@Html.DropDownList("id", new SelectList(new[] { "All", "Joe", "Jane", "Bob" }, (Model ?? "All")))
<input type="submit" value="Submit" />
</p>
}
@foreach (string str in new[] { "All", "Joe", "Jane", "Bob" })
{
<div style="margin-right: 5px; float: left">
@Ajax.ActionLink(str, "Index", new { id = str }, new AjaxOptions
{
Url = Url.Action("AppointmentData", new { id = str }),
LoadingElementId = "loading",
LoadingElementDuration = 2000,
OnSuccess = "OnSuccess2"
})
</div>
}
8. 原理:
Browser端查看html源码发现form部分为:
ajax links部分为:
所以它实际上和validation部分类似,不过是在html中隐藏了很多自定义属性,然后在unobtrusive ajax 的js中去获取,然后根据这些值来分别处理。
9. 如果禁用了unobtrusive ajax,则mvc framework会自动启用MicrosoftAjax.js和MicrosoftMVCAjax,但是你需要手动引入它们。它们效果相同,但实现原理不一样。
源码download