MVC Index Partial View for Paging

This entry is part 7 of 7 in the series Ultimate MVC Paging

This post was revised and updated on 10/24/2020.

When paging, you usually want to have a way to allow your users to search and filter the data. When they click on search, or hit enter, or click on a column heding, you want to retain that search criteria after the page displays the results. The easiest way to do that is to keep the results in a partial view that is refreshed separately from the primary view. This way, you don’t have to fight the battle of keeping track of it.

One issue I’ve run into is that the user may search for a keyword, then they modify the keyword, think better of it, and just click a sort column. Your page posts back and the search is now for the modified keyword, which wasn’t their intention. Using the partial view method described here WILL NOT have this unwanted functionality.

When writing a partial view for the search results, I’ve added in the ability to utilize my business objects for paging, shown on post: Business Object for Paging, so that paging is implemented generically. I then use the AJAX JQuery call to refresh of the page on an column click for sorting.

Like the main view, this partial view is specifically written for the LuCategory model, there is no need to reference the model as an interface. You can specify the exact model implementation you’re expecting on the page.

Don’t make the mistake of adding the Script reference to
“jquery.unobtrusive-ajax” to this partial view as well, as that will cause some wonky results.

@using YTG.MVC.Lookups.Models
@using YTG.Models
@model SearchModel<LuCategory>

<script type="text/javascript">

    function GetCategories(sortColumn) {

        // Set the global values for sorting post back
        var searchModel = {};
        searchModel.SortColumn = sortColumn;
        searchModel.PrevSortColumn = '@Model.SortColumn';
        searchModel.CurrentPage = @Model.CurrentPage;
        searchModel.PageSize = @Model.PageSize;
        searchModel.SearchTerm = '@Model.SearchTerm';
        searchModel.SortDescending = '@Model.SortDescending';
        searchModel.ActiveOnly = '@Model.ActiveOnly';

        $.ajax({
            type: "POST",
            url: "/Lookups/CatDisplay",
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(searchModel),
            dataType: "html",
            async: true,
            success: function (result, status, xhr) {
                $("#gridPartial").html(result)
            },
            error: function (xhr, status, error) {
                alert("Result: " + status + " " + error + " " + xhr.status + " " + xhr.statusText)
            }
        });

    }

</script>

<div id="CatDisplay">
    <section id="main-content" class="animated fadeInUp">

        <div class="text-center">
            <!-- Pager -->
            @if (Model.EndPage > 1)
            {
                await Html.RenderPartialAsync("_PagerPartial", Model);
            }
        </div>

        <div class="panel-default">
            <table width="100%" class="table table-bordered table-hover">
                <thead>
                    <tr>
                        <th>Edit</th>
                        <th onclick="GetCategories('Name')" title="Click to Sort">Name</th>
                        <th onclick="GetCategories('ShortName')" title="Click to Sort">Short Name</th>
                        <th onclick="GetCategories('Description')" title="Click to Sort">Description</th>
                        <th class="text-center" title="Quantity of Items">Item Count</th>
                        <th class="text-center">@Html.DisplayName("Active")</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var item in Model.SortedResults)
                    {
                    <tr>
                        <td class="text-center">
                            @Html.ActionLink(" ", "Edit", "Lookups", new { id = item.Id.ToString() }, new { @class = "fas fa-edit", @title = "Id: " + item.Id })
                        </td>
                        <td>@Html.DisplayFor(modelItem => item.Name)</td>
                        <td>@Html.DisplayFor(modelItem => item.ShortName)</td>
                        <td>@Html.DisplayFor(modelItem => item.Description)</td>
                        <td class="text-center">@item.Items.Count().ToString()</td>
                        <td class="text-center">@Html.DisplayFor(modelItem => item.IsActive)</td>
                    </tr>
                    }
                </tbody>
            </table>

            @if (Model.RecordCount == 0)
            {
                <div class="col-md-12">
                    <p class="text-center text-warning">
                        There are no Categories defined
                    </p>
                    <br /><br />
                </div>
            }

            <div class="text-center">
                <!-- Pager -->
                @if (Model.EndPage > 1)
                {
                    await Html.RenderPartialAsync("_PagerPartial", Model);
                    await Html.RenderPartialAsync("_PageCountPartial", Model);
                }
            </div>

        </div>
    </section>
</div>

I chose to not display the paging partial views when there is only one page of data using “@if (Model.EndPage > 1)”. You may prefer for them to remain, or at the very least, display the total count of records somewhere if paging is not enabled.

As I’m sure you now probably surmised, this post series took about 20 hours of effort. Please let me know if you’ve found it useful, or if you see any areas where improvements can be made (be nice). Thanks, and happy coding.


Series Navigation<< MVC Paging and PageCount Partial Views

Author: Jack Yasgar

Jack Yasgar has been developing software for various industries for two decades. Currently, he utilizes C#, JQuery, JavaScript, SQL Server with stored procedures and/or Entity Framework to produce MVC responsive web sites that converse to a service layer utilizing RESTful API in Web API 2.0 or Microsoft WCF web services. The infrastructure can be internal, shared or reside in Azure. Jack has designed dozens of relational databases that use the proper primary keys and foreign keys to allow for data integrity moving forward. While working in a Scrum/Agile environment, he is a firm believer that quality software comes from quality planning. Without getting caught up in analysis paralysis, it is still possible to achieve a level of design that allows an agile team to move forward quickly while keeping re-work to a minimum. Jack believes, “The key to long term software success is adhering to the SOLID design principles. Software written quickly, using wizards and other methods can impress the business sponsor / product owner for a short period of time. Once the honeymoon is over, the product owner will stay enamored when the team can implement changes quickly and fix bugs in minutes, not hours or days.” Jack has become certified by the Object Management Group as OCUP II (OMG Certified UML Professional) in addition to his certification as a Microsoft Certified Professional. The use of the Unified Modeling Language (UML) provides a visual guide to Use Cases and Activities that can guide the product owner in designing software that meets the end user needs. The software development teams then use the same drawings to create their Unit Tests to make sure that the software meets all those needs. The QA testing team can use the UML drawings as a guide to produce test cases. Once the software is in production, the UML drawings become a reference for business users and support staff to know what decisions are happening behind the scenes to guide their support efforts.

Leave a Reply

Your email address will not be published. Required fields are marked *