Tony
Tony

Reputation: 53

Add paging to existing ActionResult controller that passes ViewModel

I'm using an MVC 5, EF 6, Code First Web Application in Visual Studio 2013 Pro from here: http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application

I would like to combine a view that has paging functionality and that also has the ability to display related data from a ViewModel.

In the referenced web application above, the Student Index view (ViewResult in Controller) has the paging and sorting functionality and does not use a ViewModel.

In the same application, the Instructor Index view (ActionResult in Controller) does not have the paging and sorting functionality, but it does display related data (Courses) through the use of a “Select” HTML.ActionLink on the same page as the Instructor Index data.

I like the Student view that provides the paging and sorting functionality and I also like the Instructor view that provides the ability to display related data on the existing Index page, but I don't know how to combine them.

Does anybody know how I can add the paging functionality to the Instructor Index view while still keeping the ability to display the related data on the same Index view page?

Another way to ask the same question would be: How to add paging and sorting to the Instructor Index view while still keeping the ability to display the related data?

Here is the Index method from the InstructorController.cs:

        public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
    {
        ViewBag.CurrentSort = sortOrder;
        ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
        ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";

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

        ViewBag.CurrentFilter = searchString;

        var instructors = from i in db.Instructors
                       select i;
        if (!String.IsNullOrEmpty(searchString))
        {
            instructors = instructors.Where(i => i.LastName.ToUpper().Contains(searchString.ToUpper())
                                   || i.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
        }
        switch (sortOrder)
        {
            case "name_desc":
                instructors = instructors.OrderByDescending(i => i.LastName);
                break;
            case "Date":
                instructors = instructors.OrderBy(i => i.HireDate);
                break;
            case "date_desc":
                instructors = instructors.OrderByDescending(i => i.HireDate);
                break;
            default:  // Name ascending 
                instructors = instructors.OrderBy(i => i.LastName);
                break;
        }

        int pageSize = 3;
        int pageNumber = (page ?? 1);
        return View(instructors.ToPagedList(pageNumber, pageSize));
    }

Here is the beginning of the view code for Instructor/Index.cshtml:

@model PagedList.IPagedList<LakesidePurchasing.ViewModels.InstructorIndexData>
@using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />

    @{
        ViewBag.Title = "Instructors";
    }

    <h2>Instructors</h2>

    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>

        @foreach (var item in Model)
        {
            string selectedRow = "";
            if (item.ID == ViewBag.InstructorID)
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
            @Html.DisplayFor(model => Model.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.FirstMidName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.HireDate)
        </td>
        <td>
            @if (item.OfficeAssignment != null)
            {
                @item.OfficeAssignment.Location
            }
        </td>

Upvotes: 0

Views: 1070

Answers (1)

markpsmith
markpsmith

Reputation: 4918

This was your original model:

public class InstructorIndexData
{
  public IEnumerable<Instructor> Instructors { get; set; }
  public IEnumerable<Course> Courses { get; set; }
  public IEnumerable<Enrollment> Enrollments { get; set; }
}

You want to show paged Instructor data so you need to change it to this:

public class InstructorIndexData
   {
      public PagedList.IPagedList<Instructor> Instructors { get; set; }
      public IEnumerable<Course> Courses { get; set; }
      public IEnumerable<Enrollment> Enrollments { get; set; }
   }

Populated like this:

var model = new InstructorIndexData
{
    Instructors = instructors.ToPagedList(pageNumber, pageSize),
    Courses = ?,
    Enrollments = ?
}
return View(model);

The model that you pass to the view hasn't changed, but the way you access the Instructor records has, although I gather you can successfully display the paged data.
How the Courses & Enrollments properties are populated depends on what data should be shown, you should be able to set them to null initially just to get it working(you will probably have to have checks for null in the View to avoid an error if it tries to display a value from a null property)

UPDATE:

change the View @model declaration:

@model InstructorIndexData

and in the foreach...

@foreach (var item in Model.Instructors)
        {
           <td>@item.LastName</td>
           ... etc

Upvotes: 1

Related Questions