MVC3 Dynamic Search Paging using PagedList


Basically there's a great tutorial from this site:
http://unboxedsolutions.com/sean/archive/2011/03/30/15977.aspx
-I've copied the codes and add some comments.

I'll just try to add my own comments.

1.) First you need to install PagedList.Mvc from Nuget.
a.) Go to Tools->Library Package Manager->Package Manager Console
b.) In the Package Manager Console Tab execute:
Install-Package PagedList.Mvc
-It will add a reference to your project and add PagedList.css.

What you should noticed:
1.) All the fields have getter and setter.
//ViewModel
using PagedList;
namespace SearchFormResultPagingExample.Models {
    public class SearchViewModel {
        public int? Page { get; set; }
        public string EmailAddress { get; set; }
        public string LastName { get; set; }
        public IPagedList SearchResults { get; set; }
        public string SearchButton { get; set; }
    }
}

2.) No need to add Take(start, count) to the query.
//Controller
using System.Linq;
using System.Web.Mvc;
using SearchFormResultPagingExample.Models;
using PagedList; //NOTE: use Nuget to reference PagedList 

namespace SearchFormResultPagingExample.Controllers {
    public class SearchController : Controller {
        const int RecordsPerPage = 25; 

        public ActionResult Index(SearchViewModel model) {
            if (!string.IsNullOrEmpty(model.SearchButton) || model.Page.HasValue) {
                var entities = new AdventureWorksEntities();
                var results = entities.Contacts.Where(c => c.LastName.StartsWith(model.LastName) && c.EmailAddress.StartsWith(model.EmailAddress))
                    .OrderBy(o => o.LastName);
                var pageIndex = model.Page ?? 0;
                model.SearchResults = results.ToPagedList(pageIndex, 25);
            }
            return View(model);
        }
    }
}

3.) Form action should be Get
//View
@model SearchFormResultPagingExample.Models.SearchViewModel
@using PagedList.Mvc; 

@using (Html.BeginForm("Index", "Search", FormMethod.Get)) {
    @Html.ValidationSummary(false)
    <fieldset>
        <legend>Contact Searchlegend>
        <div class="editor-label">
            @Html.LabelFor(model => model.EmailAddress)
        div>
        <div class="editor-field">
            @Html.EditorFor(model => model.EmailAddress)
            @Html.ValidationMessageFor(model => model.EmailAddress)
        div> 
        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        div>
        <p>
            <input name="SearchButton" type="submit" value="Search" />
        p>
    fieldset>
} 

@if (Model.SearchResults != null && Model.SearchResults.Count > 0) {
    foreach (var result in Model.SearchResults) {
            <hr />
               <table width="100%">
                      <tr>
                             <td valign="top" width="*">
                        <div style="font-weight: bold; font-size:large;">@result.LastName, @result.FirstNamediv>
                        @result.Title<br />
                        @result.Phone<br />
                        @result.EmailAddress
                             <td>
                      <tr>
               <table>
    }
        <hr />       
        @Html.PagedListPager(Model.SearchResults,
            page => Url.Action("Index", new RouteValueDictionary() {
               { "Page", page },
               { "EmailAddress", Model.EmailAddress },
               { "LastName", Model.LastName }
            }),
            PagedListRenderOptions.PageNumbersOnly)
}

{ 5 comments... read them below or add one }

Javafun said...

This is good, but my question is most of time the search involved many tables join, so you can't use linq to sql or entity to query the data, how to handle this?

czetsuya said...

Hi, how about making a view? It might be possible but it's quite a pain for complex sql statement to convert into linq for now.

Bob said...

You can write Linq to Sql in the Controller, or any other mechanism...

Jeff Reddy said...

Could you expand upon the @Html.PageListPager part of the code. I've got it working, but I'm not exactly sure what the RouteValueDictionary is doing. I can't find any documentation on this stuff either.

Thanks

Shoaib Rashid said...

Thank you! Your post helped me a lot.