Olá amigos. Nosso objetivo neste artigo será estudar AJAX com aplicação de XML, PHP e DOM. Teremos um arquivo para paginação de resultados de consulta de banco de dados. Um modelo que procurei na internet, mas não encontrei.
Mas vamos ao que interessa! Nesse exemplo estou usando sete arquivos. Gosto muito da boa prática de programação por módulo.
Os arquivos são:
Index.php (Onde será mostrada nossa listagem);
Listagem.php (Responsável por fazer a consulta no banco de dados e gerar o arquivo XML de retorno);
Includes/conexão.php (Faz a conexão com o banco de dados);
Includes/paginação.php (Responsável pelo processo de paginação);
Includes/útil.js (Contem algumas utilidades);
Includes/ajax.js (script para o ajax);
Includes/funcoes.js (O mais importante, contêm todas as funcionalidades para o ajax);
Sql.txt (Arquivo extra – Script do banco de dados).
Vou detalhar os arquivos:
index.php
<HTML>
<HEAD>
<TITLE>Documento PHP</TITLE>
<SCRIPT type="text/javascript" src='includes/ajax.js'> </SCRIPT>
<SCRIPT type="text/javascript" src='includes/funcoes.js'> </SCRIPT>
<SCRIPT type="text/javascript" src='includes/util.js'> </SCRIPT>
</HEAD>
<BODY onLoad="javascript:listar(1)">
<h2>Paginação e Ordenação com Ajax (XML e JavaScript)</h2>
<div id="carregando" style="font:Verdana; color:#FFFFFF; background-color:#DD0000; width:180px;">
Carregando...
</div>
<br>
<table border="0">
<tr>
<td>Resgistro por página?</td>
<td>
Ordernar por?
</td>
</tr>
<form>
<tr>
<td>
<select id="regPag" onChange="javascript:listar(1);">
<option value="1">01 registro por página</option>
<option value="2">02 registros por página</option>
<option value="3">03 registros por página</option>
<option value="4">04 registros por página</option>
<option value="5">05 registros por página</option>
<option value="6">06 registros por página</option>
<option value="7">07 registros por página</option>
<option value="8">08 registros por página</option>
<option value="9">09 registros por página</option>
<option value="10" selected="selected">10 registros por página</option>
<option value="20">20 registros por página</option>
<option value="30">30 registros por página</option>
<option value="50">50 registros por página</option>
</select>
</td>
<td>
<select id="ordenacao" onChange="javascript:listar(1);">
<option value="1" selected="selected">ID Ascendente</option>
<option value="2">ID Descendente</option>
<option value="3">NOME Ascendente</option>
<option value="4">NOME Descendente</option>
</select>
</td>
</tr>
</form>
</table>
<br>
<table id="tabelaPrincipal" border="1" cellpadding="0" cellspacing="0">
<tr>
</tr>
</table>
<table id="tabelaPaginas" border="0" width="200" cellpadding="0" cellspacing="0">
<tr align="center">
<td> <a style="display:none" id="pri" href="">Primeiro</a> </td>
<td> <a style="display:none" id="ant" href="">Anterior</a> </td>
<td> <a style="display:none" id="pro" href="">Proximo </a> </td>
<td> <a style="display:none" id="ult" href="">Ultimo </a> </td>
</tr>
</table>
</BODY>
</HTML>
Linhas (4 a 6) – Importação dos arquivos necessários para o funcionamento.
Linhas (10 a 12) – Div onde irá aparecer a mensagem “Carregando…”.
Linhas (24 a 38) – Um campo select para a escolha da qtd de registro por página.
Linhas (41 a 46) – Um campo select para a escolha do tipo de ordenação.
Linhas (52 a 56) – Tabela onde irá ser exibido os registros.
Linhas (57 a 64) – Tabela onde irá ser exibido os texto “Primeiro Anterior Proximo e Ultimo”, para a paginação.
listagem.php
<?
//include do arquivo conexao.php para coneção com o BD
include("includes/conexao.php");
//SQL para a pesquisa no BD
$sql = "select ID, NOME from cidades where ID <= 30";
if($ordenacao == 1){
$sql = $sql." order by ID";
}else if ($ordenacao == 2){
$sql = $sql." order by ID DESC";
}else if ($ordenacao == 3){
$sql = $sql." order by NOME";
}else if ($ordenacao == 4){
$sql = $sql." order by NOME DESC";
}
//Include do arquivo paginacao.php Responsável pelo processamento da paginação
include("includes/paginacao.php");
//$limite contem a quantidade de registro por página definido no index.php pelo usuário
$qtd = mysql_num_rows($limite);
// Inicio da montagem do XML
Header("Content-type: text/xml");
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
$xml .= "<cidades>\n";
while(list($id,$nome) = mysql_fetch_row($limite)) {
$xml .= "<cidade>\n";
$xml .= "<id>".$id."</id>\n";
$xml .= "<nome>".$nome."</nome>\n";
$xml .= "</cidade>\n";
}
$xml.= "<totalReg>$totalRegistros</totalReg>";
$xml.= "<pagAtual>$pagAtual</pagAtual>";
$xml.= "<numPag>$numPaginas</numPag>";
$xml.= "<ordenacao>$ordenacao</ordenacao>";
$xml.= "</cidades>\n";
//Fim da montagem do XML
//Exibição do XML, isso não ficará visível para o usuário
echo $xml;
?>
Nesse arquivo temos a consulta no banco e a geração do arquivo XML que será preciso para ser exibido no index.php
conexao.php
<?
$conn = @mysql_connect("localhost", "root", "");
if (!$conn)
die("Erro ao conectar com MySQL: " . mysql_error());
if (!mysql_select_db("ajax", $conn))
die("Erro ao selecionar o banco: " . mysql_error());
?>
Nesse arquivo não tem nenhum mistério.
paginacao.php
<?
// Números de Registros por página
$registrosPorPagina = $regPorPag;
if(empty($registrosPorPagina)){
$registrosPorPagina = 5;
}
// Validação para não exibir a página 0
if (empty($pagina)): $pagAtual = 1; else: $pagAtual = $pagina; endif;
// Retorna os "$registrosPorPagina" até o número passado por "$pagina"
$inicio = $pagAtual - 1;
$inicio = $inicio * $registrosPorPagina;
// Pesquisa da página atual
$limite = mysql_query("$sql LIMIT $inicio,$registrosPorPagina");
// Número total de registros da tabela
$totalRegistros = mysql_num_rows(mysql_query("$sql"));
// verifica o número total de páginas
$numPaginas = $totalRegistros / $registrosPorPagina;
?>
util.js
//Receberá um elemento e substituirá todo o texto desse elemento pelo texto fornecido
function substituirTexto(elemento, texto) {
if (elemento != null) {
//usado para limpar todos os filho existente do elemento
limparTexto(elemento);
//<!-- Usamos para criar um novo nó texto e depois o acrescentamos aos nós filhos do elemento
var newNode = document.createTextNode(texto);
elemento.appendChild(newNode);
//-->
}
}
//Removerá todos os nós filhos do elemento que vc informar
function limparTexto(elemento) {
if (elemento != null) {
if (elemento.childNodes) {
for (var i = 0; i < elemento.childNodes.length; i++) {
var childNode = elemento.childNodes[i];
//removerá toidos os nós filhos.
elemento.removeChild(childNode);
}
}
}
}
ajax.js
//Inicio da verificação se o navegador suporta AJAX
function ObjAjax() {
try {
//Usado por algumas versões do IE
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
try {
//Usado pela maioria das versões do IE
ajax = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(ex) {
try {
//Funciona no Safari, FireFox, Mozila, Opera e
//a maioria dos navegadores que não são Microsoft
ajax = new XMLHttpRequest();
}
catch(exc) {
//Navegador sem suporte a AJAX
alert("Navegador não suporta AJAX");
ajax = null;
}
}
}
}
//Fim da Verificação
Criar o objeto a ser utilizado o AJAX.
funcoes.js
//Função responsavel por fazer a listagem dos registros.
function listar(pagina){
//criar o objAjax
ObjAjax();
if(ajax) {
//Pego a quantidade de resgistro por página definido pelo usuário no index.
var qtdRegPorPag = document.getElementById('regPag').value;
//Pego o tipo de ordenação definido pelo usuário no index.
var ordenacao = document.getElementById('ordenacao').value;
//Definir URL para onde devemos fazer a listagem passando a página que queremos.
//Definir Parametros onde devemos passar junto a url a pagina atual, qtd de registro por página, ordenação e
//dummy uma variavel criada para evitar que o IE guarde em cache a navegação com isso essa variavel "nunca" será igual.
var url = "http://localhost/ajax/listagem.php";
var parametros = "?pagina="+pagina+"®PorPag="+qtdRegPorPag+"&ordenacao="+ordenacao+'&milisegundos='+new Date().getTime();
ajax.open("GET", url+parametros, true);
//Enquanto o processa a listagem mostra para o usuário a mensagem "carregando".
var divCarregando = document.getElementById("carregando");
divCarregando.style.display = 'block';
//invoco a função paginar
ajax.onreadystatechange = paginar;
ajax.send(null);
}
}
Esse trecho acima utiliza o objeto AJAX para enviar para o servidor assincronicamente. Isso está explicito na linha 16 (3º parâmetro).
function paginar(){
//Verifico se o servidor concluiu a solicitação.
if (ajax.readyState == 4) {
//Informa o código de status do Servidor. "200" = OK
if(ajax.status == 200){
//valor guarda a resposta do servidor, que nesse caso é o XML gerado pelo arquivo listagem.php
var valor = ajax.responseXML;
var pagAtual = valor.getElementsByTagName("pagAtual")[0].firstChild.nodeValue;//pagAtual = página atual
var totalReg = valor.getElementsByTagName("totalReg")[0].firstChild.nodeValue;//totalReg = qtd total de registro do SQL
var numPag = Math.ceil(valor.getElementsByTagName("numPag")[0].firstChild.nodeValue);// numPag = qtd de páginas
if (totalReg == 0){
//caso entre aqui é pq não existe registro o banco, com isso eu "desabilito" os dois select,
//exibo a mensagem "Nenhum registro encontrado" e
//apago todo o conteúdo da tabela que exibi os registros.
document.getElementById('ordenacao').disabled = true;
document.getElementById('regPag').disabled = true;
divCarregando = document.getElementById("carregando");
substituirTexto(divCarregando, "Nenhum registro encontrado");
if(document.getElementById('tabelaPrincipal').rows.length>1){
document.getElementById('tabelaPrincipal').deleteRow(0);
document.getElementById('tabelaPrincipal').deleteRow(0);
}
}else{
//caso entre aqui é pq existe registro o banco, com isso eu "habilito" os dois select.
document.getElementById('ordenacao').disabled = false;
document.getElementById('regPag').disabled = false;
//dataArray = guarda uma matriz com todas informações do xml que pertencer a tag <estado></estado>
var dataArray = valor.getElementsByTagName("cidade");
//Utilizado para Limpar a tabela que será usada para mostrar os resgistros
while(document.getElementById('tabelaPrincipal').rows.length>0){
document.getElementById('tabelaPrincipal').deleteRow(0);
}
//definição do tamanho das tabelas:
// "tabelaPrincipal" que é usada para mostrar os resgistros
// "tabelaPaginas" que usada para paginar.
document.getElementById("tabelaPaginas").width="320";
document.getElementById("tabelaPrincipal").width="320";
//Inicio da escrita da tebela com o resultado
//isso gera uma linha com duas colunas e com conteúdo ID e NOME respectivamente
var x=document.getElementById('tabelaPrincipal').insertRow(0);
var y=x.insertCell(0);
var z=x.insertCell(1);
substituirTexto(y, 'ID');
substituirTexto(z, 'NOME');
//Início do processo da paginação propriamente dita
//quarda a página anterior
var anterior = (pagAtual - 1);
//guarda a página posterior
var proximo = (Number(pagAtual) + 1);
if ((totalReg % dataArray.length!=0)){
while(totalReg % dataArray.length!=0){
totalReg++;
}
}
if (pagAtual > 1) {
//Exibi o texto com o link Primeiro e Anterior, caso a pagina atual seja > 1
document.getElementById("pri").style.display = 'block';
document.getElementById("ant").style.display = 'block';
document.getElementById("pri").href="javascript:listar(1)";
document.getElementById("ant").href="javascript:listar("+anterior+")";
} else {
//Esconde o texto com o link Primeiro e Anterior, caso a página atual seja < 1
document.getElementById("pri").style.display = 'none';
document.getElementById("ant").style.display = 'none';
document.getElementById("pri").href="javascript:listar(1)";
document.getElementById("ant").href="javascript:listar("+anterior+")";
}
if (pagAtual < numPag) {
//Exibi o texto com o link Proximo e Ultimo, caso a pagina atual seja < qtd total de páginas
document.getElementById("pro").style.display = 'block';
document.getElementById("ult").style.display = 'block';
document.getElementById("pro").href="javascript:listar("+proximo+")";
document.getElementById("ult").href="javascript:listar("+numPag+")";
} else {
//Esconde o texto com o link Proximo e Ultimo, caso a pagina atual seja >= qtd total de páginas
document.getElementById("pro").style.display = 'none';
document.getElementById("ult").style.display = 'none';
document.getElementById("pro").href="javascript:listar("+proximo+")";
document.getElementById("ult").href="javascript:listar("+numPag+")";
}
//Laço para ir exibindo os resgistro linha a linha
for(var i = 0 ; i < dataArray.length ; i++) {
var item = dataArray[i];
//contéudo dos campos no arquivo XML
var id = item.getElementsByTagName("id")[0].firstChild.nodeValue;
var nome = item.getElementsByTagName("nome")[0].firstChild.nodeValue;
//será exibido sempre no fim da tabela
var posicaoFimTabela = document.getElementById('tabelaPrincipal').rows.length;
var x=document.getElementById('tabelaPrincipal').insertRow(posicaoFimTabela)
var y=x.insertCell(0);
var z=x.insertCell(1);
y.width = 30;
y.align = 'center';
substituirTexto(y, id);
z.width = 290;
substituirTexto(z, nome);
}
// Fim do processo da paginação propriamente dita
//LimparTexto = função usado para limpar o texto e usada tb para a função substituirTexto
var divCarregando = document.getElementById("carregando");
divCarregando.style.display = 'none';
}
}
}
}
Acima está o principal trecho, é responsável pela paginação do resultado.
*sql.txt*
CREATE TABLE `cidades` (
`ID` int(10) unsigned NOT NULL auto_increment,
`NOME` varchar(50) default NULL,
PRIMARY KEY (`ID`)
) TYPE=MyISAM AUTO_INCREMENT=1 ;
INSERT INTO `cidades` (`ID`, `NOME`) VALUES
(1, 'Recife'),
(2, 'Olinda'),
(3, 'São Paulo'),
(4, 'Maceió'),
(5, 'João Pessoa'),
(6, 'Natal'),
(7, 'Rio de Janeiro'),
(8, 'Teresina'),
(9, 'Salvador'),
(10, 'Fortaleza'),
(11, 'São Luiz'),
(12, 'Osasco'),
(13, 'Manaus'),
(14, 'Paulista'),
(15, 'Jaboatão dos Guararapes'),
(16, 'Caruaru'),
(17, 'cidade 17'),
(18, 'cidade 18'),
(19, 'cidade 19'),
(20, 'cidade 20'),
(21, 'cidade 21'),
(22, 'cidade 22'),
(23, 'cidade 23'),
(24, 'cidade 24'),
(25, 'cidade 25'),
(26, 'cidade 26'),
(27, 'cidade 27'),
(28, 'cidade 28'),
(29, 'cidade 29'),
(30, 'cidade 30')
Observações
Existem algumas melhorias que podem ser feitas como, por exemplo: pode-se substituir o campo select com as quantidades de registro por página por uma caixa de texto para o usuário ficar livre de escolher quantos registro por página ele quer, porém não esquecer de validar a entrada de dados do mesmo.
Essa é minha primeira matéria no iMasters e espero que seja apenas a primeira de muitas. Um grande abraço a todos e até a próxima.
Faça o download do arquivo.