Introduction
I find most developers new to MVC find it difficult to write the kind of code that provides them a kick-start. This is my article on that.
For adding paging to a Grid I have used PagedList.MVC.
Agenda
- Creating MVC basic application.
- Adding an ADO.Net entity model to the application.
- Adding PagedList.MVC to your application.
- Adding a Home Controller .
- Adding a View Model (CustomerView).
- Adding a View.
- Binding a dropdown to country.
- Binding a dropdown to states based on the country using JSON.
- Finally a binding grid on based on country and states.
- Final output.
Tool been Used
- Visual Studio 2012.
- SQL Server and Entity Framework 5.0.
Tables Used for Demo
Let's start.
Creating MVC basic application
For creating the basic application in MVC in Visual Studio IDE select "File" -> "New" -> "Project...". A New Project dialog will be shown. Inside that there is a template list and from that select web and in the project template list select ASP.NET MVC 4 Web Application and name your project DemoGridFilter and click on the OK button.
During the adding of the project a new dialog will be shown for selecting the Project Template and inside that select the Basic template.
After creating the application here is the complete folder view.
Now that we have created the application, let us start by adding a PagedList.MVC to the application from the NuGet Package Manager.
Adding PagedList.MVC in your application
For adding PagedList.MVC just right-click on the application then select Manage NuGet Packages.
After selecting Manage NuGet Packages a dialog will be shown.
In search type PagedList and then in the search results select the first result PagedList.MVC and click on the Install button.
Here is the view after adding.
After adding the PagedList.MVC let's add an ADO.NET Entity Data Model.
Adding an ADO.NET Entity Data Model to the application (.edmx).
Procedure to Add Entity Data Model
We will add an ADO.NET Entity Data Model in the Model folder.
- For adding, right-click on the Model Folder the select Add then inside that select ADO.NET Entity Data Model.
- After selecting, a small dialog will be shown to prompt for a name; I am providing the name DBModel. Then click on the OK button.
- After clicking on the OK button a new wizard will be shown with the name Entity Data Model wizard. In that select Generate from Database.
- Next a wizard will be shown for the Connection Properties. Here just enter all the connection related information for the database that you want to use and then select “Yes include the sensitive data in the connection string”.
- Now in the next wizard it will ask for selecting tables from the database and inside that select Country, States, DeveloperDetails then finally click on the Finish button.
After adding the Entity Data Model here is the Designer view of it.
After adding the Entity Data Model here is the complete folder view.
After adding the ADO.NET Entity Data Model let's add a Controller.
Adding Myhome Controller
For adding the Controller just right-click on the Controller folder then select Add then select Controller. After selecting, a new dialog will be shown with the name Add controller. Here we will name the controller MyhomeController and in the scaffolding option in the template select Empty MVC controller.
The Add Controller dialog snapshot is below:
After adding the Controller the default Index ActionResult is generated, here is the code.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace DemoGridFilter.Controllers
- {
- public class MyhomeController : Controller
- {
-
-
-
- public ActionResult Index()
- {
- return View();
- }
-
- }
- }
Now let's move forward and add ViewModel with name SearchModelVM.
Adding view Model (SearchModelVM)
For adding just right-click on the Model folder then select Add then select Class. A new wizard will be shown asking for a class name. Name it SearchModelVM.cs and click on the Add button.
An empty class is generated.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace DemoGridFilter.Models
- {
- public class SearchModelVM
- {
-
- }
- }
Now let's add some properties to it.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using PagedList;
-
- namespace DemoGridFilter.Models
- {
- public class SearchModelVM
- {
- public int? Page { get; set; }
- public string DeveloperCount { get; set; }
- public string DevID { get; set; }
- public IPagedList<DeveloperDetail> SearchResults { get; set; }
- public string SearchButton { get; set; }
- public IEnumerable<Country> ListCountry { get; set; }
- public int? SelectedCountryID { get; set; }
- public int? SelectedStateID { get; set; }
- }
- }
Now in the preceding code I took Page for maintaining the paging and Developercount and DevID that I will display in the Grid. Then I took an IPagedList for generating the paging control for the Webgrid. The following SearchButton is for letting us know that the user clicked on the search button. The list of Country is for binding the Dropdownlist. And SelectedCountryID and SelectedStateID are for getting the Dropdownlist's selected value.
Adding view
To add a view just right-click inside the Index ActionResult. A new dialog will be shown with the name Add View and we have a default view name that is the same as the ActionResult Name (Index). We will not be using the scaffolding template when adding the View.
A blank view is generated and now here is the default code that is generated.
- @model DemoGridFilter.Models.SearchModelVM
-
- @{
- ViewBag.Title = "Index";
- }
-
- <h2>Index</h2>
After adding the View let's add a Bind County and States Dropdownlist on the View.
The following I have Added a method (
BindCountriesName) for binding Country and this method I will call in the Index [HttpGet] Action Method.
The following is the code snippet of the BindCountriesName method:
- public void BindCountriesName(SearchModelVM model)
- {
-
- List<Country> listCountry = new List<Country> {
- new Country { CountryID = 0 , Name ="Select" }
- };
-
- var entities = new AllSampleCodeEntities();
-
- var Countrieslist = (from ad in entities.Countries select ad).ToList();
-
- foreach (var item in Countrieslist)
- {
- Country objcon = new Country();
- objcon.CountryID = item.CountryID;
- objcon.Name = item.Name;
- listCountry.Add(objcon);
- }
-
- model.ListCountry = listCountry;
- }
After completing the
Binding Country we will fill in the states depending on Country and display in the States dropdownlist. For that we will use the JSON result that will take the CountryID as input and depending on that it will get all the states from the database and return a JSON result.
Code snippet of GetStates JsonResult
- public JsonResult GetStates(string id)
- {
- if (id == null)
- {
- id = "0";
- }
-
-
- int CountryID = Convert.ToInt32(id);
-
-
- AllSampleCodeEntities objord = new AllSampleCodeEntities();
-
- var states = (from slist in objord.States
- where (slist.CountryID == CountryID)
- select new { slist.StateID , slist.StateName}).ToList();
-
- return Json(new SelectList(states, "StateID", "StateName"));
- }
Now after binding both dropdownlists let's configure the action method (Index) to bind the Webgrid.
Inside the index action method I wrote an if condition that checks that the user has clicked on a button or not. If we had clicked on a button then it will execute the method inside. it will get values from the database depending on the selection of country and state and finally it will fill in a pagedList Collection with the pageIndex and RecordsPerPage Parameters and then send an entire model to the view.
Code snippet of Index ActionResult
- const int RecordsPerPage = 1;
-
- public ActionResult Index(SearchModelVM model, FormCollection fc)
- {
-
- BindCountriesName(model);
-
-
- if (!string.IsNullOrEmpty(model.SearchButton) || model.Page.HasValue)
- {
-
- ViewData["Selectedstate"] = model.SelectedStateID;
-
- decimal mprice = Convert.ToDecimal(model.SelectedStateID);
-
- var entities = new AllSampleCodeEntities();
- var results = entities.DeveloperDetails
- .Where(p => (p.CountryID == model.SelectedCountryID || model.SelectedCountryID == null) && (p.StateID == mprice || mprice == null))
- .OrderBy(p => p.CountryID);
-
- var pageIndex = model.Page ?? 1;
- model.SearchResults = results.ToPagedList(pageIndex, RecordsPerPage);
- }
- return View("Index", model);
- }
After adding an Action method let's move toward configuring a View. We will now add a Model (SearchModelVM) and a Dropdownlist to the View.
Adding Model to View
- @model DemoGridFilter.Models.SearchModelVM
- @using PagedList.Mvc
- @{
- ViewBag.Title = "Index";
- Layout = "~/Views/Shared/_Layout.cshtml";
- }
Add a Dropdownlist of County and State to the View as in the following:
- <table style="border: 0px; width: 500px;">
- <tr>
- <td>
- <div class="editor-label">
- @Html.Label("Country")
- </div>
- <div class="editor-field">
- @Html.DropDownListFor(model => model.SelectedCountryID, new SelectList(Model.ListCountry, "CountryID", "Name"))
- </div>
- </td>
- <td>
- <div class="editor-label">
- @Html.Label("States")
- </div>
- <div class="editor-field">
- @Html.DropDownList("SelectedStateID", new SelectList(string.Empty, "StateID", "StateName"), "Select State", new { style = "width:250px", @class = "dropdown1" })
- </div>
- </td>
- <td style="vertical-align: bottom;">
- <input name="SearchButton" type="submit" value="Search" />
- </td>
- </tr>
- </table>
After adding a Dropdownlist list, now let's add a jQuery script for binding the state on a change of the country dropdownlist.
Binding dropdown states based on the country using JSON.
The following adds a jQuery Ajax script for binding the State dropdownlist.
- <link href="~/Content/PagedList.css" rel="stylesheet" />
- <script src="~/Scripts/jquery-1.9.1.min.js"></script>
- <script src="~/Scripts/jquery.validate.min.js"></script>
- <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
- <script src="~/Scripts/bootstrap.min.js"></script>
- <link href="~/Content/bootstrap.css" rel="stylesheet" />
-
- $(document).ready(function () {
-
- $("#SelectedCountryID").change(function () {
- $("#SelectedStateID").empty();
- $.ajax({
- type: 'POST',
- url: '@Url.Action("GetStates")',
- dataType: 'json',
- data: { id: $("#SelectedCountryID").val() },
- success: function (states) {
-
-
-
- $("#SelectedStateID").append('<option value="' + "0" + '">' + "Select State" + '</option>');
- debugger;
- $.each(states, function (i, state) {
- $("#SelectedStateID").append('<option value="' + state.Value + '">' + state.Text + '</option>');
-
- });
- },
- error: function (ex) {
- alert('Failed to retrieve states.' + ex);
- }
- });
- return false;
- })
- });
-
- </script>
After adding a Dropdownlist and jQuery Ajax script let's run the application and check how your dropdownlist displays.
Here is the View of Index.cshtml after rendering on the
browser.
We have a completed the binding og the dropdownlist. Now let's add a Webgrid and Pagedlist to the view.
Adding WebGrid
First I have added a Webgrid and then I passed an IPagedList (SearchResults) model to the WebGrid and 1 column (DeveloperCount).
- var grid = new WebGrid(Model.SearchResults, defaultSort: "DeveloperCount");
- @grid.GetHtml(
- tableStyle: "grid",
- headerStyle: "gvHeading",
- rowStyle: "gridrow",
- alternatingRowStyle: "gridalt",
- columns: grid.Columns(
- grid.Column("DeveloperCount", "DeveloperCount")
-
- )
- )
Adding PagedListPager
Second I have added a PagedListPager and then I passed an IPagedList (SearchResults) model to
PagedListPager.
Then we need to pass Page, SelectedCountryID and SelectedStateID parameters to the Controller. For that we need to Pass the model fields to PagedListPager as given below.
- <div class="pagination">
- @Html.PagedListPager(Model.SearchResults, page => Url.Action("Index", new RouteValueDictionary()
- {
- { "Page", page },
- { "SelectedCountryID", Model.SelectedCountryID },
- { "SelectedStateID", Model.SelectedStateID },
- }),
- PagedListRenderOptions.MinimalWithPageCountText)
- </div>
After Adding
PagedListPager list now let's Maintain state of state Dropdownlist.
Finally to maintain the state dropdownlist state I have called a rebindState() function on the $(document).ready method that will check whether or not ViewData["Selectedstate"] is “0” and depending on it will bind the State dropdownlist and then it will make the state dropdownlist selected.
Here is the complete code of the snippet of rebindState().
- <script type="text/javascript">
-
- function rebindState() {
- debugger;
- if ('@ViewData["Selectedstate"]'!= null) {
- $("#SelectedCountryID").val('@Model.SelectedCountryID');
-
- $.ajax({
- type: 'POST',
- url: '@Url.Action("GetStates")',
- dataType: 'json',
- data: {
- id: $("#SelectedCountryID").val()
- },
- success: function (states) {
-
- $.each(states, function (i, state) {
- $("#SelectedStateID").append('<option value="' + state.Value + '">' + state.Text + '</option>');
-
- if ('@ViewData["Selectedstate"]' != 0) {
- $("#SelectedStateID").val('@ViewData["Selectedstate"]');
- }
-
- });
- },
- error: function (ex) {
- alert('Failed to retrieve states.' + ex);
- }
- });
- }
-
-
- }
- </script>
The following is the completed Home Controller code.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using DemoGridFilter.Models;
- using PagedList;
-
- namespace DemoGridFilter.Controllers
- {
- public class MyhomeController : Controller
- {
- const int RecordsPerPage = 1;
-
- public ActionResult Index(SearchModelVM model, FormCollection fc)
- {
-
- BindCountriesName(model);
-
-
- if (!string.IsNullOrEmpty(model.SearchButton) || model.Page.HasValue)
- {
-
- ViewData["Selectedstate"] = model.SelectedStateID;
-
- decimal mprice = Convert.ToDecimal(model.SelectedStateID);
-
- var entities = new AllSampleCodeEntities();
- var results = entities.DeveloperDetails
- .Where(p => (p.CountryID == model.SelectedCountryID || model.SelectedCountryID == null) && (p.StateID == mprice || mprice == null))
- .OrderBy(p => p.CountryID);
-
- var pageIndex = model.Page ?? 1;
- model.SearchResults = results.ToPagedList(pageIndex, RecordsPerPage);
- }
- return View("Index", model);
- }
-
- public void BindCountriesName(SearchModelVM model)
- {
-
- List<Country> listCountry = new List<Country> {
- new Country { CountryID = 0 , Name ="Select" }
- };
-
- var entities = new AllSampleCodeEntities();
-
- var Countrieslist = (from ad in entities.Countries select ad).ToList();
-
- foreach (var item in Countrieslist)
- {
- Country objcon = new Country();
- objcon.CountryID = item.CountryID;
- objcon.Name = item.Name;
- listCountry.Add(objcon);
- }
-
- model.ListCountry = listCountry;
- }
-
- public JsonResult GetStates(string id)
- {
- if (id == null)
- {
- id = "0";
- }
-
-
- int CountryID = Convert.ToInt32(id);
-
-
- AllSampleCodeEntities objord = new AllSampleCodeEntities();
-
- var states = (from slist in objord.States
- where (slist.CountryID == CountryID)
- select new { slist.StateID, slist.StateName }).ToList();
-
- return Json(new SelectList(states, "StateID", "StateName"));
- }
-
- }
- }
The following is the completed Index.cshtml code.
- @model DemoGridFilter.Models.SearchModelVM
- @using PagedList.Mvc
- @{
- ViewBag.Title = "Search Developers";
- Layout = "~/Views/Shared/_Layout.cshtml";
- }
-
- <link href="~/Content/PagedList.css" rel="stylesheet" />
- <script src="~/Scripts/jquery-1.9.1.min.js"></script>
- <script src="~/Scripts/jquery.validate.min.js"></script>
- <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
- <script src="~/Scripts/bootstrap.min.js"></script>
- <link href="~/Content/bootstrap.css" rel="stylesheet" />
-
- <style type="text/css">
- .webgrid-table
- {
- font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
- font-size: 1.2em;
- width: 100%;
- display: table;
- border-collapse: separate;
- border: solid 1px #98BF21;
- background-color: white;
- }
-
- .webgrid-table td, th
- {
- border: 1px solid #98BF21;
- padding: 3px 7px 2px;
- }
-
- .webgrid-header
- {
- background-color: #A7C942;
- color: #FFFFFF;
- padding-bottom: 4px;
- padding-top: 5px;
- text-align: left;
- }
-
- .webgrid-footer
- {
- }
-
- .webgrid-row-style
- {
- padding: 3px 7px 2px;
- }
-
- .webgrid-alternating-row
- {
- background-color: #EAF2D3;
- padding: 3px 7px 2px;
- }
- </style>
-
- <script type="text/javascript">
- $(document).ready(function () {
-
- $("#SelectedCountryID").change(function () {
- $("#SelectedStateID").empty();
- $.ajax({
- type: 'POST',
- url: '@Url.Action("GetStates")',
- dataType: 'json',
- data: { id: $("#SelectedCountryID").val() },
- success: function (states) {
-
-
-
- $("#SelectedStateID").append('<option value="' + "0" + '">' + "Select State" + '</option>');
- debugger;
- $.each(states, function (i, state) {
- $("#SelectedStateID").append('<option value="' + state.Value + '">' + state.Text + '</option>');
-
- });
- },
- error: function (ex) {
- alert('Failed to retrieve states.' + ex);
- }
- });
- return false;
- })
- });
-
- </script>
- <script type="text/javascript">
- $(document).ready(function () { rebindState() });
- </script>
- <script type="text/javascript">
-
- function rebindState() {
- debugger;
- if ('@ViewData["Selectedstate"]' != null) {
- $("#SelectedCountryID").val('@Model.SelectedCountryID');
-
- $.ajax({
- type: 'POST',
- url: '@Url.Action("GetStates")',
- dataType: 'json',
- data: {
- id: $("#SelectedCountryID").val()
- },
- success: function (states) {
-
- $.each(states, function (i, state) {
- $("#SelectedStateID").append('<option value="' + state.Value + '">' + state.Text + '</option>');
-
- if ('@ViewData["Selectedstate"]' != 0) {
- $("#SelectedStateID").val('@ViewData["Selectedstate"]');
- }
-
- });
- },
- error: function (ex) {
- alert('Failed to retrieve states.' + ex);
- }
- });
- }
-
-
- }
- </script>
-
-
- <div class="container">
- @using (Html.BeginForm("Index", "Myhome", FormMethod.Get))
- {
-
- @Html.ValidationSummary(false)
- <div style="border-bottom: 1px solid #bbb">
- <h2>Search Developers</h2>
- </div>
- <table class="table">
- <tr>
- <td>
- <div class="editor-label">
- @Html.Label("Country")
- </div>
- <div class="editor-field">
- @Html.DropDownListFor(model => model.SelectedCountryID, new SelectList(Model.ListCountry, "CountryID", "Name"))
- </div>
- </td>
- <td>
- <div class="editor-label">
- @Html.Label("States")
- </div>
- <div class="editor-field">
- @Html.DropDownList("SelectedStateID", new SelectList(string.Empty, "StateID", "StateName"), "Select State", new { style = "width:250px", @class = "dropdown1" })
- </div>
- </td>
- <td style="vertical-align: bottom;">
- <input name="SearchButton" type="submit" value="Search" />
- </td>
- </tr>
- </table>
-
-
- <div class="table table-bordered .table-striped">
- @if (Model.SearchResults != null && Model.SearchResults.Count > 0)
- {
-
- var grid = new WebGrid(Model.SearchResults, defaultSort: "DeveloperCount");
- @grid.GetHtml(
- tableStyle: "webgrid-table",
- headerStyle: "webgrid-header",
- footerStyle: "webgrid-footer",
- alternatingRowStyle: "webgrid-alternating-row",
- selectedRowStyle: "webgrid-selected-row",
- rowStyle: "webgrid-row-style",
- mode: WebGridPagerModes.All,
- columns: grid.Columns(
- grid.Column("DeveloperCount", "DeveloperCount")))
-
- }
- </div>
- if (Model.SearchResults != null && Model.SearchResults.Count > 0)
- {
- @Html.PagedListPager(Model.SearchResults, page => Url.Action("Index", new RouteValueDictionary()
- {
- { "Page", page },
- { "SelectedCountryID", Model.SelectedCountryID },
- { "SelectedStateID", Model.SelectedStateID },
- }), PagedListRenderOptions.PageNumbersOnly)
- }
- }
- </div>
The following is the completed WebGrid code.
- if (Model.SearchResults != null && Model.SearchResults.Count > 0)
- {
- var grid = new WebGrid(Model.SearchResults, defaultSort: "DeveloperCount");
- @grid.GetHtml(
- tableStyle: "grid",
- headerStyle: "gvHeading",
- rowStyle: "gridrow",
- alternatingRowStyle: "gridalt",
- columns: grid.Columns(
- grid.Column("DeveloperCount", "DeveloperCount"),
- grid.Column("DevID")
- )
- )
- <div class="pagination">
- @Html.PagedListPager(Model.SearchResults, page => Url.Action("Index", new RouteValueDictionary()
- {
- { "Page", page },
- { "SelectedCountryID", Model.SelectedCountryID },
- { "SelectedStateID", Model.SelectedStateID },
- }),
- PagedListRenderOptions.MinimalWithPageCountText)
- </div>
- }
Final Output
Here I have selected the country India and the state Andhra Pradesh and clicked on the Search button. Then it brought all the Developer-related data of Andhra Pradesh into the grid and below you can see the Pager list.
The following is the snapshot of the grid displaying with the first record:
The following is the snapshot of the grid displaying the second record.
Here in the preceding snapshot you can see we have 2 dropdownlists and after paging it still maintains the state of the dropdownlist.
Conclusion Finally we have completed the learning of the Filter WebGrid with Cascading Dropdownlist along with Paging in MVC.