使用单个链接按字段升序和降序排序

5

我有一个MVC应用程序,其中包含一个表格,当点击表头时,我希望它可以在升序或降序之间切换,具体取决于点击次数。

目前,我只能进行升序或降序排序,不知道如何同时实现两者。 userName只是我从另一个控制器中获取的变量,当用户登录时使用switch语句,因为我计划拥有多个可排序的表头。

视图

<table>
    <tr>
        <th>
            <a href="@Url.Action("Dispatch", "Calls", new { userName = Session["UserName"], new { sortOrder = "Name_desc" })">Name</a>
        </th>
    </tr>
</table>

Controller

public ActionResult Index(string userName, string sortOrder)
{
    string userName = Session["UserName"].ToString();

    var model = from t in db.Users
                where t.UserName == userName
                select t;

    switch(sortOrder)
    {
        case "Name_desc":
            model = model.OrderByDescending(t => t.UserName);
            break;
    }
}
4个回答

9

将排序顺序放入ViewBag值中。检查内联(Viewbag.NameSort):

视图:

<th>
    <a href="@Url.Action("Dispatch", "Calls", new { userName = Session["UserName"], new { sortOrder = ViewBag.NameSort })">Name</a>
</th>

控制器:

public ActionResult Index(string userName, string sortOrder)
{
    string userName = Session["UserName"].ToString();

    // Convert sort order
    ViewBag.NameSort = sortOrder == "Name" ? "Name_desc" : "Name";

    var model = from t in db.Users
                where t.UserName == userName
                select t;

    switch(sortOrder)
    {
        case "Name_desc":
            model = model.OrderByDescending(t => t.UserName);
            break;
        case "Name":
            model = modelOrderBy(t => t.UserName);
            break;
    }
}

那么对于每个额外的标题,我需要创建一个新的ViewBag值并将其添加到switch语句中吗? - Mr.Smithyyy
正确,到目前为止我在我的项目中一直使用它,而且效果非常好。希望它能帮助你上路。 - Jelle Oosterbosch

2

我不想使用ViewBag值,所以我使用隐藏元素的属性来跟踪用户的排序选择。

我有一个主页索引页面,其中包含一个内部局部视图,该视图显示用户活动日志表中的一个部分。表格有一个标题行,在大多数列中都有一个下拉列表和右对齐的排序图标。当用户点击排序图标时,数据按该列升序或降序排序(取决于排序切换状态)。

提前道歉,我为这个简单的解决方案补充了很多代码,但我认为为了给看我的答案的人(可能是新手)提供完整的上下文,代码补充应该有助于组合一个简单而完整的数据检索和排序切换解决方案,而不使用ViewBags。

代码用法解释在帖子底部。

我的Index视图(隐藏元素所在的位置)。这里的sort属性是主要关注点:

<div class="hidden">
    <span id="act-user-sort" sort=""></span>
    <span id="act-type-sort" sort=""></span>
    <span id="act-level-sort" sort=""></span>
    <span id="act-date-sort" sort=""></span>
</div>
<section id="partial_Activity">
    @Html.Action("_Activity", "Home")
</section>

ActionResult "_Activity"最初返回上述Index视图中的"_Activity"部分视图:

public ActionResult _Activity()
{
    using (var context = new ApplicationDbContext())
    {
        //create new LogModel object.  this holds all that will be returned to the view
        LogModel logModel = new LogModel();

        //create new LogSelect object. this is the list of drop downs for the activity log table.
        LogSelect logSelect = new LogSelect();

        //query to get initial set
        var result = from log in context.Logs
                     join user in context.Users on log.UserId equals user.Id into userlog
                     from user in userlog.DefaultIfEmpty()
                     orderby log.LogDate descending
                     select new Models.UserActivity { Log = log, User = user }; //this could bring back null user objects

        //populate items for drop down lists
        logSelect.LogUsers = result.Select(u => new LogUser { Name = u.User.FirstName + " " + u.User.LastName, Id = u.User.Id }).Distinct().ToList();
        logSelect.LogTypes = result.Select(t => t.Log.Type).Distinct().ToList();
        logSelect.LogLevels = result.Select(t => t.Log.Level).Distinct().ToList();

        //initial page for pagination is 1, default page size is 10.
        int pageIndex = 1;
        int pageSize = 10;

        //return view with paginated list.
        PaginatedList<UserActivity> pgList = PaginatedList<UserActivity>.Create(result.AsNoTracking(), pageIndex, pageSize);

        //fill view model.
        logModel.LogSelect = logSelect;
        logModel.UserActivity = pgList;

        return PartialView(logModel);
    }
}

我的 "_Activity" 操作部分视图(包含表格和排序按钮):

@model Utils.Models.LogModel
<style>
...
</style>
<div>
    <h3>Recent Activity</h3>
</div>
<div style="height:20px"></div>
@* the panel class rounds the corners of the table *@
<div class="panel panel-default table-responsive" style="font-size:.9em;">
    <table id="log-table" class="table table-striped table-bordered table-hover log-table" style="width:100%;">
        <thead>
            <tr class="bg-primary">
                <th class="dropdown log-dropdown">
                    <a href="#" data-toggle="dropdown" class="dropdown-toggle">User&nbsp;&nbsp;<b class="caret"></b></a>
                    <div class="log-dropdown-sort log-dropdown-sort-init">
                        <a sort="" href="#" id="log-dropdown-user-sort"><img src="~/Images/ui/alpha-sort-white.png" /></a>
                    </div>
                    <ul id="log-dropdown-user" class="dropdown-menu log-dropdown">
                        @foreach (var user in Model.LogSelect.LogUsers)
                        {
                            <li><a id="log-user" href="#">@user.Name</a><span id="log-user-id" class="hidden">@user.Id</span></li>
                        }
                    </ul>
                </th>
                <th>Action</th>
                <th class="dropdown log-dropdown">
                    <a href="#" data-toggle="dropdown" class="dropdown-toggle">Type&nbsp;&nbsp;<b class="caret"></b></a>
                    <div class="log-dropdown-sort log-dropdown-sort-init">
                        <a sort="" href="#" id="log-dropdown-type-sort"><img src="~/Images/ui/alpha-sort-white.png" /></a>
                    </div>
                    <ul id="log-dropdown-type" class="dropdown-menu">
                        @foreach (var log in Model.LogSelect.LogTypes)
                        {
                            <li><a id="log-type" href="#">@log</a><span class="hidden">@log</span></li>
                        }
                    </ul>
                </th>
                <th class="log-dropdown">
                    Date
                    <div class="log-dropdown-sort log-dropdown-sort-init">
                        <a sort="" href="#" id="log-dropdown-date-sort"><img src="~/Images/ui/alpha-sort-white.png" /></a>
                    </div>
                    <div class="log-dropdown-date log-dropdown-date-init">
                        <a href="#" id="log-dropdown-date-range"><img src="~/Images/ui/calendar-white.png" /></a>
                    </div>
                </th>
            </tr>
        </thead>
        <tbody>

            @foreach (var log in Model.UserActivity)
            {
                <tr>
                    <td>@log.User.FirstName @log.User.LastName</td>
                    <td class="log-message">@log.Log.Message</td>
                    <td>@log.Log.Type</td>
                    <td class="log-date">@log.Log.LogDate</td>
                </tr>
            }
        </tbody>
    </table>

</div>
<div>
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        @for (int pg = 1; pg <= Model.UserActivity.TotalPages; pg++)
        {
            if (pg == Model.UserActivity.PageIndex)
            {
                <li class="active"><a href="#">@pg</a></li>
            }
            else
            {
                <li><a href="#">@pg</a></li>
            }
        }
        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</div>

处理事件的jQuery代码如下:
/**********************************************************************************************
_Activity.cshtml

/*********************************************************************************************/

//activity log sort buttons.
$('#partial_Activity').on('click', '#log-dropdown-user-sort', function (e) {
    e.preventDefault();
    var data = {};
    data.sortOrder = setSort($("#act-user-sort"), "user");
    GetActivity(data);
});

$('#partial_Activity').on('click', '#log-dropdown-type-sort', function (e) {
    e.preventDefault();
    var data = {};
    data.sortOrder = setSort($("#act-type-sort"), "type");
    GetActivity(data);
});

$('#partial_Activity').on('click', '#log-dropdown-level-sort', function (e) {
    e.preventDefault();
    var data = {};
    data.sortOrder = setSort($("#act-level-sort"), "level");
    GetActivity(data);
});

$('#partial_Activity').on('click', '#log-dropdown-date-sort', function (e) {
    e.preventDefault();
    var data = {};
    data.sortOrder = setSort($("#act-date-sort"), "date");
    GetActivity(data);
});


//this function checks and sets the "sort" attribute of the passed element.
//then based on setting of the "sort" attribute, returns a string value that will be used by code-behind to sort values in the table.
function setSort(element, sort) {

    if (element.attr("sort") == "") {
        element.attr("sort", "asc");
        sort = sort + "_asc";
    }
    else {
        if (element.attr("sort") == "asc") {
            element.attr("sort", "desc")
            sort = sort + "_desc";
        }
        else {
            element.attr("sort", "asc")
            sort = sort + "_asc";
        }
    }
    return sort;
}

function GetActivity(options) {
    $.ajax({
        cache: false,
        type: "GET",
        url: "../Home/GetActivity",
        data: options,
        contentType: "application/json; charset=utf-8",
        success: function (obj) {
            $("#partial_Activity").html(obj);
        }
    }).done(function () {
    });
}

当用户点击排序按钮时,会返回部分视图的GET方法:
[HttpGet]
public PartialViewResult GetActivity(
    string sortOrder,
    string userFilter,
    string typeFilter,
    string levelFilter,
    DateTime? startDate,
    DateTime? endDate,
    int pageIndex = 1,
    int pageSize = 10)
{

    using (var context = new ApplicationDbContext())
    {
        //create new LogModel object.  this holds all that will be returned to the view
        LogModel logModel = new LogModel();

        //create new LogSelect object. this is the list of drop downs for the activity log table.
        LogSelect logSelect = new LogSelect();

        //query
        var result = from log in context.Logs
                     join user in context.Users on log.UserId equals user.Id into userlog
                     from user in userlog.DefaultIfEmpty()
                     orderby log.LogDate descending
                     select new Models.UserActivity { Log = log, User = user }; //this could bring back null user objects.

        //populate items for drop down lists
        logSelect.LogUsers = result.Select(u => new LogUser { Name = u.User.FirstName + " " + u.User.LastName, Id = u.User.Id }).Distinct().ToList();
        logSelect.LogTypes = result.Select(t => t.Log.Type).Distinct().ToList();
        logSelect.LogLevels = result.Select(t => t.Log.Level).Distinct().ToList();

        //filters
        if (!String.IsNullOrEmpty(userFilter)) { result = result.Where(r => r.User.UserName.Equals(userFilter)); }
        if (!String.IsNullOrEmpty(typeFilter)) { result = result.Where(r => r.Log.Type.Equals(typeFilter)); }
        if (!String.IsNullOrEmpty(levelFilter)) { result = result.Where(r => r.Log.Level.Equals(levelFilter)); }
        if (startDate.HasValue) { result = result.Where(r => r.Log.LogDate >= startDate); }
        if (endDate.HasValue) { result = result.Where(r => r.Log.LogDate <= endDate); }

            //always default sorting by date desc
            result = result.OrderByDescending(r => r.Log.LogDate);

            //sorting (any selection other than date sorting will be sorted secondarily by date descending)
            switch (sortOrder)
            {
                case "date_asc":
                    result = result.OrderBy(r => r.Log.LogDate);
                    break;
                case "date_desc":
                    result = result.OrderByDescending(r => r.Log.LogDate);
                    break;
                case "user_asc":
                    result = result.OrderBy(r => r.User.FirstName)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                case "user_desc":
                    result = result.OrderByDescending(r => r.User.FirstName)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                case "type_asc":
                    result = result.OrderBy(r => r.Log.Type)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                case "type_desc":
                    result = result.OrderByDescending(r => r.Log.Type)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                case "level_asc":
                    result = result.OrderBy(r => r.Log.Level)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                case "level_desc":
                    result = result.OrderByDescending(r => r.Log.Level)
                                   .ThenByDescending(r => r.Log.LogDate);
                    break;
                default:
                    break;
            }

        //turn result into paginated list
        PaginatedList<UserActivity> pgList = PaginatedList<UserActivity>.Create(result.AsNoTracking(), pageIndex, pageSize);

        //fill view model.
        logModel.LogSelect = logSelect;
        logModel.UserActivity = pgList;

        //return model to the view
        return PartialView("_Activity", logModel);
    }
}
解释:

当您在_Activity局部视图中单击<a id="log-dropdown-user-sort"><img.../></a>时,JavaScript点击事件$('#partial_Activity').on('click', '#log-dropdown-user-sort', function (e) {}将触发并调用setSort(DOM element, string)函数。

setSort()函数设置传递元素的"sort"属性,将属性值在'asc''desc'之间切换,从而影响函数内未来的逻辑流,并返回一个连接的字符串值,该值将用作下一步调用的GetActivity GET方法中的sortOrder参数。

然后,GetActivity GET方法根据switch语句评估的sortOrder参数查询并返回排序数据。

0
只需在您的 .js 文件中放置代码 - "order": [[6,"asc"]]。其中 6 表示列的 placeNumber。例如 1.id,2.name 等。

为了得到一个有用的答案,这个回答需要进一步扩展。解释为什么这是对问题的回答。 - Jeroen Heier

0
对于 Razor 页面,我只需在页面模型中添加一个 if-else 语句和 "CurrentSortDir" 变量以及 "ToggleSortDir" 变量即可。
因此我的“index.cshtml”如下:
         <th>
            <a asp-page="./Index" 
            asp-route-sortOrder="ManufacturerPN"
            asp-route-sortDir = "@Model.ToggleSortDir">
                @Html.DisplayNameFor(model => model.Inventory[0].ManufacturerPN)
            </a>
          </th>

我的 index.cshtml.cs 文件:

public string CurrentSortDir { get; set; }
public string ToggleSortDir {get; set; }
public async Task OnGetAsync(string sortOrder, string sortDir, string currentFilter, string searchString, int? pageIndex)
    {
        CurrentSort = sortOrder;
        CurrentSortDir = sortDir;
  if (CurrentSortDir == "DESC")
        {
            ToggleSortDir = "ASC";
            switch (sortOrder)
            {
                case "ManufacturerPN":
                    Items = Items.OrderByDescending(s => s.ManufacturerPN);
                    break;
             ....
             }
         }
         else
         {
           ToggleSortDir = "DESC";
            switch (sortOrder)
            {
                case "ManufacturerPN":
                    Items = Items.OrderBy(s => s.ManufacturerPN);
                    break;
               ....
             }
           }

你最终会得到一个全局的排序方向...但我认为这是可以接受的。否则,你需要为每一列都创建一个单独的变量,然后在每种情况下添加if else语句。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接