Afinal, o que é AJAX?
Para entender o AJAX, é interessante recapitular o funcionamento de requisições / respostas e a exibição de paginas web, e soluções para problemas comuns que ocorrem com essas operações. Numa paginas web, quando o usuário clica num link ou submete um formulário,o servidor processa as informações submetidas e devolve como resposta outra página web completa, que então é renderizada pelo browser em substituição à primeira. Um problema é que o atraso da transferência dos dados, somando ao tempo de renderização pelo browser resulta na apresentação de páginas vazias e lentidão na resposta a ações do usuário.
Para minimizar esse efeito, uma abordagem é fazer a submissão de parâmetros e dados por um “canal separado” (através de uma thread própria dentro do browser) utilizando JavaScript. Em seguida o servidor devolve a resposta através do mesmo canal, evitando a necessidade de uma nova renderização da página. Dessa forma, a resposta não terá o conteúdo de uma página inteira, mas apenas os dados que necessitam ser modificados (ex.: o conteúdo de uma combobox). Um trecho de código JavaScript se encarrega de manipular esses dados e atualizar a página – e é dada a impressão para o usuário de uma aplicação mais interativa e responsiva.
Tal idéia existe desde que se começou a usar scripts para manipular elementos de páginas HTML. Inicialmente, a técnica do “canal separado” era implementada por meio de um frame HTML de tamanho mínimo, que realizava a requisição e obtinha como resposta uma pagina contendo, além dos dados, um script que atualizava o frame principal. O problema é que tal abordagem aumenta demais a complexidade de gerenciamento. Construir uma página desse modo exige uma página contendo o frameset (que define o layout dos frames na janela), um frame principal para mostrar os dados, e uma ou mais páginas para implementar a atualização do frame principal (cada atualização normalmente precisa de uma página de resposta específica).
A situação melhorou com a introdução, no Internet Explorer 5, da classe XMLHttpRequest, que permite a requisição assíncrona de páginas web e a manipulação do conteúdo dessas páginas na forma de dados (desde que a página esteja num formato apropriado). Isso simplificou muito a implementação de requisições através de threads próprias dentro do browser, sem a necessidade de utilização de utilização de artifícios como frames escondidos.
Além disso, num esforço por maior compatibilidade entre browser, o grupo Mozilla implementou uma classe equivalente ao XMLHttpRequest, o que foi seguido por outros browsers como Safari, Konqueror, OmniWeb e Opera. Criou-se então uma ambiente propício para atualização da classe XMLHttpRequest (ou equivalentes) por grandes aplicações como GMail, Google Earth, Google Suggest e Yahoo! Flickr, entre outras.
A técnica de criar uma página atualizada dinamicamente e parcialmente através de requisições ao servidor, utilizando o objeto XMLHttpRequest, ficou conhecida como AJAX.
Implementação AJAX
Após esse posicionamento histórico e tecnológico, está na hora de vermos a técnica em ação. Como exemplo, vamos criar uma página simples, onde temos uma combobox com projetos cadastrados num sistema: ao mudar o projeto selecionado, é mostrada logo abaixo da combo uma tabela com as atividades cadastradas naquele projeto.
A Listagem 1 apresenta a página de exemplo. A chamada a Fabrica.getProjetos() simula a obtenção de todos os projetos cadastrados no sistema; sua implementação não é discutida neste artigo, porém os fontes completos podem ser obtidos no site da Java Magazine.
O fragmento JavaScript abaixo cria a referência para o objeto XMLHttpRequest:
var xmlhttp=false;
try {
xmlhttp=new ActiveXObject(“Msxml2.XMLHTTP”);
} catch (e) {
try { xmlhttp=new ActiveXObject(“Microsoft.XMLHTTP”);}
catch (E) { xmlhttp=false;}
}
if (!xmlhttp && typeof XMLHttpRequest!=’undefined’){
xmlhttp=new XMLHttpRequest();
}
Este script é encontrado como exemplo em vários sites sobre AJAX e tem sido considerado um dos padrões para a criação da instância de XMLHttpRequest de forma independente de browser. Inicialmente, tenta-se obter a instância de Msxml12.XMLHTTP ou Microsoft.XMLHTTP, para o Internet Explorer (o nome da classe depende da versão da biblioteca de XML da Microsoft instalada na máquina cliente). Caso o browser tenha a sua própria implementação do tipo XMLHttpRequest, o script cria uma instância desse tipo no bloco condicional no final do script.
O evento onchange da combobox invoca a função JavaScript alteraProjeto():
function alteraProjeto() {
var theUrl=”obtemAtividadesXML.jsp?projeto=”
+document.getElementByld(“projeto”).value;
xmlhttp.open(“GET,theUrl,true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
criaTabela(xmlhttp.responseXML);
}
}
xmlhttp.send(null);
};
Essa função requisita a página obtemAtividadesXML.jsp, passando como parâmetros a identificação do projeto selecionado. Note que a execução de uma chamada AJAX segue sempre os mesmos passos:
- É invocado o método open() do objeto XMLHttpRequest, passando o método http desejado (normalmente GET ou POST), além da URL a ser requisitada e um flag indicando se a chamada é assíncrona ou não.
- Como a chamada é assíncrona, é definido no nosso caso um manipulador de eventos para notificar quando a resposta do servidor estiver completa (readyState igual a 4). Será invocada a função criaTabela(), passando-se o conteúdo XML obtido como resposta do servidor.
- Finalmente, o método send() realiza o envio da requisição, passando como parâmetro o corpo da mensagem a ser enviado (no caso de uma requisição POST).
A página obtemAtividadesXML.jsp, apresentada na Listagem 2, é responsável por gerar um documento XML com os dados de atividades do projeto passado como parâmetro. A Listagem 3 apresenta o resultado da execução da página JSP: esse XML será utilizado para facilitar a explicação do código JavaScript que faz a criação da tabela.
A página JSP utiliza somente conceitos de JSP e JSTL. O único detalhe que vale a pena mencionar é a inclusão da tag <pag> definindo o tipo de conteúdo da resposta (contentType) como sendo text/xml. Isso é importante para que o objeto XMLHttpRequest no browser consiga montar as estrutura XML a partir desse conteúdo.
Um ponto muito importante é que a manipulação dos dados de resposta como uma estrutura XML dentro do JavaScript requer duas condições:- O content-type de página de resposta deve ser definido como text/xml.
- Os dados de resposta precisam ser obtidos através da propriedade responseXML do objeto XMLHttpRequest.
Finalmente, a função JavaScript criaTabela() monta uma tabela HTML utilizando os dados XML obtidos pelo objeto XMLHttpRequest, e define essa tabela como valor do campo innerHTML do elemento Dentro dessa função, toda a manipulação dos dados do XML é feita através do método getElementByTagName() do objeto XMLDocument. Esse método recebe como parâmetro um nome da tag e retorna uma lista de elementos XML referentes à tag passada. Cada elemento XML será representado pela sua estrutura DOM. Assim, a linha: Atribui à variável data um array com três elementos (considerando como resposta o XML da Listagem 3). Cada elemento representa a estrutura DOM de cada atividade definida dentro da tag raiz <dados>.
Com isso, definimos os conceitos básicos para o próximo comando, que é responsável por obter o valor das tags < descricao>, <dataInicial> e <dataFinal>, dentro de cada tag <atividade>: Como já visto, getElementsByTagName() retorna um array com as estruturas DOM representando os elementos associados à tag passada. Neste caso, o método retorna uma lista de apenas um elemento, pois só existe uma tag < descricao> dentro de < atividade>. Como o retorno é uma lista e sabemos que haverá um só elemento, usamos diretamente uma chamada item(0). Dessa forma, a variavel desc contém a estrutura DOM da tag < descricao> Alguma confusão às vezes acontece quando é necessário obter o texto que está dentro de uma tag, mas não se está acostumado com a estrutura DOM. No exemplo, o texto da tag <descricao> é obtido com o seguinte comando: Pode parecer estranha a construção firstChild.data: como firstChild denota a primeira tag filha de uma tag, e <descricao> não possui tags filhas, então porque fazer o acesso dessa forma? A questão é que em DOM, o texto dentro de uma tag na realidade é o valor de uma tag filha especial. Assim, para obter a string “texto” dentro de <descricao>, é necessário primeiro obter essa tag filha (através da propriedade firstChild) para então obter o texto a partir da sua propriedade data. Pessoalmente, acho a manipulação da resposta do servidor através do modelo DOM pouco prática, além de não ser reutilizável – principalmente quando é necessário manipular estruturas de respostas mais complexas, com vários níveis de tags aninhadas. Melhor seria se pudéssemos manipular diretamente objetos JavaScript, o que facilitaria a criação de rotinas AJAX reutilizáveis, que pudessem ficar definidas num arquivo de inclusão separado, ou mesmo ser encapsuladas em taglibs JSP. Para isso, podemos utilizar a notação JSON (JavaScript Object Notation) em vez de XML, para a formatação dos dados nas páginas de resposta. A vantagem é que o JavaScript consegue, a partir de um documento escrito em JSON, criar automaticamente a estrutura de objetos correspondente, o que não seria possível para uma estrutura XML. Você pode ver uma definição mais formal de JSON no links, mas por ora, o que é necessário saber que é essa notação representa uma estrutura de objetos através da definição de pares atributo-valor na seguinte forma: Um array de objetos escritos em JSON é uma seqüência de definições de objetos, como a mostrada acima, separadas por vírgulas e delimitadas por colchetes: Para aplicar estruturas JSON no nosso exemplo, primeiro alteramos a página de resposta para que as informações sobre as atividades associadas a um projeto sejam escritas nessa notação e não em XML. A alteração pode ser vista na Listagem 4. Note que não é mais necessário definir o conteúdo da resposta como text/xml. Na realidade, não fará diferença, ao usar JSON, qual o tipo de conteúdo de retorno, desde que seja do grupo text/xxxx. A Listagem 5 apresenta a página de lista de atividades, alterada para o suporte a JSON. As diferenças mais significativas são: Note como se tem maior simplicidade e legibilidade com o modo de acesso em JSON. Cada elemento do array data é um objeto JavaScript com as propriedades descricao, dataInicial e dataFinal, as quais podem ser acessadas diretamente através do operador “ponto”. Enquanto que em uma estrutura XML, sempre seria necessário navegar dentro da hierarquia DOM para obter os dados desejados. AJAX é uma técnica que, de uma forma ou de outra, vem sendo aplicada em aplicações web há algum tempo. Recordo-me de um projeto em 2001 que utilizava um conceito semelhante, mas lançando mão de frames escondidos para realizar a tarefa de requisição de dados e atualização da página principal. Também tenho noticia de vários projetos que já faziam uso da atualização dinâmica de páginas através do objeto XMLHttpRequest, nessa mesma época. Então podemos perguntar o porquê de tanto alarde e de um novo nome para uma técnica antiga. Existem várias discussões na internet sobre o tema, algumas atacando a empresa Adaptive Path por tentar assumir o crédito (veja links), outras argumentando que o AJAX não passa de oportunismo de alguns aproveitando a onda de interfaces internet “ricas” (RIAs ou Rich Internet Applications) e outros defendendo uma miríade de opiniões (contra e a favor) sobre o AJAX. De uma perspectiva pragmática, minha opinião sobre AJAX é que se trata de uma técnica antiga que está sendo resgatada e destacada, principalmente porque o problema da incompatibilidade entre browser que existia no começo da década foi hoje em grande parte resolvido. O fato é que hoje em grande parte resolvido. O fato é que AJAX traz um benefício muito grande para as interfaces de aplicações web, com custo relativamente baixo. E levando em consideração o número de bibliotecas e tag libraries que estão surgindo com o objetivo de facilitar ainda mais a criação de interfaces AJAX, esta técnica deveria ser carta sempre disponível na manga do desenvolvedor web. Finalmente, sempre que surge uma “grande nova onda” é importante observar o movimento dos grandes da indústria, em vez de ouvir os neo-xiitas tecnológicos de plantão: Em resumo, nova ou não, a técnica AJAX apresenta uma visão diferente para o desenvolvimento de interfaces mais intuitivas e usáveis para o ambiente web, sem a necessidade de applets ou plug-ins. Desenvolvedor com AJAX “no braço” já não é mais uma tarefa complicada, e com os novos frameworks e taglibs que estão surgindo, a tarefa irá ficar mais simples ainda. Então, para aqueles que (como eu) sempre consideraram JavaScript um “mal necessário”, fica a sugestão: talvez seja a hora de tirar a poeira daquele manual de JavaScript e começar a olhar a arquitetura de sistemas web de uma perspectiva mais interativa! Black November Desconto exclusivo para as primeiras 200 matrículas! Pagamento anual 12x no cartão De: R$ 69,00 Por: R$ 54,90 Total: R$ 658,80 Garanta o desconto Pagamento recorrente Cobrado mensalmente no cartão De: R$ 79,00 Por: R$ 54,90 /mês Total: R$ 658,80 Garanta o desconto Nossos casos de sucesso Eu sabia pouquíssimas coisas de programação antes de começar a estudar com
vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa
bagagem consegui um estágio logo no início do meu primeiro
período na faculdade. Estudo aqui na Dev desde o meio do ano passado!
Nesse período a Dev me ajudou a crescer muito aqui no trampo. Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a
pena, pois a plataforma é bem intuitiva e muuuuito
didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito
obrigado! Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento
front-end, tinha coisas que eu ainda não tinha visto. A
didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado,
adorando demais. Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É
um passo a passo incrível. Só não aprende quem não quer.
Foi o melhor investimento da minha vida! Foi um dos melhores investimentos que já fiz na vida e tenho aprendido
bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da
programação, irei assinar meu contrato como programador
graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana,
aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem
como não aprender, estão de parabéns! Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de
seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com
React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo
muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na
área. Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.
var data = AjaxResponse.getElementByTagName(“atividade”);
var desc=data[i];getElementsByTagName(“descricao”).item(0);
desc.firstChild.data
<%@ page import=”jm.ajax.data.*”%>
<%@ taglib uri=http://java.sun.com/jsp/jstl/core” prefix=”c”%>
<script type=”text/javascript”>
var xmlhttp=false;
try {
xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP”);
} catch (e) {
try { xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”); }
catch (E) { xmlhttp = false; }
}
if (!xmlhttp && typeof XMLHttpRequest!=’undefined’) {
xmlhttp = new XMLHttpRequest();
}
function alteraProjeto()
{
var theUrl = “obtemAtividadesXML.jsp?projeto=”
+ document.getElementById(“projeto”).value;
xmlhttp.open(“GET”, theUrl,true);
xmlhttp.onreadystatechange-function() {
if (xmlhttp.readyState==4) {
criaTabela(xmlhttp.responseXML);
}
}
xmlhttp.send(null);
};
function criaTabela(AjaxResponse)
{
var data = AjaxResponse.getElementsByTagName(“atividade”);
var htmlText = “<table border=’1’>”
+” <tr>”
+” <th>Descrição</th>”
+” <th>Data Inicial</th>”
+” <th>Data Final</th>”
+” </tr>”
for(i=0;i<data.length;i++)
{
var desc = data[i].getElementsByTagName(
“descrição”).item(0);
var dataInicial = data[i].getElementsByTagName(
“dataInicial”).item(0);
var dataFinal = data[i].getElementsByTagName(
“dataFinal”).item(0);
htmlText=htmlText+”<tr><td>”
+ desc.firstChild.data+”</td><td>”
+ dataInicial.firstChild.data+”</td><td>”
+ dataFinal.firstChild.data+”</td><td></tr>”;
}
htmlText=htmlText+”</table>”;
document.getElementById(“tabela”).innerHTML=htmlText;
}
</script>
<html>
<c:set var=”projetos” value=”<%= Fabrica.getProjetos()%>” />
<center>
<select id=”projeto” onchange=”javascript:alteraProjetos()”>
<c:forEach var=”p” items=”${projetos}”>
<option value=”${p.id}”>${p.nome}</option>
</c:forEach>
</select>
<br><br>
<div id=”tabela”></div>
</center>
</html>
<%@ page import=”jm.ajax.data.*” %>
<%@ page contentType=”text/xml” %>
<%@ taglib uri=http://java.sun.com/jsp/jstl/core” prefix=”c” %>
<%@ taglib uri=http://java.sun.com/jsp/jstl/fmt” prefix=”fmt” %>
<c:set var=”atividades” value=
“<%= Fabrica.getAtividades(request.getParameter(“projeto”))%>” />
<dados>
<c:forEach var=”atividade” items=”${atividades}”
varStatus=”status”>
< atividade id=”${atividade.id}”>
<descricao>${atividade.descricao}</descricao>
<dataInicial>
<fmt:formatDate value=”${atividade.dataInicial}”
dataStyle=”short”/>
</dataInicial>
<dataFinal>
<fmt:formatDate value=”${atividade.dataFinal}”
dateStyle=”short”/>
</dataFinal>
< /atividade>
</c:forEach>
</dados>
<?xml version=”1.0” encoding=”UTF -8”?>
<dados>
< atividade id=”1”>
<descricao>Instalar Laszlo</descricao>
<dataInicial>01/08/05</dataInicial>
<dataFinal>01/08/05</dataFinal>
< /atividade>
< atividade id=”2”>
<descricao>Criar o projeto exemplo</descricao>
<dataInicial>02/08/05</dataInicial>
<dataFinal>08/08/05</dataFinal>
< /atividade>
< atividade id=”3”>
<descricao>Escrever o artigo</descricao>
<dataInicial>10/08/05</dataInicial>
<dataFinal>20/08/05</dataFinal>
< /atividade>
</dados>
Implementando AJAX com JSON
{atr1:vlr1,atr2: vlr2, ..., atrN, vlrN}
[{atr1.1:vlr1.1,...,atr1.N,vlr1.N}, {atr2.1,vlr2.1,...,atr2.N:vlr2.N},...]
data[i].getElementsByTagName(
“dataInicial”).item(0).firstChild.data
<%@ page import=”jm.ajax.data.*” %>
<%@ page contentType=”text/xml” %>
<%@ taglib uri=http://java.sun.com/jsp/jstl/core” prefix=”c” %>
<%@ taglib uri=http://java.sun.com/jsp/jstl/fmt” prefix=”fmt” %>
<c:set var=”atividades” value=
“<%= Fabrica.getAtividades(request.getParameter(“projeto”))%>” />
[
<c:forEach var=”atividade” items=”${atividades}” varStatus=”status”>
{
id:’${atividade.id}’,
descricao:’${atividade.descricao}’,
dataInicial: ‘<fmt:formatDate value=
“${atividade.dataInicial}” dateStyle=”short”/>’,
dataFinal: ’<fmt:formatDate value=
“${atividade.dataFinal}” dateStyle=”short”/>’
}
<c:if test=”${not status.last}”>
</c:if>
</c:forEach>
]
<%@ page import=”jm.ajax.data.*” %>
<%@ taglib uri=http://java.sun.com/jsp/jstl/core” prefix=”c” %>
<script>
var xmlhttp=false;
try {
xmlhttp = new ActiveXObject(“Msxml.XMLHTTP”);
}catch (e) {
try { xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”);}
catch(E) { xmlhttp = false; }
}
If (!xmlhttp && typeof XMLHttpRequest!=’undefined’) {
Xmlhttp = new XMLHttpRequest();
}
function alteraProjeto()
{
var theUrl = “obtemAtividades.jsp?projeto=”
+ document.getElementById(“projeto”).value;
xmlhttp.open(“GET”, theUrl.true);
xmlhttp.onreadystatechange=function() {
If (xmlhttp.readyState==4) {
criaTabela(xmlhttp.responseText);
}
}
xmlhttp.send(null);
};
function criaTabela(AjaxResponse)
{
var data = eval(AjaxResponse);
var htmlText = “<table border=’1’>”+
“ <tr>”+
“ <th> Descrição</th>”+
“ <th>Data Inicial</th>”+
“ <th>Data Final</th>”+
“ </tr>”
for(i=0;i<data.length;i++)
{
htmlText=htmlText+”<tr><td>”
+ desc.firstChild.data+”</td><td>”
+ dataInicial.firstChild.data+”</td><td>”
+ dataFinal.firstChild.data+”</td><td></tr>”
}
htmlText=htmlText+”</table>”;
document.getElementById(“tabela”).innerHTML=htmlText;
}
</script>
<html>
<c:set var=”projetos” value=”<%= Fabrica.getProjetos()%>” />
<center>
<select id=”projeto” onchange=”javascript:alteraProjetos()”>
<c:forEach var=”p” items=”${projetos}”>
<option value=”${p.id}”>${p.nome}</option>
</c:forEach>
</select>
<br><br>
<div id=”tabela”></div>
</center>
</html>
Conclusões
Confira também
Confira outros conteúdos:
O que são arrays e como utilizá-los no...
Fundamentos básicos de JavaScript...
JavaScript setInterval: executando...
<Perguntas frequentes>
Fui o primeiro desenvolvedor contratado pela minha
empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um
Full-Stack Dev!