Criando um Grid de Dados Simples usando MYSQL, PHP e AJAX - Paginação
Luis Carlos

Luis Carlos @luis_carlos60

About: Seja bem-vindo! Eu sou um programador brasileiro que ama aprender coisas novas, usuário linux e intermediário no mundo da programação.

Joined:
May 20, 2025

Criando um Grid de Dados Simples usando MYSQL, PHP e AJAX - Paginação

Publish Date: May 29
2 0

No último post publicado, foi ensinado a maneira para poder listar os alunos e suas respectivas informações. Nesse atual post, será mostrado como fazer uma paginação padrão, limitada pelo tamanho de itens dentro da lista, podendo clicar no final se a página não for a página fim, podendo clicar no início caso a página atual não seja a página início, com espaçamento, caso seja uma paginação de uma lista grande, e tudo funcionando sem precisar recarregar a página, ou seja, utilizando AJAX e o PHP, utilizado para montar a lógica do funcionamento da paginação.

Em primeiro lugar, precisamos entender como funciona uma paginação básica:

- LIMIT

O comando LIMIT no SQL limita a quantidade de dados você quer que apareça, logo, se colocar no final da query um LIMIT 5

$sqlAlunos = "SELECT
    aluno.id, aluno.nome, aluno.idade, aluno.media, status.nome AS status_nome, aluno.foto
    FROM aluno 
    JOIN status ON aluno.idStatus = status.id
    LIMIT 5";
Enter fullscreen mode Exit fullscreen mode

Nós iremos receber apenas as primeiras 5 linhas

Image description

Esse dado é fixo, porém, iremos setar uma variável para armazenar seu valor:

$pageSize = isset($_GET['pageSize']) ? (int) $_GET['pageSize'] : 5; // Se não estiver setado, define o valor para 5
Enter fullscreen mode Exit fullscreen mode

Agora, ao invés de usar LIMIT 5, trocaremos por :pageSize e diremos para o $stmt que o valor de pageSize é $pageSize e é um valor do tipo INT:

$stmt->bindValue(':pageSize', $pageSize, PDO::PARAM_INT);
Enter fullscreen mode Exit fullscreen mode

- Offset

Já cortamos a tabela em partes, mas agora, como será feito para ver as outras partes? É aí que entra o offset, ele permite que nós possamos começar a partir de um intervalo de linha, então se eu quero começar na linha 5, com um limite de 5 linhas, eu poderia usar no final da minha query:

LIMIT :pageSize OFFSET 5
Enter fullscreen mode Exit fullscreen mode

E isso nos traria o que seria a próxima página:

Image description

Logo, mais uma vez teremos que adicionar mais umas variáveis, nesse caso, mais duas: $page para definir a página atual que estamos naquele momento e $offset, em resumo, se quisermos ver a 2º parte dos dados e assim consecutivamente precisaremos fazer uma simples equação $offset = ($page - 1) * $pageSize, lembrando que a primeira página é a página 1, e precisamos pegar desde a linha 0, por isso $page - 1 e a variável $page que será $page = isset($_GET['page']) ? (int) $_GET['page'] : 1;

Agora, poderemos adicionar ao final da query:

LIMIT :pageSize OFFSET :offset
Enter fullscreen mode Exit fullscreen mode

Ou simplificando:

LIMIT :offset, :pageSize
Enter fullscreen mode Exit fullscreen mode

E por último, entregar para o $stmt o valor de :offset

$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
Enter fullscreen mode Exit fullscreen mode

- LÓGICA

Para começar, devemos contar qual é o total de registros que temos para descobrir a quantidade de páginas que o sistema possuirá, assim possibilitando para que nos retorne a primeira e a última página na paginação sempre.

$sqlCount = "SELECT COUNT(*) FROM aluno";
$stmtCount = $pdo->prepare($sqlCount);
$stmtCount->execute();
$totalRegistros = $stmtCount->fetchColumn();
$totalPaginas = ceil($totalRegistros / $pageSize) // a função ceil retorna o valor acima mais próximo, caso seja um número quebrado.

// vão ser o intervalo do meu for loop
$start = max(1, $page - 2);
$end = min($totalPaginas - 1, $page + 2);

Enter fullscreen mode Exit fullscreen mode

O que é necessário saber sobre a lógica a seguir:

  1. Se a página atual for maior do que 3, então ele volta com o 1 no início, já que é a partir do 3 que o intervalo entre $start e $end não pegam mais o número 1;
  2. Entre $start e $end, ele deve imprimir todos os números presentes dentro do intervalo. Se a variável do loop $i for igual à página atual $page, logo, o número fica em destaque dos outros. Se não, ele apenas printa o número na tela
  3. Enquanto a página atual $page é menor que o total de páginas - 3, ele irá printar "..." em seguida, representando que tem continuidade.
  4. Se o total de páginas $totalPaginas for maior do que 1 e a página atual for diferente da última página que também é representado pela variável $totalPaginas, ele irá printar a página final, sem estar em destaque.
echo "<div class='paginacao'>";

if ($page > 3){
    echo "<a href='#' data-page='1'> 1 </a>";
    echo "<span> ... </span>";
}

for ($i = $start; $i <= $end; $i++){
    if ($i === $page){
        echo "<a href='#' data-page='$i'>
        <strong> $i
        </strong></a>";
    } else {
        echo "<a href='#' data-page='$i'> $i </a>";
    }
}

if ($page < $totalPaginas - 3){
    echo "<span> ... </span>";
}

if ($totalPaginas > 1 && $page != $totalPaginas){
    echo "<a href='#' data-page='$totalPaginas'> $totalPaginas </a>";
}
echo "</div>";
Enter fullscreen mode Exit fullscreen mode

Como resultado, teremos isso aqui:

Image description

Porém, ele ainda não está completo, ainda precisamos inserir a lógica com ajax para que ele funcione e não precise recarregar a página toda vez

- AJAX

AJAX é "JavaScript Assíncrono e XML", ele faz requisições em segundo plano para o servidor sem que seja necessário recarregar todo o html da página, permitindo que o usuário, no caso atual, acesse os outros dados de maneira assíncrona, recebendo apenas os dados que foram pedidos instantaneamente.

Para isso, crie dois arquivos. Um que será parte do front: index.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lista de Alunos</title>
</head>
<body>

<h2>Alunos</h2>
<div id="resultado">
    <?php include 'artigos.php'; ?>
</div>

<script src="./app.js"></script>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

E outro de nome app.js:

document.addEventListener('DOMContentLoaded', function () {
  const resultado = document.getElementById("resultado");
  document.addEventListener('click', function (e) {
    if (e.target.matches('[data-page]')) {
      e.preventDefault();

      const page = e.target.getAttribute('data-page');

      fetch(`artigos.php?page=${page}&ajax=1`)
        .then(res => res.text())
        .then(html => {
          resultado.innerHTML = html;
        })
    }
  });
});
Enter fullscreen mode Exit fullscreen mode

Ele funciona da seguinte forma:

  1. document.addEventListener('DOMContentLoaded', function (): espera o carregamento completo da página para executar alguma função;

  2. const resultado = document.getElementById("resultado");: seleciona onde serão feitas as requisições que irão envolver o ajax;

  3. document.addEventListener('click', function (e): adiciona um listener para todos os botões na página, isso se chama event delegation, ao invés de pegar botão por botão, ele pega todos os botões para depois tratar eles;

  4. if (e.target.matches('[data-page]')): se o elemento clicado tiver o atributo data-page;

  5. e.preventDefault();: evita comportamento padrão de recarregar a página;

  6. const page = e.target.getAttribute('data-page');: pega o valor do atributo data-page para adicioná-lo na requisição ajax;

  7. fetch('artigos.php?page=${page}&ajax=1\'): faz a requisição a página de artigo correspondente, o ajax é para dizer que somente deve ser entregue o conteúdo solicitado;

  8. .then(res => res.text()): como a resposta não é em JSON, usamos .text;

  9. .then(html => {resultado.innerHTML = html;}): atualiza a div resultado.

Por fim, a paginação após isso deve estar funcionando de forma assíncrona, sem recarregar a página e entregando todos os conteúdos solicitados.

Na próxima parte, irei mostrar como fazer uma barra de pesquisa usando também ajax. Muito obrigado por lerem até aqui!

O repositório oficial do projeto se encontra aqui: https://github.com/Luis-60/lista-de-alunos.

Comments 0 total

    Add comment