更改页面上显示的表格元素数量会重置我的搜索结果

Posted

技术标签:

【中文标题】更改页面上显示的表格元素数量会重置我的搜索结果【英文标题】:Changing number of table elements displayed on page resets my search results 【发布时间】:2018-06-19 10:09:00 【问题描述】:

我有很多数据显示在一个表中,比如说一长串用户(名字和姓氏),所以我设置了一个分页功能,通过 PagedList NuGet 包按页面显示元素。我受到本教程的启发:https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application

我在视图中实现了一个下拉列表,这样我就可以直接选择每页显示的元素数量。我设法包含了一个 jQuery 脚本,只要下拉列表有一个新的选定值,它就会更新页面大小。

使用上述教程,我还添加了一个搜索功能:在搜索表单中提交字符串允许过滤数据。

我的问题是:在完成搜索后在下拉列表中选择一个新值来更改页面大小不起作用:搜索结果被重置,所有条目都被显示反而。我想我忘了在某处传递一些参数,但我就是不知道在哪里......

这是我的控制器:

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? PageSize)

    // Sort order is passed to view in order to keep it intact while clicking in another page link
    ViewBag.CurrentSort = sortOrder;

    // Ascending or descending sorting by first or last name according to sortOrder value
    ViewBag.LastNameSortParm = String.IsNullOrEmpty(sortOrder) ? "lastname_desc" : "";
    ViewBag.FirstNameSortParm = sortOrder == "firstname" ? "firstname_desc" : "firstname";

    // Not sure here
    if (searchString == null)
    
        searchString = currentFilter;
    

    // Pass filtering string to view in order to maintain filtering when paging
    ViewBag.CurrentFilter = searchString;

    var users = from u in _db.USER select u;

    // FILTERING
    if (!String.IsNullOrEmpty(searchString))
    
        users = users.Where(u => u.lastname.Contains(searchString)
                              || u.firstname.Contains(searchString)
    

    // Ascending or descending filtering by first/last name
    switch (sortOrder)
    
    case "lastname": // Ascending last name
        users = users.OrderBy(u => u.lastname);
        break;
    case "lastname_desc": // Descending last name
        users = users.OrderByDescending(u => u.lastname);
        break;
    case "firstname": // Ascending first name
        users = users.OrderBy(u => u.firstname);
        break;
    case "firstname_desc": // Descending first name
        users = users.OrderByDescending(u => u.firstname);
        break;
    default:
        users = users.OrderBy(u => u.lastname);
        break;



// DROPDOWNLIST FOR UPDATING PAGE SIZE
int count = _db.USER.OrderBy(e => e.Id).Count(); // Total number of elements

// Populate DropDownList
ViewBag.PageSize = new List<SelectListItem>() 
    new SelectListItem  Text = "10", Value = "10", Selected = true ,
    new SelectListItem  Text = "25", Value = "25" ,
    new SelectListItem  Text = "50", Value = "50" ,
    new SelectListItem  Text = "100", Value = "100" ,
    new SelectListItem  Text = "All", Value = count.ToString() 
;

int pageNumber = (page ?? 1);
int pageSize = (PageSize ?? 10);
ViewBag.psize = pageSize;

return View(users.ToPagedList(pageNumber, pageSize));

还有我的 Index.cshtml 视图:

<script src="~/Scripts/jquery-3.2.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function ()  // Submit pageSizeForm when another pageSize value is selected
    $("#pageSize").change(function () 
        $("#pageSizeForm").submit();
    );
);
</script>

@model PagedList.IPagedList<AfpaSIPAdmin.Models.USER>
@using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />

@
    ViewBag.Title = "Users management";


<h1>Users management</h1>

<!-- Creating a new entry in table -->
<p>
    @Html.ActionLink("Create new user", "Create")
</p>


<!-- Filtering table entries -->
@using (Html.BeginForm("Index", "Users", FormMethod.Get, new  id = "filterForm" ))

    <p>
        Filter: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string, new  @placeholder = "First or last name..." )
        <input type="submit" value="Apply"/>
    </p>


<!-- Display table -->
<table class="table">
    <tr>
        <th>
            @Html.ActionLink("Last name", "Index", new 
                sortOrder = ViewBag.LastNameSortParm,
                currentFilter = ViewBag.CurrentFilter
            )
        </th>
        <th>
            @Html.ActionLink("First name", "Index", new 
                sortOrder = ViewBag.FirstNameSortParm,
                currentFilter = ViewBag.CurrentFilter
            )
        </th>
        <th style="min-width: 170px"></th>
    </tr>

    @foreach (var item in Model)
    
        <tr>
           <td style = "min-width: 150px">
                @Html.DisplayFor(modelItem => item.lastname)
            </td>
            <td style = "min-width: 150px">
                @Html.DisplayFor(modelItem => item.firstname)
            </td>

            <td> <!-- Using images as buttons for actions -->
                <a href="@Url.Action("Edit", "Users", new  id = item.Id )" title="Edit">
                    <img src="~/Content/images/edit.gif" />
                </a>
                <a href="@Url.Action("Details", "Users", new  id = item.Id )" title="Details">
                    <img src="~/Content/images/info.gif" />
                </a>
                <a href="@Url.Action("Delete", "Users", new  id = item.Id )" title="Delete">
                    <img src="~/Content/images/delete.gif" />
                </a>
            </td>
        </tr>
    
</table>

<br/>

<!-- Paging -->
@using (Html.BeginForm("Index", "Users", FormMethod.Get, new  id = "pageSizeForm" ))

    <div class="pager">
        Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) sur @Model.PageCount<br/>

        @Model.Count of @Model.TotalItemCount elements 

        @Html.PagedListPager(Model, page => Url.Action("Index", new 
            page,
            sortOrder = ViewBag.CurrentSort,
            currentFilter = ViewBag.CurrentFilter,
            searchString = ViewBag.CurrentFilter,
            pageSize = ViewBag.psize
        ))

        <!-- DropDownList for setting page size -->
        Elements per page :
        @Html.DropDownList("pageSize")
    </div>

【问题讨论】:

首先,永远不要在下拉列表的更改事件上提交表单(使用提交按钮)。你应该有一个包含文本框和下拉列表的表单。 不确定您期望发生什么 - 当您提交第二个表单时,您发送给控制器的只是 pageSize 的值 - 所有其他参数将是它们的默认值(对于 currentFilternull) 我猜你不需要在 Paging 区域搜索 Html.PagedListPager 时传递 searchString 参数 @StephenMuecke 为什么不使用更改事件?我发现它比提交按钮更舒服。安全原因? 如果您使用VS,您可以尝试调试并检查正确的过滤器行为 【参考方案1】:

原因是因为您有 2 个表单。当您提交包含文本框的第一个表单时,您发送回控制器的唯一值是 SearchString 并且您方法中的所有其他参数将是它们的默认值(例如,当您返回视图时,PageSize 将默认为null,因此即使用户之前选择了 50 条记录,也只返回 10 条记录。

同样,当您提交包含页面大小下拉列表的第二个表单时,SearchString 的值将是 null,因为它没有在请求中发送。

您需要一个只包含两个表单控件的表单。如果您想发送其他属性,例如当前的排序顺序,那么您可以将它们作为查询字符串值添加到表单元素中(例如,@using(Html.BeginForm("Index", "Users", new sortOrder = .... , FormMethod.Get))

我还强烈建议您使用包含视图中所需属性的视图模型并强烈绑定到它们,而不是使用ViewBag

public class UsersVM

    public string SearchString  get; set; 
    public int PageSize  get; set; 
    public IEnumerable<SelectListItem> PageSizeOptions  get; set; 
    .....
    public IPagedList<USER> Users  get; set; 

查看

@model UsersVM
...
@using(Html.BeginForm("Index", "Users", FormMethod.Get))

    @Html.LabelFor(m => m.SearchString)
    @Html.TextBoxFor(m => m.SearchString)

    @Html.LabelFor(m => m.PageSize)
    @Html.DropDownListFor(m => m.PageSize, Model.PageSizeOptions)

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

....
<div class="pager">
    Page @(Model.Users.PageCount < Model.Users.PageNumber ? 0 : Model.Users.PageNumber)
    ....
    @Html.PagedListPager(Model.Users, page => Url.Action("Index", new 
        page,
        sortOrder = Model.CurrentSort,
        currentFilter = Model.CurrentFilter,
        searchString = Model.CurrentFilter,
        pageSize = Model.PageSize
    ))
</div>

并在控制器方法中,初始化UsersVM 的新实例并分配其属性

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? pageSize)

    UsersVM model = new UsersVM();
    ....
    var users = from u in _db.USER select u;
    ....
    pageSize = pageSize ?? 10;
    model.PageSize = pageSize.Value;
    model.Users = users.ToPagedList(pageNumber, pageSize);
    model.PageSizeOptions = new List<SelectListItem>  .... ;
    return View(model);

【讨论】:

太棒了!但是还有一个问题:完成搜索后,转到第 2、3、4 页……会重置搜索结果! currentFilter 和 searchString 为空 你是否在控制器方法中分配了Model.CurrentFilter = searchString; (as you previously did it for ViewBag.CurrentFilter = searchString;),所以@Html.PagedListPager()选项中的currentFilter = Model.CurrentFilter,会再次传回。 确实,我无意中评论了它!现在效果很好!

以上是关于更改页面上显示的表格元素数量会重置我的搜索结果的主要内容,如果未能解决你的问题,请参考以下文章

使用重置按钮重置表格

Dropzone.js上传后不显示结果

如何隐藏博客标签搜索中的小部件

搜索后django刷新div元素

出现无法显示此页。确保Web地址正常。使用搜索引擎查找页面。请过几分钟后刷新页面

当搜索栏成为第一响应者时更改表格 - swift