2012年7月8日 星期日

ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 Part.3:AJAX 分頁 - jQuery

上一篇「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 Part.2:AJAX 分頁」用 MvcPaging 所提供的 Ajax 分頁來完成,MvcPaging 的 Ajax 分頁是使用了 System.Web.Mvc.Ajax 的 AjaxOptions 來完成,其實也可以用 jQuery 來完成 Ajax 分頁的功能需求,這一次就來說明使用 jQuery 並且以 POST 方式完成 Ajax 分頁。

 


 

首先要回顧一下「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 Part.1:一般、表單(Form)」裡面的第二個部分,

使用 jQuery 讓 MVCPaging 可以 POST

其實那一段的說明當中已經有說明了如何以 jQuery 來做 POST 的分頁功能,這一次要做的有點不同,這一次我們的網頁中是沒有 form 的存在,所以分頁的 POST 就直接使用 jQuery.Ajax() 來完成。

後端的 Controller 程式內容與上一篇的程式內容並沒有太大的變化,有不一樣的地方就在於處理分頁內容 PartialView 的 DefaultPageAjax2Partial 這個 Action 方法,

在 Action 方法上標註 [HttpPost] Attribute, 限定 Action() 只能接收前端與 POST 所傳回來的資料

   1:  #region -- DefaultPageAjax2 --
   2:   
   3:  public ActionResult DefaultPageAjax2()
   4:  {
   5:      int currentPageIndex = 0;
   6:   
   7:      this.PrepareDropDownLists(this.FilterCity, this.SortColumnName, this.SortType);
   8:   
   9:      ViewBag.City = this.FilterCity;
  10:      ViewBag.SortColumnName = this.SortColumnName;
  11:      ViewBag.Sort = this.SortType;
  12:   
  13:      ViewData.Model = this.allCustomers.ToPagedList(currentPageIndex, DefaultPageSize);
  14:      return View();
  15:  }
  16:   
  17:  [HttpPost]
  18:  public ActionResult DefaultPageAjax2Partial(int? page,
  19:      string city = "all",
  20:      string sortColumnName = "CustomerID",
  21:      string sort = "asc")
  22:  {
  23:      int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
  24:   
  25:      this.FilterCity = city;
  26:      this.SortColumnName = sortColumnName;
  27:      this.SortType = sort;
  28:   
  29:      ViewBag.City = city;
  30:      ViewBag.SortColumnName = sortColumnName;
  31:      ViewBag.Sort = sort;
  32:   
  33:      using (NorthwindEntities db = new NorthwindEntities())
  34:      {
  35:          var query = db.Customers.Select(x => x);
  36:   
  37:          if (!city.Equals("all"))
  38:          {
  39:              query = query.Where("City == @0", city ?? "London");
  40:          }
  41:   
  42:          query = query.OrderBy(string.Format("{0} {1}", sortColumnName, sort));
  43:   
  44:          ViewData.Model = query.ToPagedList(currentPageIndex, DefaultPageSize);
  45:   
  46:          return PartialView("DefaultPageAjax2Partial");
  47:      }
  48:  }  
  49:  #endregion

 

而前端網頁也稍微做了一點修改,先看主頁面的 View Page「DefaultPageAjax2.cshtml

   1:  @model IPagedList<MvcMSSQL.Models.Customer>
   2:  @{
   3:      ViewBag.Title = "DefaultPageAjax - jQuery";
   4:      Layout = "~/Views/Shared/_Layout.cshtml";
   5:  }
   6:  <script type="text/javascript" src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")"></script>
   7:   
   8:  <h2>DefaultPageAjax - jQuery</h2>
   9:  <fieldset>
  10:      <br />
  11:      City:@Html.Raw(ViewData["CityDDL"].ToString()) 
  12:      Sort ColumnName:@Html.Raw(ViewData["ColumnDDL"].ToString())
  13:      Sort Type:@Html.Raw(ViewData["SortDDL"].ToString())
  14:      <input type="button" value="submit" id="ButtonSubmit" />
  15:      <input type="button" value="Reset" id="ButtonReset" />
  16:  </fieldset>
  17:   
  18:  <div id="gridcontainer">
  19:      @Html.Partial("DefaultPageAjax2Partial", Model)
  20:  </div>
  21:   
  22:  @if (false){ <script src="../../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> }
  23:  <script type="text/javascript">
  24:  <!--
  25:      $(document).ready(function () {
  26:          $('#ButtonSubmit').click(function () { ButtonSubmitEventHandler(); });
  27:          $('#ButtonReset').click(function () { ButtonResetEventHandler(); });
  28:      });
  29:   
  30:      function ButtonSubmitEventHandler() {
  31:          var cityValue = $('#city option:selected').val();
  32:          var columnValue = $('#sortColumnName option:selected').val();
  33:          var sortValue = $('#sort option:selected').val();
  34:   
  35:          $.ajax({
  36:              url: '@Url.Action("DefaultPageAjax2Partial", "Home")',
  37:              data: { city: cityValue, sortColumnName: columnValue, sort: sortValue },
  38:              type: 'post',
  39:              async: false,
  40:              cache: false,
  41:              dataType: 'html',
  42:              success: function (data) {
  43:                  $('#gridcontainer').html(data);
  44:   
  45:                  $('#city').attr('disabled', true);
  46:                  $('#sortColumnName').attr('disabled', true);
  47:                  $('#sort').attr('disabled', true);
  48:              }
  49:          });
  50:      }
  51:   
  52:      function ButtonResetEventHandler() {
  53:          $('#city option:eq(0)').attr('selected', true);
  54:          $('#sortColumnName option:eq(0)').attr('selected', true);
  55:          $('#sort option:eq(0)').attr('selected', true)
  56:   
  57:          $('#city').removeAttr('disabled');
  58:          $('#sortColumnName').removeAttr('disabled');
  59:          $('#sort').removeAttr('disabled');
  60:   
  61:          $('#gridcontainer').empty();
  62:      }
  63:   
  64:      function postPage(page) {
  65:          var cityValue = $('#city option:selected').val();
  66:          var columnValue = $('#sortColumnName option:selected').val();
  67:          var sortValue = $('#sort option:selected').val();
  68:   
  69:          $.ajax({
  70:              url: '@Url.Action("DefaultPageAjax2Partial", "Home")',
  71:              data: { page: page, city: cityValue, sortColumnName: columnValue, sort: sortValue },
  72:              type: 'post',
  73:              async: false,
  74:              cache: false,
  75:              dataType: 'html',
  76:              success: function (data) {
  77:                  $('#gridcontainer').html(data);
  78:   
  79:                  $('#city').attr('disabled', true);
  80:                  $('#sortColumnName').attr('disabled', true);
  81:                  $('#sort').attr('disabled', true);
  82:              }
  83:          });
  84:      };
  85:   
  86:  -->
  87:  </script>

這邊要看的重點在於 Line 64 ~ Line 84 的 postPage() 這個 function,postPage() 這個 function 的觸發是綁定在產生於 PartialView 裡的 Pager 上,當點擊 Pager 上的分頁連結就會觸發執行 postPage(),這個 function 再去取下拉選單所選取的值以及所傳進來的分頁索引碼,使用 jQuery.Ajax() 將資料 POST 到後端,最後取得分頁的內容,再顯示到前端頁面上指定的容器裡。

 

以下是 PartialView「DefaultPageAjax2Partial.cshtml

   1:  @model IPagedList<MvcMSSQL.Models.Customer>
   2:      
   3:  @if (Model != null && Model.Count > 0)
   4:  { 
   5:      <div class="pager">
   6:          @Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount)
   7:   
   8:          Displaying @Model.ItemStart - @Model.ItemEnd of @Model.TotalItemCount item(s)
   9:      </div>
  10:      <br />
  11:   
  12:      <table>
  13:          <tr>
  14:              <th>
  15:                  CompanyName
  16:              </th>
  17:              <th>
  18:                  ContactName
  19:              </th>
  20:              <th>
  21:                  ContactTitle
  22:              </th>
  23:              <th>
  24:                  Address
  25:              </th>
  26:              <th>
  27:                  City
  28:              </th>
  29:              <th>
  30:                  Region
  31:              </th>
  32:              <th>
  33:                  PostalCode
  34:              </th>
  35:              <th>
  36:                  Country
  37:              </th>
  38:              <th>
  39:                  Phone
  40:              </th>
  41:              <th>
  42:                  Fax
  43:              </th>
  44:          </tr>
  45:      @foreach (var item in Model)
  46:      {
  47:          <tr>
  48:              <td>
  49:                  @item.CompanyName
  50:              </td>
  51:              <td>
  52:                  @item.ContactName
  53:              </td>
  54:              <td>
  55:                  @item.ContactTitle
  56:              </td>
  57:              <td>
  58:                  @item.Address
  59:              </td>
  60:              <td>
  61:                  @item.City
  62:              </td>
  63:              <td>
  64:                  @item.Region
  65:              </td>
  66:              <td>
  67:                  @item.PostalCode
  68:              </td>
  69:              <td>
  70:                  @item.Country
  71:              </td>
  72:              <td>
  73:                  @item.Phone
  74:              </td>
  75:              <td>
  76:                  @item.Fax
  77:              </td>
  78:          </tr>
  79:      }
  80:      </table>
  81:  }
  82:   
  83:  @if (false)
  84:  { <script src="../../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> }
  85:   
  86:  <script type="text/javascript">
  87:      $(document).ready(function () {
  88:          $('.pager> a').each(function (i, item) {
  89:              var page = $(item).attr('href').replace('@(Url.Action("DefaultPageAjax2Partial", "Home"))?page=', '');
  90:              $(item).attr('href', '#').click(function () { postPage(page); });
  91:          });
  92:      });
  93:  </script>

當這個 PartialView 顯示到前端頁面上時都必須要執行一段 jQuery 程式,這是要讓 Pager 上的分頁連結的 click 都綁定 postPage() 這個 function,讓分頁連結的點擊不是執行一段 HyperLink 的連結,而是去執行 jQuery.Ajax() 以完成分頁。

 

執行

image

image

image

image

image

image

 

這一次就不再錄影了,反正看來看去都是一樣的內容,做 AJAX 功能時,我會優先考慮使用 jQuery 來處理需求,而不會去考慮使用 System.Web.Mvc.Ajax 的方式,其實做出來的結果都是大同小異的,但是使用 jQuery 來處理的話,如果後續還有什麼需要再添加或需要再處理,使用 jQuery 一貫的方式就容易許多,而且也比較容易再遇到問題時找到解決方法。

 

下回把「Dynamic LINQ + Entity Framework - Part.4:ASP.NET MVC 進階應用」的內容加上分頁功能,另外也修改一下表格欄位顯示排序的進階處理方式,讓整個網頁的顯示與操作能後更加的方便。

 

以上

15 則留言:

  1. 請問如果小弟現在只單純做Ajax分頁的部份我該如何動手做呢?

    大大分享的很清楚,只是小的程度低..還無法消化吸收

    回覆刪除
    回覆
    1. 我會建議你先去 github 把 MvcPaging 2.0 的原始檔給抓下來看
      裡面有個 MvcPaging.Demo 的 Sample Project
      這個 MvcPaging.Demo 的程式都相當淺顯
      你先不要想怎麼去把你所做的網頁改成 AJAX 分頁
      先做一個一般的資料分頁然後照著 MvcPaging.Demo 再去修改為 AJAX 的資料分頁
      這樣你就可以做得出來

      刪除
  2. 這一系列的「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用」就是讓大家從一般的分頁顯示慢慢改成 AJAX 分頁...
    如果會使用 MvcPaging 2.0 來讓你的資料可以分頁顯示的話,
    那麼按照我所說的步驟就會做 AJAX 資料分頁啦
    Part.1 就是一般無 AJAX 的資料分頁
    Part.2 就是使用 MvcPaging 所提供的 AJAX 資料分頁
    Part.3 則是使用 MvcPaging 搭配 jQuery 來做 AJAX 資料分頁

    回覆刪除
  3. 恩~感謝你給我的建議

    那我想問問大大以下這段View
    @model IPagedList
    要怎麼新增出來?
    我Controllers打完後按右鍵add view..
    也只能新建以下這兩種
    1.MvcPaging.IPagedList
    2.PagedList.IPagedList

    回覆刪除
    回覆
    1. 那個 View 上頭的 @model IPagedList
      這個要建立 View 之後再去做修改
      建立 View 的時候可以不用先選 View 要使用的資料模型類別

      刪除
  4. 打上這行@model IPagedList就一值顯示錯誤
    "the type or namespace name'IPagedList' could not be found(are you missing a using directive or anassembly reference?)"

    是因為我controllers那裡沒using好嗎?

    回覆刪除
    回覆
    1. 你有在你的專案中加入 MvcPaging assembly 參考嗎?

      刪除
  5. 恩~有的
    我去抓MvcPaging 2.0
    把MvcPaging這Project加進來
    然後再從References把Mvcpaging加入進來

    回覆刪除
    回覆
    1. 如果你有看「ASP.NET MVC 資料分頁 MVCPaging 2.0 應用 Part.1:一般、表單(Form)」
      其實 MvcPaging 是可以不必把 Source Code 的 Project 給加入到 Solution 中
      可以透過 NuGet 加入 MvcPaging 的 Assembly 到 Project 中

      因為你的錯誤訊息是「the type or namespace name'IPagedList' could not be found(are you missing a using directive or anassembly reference?)」

      所以有兩個方向可以找錯誤原因,其一是有無加入 Assembly Reference,而你說已經有加入,所以就看第二個可能的原因,
      其二就是你的 Web.Config 中是否有加入 namespace 呢?
      如果沒有在 System.Web > pages > namespaces 區段中加入要給 page 用的 namespace 的話,
      要在 View 上使用 IPagedList 就必須要輸入完整的 namespace 名稱,@model MvcPaging.IPagedList
      而要在 View 只想要使用 IPagedList 的話,就必須在 Web.Congif 中做修改,
      可以參考 twMVC 另一位成員 Jerry 的部落格文章,文章中有說明如何在 Web.Config 中做修改,

      「初學ASP.NET MVC學習筆記(十)-分頁」
      http://www.dotblogs.com.tw/lastsecret/archive/2010/04/06/14422.aspx

      刪除
    2. 喔~了解~所以在Config的namespace那加上MvcPaging後我在View那邊才可以簡寫寫成IPagedList~

      那...@Html.Pager的Pager這個點不出來,html點後面沒有Pager可以選,是我還要在@import什麼進去嗎?

      刪除
    3. 有關 HtmlHelper 的資訊,請參考以下:

      「demoshop - ASP.NET MVC 你一定要知道怎麼創立HTML Helper」
      http://demo.tc/Post/459

      刪除
  6. 請教:
    刪除的部分,如果我透過JQuery ajax去進行刪除,都會出現404 not found的錯誤...
    Controller我只建
    [HttpPost]
    public ActionResult Delete(int id)
    {
    var news = db.get(id);
    if (news == null)
    {
    return HttpNotFound();
    }
    db.Delete(id);
    return View();
    }
    如果再把View建出來就可以正常執行,這樣做法對嗎?還是有更好的做法?每次為了刪除還要建一個View...Orz

    回覆刪除
  7. 因為你最後刪除完成會執行「return View();」
    在 Action 方法裡的 return View() 如果不指定 View 的話,就會預設返回與 Action 名稱一樣的 View,
    因為你沒有建立 Delete 的 View,所以最後結果就會出現 404 錯誤,
    解決方式就是,最後的 return View() 要去指定刪除完成後要指定移轉的 View,
    這個是 Controller 的基本操作喔~

    那麼你所做的操作是 AJAX 進行刪除,所以回傳的結果就不應該是 return View,
    應該是要回傳刪除的成功與否的結果,建議應該回傳 JSON 內容,然後前端接值處理。

    你可以參考「http://kevintsengtw.blogspot.tw/2013/08/aspnet-mvc-4-jquery-easyui-tree-and.html」裡的作法,
    雖然這一篇的功能有使用到第三方的前端套件,但是你需要看的是後端 Controller 與前端 javascript 的操作處理,
    我在哪一篇的功能都完全是 AJAX 進行資料的 CRUD,所以給你作為參考。

    回覆刪除
    回覆
    1. 多謝..已解決這個長久的疑問!!^^

      刪除
  8. 作者已經移除這則留言。

    回覆刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。