Utilizando os botões voltar, avançar e atualizar com AJAX

Artigo que apresenta um recurso que permite simular o funcionamento dos botões voltar, avançar e atualizar do navegador, mesmo que a aplicação utilize Ajax para atualizar o conteúdo da página.

Botões voltar, avançar e atualizar do navegador
Introdução

Fim da guerra entre AJAX e Botões do Navegador!

Um dos maiores inconvenientes dos sistemas que utilizavam AJAX é que era relativamente complexo utilizar este modelo e manter funcionando os botões voltar, avançar e atualizar do navegador. Porém, o novo Firefox 4 trouxe outro recurso previsto no HTML 5 que resolve este problema com bastante facilidade. Este artigo mostra como voltar o suporte a estes botões do navegador através do método history.pushState.


Como funciona o AJAX?

Antes de apresentar a solução para o problema apresentado, vale relembrar resumidamente como funciona o AJAX. Se você já conhece, pode pular para a próxima seção.

Ajax

Basicamente, AJAX - sigla para Assynchronous JavaScript And XML - é um conjunto de tecnologias que visa uma maior interatividade dos usuários em sistemas Web. Ele se sustenta na ideia de que, quando um usuário realiza alguma ação no site que é bastante pontual, nem sempre é necessário recarregar toda a página. Ao invés disso, AJAX permite que o JavaScript realize uma requisição assíncrona (ou seja, o JavaScript não fica esperando o resultado da requisição para continuar fazendo outras coisas), e, quando o resultado chega (normalmente na forma de XML), o JavaScript interpreta a mensagem devolvida pelo servidor e atualiza dinamicamente apenas um trecho da página.

Inicialmente, este recurso foi muito utilizado para caixas de votação (por exemplo, lançar quantas estrelas esta postagem merece), botões para ativar/desetivar algum registro, botões para "curtir", etc. Porém, este recurso também foi utilizado em sites e sistemas para recarregar páginas quase completas. Digo "quase completas" pois o cabeçalho da página, o rodapé e, em alguns casos, o menu principal não precisavam ser recarregados. No entanto, utilizar este recurso para atualizar páginas pode ser um problema para o usuário que estava acostumado que uma nova página é um novo link e, portanto, pode-se usar o botão voltar para retornar à página anterior. Com AJAX, por padrão, o usuário se mantém na mesma página (mesmo link) e o JavaScript apenas modifica o conteúdo da página que realizou a requisição assíncrona.


A Solução

A solução para o problema foi implementada para o novo navegador Firefox 4. Trata-se do método pushState do objeto especial history. Para quem não sabe, history é um objeto que guarda o histórico de navegação do usuário, ou seja, guarda internamente um array com as páginas de onde o usuário veio (o mesmo array usado pelo navegador para saber para onde o usuário deve ir quando clica em voltar/avançar). Este objeto já permitia acionar o avançar/voltar via JavaScript. Porém, até então, não permitia incluir um novo link. O método pushState serve justamente para isso. Portanto, a solução consiste em acionar este método assim que o AJAX é utilizado para atualizar uma página "quase completa". Note que não é utilizá-lo em todos pontos que utilizavam AJAX. Caso tenha dúvidaas, leia novamente a seção anterior.


Exemplo

Quando utilizamos AJAX, definimos um método/função que será chamado assim que o resultado (XML) for recebido. Neste método, vamos incluir o seguinte trecho de código:

function atualizar() {

    // Atualiza um trecho da pagina
    ...

    // Atualiza o titulo da pagina (recebido do XML)
    document.title = title;

    // Incluir a pagina no historico de navegacao
    try {
        history.pushState({url:url}, document.title, url);
    } catch (e) {
        // O navegador nao tem suporte a pushState
    }
}

O método pushState recebe 3 parâmetros: (1) o novo estado, que é um objeto que pode guardar outras informações sobre a página (veremos pra que serve isso), mas pode ser null, caso não tenha nenhuma informação especial; (2) o título da página no histórico (nome do estado), que normalmente é o valor armazenado em document.title; e (3) a URL da nova página, que será acessada quando o usuário clicar para voltar para esta página. Você também vai notar que ao chamar este método, a barra de endereço do navegador será atualizado sem necessariamente "ir" para a página, afinal, o AJAX já realizou esta tarefa manualmente.

Bom, com isso, a URL é incluída no histórico do navegador, mas ainda não significa que, quando o usuário clicar em voltar, ele voltará para a URL indicada. Para isso, ainda precisamos implementar um evento chamado onpopstate do objeto window. A implementação deste método é bastante simples, basta fazer o navegador ir para a página indicada via location ou via Ajax também, desde que tenha recebido um state:

window.onpopstate = function(e) {
    if (e.state) {
        window.location.reload();
    }
};

Ao realizar um reload, o navegador vai para o endereço indicado no documento. Em document.location fica guardada a URL da barra de endereço do documento ativo. Mas e pra que serve o objeto de estado? ele é informado pelo parâmetro "e" (evento ocorrido), e pode ser obtido por e.state, então se você colocou um atributo "titulo" ao seu objeto de estado, pode obtê-lo por "e.state.titulo".

Porém, ainda há mais um detalhe. O código mostrado até aqui funciona bem para a segunda página visitada em diante, mas não volta para a página inicial. Para tanto, é preciso executar um trecho de código uma única vez que vai definir o estado padrão quando o usuário entrar na página:

try {
    if (url_inicial) {
        history.replaceState({url:url_inicial}, '', url_inicial);
        url_inicial = null;
    }
} catch (e) {
    //void
}

Supondo que url_inical seja uma variável global e reservada para este propósito. O método repaceState apenas modifica o estado atual da página avaliada. Como mudamos o valor de url_inicial para null, ela não é executada com as próximas chamadas via Ajax.

Com isso, está tudo pronto para seu site ou sistema web que utiliza AJAX passar a usufruir dos botões de voltar, avançar e atualizar, sem precisar fazer nenhuma mágica com JavaScript.

3 comentários

Unknown disse...

Estávamos com um problema aqui no "voltar" do navegador mas quando vi esse:
window.onpopstate = function(e) {
if (e.state) {
window.location.reload();
}
};

o problema foi resolvido, obrigado.