Múltiplas galerias de fotos dinâmicas com Fancybox, Ajax e JSON

Transferindo dados entre o PHP e Javascript do jeito certo.

por pdechery 27/02/2015

Introdução

Ano passado trabalhei em um projeto que era um concurso de fotografia online, o Prix Photo Web, onde cada fotógrafo podia se cadastrar, fazer upload de suas fotos e concorrer a um prêmio.

O site tinha uma página de galeria, onde se podia ver os diversos trabalhos publicados a partir de thumbnails.

Eu havia pego o código já quase todo pronto, mas resolvi atualizar algumas coisas e uma delas foi a tal galeria.

No decorrer do processo acabei tendo que usar o JSON para trocar informações entre scripts PHP e JavaScript, e achei muito interessante a maneira como isso aconteceu.

O resultado final pode ser conferido aqui, e a seguir vou descrever o passo a passo do processo que percorri.

Escopo

O conteúdo do site era totalmente dinâmico, ou seja, vinha de consultas ao banco de dados feitas no carregamento da página. Veja abaixo como ficou a página da galeria, com os thumbnails clicáveis:

galeria-prix-1

Ao dar o clique em um dos thumbs se abria uma galeria de fotos em lightbox, usando o plugin jQuery fancybox (um velho favorito meu):

galeria-prix-2

O problema

Eu já tinha toda a lógica para exibir os thumbnails na página e também as galerias em lightbox, mas achei o código meio ‘macarrônico’ e me questionei se não podia ser mais simples e limpo.

Para demonstrar o funcionamento do sistema existente de carregamento das galerias, segue um diagrama:

diagrama-prix

Trata-se de um exemplo básico de uso de Ajax, aonde temos:

  1. Página HTML: Renderiza a galeria de thumbnails e as galerias de fotos em lightbox.
  2. Script JS: Ativado a cada clique em um thumbnail, faz a requisição de um arquivo PHP através de Ajax.
  3. Arquivo PHP: Faz as consultas no banco de dados para pegar todas os dados necessários para exibição da galeria, e devolve estes dados ao script, que finalmente vai exibir a galeria, usando o plugin fancybox.

O sistema como um todo funcionava, mas faltava um toque de agilidade, que foi dado ao acrescentar o JSON no sistema.

Vamos então ver agora como isso foi feito.

O código

O HTML da galeria era mais ou menos assim:

<div class="projetos">
    <a id="10">
        <img src="dir/nome-img.jpg">
    </a>
    <a id="11">
        <img src="dir/nome-img.jpg">
    </a>
</div>

E abaixo o código JS (usando jQuery) que fazia acontecer a mágica a cada clique nos thumbnails:

$(document).ready(function(){
    $('.projetos > a').click(function(){
        var id = $(this).attr('id');
        $.post('ajax-projetos.php',{'idp':id}, function(data){
            fancyPrix(data);
        },'text');
    });
});

Observando o script, vemos que ele aplica algumas ações ao evento click nos links, conforme indicado neste trecho: $('.projetos > a').click(function(){

As ações basicamente são: a requisição do arquivo ajax-projetos.php usando o método do jQuery $.post (método do jQuery para chamadas Ajax), passando como parâmetro a variável id, cujo valor vem de um atributo em cada link. O retorno dado pelo arquivo php, representado na variável data, era em seguida passado pela função fancyPrix.

Se ficou com dúvidas examine novamente o script até entender todo o processo.

Usando o JSON

Agora que ficou claro (espero) o importante papel do script JS, vamos ao arquivo ajax-projetos.php. Como explicado no diagrama apresentado anteriormente, este arquivo fazia a consulta no banco de dados entregando ao final um array contendo os dados necessários para a renderização da galeria de imagens em lightbox.

Ao final do processo, o array produzido tinha a seguinte estrutura:

$proj = array (
    "candidato" => "Felisbério dos Santos",
    "imgs"  => array ( 
        0 => "http://localhost/projeto/diretorio/nome-arquivo.jpg",
        1 => "http://localhost/projeto/diretorio/nome-arquivo.jpg",
        2 => "http://localhost/projeto/diretorio/nome-arquivo.jpg",
    ),
    "projeto" => "Sombras Negras"
);

Como se pode ver, o array tinha todos os dados necessários para criação da galeria: nome do candidato, nome do projeto e as imagens, como um sub-array.

No código original, a grande falha no entanto era a forma como esses dados eram devolvidos ao script JS. Havia uma mistura de código JS como variáveis do php dentro do mesmo script que tornava tudo confuso e difícil de manter.

Porque não passar o array de volta como um objeto JSON, que pode ser interpretado dentro do script JS original, abolindo assim o uso de código php macarrônico?

Isto foi feito simplesmente adicionando-se ao código esta linha:

echo json_encode($proj);

A função nativa do PHP ‘json_encode‘, como diz o nome, converte o array $proj para um objeto JSON, que ficará assim:

{
    "candidato":"Felisbério dos Santos",
    "imgs":[
        "http://path/da/imagem/136/000-1.jpg",
        "http://path/da/imagem/136/000-2.jpg",
        "http://path/da/imagem/136/000-3.jpg"
        ],
    "nome":"Sombras Negras"
 }

Este objeto pode ser passado tranquilamente pela script JS, aonde será usado na já citada função fancyPrix(), que é quem vai pegar cada informação do objeto JSON e aplicar no _plugin fancybox_, da seguinte maneira:

function fancyPrix(projeto) {
    $.fancybox.open(projeto.imgs, {
        padding: 0,
        maxWidth : '680px',
        maxHeight : '660px',
        title: projeto.nome + " - "+ projeto.candidato,
        loop : 'false',
        prevEffect : 'none',
        nextEffect : 'none'
    });
}

Vemos que o plugin fancybox possui um método que permite trabalhar com objetos JSON, o fancybox.open.

Repare como foram passadas as imagens logo no início do código: $.fancybox.open(projeto.imgs, {. Com a simples propriedade projeto.imgs conseguimos passar todas as imagens que fazem parte da galeria. O restante das propriedades são usadas como opções dentro do plugin, como mostrado acima.

Relembrando o script jQuery original podemos ver como a galeria toda é criada em apenas uma linha de código.

$(document).ready(function(){
    $('.projetos a').click(function(){
        var id = $(this).attr('id');
        $.post('ajax-projetos.php',{'idp':id}, function(data){
            fancyPrix(data);
        },'text');
    });
});

Conclusão

Quando apliquei esta solução e vi tudo funcionando o orgulho (e o alívio) foram grandes, mas maior ainda foi a sensação de ‘uau’ ao ver as diferentes linguagens da web conversando juntas e de maneira tão integrada.