Unobtrusive Ajax in Asp.net MVC

     讲述怎么使用Unobtrusive Ajax之前,先看在Asp.net MVC传统情况下怎么来实现一个下拉框联动效果:

     1. 简单的定义一个model:

    public class Appointment
    {
        public string ClientName { getset; }
        [DataType(DataType.Date)]
        public DateTime Date { getset; }
        public bool TermsAccepted { getset; }
    }

     2. controller和action的实现:

     index.cshtml: 

@model string
@{
    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:

@using UnobtrusiveAjax.Models
@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-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>    

    5. 页面中更新form为ajax form:

@model string
@{
    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。利用这些属性,我们来一个完美的吧:

@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 OnBegin() {
            alert("This is the OnBegin Callback");
        }
        function OnSuccess(data) {
            alert("This is the OnSuccessCallback: " + data);
        }
        function OnFailure(request, error) {
            alert("This is the OnFailure Callback:" + error);
        }
        function OnComplete(request, status) {
            alert("This is the OnComplete Callback: " + status);
        }
    </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>
}

其中标黄部分是为了兼容不支持js的浏览器(原有实现在不支持js的浏览器中直接返回没有html的原始数据)。

      6. 增加Ajax Links(支持Ajax的超链接)。在index顶部增加:

@foreach (string str in new[] { "All""Joe""Jane""Bob" })
{
    <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 class AppointmentController : 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部分为:

<form action="/Appointment" data-ajax="true" data-ajax-confirm="Do you wish to request new data?" data-ajax-loading="#loading" data-ajax-loading-duration="2000" data-ajax-mode="replace" data-ajax-update="#tabledata" id="form0" method="post">    

     ajax links部分为:

<data-ajax="true" data-ajax-loading="#loading" data-ajax-loading-duration="2000" data-ajax-success="OnSuccess2" data-ajax-url="/Appointment/AppointmentData/Bob" href="/Appointment/Index/Bob">Bob</a>

所以它实际上和validation部分类似,不过是在html中隐藏了很多自定义属性,然后在unobtrusive ajax 的js中去获取,然后根据这些值来分别处理。

      9. 如果禁用了unobtrusive ajax,则mvc framework会自动启用MicrosoftAjax.js和MicrosoftMVCAjax,但是你需要手动引入它们。它们效果相同,但实现原理不一样。

      源码download 

原文地址:https://www.cnblogs.com/Langzi127/p/2734836.html