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.
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
legal
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.
Perfeito meu amigo! OBRIGADO MESMO!
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com