如何在我的视图中排序列表(IEnumerable)并保持我的过滤?

时间:2015-03-25 16:48:10

标签: javascript c# sorting asp.net-mvc-5 filtering

我正在创建一个数字留言簿自助服务程序。我有一个管理部分,管理员可以登录并查看所有已注册的访客。此功能的视图顶部是一个带有文本框和下拉列表的区域,管理员可以在其中添加其过滤器。当他们点击“过滤器”时,列表会刷新以仅包含符合过滤条件的项目。这是有效的,但我现在尝试将字母排序包括在列表中。当有人点击表头“First Name”或“Last Name”时,它会向控制器发送一个命令,以便按此列的升序或降序对列表进行排序。唯一的问题是它每次都会从数据库中获取一个新列表并丢失所有过滤器。

我试图通过ViewBag和会话变量将过滤后的列表作为变量传递。有一段时间,当我试图迭代它(使用会话变量)时,我得到了一个“操作无法完成,因为DbContext已被处理掉”。

我曾尝试过这个教程:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application但是没有任何内容显示如何保留过滤器。经过数小时的反复试验和互联网研究后,我不确定下一步该解决这个问题。我一直在考虑寻找一个javascript解决方案,但我不是很擅长javascript,但不知道从哪里开始寻找。

以下是视图代码:

    @model IEnumerable<VirtualGuestbook.Models.Guest>
    @using System.Collections;
    @{
        ViewBag.Title = "Index";
        Layout = "~/Views/Shared/_BackendLayout.cshtml";
    }


    <div class="blackserif">
        <p class="maroonLfont">Guests</p>
        <hr />
        <h2>Search by:</h2>
        @using (Html.BeginForm("Index", "Guests", FormMethod.Get))
        {
            <div class="searchblackserif">
                <p>
                    <div id="left30search">
                        <span class="maroonfont">Personal Information</span><br /><br />
                        Name (First or Last): @Html.TextBox("NameString")<br /><br />
                        Phone #: @Html.TextBox("PhoneString")<br /><br />
                        Email: @Html.TextBox("EmailString")
                    </div>
                    <div id="right30search">
                        <span class="maroonfont">Visit Specifics</span><br /><br />
                        After (Date): @Html.TextBox("startDate")<br />(AND / OR)<br />
                        Before (Date): @Html.TextBox("endDate")<br /><br />
                        Minimum Times Visited: @Html.TextBox("VisitString")
                    </div>
                    <div id="middle30search">
                        <span class="maroonfont">Address Specifics</span><br /><br />
                        City: @Html.TextBox("CityString")<br /><br />
                        State: @Html.DropDownList("stateList", "All")<br /><br />
                        ZipCode: @Html.TextBox("ZipString")<br /><br />
                        <input type="submit" value="Filter" />
                    </div>
                </p>
            </div>
        }
        <div id="postSearch">
            <table id="myTable" class="table">
                <thead>
                    <tr class="maroonfont">
                        <th>
                            Prefix
                        </th>
                        <th>
                            First Name
                        </th>
                        <th>
                            Last Name
                        </th>
                        <th>
                            Phone #
                        </th>
                        <th>
                            Email
                        </th>
                        <th>
                            Address (Line 1)
                        </th>
                        <th>
                            Address (Line 2)
                        </th>
                        <th>
                            City
                        </th>
                        <th>
                            State
                        </th>
                        <th>
                            ZipCode
                        </th>
                        <th>
                            College Rating
                        </th>
                        <th>
                            Heard About How?
                        </th>
                        <th>
                            Times Visited
                        </th>
                        <th>
                            Date of Last Visit
                        </th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var item in Model)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.Prefix)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.FirstName)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.LastName)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Phone)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Email)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.AddressL1)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.AddressL2)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.City)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.State)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Zip)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Rating)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.HearAbout)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.VisitNumber)
                            </td>
                            <td>
                                @{string date = item.datevisited.ToShortDateString();
                                }
                                @date
                            </td>

                            <td>
                                @if (User.IsInRole("S"))
                                {
                                    @Html.ActionLink("Delete", "Delete", new { id = item.GuestID })
                                }
                            </td>
                        </tr>
                    }
                </tbody>

            </table>
        </div>
    </div>

   @section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <!-- DataTables -->
    <script type="text/javascript" charset="utf8" src="~/Scripts/jquery.dataTables.js">
        $(document).ready(function () {
            $('#myTable').dataTable();
        });
    </script>
}

这是索引方法的控制器代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using VirtualGuestbook.Models;

namespace VirtualGuestbook.Controllers
{
    public class GuestsController : Controller
    {
        private VirtualGuestbookDBEntities db = new VirtualGuestbookDBEntities();
        [Authorize(Roles = "A, E, S")]
        public ActionResult Index(string NameString, string PhoneString, string EmailString, string CityString, string stateList, string ZipString, string startDate, string endDate, string VisitString, string sortOrder)
        {
            ViewBag.LastNameSortParam = String.IsNullOrEmpty(sortOrder) ? "last_name_desc" : "";
            ViewBag.FirstNameSortParam = String.IsNullOrEmpty(sortOrder) ? "first_name_desc" : "";
            string[] stateCodeList = { "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY" };
            ViewBag.stateList = new SelectList(stateCodeList);

              var guests = from g in db.Guests select g;
                if (!String.IsNullOrEmpty(NameString))
                {
                    guests = guests.Where(s => s.FirstName.Contains(NameString) || s.LastName.Contains(NameString));
                }
                if (!String.IsNullOrEmpty(PhoneString))
                {
                    guests = guests.Where(s => s.Phone.Contains(PhoneString));
                }
                if (!String.IsNullOrEmpty(EmailString))
                {
                    guests = guests.Where(s => s.Email.Contains(EmailString));
                }
                if (!String.IsNullOrEmpty(CityString))
                {
                    guests = guests.Where(s => s.City.Contains(CityString));
                }
                if (!String.IsNullOrEmpty(ZipString))
                {
                    guests = guests.Where(s => s.Zip.Contains(ZipString));
                }
                if (!String.IsNullOrEmpty(stateList))
                {
                    guests = guests.Where(s => s.State.Contains(stateList));
                }
                if (!String.IsNullOrEmpty(startDate))
                {
                    System.DateTime dt = Convert.ToDateTime(startDate);
                    guests = guests.Where(s => s.datevisited >= dt);
                }
                if (!String.IsNullOrEmpty(endDate))
                {
                    System.DateTime dt = Convert.ToDateTime(endDate);
                    guests = guests.Where(s => s.datevisited <= dt);
                }
                if (!String.IsNullOrEmpty(VisitString))
                {
                    int minNumVisits = Convert.ToInt32(VisitString);
                    guests = guests.Where(s => s.VisitNumber >= minNumVisits);
                }

            switch (sortOrder)
            {
                case "last_name_desc":
                    guests = guests.OrderByDescending(s => s.LastName);
                    break;
                case "first_name_desc":
                    guests = guests.OrderByDescending(s => s.FirstName);
                    break;
                default:
                    guests = guests.OrderBy(s => s.LastName);
                    break;
            }
            return View(guests);
        }
    }
}

最后,这是视图代码背后的布局页面。这可能是我搞乱javascript / css引用的地方。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" href="~/Content/images/favicon.ico">
    <title>@ViewBag.Title - VirtualGuestbook</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    <script src="~/Scripts/modernizr-2.6.2.js"></script>
    <!-- DataTables CSS -->
    <link rel="stylesheet" type="text/css" href="~/Content/jquery.dataTables.css">
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">

            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "AdminIndex", "Home")</li>
                    @if (User.Identity.IsAuthenticated)
                    {
                        <li>@Html.ActionLink("Guest List", "Index", "Guests")</li>
                        if (!User.IsInRole("A, S"))
                        {
                            <li>@Html.ActionLink("Employees List", "Index", "Administrators")</li>
                            <li>@Html.ActionLink("Add New Employee", "Create", "Administrators")</li>
                        }
                        if (User.IsInRole("S"))
                        {
                            <li></li>
                        }
                        <li>
                            <img src="~/Content/images/vertBar.png"
                                 alt="vertical bar for logical separation" width="3" height="50" />
                        </li>
                        @*<li><a href="#">Welcome @User.Identity.Name!</a></li>*@
                        <li><a href="#">Welcome!</a></li>
                        if (Session["AdminID"] != null)
                        {
                            int logID = (int)Session["AdminID"];
                            if (logID != null)
                            {
                                <li>@Html.ActionLink("Set/Change Security Questions", "SetQuests", new { controller = "Accounts", id = logID })</li>
                                <li>@Html.ActionLink("Change Password", "ChangePass", new { controller = "Accounts", id = logID })</li>
                            }
                        }
                        <li>@Html.ActionLink("Logout", "Logout", "Accounts")</li>
                    }
                    else
                    {
                        <li>
                            <img src="~/Content/images/vertBar.png"
                                 alt="vertical bar for logical separation" width="3" height="50" />
                        </li>
                        <li><a href="#">Welcome!</a></li>
                        <li>@Html.ActionLink("Login", "Login", "Accounts")</li>
                    }
                </ul>
            </div>
        </div>
    </div>

    <div class="sec-wrapper">
        @RenderBody()
        <hr />
        <footer>
            <div id="clearBoth">
                <p>&copy; @DateTime.Now.Year - VirtualGuestbook</p>
            </div>
        </footer>
    </div>

    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

非常感谢任何帮助!

-Darren

2 个答案:

答案 0 :(得分:0)

恕我直言,你可以按照步骤进行操作 ` 1.按列排序时,超链接列在隐藏字段中设置字段名称。

  1. 单击过滤器按钮,发布隐藏字段及其方向

  2. 在控制器中,验证排序字符串和方向以及任何恶意输入的值

  3. 将这些传递到数据访问层

  4. 对数据进行过滤和排序

  5. 刷新网格 `

  6. 我强烈建议您使用服务器端分页和排序,因为这会降低数据库和应用程序之间的数据传输。

    几行JavaScript或一些插件都可以帮到你。

    排序信息可以通过post方法中的json字符串传递给服务器。它可以采用格式

    var sort data=[{ Field:"username ", Direction:"asc" }]

    这样,您可以将所有已排序的字段数据发送到服务器端代码以进行处理。其中,您将反序列化这些数据并在形成SQL查询时使用或在EF

    中使用

答案 1 :(得分:0)

如果您打算对记录进行排序,那么如果您有超过几百条记录,那么javascript将无法正常运行。但是,使用javascript填充表单字段并触发表单提交是一个很好的主意,应该提供良好的用户体验。

从创建ViewModel开始,这是一个可用于将数据发送到视图并从中接收数据的对象。

public class GuestListViewModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    // And the rest of the fields

    //These fields are new
    public string LastNameSort { get; set; }
    public string FirstNameSort { get; set; }
    public List<Guest> Guests { get; set; }
}

在控制器中,使用所有数据填充此视图模型,包括输入数据以及已排序和已过滤的访客列表。

然后,您的视图的精简版本看起来像这样。

@model VirtualGuestbook.Models.GuestListViewModel

@using (Html.BeginForm("Index", "Guests", FormMethod.Get, new { @id="filter-form"))
    {
        <div id="left30search">
            Name (First or Last): @Html.TextBoxFor(x => Model.Name)<br /><br />
            Phone: @Html.TextBoxFor(x => Model.Phone)<br /><br />
            Email: @Html.TextBoxFor(x => Model.Email)
            // Note the TextBoxFor referencing value in the model. This ensures that the previously submitted values are retained
            // Make sure to include the rest of the filter fields
        </div>
        <div>
            @Html.HiddenFor(x => Model.FirstNameSort, new { id= "first-name-sort" })
            @Html.HiddenFor(x => Model.LastNameSort, new { id= "last-name-sort" })
            // Note hidden fields to hold value of sort direction

            <input type="submit" value="Filter" />
        </div>
    </div>
    }

//Now for the table

<table id="myTable" class="table">
    <thead>
        <th>Prefix</th>
        <th id="first-name-header">First Name</th>
        <th id="last-name-header">Last Name</th>
        // Note the id field for easy javascript selection
        <th>Phone</th>
        <th>Email</th>
        // And the rest of your fields
    </thead>
    <tbody>
        @foreach(var guest in Model.Guests)
        {
            // Note change to list within the model, not just the whole model
        }
    </tbody>

然后你的javascript看起来像这样

$(document).ready(function () {

    $("#first-name-header").on("click", function(){
        var $first = $("#first-name-sort");
        switch($first.val()){
            case "asc":
                $first.val("desc");
                break;
            case "desc":
                $first.val("");
                break;
            default:
                $first.val("asc");
        }

       $("#filter-form").submit();
    };

    // When the header row is click, read the value in the hidden field
    // Toggle the value according to its current value
    // Submit the form, complete with old filter values and new sort values
});

对于您的控制器,您可以改进搜索功能 - 请看一下:Dynamic LINQ OrderBy on IEnumerable<T>