ASP.NET MVC Paging

16

I currently work with data like this:

The context returns me all the Bank Customers

    public IEnumerable<Clientes> ListarTodos()
    {
        return contexto.Clientes.ToList();
    }

In the controller I call ListAll ()

    public PartialViewResult Index()
    {
        var clientes = bdCliente.ListarTodos();
        return PartialView(clientes);
    }

And then I display in the View and with JQuery I am adding paging by adding a search field that searches the table already mounted. The JQuery search process is extremely fast since you already have all the data in the table. But the time to set up the table for the first time is somewhat time-consuming.

To make paging more efficient, should I use paging in the context, or in the controller, or else in the View in some other way (I believe this is not the most efficient way)? And how would the controller / context look using paging.

    
asked by anonymous 07.07.2014 / 16:27

2 answers

17

Download through Nuget the PagedList ( PageList and PagedList.Mvc )

Afterinstallation,dothefollowing:

ChangethismethodtoIQueryableandtakeToList()

Method

publicIQueryable<Clientes>ListarTodos(){returncontexto.Clientes;}

NoController:

usingPagedList;publicPartialViewResultIndex(int?page,Stringfiltro){IQueryable<Clientes>clientes=bdCliente.ListarTodos();IPagedList<Clientes>model=!string.IsNullOrEmpty(filtro)?clientes.Where(x=>x.Nome.Contains(filtro)).OrderBy(x=>x.Nome).ToPagedList(page??1,10):clientes.OrderBy(x=>x.Nome).ToPagedList(page??1,10);returnPartialView(model);}

Note:OrderbyisrequiredwhenusingToPagedList.

NaView

@usingPagedList;@usingPagedList.Mvc;@modelIPagedList<Clientes>@{Layout="~/Views/Shared/_LayoutPageAdm.cshtml"; }
<nav class="navbar navbar-default" role="navigation">
    <div class="navbar-header">
        <a class="navbar-brand" href="#">Configurações</a>
    </div>
    <form class="navbar-form navbar-left" role="search">
        <div class="form-group">
            <input name="filtro" value="@ViewBag.Filtro" id="filtro" type="text" class="form-control input-sm" placeholder="Digite a descrição...">
        </div>
        <button type="submit" class="btn btn-default">Filtro</button>        
    </form>
</nav>
<table class="table table-hover table-condensed">
    <tr>
        <th style="width: 75%">
            @Html.Raw("Nome Completo")
        </th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Nome)
            </td>            
        </tr>
    }
</table>
@if (Model.HasNextPage || Model.HasPreviousPage)
{
    <div style="text-align: center">
        @Html.PagedListPager(Model, (page) => Url.Action("Index", new { page = page, filtro = @ViewBag.filtro }), PagedListRenderOptions.Classic)
    </div>
}
07.07.2014 / 16:53
10

Just to state, as an alternative for those who want to learn how to do it in a simple way (not that PagedList is not, it just does not reveal what it does underneath the cloths), just create a method that accept the current page and the quantity of items per page and use the methods Skip() and Take() of linq:

public IEnumerable<Clientes> ListarPagina(int paginaAtual, int itensPorPagina)
{
    return contexto.Clientes.Skip((paginaAtual - 1) * itensPorPagina).Take(itensPorPagina).ToList();
}

If you want to assemble the paging links and have a specific ViewModel with what you need to work, you can slightly modify the case and create a generic template for your paginated lists that accepts the total of records, page the number of items per page and the collection of items:

public class ListaPaginada<T>
{
    public int TotalItens { get; private set; }
    public int ItensPorPagina { get; private set; }
    public int PaginaAtual { get; private set; }

    public int TotalPaginas
    {
        get { return Math.Ceiling(TotalItens / ItensPorPagina); }
    }

    public List<T> Itens { get; private set; }

    public ListaPaginada(List<T> itens, int totalItens, int itensPorPagina, int paginaAtual)
    {
        this.Itens = itens;
        this.TotalItens = totalItens;
        this.ItensPorPagina = itensPorPagina;
        this.PaginaAtual = paginaAtual;
    }
}



public ListaPaginada<Clientes> ListarPagina(int paginaAtual, int itensPorPagina)
{
    var clientes = contexto.Clientes;
    var totalClientes = clientes.Count();
    var clientesDaPagina = clientes.Skip((paginaAtual - 1) * itensPorPagina).Take(itensPorPagina).ToList();

    return new ListaPaginada<Clientes> (clientesDaPagina, totalClientes, itensPorPagina, paginaAtual);
}

In your view, you will have a single object with the properties to do the loops and generate the pagination and the list as desired:

@model ListaPaginada<Clientes>

if (Model.TotalItens > 0)
{
    foreach(var item in Model.Itens)
    {
        <li>@item.Nome</li>
    }

    if (Model.TotalPaginas > 1)
    {
        <div class="paginacao">
            @for(var i = 1; i < Model.TotalPaginas; i++)
            {
                Url.Action("Index", new { pagina = i })
            }
        </div>
    }
}
else
{
    <p>Nenhum item disponível no momento!</p>
}

I do not recommend replacing the component, I just present a way to do the same in a custom way, with good performance and probably what the component does underneath the cloths, without the unnecessary additions.

    
18.08.2014 / 15:58