| Por Carlos Eduardo Barros cebarros@gmail.com Carlos Eduardo é desenvolvedor .NET e atualmente trabalha como analista-desenvolvedor no IPANRIO (Empresa Municipal de Informática) |
|
|
|
|
| Atualizando Dados na Página sem Postback | |
|
|
|
Hoje em dia, podemos atualizar informações em uma página web de duas formas: por javascript ou gerando um postback. A desvantagem da primeira forma é que todos os dados devem ser enviados junto com a página, o que torna a requisição mais lenta. Já o problema da segunda forma é que o usuário tem que esperar a página voltar do servidor para continuar seu trabalho.
Nesse artigo veremos uma outra forma para realizar essa atualização. Utilizaremos o objeto XmlHttpRequest, presente nos browsers da família Mozilla e no Internet Explorer 5.0 ou superior.
Nessa abordagem, receberemos XML do servidor ao invés de HTML, como no exemplo abaixo:
<funcionarios>
<funcionario mat="1">Carlos</funcionario>
<funcionario mat="2">José</funcionario>
<funcionario mat="3">João</funcionario>
</funcionarios>
Criaremos uma página com duas combos, uma de cargos e a outra de funcionários. O objetivo é quando selecionarmos um cargo apareça todos os funcionários daquele cargo. Abaixo segue o código HTML da página de apresentação:
<html>
<head>
</head>
<body>
<form id="form1" name="form1">
<table>
<tr>
<td>Cargo:</td>
<td>
<select id="cargo" name="cargo" onchange="onSelectionChange();">
<option>Selecione o cargo</option>
<option value="1">Diretor</option>
<option value="2">Gerente</option>
<option value="3">Coordenador</option>
</select>
</td>
</tr>
<tr>
<td>Funcionários:</td>
<td>
<select id="funcionario" name="funcionario">
</select>
</td>
</tr>
</table>
</form>
</body>
</html>
Note que a combo de cargos possui em seu evento "onchange" uma chamada à função "onSelectionChange()", que deverá popular a combo de funcionários (que encontra-se vazia) com os funcionários do cargo selecionado. Vamos ver a implementação dessa função, que deverá ficar dentro da tag <head></head> do HTML:
function onSelectionChange() {
var cboCargo = document.forms[0].cargo;
if (cboCargo.selectedIndex > -1){
// Verifica se existe a coleção document.all (exclusiva do IE) para determinar o browser
if (document.all) {
// IE
xhttp = new ActiveXObject("MSXML2.XMLHTTP");
} else {
// Família Mozilla
xhttp = new XMLHttpRequest();
}
// Associa a função que tratará o evento
xhttp.onreadystatechange = HandlerOnReadyStateChange;
// Prepara a chamada HTTP - parâmetros: http method, URL, false = chamada assíncrona
xhttp.open("GET", "http://localhost/func.ashx?cargo=" + cboCargo.value, false);
// Envia a chamada
xhttp.send();
}
}
Essa função instancia um objeto XMLHttpRequest, (tanto para o IE quanto para o Mozilla o objeto é o mesmo, só muda o nome), associa a função que será chamada a cada mudança no estado do objeto e faz a chamada para o endereço que retornará o XML. Vejamos o código de "HandlerOnReadyStateChange()" (também deve estar na tag <head></head>, abaixo de "onSelectionChange()":
function HandlerOnReadyStateChange(){
var cboFuncionario = document.forms[0].funcionario;
// Este evento é chamado 4 vezes, para cada mudança de estado no xmlhttp
// Os estados são: 0 uninitialized, 1 loading, 2 loaded, 3 interactive, 4 complete
if (xhttp.readyState == 4){
cboFuncionario.innerHTML = "";
// responseXML contém um objeto XMLDOM
var nodes = xhttp.responseXML.selectNodes("//funcionario");
// Adiciona o item na combo
for (var i=0; i<nodes.length; i++){
var o = new Option();
o.text = nodes(i).text;
o.value = nodes(i).attributes.getNamedItem('mat').text;
cboFuncionario.add(o);
}
}
}
Nesse caso estamos buscando o XML de "func.ashx", um "web handler". Esse arquivo é igual a um .aspx, porém temos controle sobre o que será enviado. Aqui, iremos enviar um XML. Vamos ao código desse arquivo:
<%@ webhandler language="C#" class="MyHandler" %>
using System;
using System.Web;
using System.Xml;
public class MyHandler : IHttpHandler
{
public bool IsReusable
{
get
{
return true;
}
}
public void ProcessRequest(HttpContext ctx)
{
ctx.Response.ContentType = "application/xml";
XmlTextWriter xw = new XmlTextWriter(ctx.Response.OutputStream, new System.Text.UTF8Encoding());
xw.WriteStartElement("empregados");
if (Convert.ToInt32(ctx.Request["cargo"]) == 1)
{
xw.WriteStartElement("funcionario");
xw.WriteAttributeString("mat", "1");
xw.WriteString("Carlos");
xw.WriteEndElement();
}
else if (Convert.ToInt32(ctx.Request["cargo"]) == 2)
{
xw.WriteStartElement("funcionario");
xw.WriteAttributeString("mat", "2");
xw.WriteString("José");
xw.WriteEndElement();
}
else if (Convert.ToInt32(ctx.Request["cargo"]) == 3)
{
xw.WriteStartElement("funcionario");
xw.WriteAttributeString("mat", "3");
xw.WriteString("João");
xw.WriteEndElement();
}
xw.WriteEndElement();
xw.Close();
}
}
A primeira coisa que temos que fazer é implementar a interface "IHttpHandler". Devemos então implementar uma propriedade e um método. A propriedade "IsReusable" nos diz se aceitaremos requisições simultâneas, e o método "ProcessRequest" é o responsável por gerar nosso retorno. Note que esse método recebe como parâmetro um HttpContext, que contém as propriedades "Request" e "Response", as mesmas usadas no .aspx.
Nesse exemplo, estamos retornando um XML com um elemento apenas, para cada cargo passado como parâmetro. Também podemos criar essa classe dentro de um arquivo .cs ou .vb, bastando colocar a DLL gerada no diretório bin do servidor.
Assim como as outras abordagens citadas no início do artigo, essa também tem seus pontos positivos e negativos. Cabe a cada desenvolvedor avaliar cada uma e aplicar a melhor para sua necessidade.