La paginación de este blog en cuatro pasos


Publicado el viernes, 21 de abril de 2017


Una de las características más comunes de las aplicaciones es mostrar listas en pantalla. En el caso de un blog, la pantalla principal es justamente una lista que muestra los "posts".

Si la lista es corta, por ejemplo, entre diez y veinte elementos, lo más común es mostrarlos todos. Si en cambio la lista contiene muchos elementos, eso no resulta eficaz. Cuando hay muchos elementos lo habitual es mostrar una parte de ellos, por ejempo los diez primeros, y permitir al usuario poder escoger si quiere ver los siguientes.

Esto lo podemos conseguir rápidamente en cuatro pasos utilizando PagedList.Mvc

Paso 1. Instalar el paquete Nuget PagedList.Mvc

Instalar el paquete de nuget "PagedList.Mvc" que contiene clases y métodos para poder paginar los elementos:

Botón derecho sobre las referencias de Blog.Web:

Buscar "pagedlist" e instalar "PagedList.Mvc". Como este paquete de Nuget depende de "PagedList" con la instalación del primero también se instalará el segundo:

Al finalizar la instalación del paquete se ha añadido un archivo .css al proyecto que contiene las clases CSS de estilo del "control paginador"

  

Paso 2. Modificar el tipo de la ViewModel

Modificar el tipo de la ViewModel asociado a la vista que muestra las entradas del blog. En concreto cambiar List por IPagedList:

En /ViewModels/Blog/ListaPostsBlogViewModel.cs

Cambiar List

    
    public class ListaPostsBlogViewModel
    {
       public List<LineaResumenPost> ListaPosts { get; set; }
    }

Por IPagedList

    public class ListaPostsBlogViewModel
    {
        public IPagedList<LineaResumenPost> ListaPosts { get; set; }
    }

  

Paso 3. Añadir el paginador a la vista

Modificar la PartialView que renderiza la lista de entradas del blog:

Así queda la PartialView Views/Blog/_ListaLineasResumenPost.cshtml:

@using Blog.Web.Helpers
@using PagedList.Mvc;
@using PagedList;
@model IPagedList<Blog.Modelo.Posts.LineaResumenPost>

@foreach (var item in Model)
{

    <h2>
        <a href="@Url.RutaUrlBlogPost(item.FechaPost, item.UrlSlug)">@item.Titulo</a>
    </h2>
            @*<p class="lead">
                    by @item.Autor
                </p>*@
            <p>
                <span class="glyphicon glyphicon-time"></span> Publicado el @item.FechaPost.ToString("D")
            </p>
            @Html.Raw(item.Subtitulo)
            <a class="btn btn-primary btn-sm" href="@Url.RutaUrlBlogPost(item.FechaPost, item.UrlSlug)">leer más<span class="glyphicon glyphicon-chevron-right"></span></a>
            <hr style="border-color: black">
}


<ul class="pager">
    @if (Model.HasNextPage)
    {
        <li class="previous">
            <a href="@Url.Action("Index", new {pagina = Model.PageNumber + 1})">&larr; Entradas más antiguas</a>
        </li>
    }
    @if (Model.HasPreviousPage)
    {
        <li class="next">
            <a href="@Url.Action("Index", new {pagina = Model.PageNumber - 1})">Entradas más recientes &rarr;</a>
        </li>
    }
</ul>

Por un lado, hay que cambiar el modelo de la vista por IPagedList<Blog.Modelo.Posts.LineaResumenPost> y por el otro, al final del listado hay que añadir el paginador. 

El paginador consistirá en dos links/botones que permitirán al usuario visualizar entradas más antiguas. Inicialmente sólo se muestran las diez entradas más recientes:

Este es el resultado:

En la primera página sólo se ve el link/botón "Entradas más antiguas". Si hacemos clic sobre el botón y navegamos a la siguiente página entonces se muestra el botón "Entradas más recientes" mientras que el botón anterior no aparece:

Dado que la paginación es de diez entradas y a día día de hoy en este blog existen doce, sólo hay dos páginas para navegar :(.

Cuando el blog tenga más de dos páginas y naveguemos a cualquiera que no sea ni la última ni la primera entonces ambos links/botones serán visibles.

Paso 4. Modificar la acción del Controller

using PagedList;

namespace Blog.Web.Controllers
{
    public class BlogController : Controller
    {
        private readonly ContextoBaseDatos _db = new ContextoBaseDatos();
        private const int NumeroItemsPorPagina = 10;

        public ActionResult Index(int? pagina)
        {
            var viewModel = new ListaPostsBlogViewModel
            {
                ListaPosts = _db.Posts
                .Publicados()
                .SeleccionaLineaResumenPost()
                .OrderByDescending(m => m.FechaPost)
                .ToPagedList(pageIndex: pagina, pageSize: NumeroItemsPorPagina)
            }; 
            return View(viewModel);
        }
...
}

La acción "Index" debe recibir un parámetro que indica qué pagina quiere visualizar el usuario. Si el parámetro no se indica, entonces le asignamos un uno, que es la primera página.

Añado una constante "NumeroItemsPorPagina" con valor diez para indicar el número de elementos que se muestra por página.

Y por último, en la consulta Linq, al final de todo en lugar de llamar al .ToList() utilizamos el método .ToPagedList() pasándole como parámetro la página que quiere visualizar el usuario (pageIndex) y el tamaño de cada página (pageSize).

Así es como creé la paginación de este blog en cuatro pasos :)