Skip to content

Instantly share code, notes, and snippets.

@Whistler092
Last active May 13, 2021 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Whistler092/937792da90d02c88973f456ba76f6f93 to your computer and use it in GitHub Desktop.
Save Whistler092/937792da90d02c88973f456ba76f6f93 to your computer and use it in GitHub Desktop.
Config Pagination
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using API.DTOs;
using API.Entidades;
using API.Utilidades;
namespace API.Controllers
{
[Route("api/generos")]
[ApiController]
public class GenerosController : ControllerBase
{
private readonly ILogger<GenerosController> logger;
private readonly ApplicationDbContext context;
private readonly IMapper mapper;
public GenerosController(ILogger<GenerosController> logger, ApplicationDbContext context, IMapper mapper)
{
this.logger = logger;
this.context = context;
this.mapper = mapper;
}
[HttpGet]
public async Task<ActionResult<List<GeneroDTO>>> Get([FromQuery] PaginacionDTO paginacionDTO)
{
var queryable = context.Generos.AsQueryable();
await HttpContext.IntertarParametrosPaginacionEnCabecera(queryable);
var generos = await queryable
.OrderBy(x => x.Nombre)
.Paginar(paginacionDTO)
.ToListAsync();
return mapper.Map<List<GeneroDTO>>(generos);
}
}
}
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
namespace API.Utilidades
{
public static class HttpContextExtensions
{
public async static Task IntertarParametrosPaginacionEnCabecera<T>(this HttpContext httpContext, IQueryable<T> queryable)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
double cantidad = await queryable.CountAsync();
httpContext.Response.Headers.Add("cantidadTotalRegistros", cantidad.ToString());
}
}
}
import axios, { AxiosResponse } from "axios";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import Button from "../utils/Button";
import { urlGeneros } from "../utils/endpoints";
import ListadoGenerico from "../utils/ListadoGenerico";
import Paginacion from "../utils/Paginacion";
import { generoDTO } from "./generos.model";
export default function IndiceGeneros() {
const [generos, setGeneros] = useState<generoDTO[]>();
const [totalDePaginas, setTotalDePaginas] = useState(0);
const [recordsPorPagina, setRecordsPorPagina] = useState(5);
const [pagina, setPagina] = useState(1);
useEffect(() => {
axios
.get(urlGeneros, {
params: { pagina, recordsPorPagina },
})
.then((respuesta: AxiosResponse<generoDTO[]>) => {
console.log("data", respuesta.data);
const totalDeRegistros = parseInt(
respuesta.headers["cantidadtotalregistros"],
10
);
const totalDePaginas = Math.ceil(totalDeRegistros / recordsPorPagina);
console.log("totalDePaginas", totalDePaginas);
setTotalDePaginas(totalDePaginas);
setGeneros(respuesta.data);
});
}, [pagina, recordsPorPagina]);
return (
<>
<h3>Géneros</h3>
<Link className="btn btn-primary" to="generos/crear">
Crear Géneros
</Link>
<div className="form-group" style={{ width: "150px" }}>
<label htmlFor="setRecordsPorPagina">Registros Por Pagina</label>
<select
className="form-control"
defaultValue={10}
onChange={(e) => {
setPagina(1);
setRecordsPorPagina(parseInt(e.currentTarget.value, 10));
}}
name="setRecordsPorPagina"
id="setRecordsPorPagina"
>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={25}>25</option>
<option value={50}>50</option>
</select>
</div>
<Paginacion
cantidadTotalDePaginas={totalDePaginas}
paginaActual={pagina}
onChange={(nuevaPagina) => setPagina(nuevaPagina)}
></Paginacion>
<ListadoGenerico listado={generos}>
<table className="table table-striped">
<thead>
<tr>
<th></th>
<th>Nombre</th>
</tr>
</thead>
<tbody>
{generos?.map((genero) => (
<tr key={genero.id}>
<td>
<Link
className="btn btn-success"
to={`/generos/${genero.id}`}
>
Editar
</Link>
<Button className="btn btn-danger">Borrar</Button>
</td>
<td>{genero.nombre}</td>
</tr>
))}
</tbody>
</table>
</ListadoGenerico>
</>
);
}
using System.Linq;
using API.DTOs;
namespace API.Utilidades
{
public static class IQueryableExtensions
{
public static IQueryable<T> Paginar<T>(this IQueryable<T> queryable, PaginacionDTO paginationDTO)
{
return queryable
.Skip((paginationDTO.Pagina - 1) * paginationDTO.RecordsPorPagina)
.Take(paginationDTO.RecordsPorPagina);
}
}
}
import { useEffect, useState } from "react";
export default function Paginacion(props: paginacionProps) {
const [listadoLinks, setListadoLinks] = useState<modeloLink[]>([]);
useEffect(() => {
const paginaAnteriorHabilitada = props.paginaActual !== 1;
const paginaAnterior = props.paginaActual - 1;
const links: modeloLink[] = [];
links.push({
texto: "Anterior",
habilitado: paginaAnteriorHabilitada,
pagina: paginaAnterior,
activo: false,
});
console.log(props);
for (let i = 1; i <= props.cantidadTotalDePaginas; i++) {
if (
i >= props.paginaActual - props.radio &&
i <= props.paginaActual + props.radio
) {
links.push({
texto: `${i}`,
activo: props.paginaActual === i,
habilitado: true,
pagina: i,
});
}
}
const paginaSiguienteHabilitada =
props.paginaActual !== props.cantidadTotalDePaginas &&
props.cantidadTotalDePaginas > 0;
const paginaSiguiente = props.paginaActual + 1;
links.push({
texto: "Siguiente",
pagina: paginaSiguiente,
habilitado: paginaSiguienteHabilitada,
activo: false,
});
setListadoLinks(links);
}, [props.paginaActual, props.cantidadTotalDePaginas, props.radio]);
function obtenerClase(link: modeloLink) {
if (link.activo) {
return "active pointer";
}
if (!link.habilitado) {
return "disabled";
}
return "pointer";
}
function seleccionarPagina(link: modeloLink) {
if (link.pagina === props.paginaActual) {
return;
}
if (!link.habilitado) {
return;
}
props.onChange(link.pagina);
}
return (
<nav>
<ul className="pagination justify-content-center">
{listadoLinks.map((link) => (
<li
key={link.texto}
onClick={() => seleccionarPagina(link)}
className={`page-item cursor ${obtenerClase(link)}`}
>
<span className="page-link">{link.texto}</span>
</li>
))}
</ul>
</nav>
);
}
interface modeloLink {
pagina: number;
habilitado: boolean;
texto: string;
activo: boolean;
}
interface paginacionProps {
paginaActual: number;
cantidadTotalDePaginas: number;
radio: number;
onChange(pagina: number): void;
}
Paginacion.defaultProps = {
radio: 3,
};
using System;
namespace API.DTOs
{
public class PaginacionDTO
{
public int Pagina { get; set; } = 1;
private int recordsPorPagina = 10;
private readonly int cantidadMaximaRecordsPorPagina = 50;
public int RecordsPorPagina
{
get
{
return recordsPorPagina;
}
set
{
recordsPorPagina = (value > cantidadMaximaRecordsPorPagina)
? cantidadMaximaRecordsPorPagina : value;
}
}
}
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
var frontendUrl = Configuration.GetValue<string>("frontend_url");
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(frontendUrl)
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders(new string[] { "cantidadTotalRegistros" });
});
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment