【问题标题】:MVC: Pagination hindering the way a list is sortedMVC:分页阻碍了列表的排序方式
【发布时间】:2013-07-22 21:49:27
【问题描述】:

我正在构建一个 MVC 应用程序,我正在寻找一种在我看来进行分页的有效方法。

到目前为止,我已经安装了following 寻呼系统。但是,如果这个分页系统运行良好,它就有一个缺陷:视图中显示的列表不是完整的列表,而是用户根据页码查看列表的哪个部分。缺陷是如果我使用 jQuery 系统对项目进行排序,它只会对当前页面中的项目进行排序,而不是对总列表进行排序。

请允许我表明我的意思。说我有这个观点:

@using MyApp.Models
@model PagedList.IPagedList<MyApp.Utilities.CardDisplay>

<h2>
    Cards Display Results
</h2>

<script type="text/javascript">
    $(document).ready(function(){
        $('#cardRarity').change(function () {
            var showCardRarity = $(this).val();
            if (showCardRarity == "All") {
                $(".cardRarity").show();
            } else {
                $(".cardRarity").hide();
                $(".cardRarity-" + showCardRarity).each(function() {
                    $(this).show();
                });
            }
        });
        $('#cardType').change(function() {
            var showCardType = $(this).val();
            if (showCardType == "All") {
                $(".cardType").show();
            } else {
                $(".cardType").hide();
                $(".cardType-" + showCardType).each(function() {
                    $(this).show();
                });
            }
        });
        $('#cardColor').change(function() {
            var showCardColor = $(this).val();
            if (showCardColor == "All") {
                $(".cardColor").show();
            } else {
                $(".cardColor").hide();
                $(".cardColor-" + showCardColor).each(function() {
                    $(this).show();
                });
            }
        });
    });
</script>

@using (Html.BeginForm())
{
    <p>Filter by rarity: <select name="cardRarity" id="cardRarity" tabindex="1">
                             <option value="All">All</option>
                             <option value="Land">Land</option>
                             <option value="Common">Common</option>
                             <option value="Uncommon">Uncommon</option>
                             <option value="Rare">Rare</option>
                             <option value="Mythic Rare">Mythic Rare</option>
                             <option value="Special">Special</option>
                         </select>
        Filter by type: <select name="cardType" id="cardType" tabindex="2">
                            <option value="All">All</option>
                            <option value="Artifact">Artifact</option>
                            <option value="Instant">Instant</option>
                            <option value="Creature">Creature</option>
                            <option value="Land">Land</option>
                            <option value="Planeswalker">Planeswalker</option>
                            <option value="Enchantment">Enchantment</option>
                            <option value="Sorcery">Sorcery</option>
                            <option value="Tribal">Tribal</option>
                        </select>
        Filter by color: <select name="cardColor" id="cardColor" tabindex="3">
                            <option value="All">All</option>
                            <option value="White">White</option>
                            <option value="Red">Red</option>
                            <option value="Blue">Blue</option>
                            <option value="Green">Green</option>
                            <option value="Black">Black</option>
                            <option value="Gold">Gold</option>
                            <option value="Colorless">Colorless</option>
                        </select>
    </p>
}
@if (Model.Count > 0)
{
    if (Model.PageCount > 1)
    {
        <div class="center">
            Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
            of @Model.PageCount

            @if (Model.HasPreviousPage)
            {
                @Html.ActionLink("<<", "DisplayCardsResults", new { _page = 1, _sortOrder = ViewBag._currentSort })
                @Html.Raw(" ")
                @Html.ActionLink("< Prev", "DisplayCardsResults", new { _page = Model.PageNumber - 1, _sortOrder = ViewBag._currentSort })
            }
            else
            {
                @:<<
                @Html.Raw(" ");
                @:< Prev
            }

            @if (Model.HasNextPage)
            {
                @Html.ActionLink("Next >", "DisplayCardsResults", new { _page = Model.PageNumber + 1, _sortOrder = ViewBag._currentSort })
                @Html.Raw(" ")
                @Html.ActionLink(">>", "DisplayCardsResults", new { _page = Model.PageCount, _sortOrder = ViewBag._currentSort })
            }
            else
            {
                @:Next >
                @Html.Raw(" ")
                @:>>
            }
        </div>
    }
    <table id="resultTable">
        <tr>
            <th>Item number</th>
            <th>Card Name</th>
            <th>Number</th>
            <th>Color</th>
            <th>Mana Cost</th>
            <th>Mana Converted</th>
            <th>Card Type</th>
            <th>Power</th>
            <th>Toughness</th>
            <th>Rarity</th>
            <th>Card Set</th>
            <th>Artist Name </th>
            <th>Actions </th>
        </tr>
        @for (int i = 0; i < Model.Count; i++)
        {
            var className = i % 2 == 0 ? "even" : "odd";

            var row = ((i + 1) + ((Model.PageNumber - 1) * 50));

            <tr class="@className cardRarity cardRarity-@(Model[i].mCardRarity.Replace(" ", "-")) 
                cardType cardType-@(Model[i].mStrippedCardType)
                cardColor cardColor-@(Model[i].mCardColor)">
                <td>@row</td>
                <td class="center">
                    @(Model[i].mCardFlagFace == CardInfo.FlagFaceValue.Normal ?
                    Html.ActionLink(Model[i].mCardName, "CardDetails", new {_cardId = Model[i].mCardID}) :
                    Html.ActionLink(Model[i].mCardName + " // " + Model[i].mChildCard.mCardName, "CardDetails", new {_cardId = Model[i].mCardID}))
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardNumber)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardColor)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardManaCost)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardManaConverted)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardType)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardPower)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardToughness)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardRarity)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardSet.mCardSetName)
                </td>
                <td>
                    @Html.DisplayFor(_item => _item[i].mCardArtistName)
                </td>
                <td>
                    @Html.ActionLink("Details", "Details", new {@_cardId = Model[i].mCardID})
                    @Html.ActionLink("Edit", "Edit", new {@_cardId = Model[i].mCardID})
                    @Html.ActionLink("Delete", "Delete", new {@_cardId = Model[i].mCardID})
                </td>
            </tr>
        }
    </table>
    if (Model.PageCount > 1)
    {
        <div class="center">
            Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
            of @Model.PageCount

            @if (Model.HasPreviousPage)
            {
                @Html.ActionLink("<<", "DisplayCardsResults", new { _page = 1, _sortOrder = ViewBag._currentSort })
                @Html.Raw(" ")
                @Html.ActionLink("< Prev", "DisplayCardsResults", new { _page = Model.PageNumber - 1, _sortOrder = ViewBag._currentSort })
            }
            else
            {
                @:<<
                @Html.Raw(" ");
                @:< Prev
            }

            @if (Model.HasNextPage)
            {
                @Html.ActionLink("Next >", "DisplayCardsResults", new { _page = Model.PageNumber + 1, _sortOrder = ViewBag._currentSort })
                @Html.Raw(" ")
                @Html.ActionLink(">>", "DisplayCardsResults", new { _page = Model.PageCount, _sortOrder = ViewBag._currentSort })
            }
            else
            {
                @:Next >
                @Html.Raw(" ")
                @:>>
            }
        </div>
    }
}

假设我有 50 张卡片要显示的列表,但允许的卡片页数为 20。基于此视图,如果我将所选选项 Card Type 更改为 Creature,该视图确实会排序和显示所有生物,但仅显示 20 张卡片,而不是整个列表

这就是我需要帮助的原因:我需要想办法要么将整个列表加载到视图中,然后整理出一些分页方式,要么只重新显示想要的项目,我很乐意这样做它无需重写我的控制器方法,尽管我不介意添加新功能。我听说 JSon 可能会有所帮助,但我不知道它是如何工作的。谁能帮帮我?

编辑

这是工作代码!

首先,我已经像这样修改了javascript函数:

<script type="text/javascript">
    $(document).ready(function () {
        $('#cardRarity').change(function () {
            var showCardRarity = $(this).val();
            refreshResults(($(this).attr("id")), showCardRarity);
        });
        $('#cardType').change(function () {
            alert("Type changed");
            var showCardType = $(this).val();
            refreshResults(($(this).attr("id")), showCardType);
        });
        $('#cardColor').change(function () {
            alert("Color changed");
            var showCardColor = $(this).val();
            refreshResults(($(this).attr("id")), showCardColor);
        });

        function refreshResults(filter, value) {
            alert(filter);
            $.get("@Url.Action("DisplayCardsResults", "Card")", {
                _page: 1,
                _sortOrder: "@ViewBag._sortOrder",
                _filter: filter,
                _searchValue: value
            }, function(data) {
                $("#resultTable").html(data);
            });
        }
    });
</script>

function refreshResults 有点棘手,因为我必须弄清楚如何从 javascript 函数调用控制器方法并通过它传递数据。我喜欢 stackOverflow!

然后我删除了@if(Model.Count &gt; 0) 之外的所有内容,并将其放在我这样调用的局部视图中:

<div id="resultsDiv">
    @{
        Html.RenderPartial("_ResultsTable", @Model);
    }
</div>

然后,在我的控制器中,我必须对事物进行排序:

public ActionResult DisplayCardsResults(int? _page, string _sortOrder, string _filter = "", string _searchValue = "")
{
    ViewBag._searchValue = _searchValue;
    ViewBag._filter = _filter;

    if (Request.HttpMethod != "GET")
    {
        _page = 1;
    }

    int pageNumber = (_page ?? 1);

    if (Request.IsAjaxRequest())
    {
        switch (_filter)
        {

            // The mListCardsToShow is an inner list I keep and it is different from the mListCards because of the where clause which flush the rest of the data.

            case "cardRarity":
                if (_searchValue == "All")
                {
                    mListCardsToShow = mListCards.ToList();
                }
                else
                {
                    mListCardsToShow.AddRange(mListCards.Where(_item => _item.mMasterCard.mCardRarity == _searchValue));
                }
                break;
            case "cardType":
                if (_searchValue == "All")
                {
                    mListCardsToShow = mListCards.ToList();
                }
                else
                {
                    mListCardsToShow.AddRange(mListCards.Where(_item => _item.mMasterCard.mCardType == _searchValue));
                }
                break;
            case "cardColor":
                if (_searchValue == "All")
                {
                    mListCardsToShow = mListCards.ToList();
                }
                else
                {
                    mListCardsToShow.AddRange(mListCards.Where(_item => _item.mMasterCard.mCardColor == _searchValue));
                }
                break;
            default:
                mListCardsToShow = mListCards.ToList();
                break;
        }

        return PartialView("_ResultsTable", mListCardsToShow.ToPagedList(pageNumber, ValueDomain.PAGE_SIZE));
    }

    return View(mListCards.ToPagedList(pageNumber, ValueDomain.PAGE_SIZE));
}

现在,我必须承认排序并不完美,例如,我需要考虑过滤器的每三个,但那是另一回事了。一切正常,我为此感到高兴!

【问题讨论】:

    标签: c# jquery asp.net-mvc razor pagination


    【解决方案1】:

    这听起来确实像是 AJAX 可以帮助解决您的问题并使事情变得更优雅的东西 - 值得做一些研究。现在,每当用户单击其中一个链接时,都需要重新加载整个页面才能简单地获取表中的下一页数据。您可以在需要时仅动态更新表格。

    查看jQuery.ajax 的文档 - 在您传递给服务器的 URL 中,您可以设置过滤器(分页和排序),并在成功处理程序中更新表中的值。也不要被术语 JSON 吓倒,这只是 js 主要使用的数据存储术语,您可以在控制器上设置一个操作,该操作将返回 JSON 中的信息,该信息在 AJAX 成功处理程序中处理。

    PS:Yay MtG,祝你好运:)

    【讨论】:

    • 我想尝试一下 Ajax!但我不确定我该怎么做。
    【解决方案2】:

    如果您有很多值,加载整个列表通常不是一个好主意。在您的情况下,虽然 50 条记录并不多,但通常不是一个有效的设计。 看看下面的文章。

    http://demo.aspnetawesome.com/GridDemo/CustomQuerying

    http://kevww.wordpress.com/2011/12/20/how-to-implement-paging-sorting-in-mvc-3-part-2-how-to-use-it-for-paging-sorting/

    http://www.4guysfromrolla.com/articles/012611-1.aspx

    Mvc 也有一个开箱即用的 WebGrid,它通常适用于这种类型的场景。 可能会满足您的需求。

    http://stick2basic.wordpress.com/2013/03/18/efficient-paging-and-sorting-with-webgrid-web-helper-asp-net-mvc/

    http://msdn.microsoft.com/en-us/magazine/hh288075.aspx

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      +1 为泰勒。 AJAX 是我能想到的唯一优雅的方式。每次更改下拉列表时,您都必须将页面提交到服务器,您将获得数据,但您的页面每次都会刷新而无需 AJAX。

      编辑:

      这就是使用 ajax 的方式。

      这是你的看法

      @using MyApp.Models
      @model PagedList.IPagedList<MyApp.Utilities.CardDisplay>
      
      <h2>
          Cards Display Results
      </h2>
      
      <script type="text/javascript">
          $(document).ready(function(){
              $('#cardRarity').change(function () {
                  var showCardRarity = $(this).val();
                  refreshResults(($(this).attr("id")),showCardRarity );
              });
              $('#cardType').change(function() {
                  var showCardType = $(this).val();
                  refreshResults(($(this).attr("id")),showCardRarity );
              });
              $('#cardColor').change(function() {
                  var showCardColor = $(this).val();
                  refreshResults(($(this).attr("id")),showCardRarity );
              });
      
              function refreshResults(filter, value){
                $.get("YourController/DisplayCardsResults", 
                  { 
                      _page = 1,   
                      _sortOrder = ViewBag._currentSort,
                      _filter = filter,
                      _searchValue =  value 
                  },
                  function (data{
                    $("#resultsDiv").html(data);
                  }
          });
      </script>
      
      @using (Html.BeginForm())
      {
          <p>Filter by rarity: <select name="cardRarity" id="cardRarity" tabindex="1">
                                   <option value="All">All</option>
                                   <option value="Land">Land</option>
                                   <option value="Common">Common</option>
                                   <option value="Uncommon">Uncommon</option>
                                   <option value="Rare">Rare</option>
                                   <option value="Mythic Rare">Mythic Rare</option>
                                   <option value="Special">Special</option>
                               </select>
              Filter by type: <select name="cardType" id="cardType" tabindex="2">
                                  <option value="All">All</option>
                                  <option value="Artifact">Artifact</option>
                                  <option value="Instant">Instant</option>
                                  <option value="Creature">Creature</option>
                                  <option value="Land">Land</option>
                                  <option value="Planeswalker">Planeswalker</option>
                                  <option value="Enchantment">Enchantment</option>
                                  <option value="Sorcery">Sorcery</option>
                                  <option value="Tribal">Tribal</option>
                              </select>
              Filter by color: <select name="cardColor" id="cardColor" tabindex="3">
                                  <option value="All">All</option>
                                  <option value="White">White</option>
                                  <option value="Red">Red</option>
                                  <option value="Blue">Blue</option>
                                  <option value="Green">Green</option>
                                  <option value="Black">Black</option>
                                  <option value="Gold">Gold</option>
                                  <option value="Colorless">Colorless</option>
                              </select>
          </p>
      }
      
      <div id="resultsDiv">
          @Html.RenderPartial("_ResultsTable",@Model)
      <div>
      

      把这个放在局部视图_ResultsTable中

      @using MyApp.Models
      @model PagedList.IPagedList<MyApp.Utilities.CardDisplay>
      
      @if (Model.Count > 0)
          {
              if (Model.PageCount > 1)
              {
                  <div class="center">
                      Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
                      of @Model.PageCount
      
                  @if (Model.HasPreviousPage)
                  {
                      @Html.ActionLink("<<", "DisplayCardsResults", new { _page = 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                      @Html.Raw(" ")
                      @Html.ActionLink("< Prev", "DisplayCardsResults", new { _page = Model.PageNumber - 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                  }
                  else
                  {
                      @:<<
                      @Html.Raw(" ");
                      @:< Prev
                  }
      
                  @if (Model.HasNextPage)
                  {
                      @Html.ActionLink("Next >", "DisplayCardsResults", new { _page = Model.PageNumber + 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                      @Html.Raw(" ")
                      @Html.ActionLink(">>", "DisplayCardsResults", new { _page = Model.PageCount, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                  }
                  else
                  {
                      @:Next >
                      @Html.Raw(" ")
                      @:>>
                  }
              </div>
          }
          <table id="resultTable">
              <tr>
                  <th>Item number</th>
                  <th>Card Name</th>
                  <th>Number</th>
                  <th>Color</th>
                  <th>Mana Cost</th>
                  <th>Mana Converted</th>
                  <th>Card Type</th>
                  <th>Power</th>
                  <th>Toughness</th>
                  <th>Rarity</th>
                  <th>Card Set</th>
                  <th>Artist Name </th>
                  <th>Actions </th>
              </tr>
              @for (int i = 0; i < Model.Count; i++)
              {
                  var className = i % 2 == 0 ? "even" : "odd";
      
                  var row = ((i + 1) + ((Model.PageNumber - 1) * 50));
      
                  <tr class="@className cardRarity cardRarity-@(Model[i].mCardRarity.Replace(" ", "-")) 
                      cardType cardType-@(Model[i].mStrippedCardType)
                      cardColor cardColor-@(Model[i].mCardColor)">
                      <td>@row</td>
                      <td class="center">
                          @(Model[i].mCardFlagFace == CardInfo.FlagFaceValue.Normal ?
                          Html.ActionLink(Model[i].mCardName, "CardDetails", new {_cardId = Model[i].mCardID}) :
                          Html.ActionLink(Model[i].mCardName + " // " + Model[i].mChildCard.mCardName, "CardDetails", new {_cardId = Model[i].mCardID}))
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardNumber)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardColor)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardManaCost)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardManaConverted)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardType)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardPower)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardToughness)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardRarity)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardSet.mCardSetName)
                      </td>
                      <td>
                          @Html.DisplayFor(_item => _item[i].mCardArtistName)
                      </td>
                      <td>
                          @Html.ActionLink("Details", "Details", new {@_cardId = Model[i].mCardID})
                          @Html.ActionLink("Edit", "Edit", new {@_cardId = Model[i].mCardID})
                          @Html.ActionLink("Delete", "Delete", new {@_cardId = Model[i].mCardID})
                      </td>
                  </tr>
              }
          </table>
          if (Model.PageCount > 1)
          {
              <div class="center">
                  Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
                  of @Model.PageCount
      
                  @if (Model.HasPreviousPage)
                  {
                      @Html.ActionLink("<<", "DisplayCardsResults", new { _page = 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                      @Html.Raw(" ")
                      @Html.ActionLink("< Prev", "DisplayCardsResults", new { _page = Model.PageNumber - 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                  }
                  else
                  {
                      @:<<
                      @Html.Raw(" ");
                      @:< Prev
                  }
      
                  @if (Model.HasNextPage)
                  {
                      @Html.ActionLink("Next >", "DisplayCardsResults", new { _page = Model.PageNumber + 1, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                      @Html.Raw(" ")
                      @Html.ActionLink(">>", "DisplayCardsResults", new { _page = Model.PageCount, _sortOrder = ViewBag._currentSort, _filter = ViewBag._filter, _searchValue = ViewBag._searchValue })
                  }
                  else
                  {
                      @:Next >
                      @Html.Raw(" ")
                      @:>>
                  }
              </div>
          }
      }
      

      在控制器中这样做:

      public ActionResult DisplayCardsResults(int _page, string _sortOrder, string _filter = "", string _searchValue = "")
      {
        ViewBag._filter = _filter;
        ViewBag._searchValue= _searchValue;
      
        //Do whatever you are doing to get the cards but to the resultant collection add the following where condition, suppose the collection is in var cards
      
      
       switch (_filter)
                  {
                      case "cardRarity":
                          cards = cards.Where(s => s.CardRarity == _searchValue);
                          break;
                      case "cardType":
                          cards = cards.Where(s => s.CardType == _searchValue);
                          break;
                      case "cardColor":
                          cards = cards.Where(s => s.CardColor == _searchValue);
                          break;
                      default:
                          // no filter
                          break;
                  }
         if(Request.isAjaxRequest)
            return PartialView("_ResultsTable",cards);
        return View(cards);
      }
      

      【讨论】:

      • 正如我所提到的,我确实认为这将是一个有趣的想法,但我不知道如何做到这一点,因为我不知道 AJAX,以免它存在......:S
      • 我在编辑中添加了一个使用 AJAX 执行此操作的操作,但您可能希望在页面加载时显示进度条,以便用户知道表格正在刷新。
      • 我明白你想让我做什么,我很感激。唯一的问题是您包含的 javascript 包含很多错误并且不能这样编写。我正在努力让它发挥作用,所以如果你不介意检查一下,那就太好了。 :)
      • 至于进度条,这也是我需要做的,但不知道怎么做。
      • 是函数 refreshResults 似乎不对。在我看来,出现了许多错误。
      猜你喜欢
      • 2017-08-30
      • 2016-08-04
      • 1970-01-01
      • 1970-01-01
      • 2015-11-18
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多