【问题标题】:Sorting fields ascending and descending with single link使用单个链接对字段进行升序和降序排序
【发布时间】:2016-02-21 20:33:24
【问题描述】:

所以我有一个带有表格的 MVC 应用程序,当点击标题时,我希望它根据点击次数在升序或降序排序之间切换。

目前我只能降序或升序排序,我不知道如何实现。 userName 只是我在用户登录时从另一个控制器获取的变量,并且我正在使用开关,因为我计划拥有多个可排序的标题。

查看

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

控制器

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;
    }
}

【问题讨论】:

    标签: asp.net-mvc linq sorting asp.net-mvc-5


    【解决方案1】:

    将您的排序顺序放入 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 语句中?
    • 正确,到目前为止,我一直在我的项目中使用它并且像魅力一样工作。希望它可以帮助您顺利上路。
    【解决方案2】:

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

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

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

    文章底部的代码使用说明。

    我的索引视图(隐藏元素所在的位置)。 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>
    

    最初将_Activity部分视图返回到上述Index视图中的ActionResult“_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 部分视图中单击&lt;a id="log-dropdown-user-sort"&gt;&lt;img.../&gt;&lt;/a&gt; 时,javascript 点击事件$('#partial_Activity').on('click', '#log-dropdown-user-sort', function (e) {} 会触发并调用setSort(DOM element, string) 函数。

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

    然后GetActivity GET 方法当然会查询并返回基于sortOrder 参数排序的数据,该参数由switch 语句评估。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 为了得到一个有用的答案,这个反应需要扩展。解释为什么这是问题的答案。
      【解决方案4】:

      对于 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;
                     ....
                   }
                 }
      

      你最终会得到一个全局排序方向......但我认为这没关系。否则,您需要为每列一个单独的 var,然后在每种情况下添加 if else。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-01
        • 2020-06-06
        • 2016-11-05
        • 2017-06-10
        • 1970-01-01
        • 2020-12-10
        • 2015-11-30
        • 2013-05-13
        相关资源
        最近更新 更多