PagedList loses search filter on second page

20.2k Views Asked by At

I'm implementing a simple paged list Index using the example at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application

My problem is that the search string is 'lost' when I page to the second page, so instead of a filtered set of results, I'm shown all the records.

My index.cshtml:

@using (Html.BeginForm("Index", "", FormMethod.Get))
{
    <p>
        @Html.TextBox("searchString", ViewBag.currentFilter as string, new { @placeholder = "Search by title or author" })
        <input type="submit" value="Search" />
    </p>
}

@if (Model.PageCount > 1)
{ 
    @Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )
}

My controller:

public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
    {
        ViewBag.TitleSortParm = sortOrder == "Title" ? "Title desc" : "Title";
        ViewBag.AuthorSortParm = sortOrder == "Author" ? "Author desc" : "Author";
        ViewBag.DateSortParm = sortOrder == "Date" ? "Date desc" : "Date";

        if (searchString != null)
        {
            page = 1;
        }
        else
        {
            searchString = currentFilter;

        }

        ViewBag.currentFilter = searchString;

        var Articles = from a in db.Articles
                       select a;
        if (!String.IsNullOrEmpty(searchString))
        {
            //page = 1;
            Insights = Articles.Where(s => s.Title.ToUpper().Contains(searchString.ToUpper())
                               || s.Author.ToUpper().Contains(searchString.ToUpper()));
        }

        switch (sortOrder)
        {
            case "Author":
                Insights = Articles.OrderBy(s => s.Author);
                break;
            case "Author desc":
                Insights = Articles.OrderByDescending(s => s.Author);
                break;
            case "Title":
                Insights = Articles.OrderBy(s => s.Title);
                break;
            case "Title desc":
                Insights = Articles.OrderByDescending(s => s.Title);
                break;
            case "Date":
                Insights = Articles.OrderBy(s => s.DatePublished);
                break;
            default:
                Insights = Articles.OrderByDescending(s => s.DatePublished);
                break;
        }
        int pageSize = 3;
        int pageNumber = (page ?? 1);
        return View(Articles.ToPagedList(pageNumber, pageSize));

    }

When I go to Page 2 as an example, all my variables, sortOrder, currentFilter and searchString are all null.

Robbie

4

There are 4 best solutions below

0
On BEST ANSWER

The problem is your PagedList entry doesn't include your sort order nor your current filter.

In addition to adding ViewBag.CurrentSort as suggested by Vasanth, you also need to change your PagedListPager to:

@Html.PagedListPager( Model, page => Url.Action("Index", new { page, currentFilter=ViewBag.CurrentFilter, sortOrder = ViewBag.sortOrder}) )
0
On

If you have a complex search/filtering section with more than one field, you might need to use something like :

<div class="pagedList">
   @Html.PagedListPager(Model, page => Url.Action("Index", new { 
     page, sortOrder = ViewBag.CurrentSort,
     currentFilter = ViewBag.CurrentFilter,
     filter2= Request.QueryString["filter2"],
     filter3= Request.QueryString["filter3"],
     filter4= Request.QueryString["filter4"],
     filter5= Request.QueryString["filter5"] }))

   Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
</div>

This worked for me and now I can use complex filtering and view the results on multiple pages.

0
On

To filter the data by applying multiple filters we can use ViewBag like this in View. For example if we want to apply filter for three fields(i.e EmpFirstName, EmpLastName, EmpLocation).

@Html.PagedListPager(Model, page => Url.Action("Index", new { 
                           page,
                           sortOrder = ViewBag.sortOrder,
                           currentFilter1 =ViewBag.CurrentFilterForEmpFirstName,
                           currentFilter2 =ViewBag.CurrentFilterForEmpLastName,
                           currentFilter3 =ViewBag.CurrentFilterForEmpLocation}))

Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount

In controller i wroted code like this:

public ActionResult Index( int ?page, string currentFilter1, string currentFilter2, string currentFilter3,
 string searchEmpFirstName , string searchEmpLastName, string searchEmpLocation)

int pageSize = 10;
int pageNumber = (page??1);

var emp_master = db.Emp_Master.Include(l => l.Emp_Location);
   if (searchEmpFirstName != null || searchEmpLastName != null || searchEmpLocation != null)
   {
      page = 1;
   }
   else
   {
      searchEmpFirstName = currentFilter1;
      searchEmpLastName = currentFilter2;
      searchEmpLocation = currentFilter3;
   }

   ViewBag.CurrentFilterForEmpFirstName = searchEmpFirstName;
   ViewBag.CurrentFilterForEmpLastName = searchEmpLastName;
   ViewBag.CurrentFilterForEmpLocation = searchEmpLocation;

  if(!String.IsNullOrEmpty(searchEmpFirstName))
  {
      emp = emp.Where(s => s.ModelName == searchEmpFirstName)
  }
  if(!String.IsNullOrEmpty(searchEmpLastName))
  {
      emp = emp.Where(s => s.ModelName == searchEmpLastName)
  }
  if(!String.IsNullOrEmpty(searchEmpLocation))
  {
      emp = emp.Where(s => s.ModelName == searchEmpLocation)
  }
0
On

Hello I figured this out, Use a Tempdata to hold the search parameters. When the search method is called with some values, store the values in a tempdata. When the page list calls the method for page 2, collect the Search parameters from the TempData.

See this:

            if (SearchParameter != null)
            {
                TempData["HoldSearch"] = SearchParameter;
                TempData.Keep();
            }
            else
            {
                SearchParameter  = (CastBacktoType)TempData["HoldSearch"];
                TempData.Keep();
            }

Have tried this, it works well