Jump to content


Photo

Xmlhttprequest


  • Faça o login para participar
191 replies to this topic

#1 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 06/05/2005, 14:13

Tutorial: Utilização do XMLHttpRequest (JavaScript), para apresentar conteúdo sem necessidade de atualizar a página.
Nível: Básico - Intermediário.
Requerimentos Extras (bibliotecas): Nenhum.

===============-===============

Hello there!

Antes de mais nada, algumas explicações. Esse tutorial tem como base para o script, praticamente, JavaScript, mas porque PHP? Simples, estamos combinando as duas linguaguens para podermos trabalhar com dados em formulários (pode ir muito além), que se alteram dependendo de opções selecionadas, sem ter que atualizar a página, para fazer a requisição PHP novamente.

No mais, vamos ao que interessa.

===============-===============

Como é feito essa consulta?
Você se pergunta. É algo simples como uma query string. Na verdade, é uma pura query string. Quem já trabalhou com a integração de PHP + Flash, para fazer loadMovie()'s dinâmicos, etc, terá uma maior afinidade com esse tutorial.

Basicamente a consulta consiste em:
- Alterar algum valor;
- Passar esse valor como parâmetro para o PHP;
- Retornar o resultado que desejamos;

Beleza, vamos começar por onde?
Para todos terem o mesmo ponto de inicio, vamos seguir um exemplo do inicio ao fim. Nossa idéia é:

- Apresentar SubCategorias, dependendo da Categoria principal selecionada.

Simples? Sim, algumas consultas ao Banco de Dados, e está resolvido nosso problema.

Para começar, vamos a criação das Tabelas:

CREATE TABLE `categorias` (
  `codigo` int(3) NOT NULL auto_increment,
  `nome` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`codigo`)
);

CREATE TABLE `subcategoria` (
  `codigo` int(3) NOT NULL auto_increment,
  `categoria` int(3) NOT NULL default '0',
  `nome` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`codigo`)
);

Prontinho, vamos entender a estrutura:

Tabela Categoria:
- codigo: Campo AUTO_INCREMENT para armazenar o código de cada categoria.
- nome: Campo para adicionar o nome da categoria.

Tabela SubCategoria:
- codigo: Campo AUTO_INCREMENT para armazenar o código de cada subcategoria.
- categoria: Campo para referenciar à qual categoria cada categoria faz parte.
- nome: Campo para adicionar o nome da subcategoria.

Eita, já temos as tabelas, agora vamos colocar alguns valores para elas:

INSERT INTO `categorias` VALUES (1, 'Refrigerantes');
INSERT INTO `categorias` VALUES (2, 'Frutas');
INSERT INTO `categorias` VALUES (3, 'Carnes');
INSERT INTO `categorias` VALUES (4, 'Cervejas');

INSERT INTO `subcategoria` VALUES (1, 2, 'Maçã');
INSERT INTO `subcategoria` VALUES (2, 3, 'Alcatra');
INSERT INTO `subcategoria` VALUES (3, 1, 'Sprite');
INSERT INTO `subcategoria` VALUES (4, 1, 'Fanta');
INSERT INTO `subcategoria` VALUES (5, 2, 'Laranja');
INSERT INTO `subcategoria` VALUES (6, 4, 'Skol');
INSERT INTO `subcategoria` VALUES (7, 4, 'Bohemia');
INSERT INTO `subcategoria` VALUES (8, 1, 'Coca-Cola');
INSERT INTO `subcategoria` VALUES (9, 3, 'Coxão Mole');
INSERT INTO `subcategoria` VALUES (10, 2, 'Limão');
INSERT INTO `subcategoria` VALUES (11, 3, 'Picanha');
INSERT INTO `subcategoria` VALUES (12, 4, 'Brahma');

Certo, já temos algumas informações nas tabelas, vamos a parte que interessa agora.

===============-===============

Como apresentar as Categorias?
Para realizar a consulta das categorias, simplesmente, criamos nossa query selecionando os campos desejados:

SELECT * FROM categori<span style='color:green'>as ORDER BY nome ASC

Estamos selecionando todos os campos de todos os registros, ordenados pelo nome em ordem crescente (A-Z).

E como apresentar no form tudo isso?
Vamos criar nossa página então:

<select name="categoria">
	<option></option>
<?php
$consulta = mysql_query("SELECT * FROM categorias ORDER BY nome ASC");
while( $row = mysql_fetch_assoc($consulta) )
{
echo "<option value=\"{$row['codigo']}\">{$row['nome']}</option>\n";
}
?>
</select>

Pronto, já temos um select com todas as categorias e um campo em branco no inicio, mas porque esse campo em branco? Pois nossa ação de XMLHttpRequest será no evento onchange, que é executa ao alterar o valor inicial.

Como ficaria nosso onchange?

<select name="categoria" onchange="pesquisar_dados( this.value )">

Para os conhecedores de JavaScript, chamamos uma função pesquisar_dados e passamos como um parâmetro, o value do select.

Uipi! Até agora, tudo beleza, e como montar o select para SubCategorias?!
Veja e surpreenda-se pequeno Gafanhoto.

<select name="subcategoria"></select>

Estava com preguiça, e vai ficar só assim nosso select. :P

Na verdade, os valores para ele, vai depender da Categoria selecionada, então, por inicio, não atribuimos nenhum valor à ele.

function pesquisar_dados()
Ahhh bom, achei que nunca iriamos chegar aqui. Veja o que seria essa função para receber o value da categoria selecionada:

function pesquisar_dados( valor )
{
  http.open("GET", "consultar.php?id=" + valor, true);
  http.onreadystatechange = handleHttpResponse;
  http.send(null);
}

Vamos entender ela:

"Abrimos" a página consultar.php?id=X, digo "abrimos", pois na verdade, essa janela não será apresentada ao usuário, só será processada puxaremos o valor retornado. Logo após, aguardamos a resposta do processamento da página, e assim que finalizado, chamamos a nova função handleHttpResponse. Que processará nossa resposta.

function handleHttpResponse
Essa função tem a finalidade de "pegar" o resultado da página processada, e apresentar no seu defido lugar. Poderiamos jogar em um textarea, uma <div>, um <p>, ou até mesmo um alert.

function handleHttpResponse()
{
  campo_select = document.forms[0].subcategoria;
  if (http.readyState == 4) {
    campo_select.options.length = 0;
    results = http.responseText.split(",");
    for( i = 0; i < results.length; i++ )
    { 
      string = results[i].split( "|" );
      campo_select.options[i] = new Option( string[0], string[1] );
    } 
  }
}

OOOOOOO LOOOOOOCOOOOOOOO MEEEEEUUUU!!! By Fausto Silva

Calma, calma, não corram. Vamos entender:

Antes de mais nada, definimos que campo será o receptor dos novos dados. Em seguida, verificamos se o estado do retorno é igual 4 (concluído), caso seja, definimos o campo receptor como 0 de length, ou seja, eliminamos todos as opções que existiam. Logo após, explodimos a resposta retornada pela nossa execução por ",", ou seja, cada SubCategoria, será separada por ",". Após isso, para cada índice retornado, explodimos ainda por "|", mas por que isso, você se pergunta, simples, nosso select não é somente 1 valor, mas 2, uma para a propriedade value e outro para a apresentação, primeiro a apresentação e em seguida o value. E por fim, adicionamos a opção ao nosso select.

OBA! Acabamos!!! Estamos vivos!!!!!
Calma jovem Anakin, o lado negro da força está por vir. Teríamos acabado se não tivessemos tantos navegadores por ai afora, e cada um com seu método de interpretação.

Como resolver? Simples, com mais uma função extra. Essa não precisará que nada seja alterado, afinal, é somente para identificação do Navegador e Suporte ao XMLHttpRequest.

function getHTTPObject() {
  var xmlhttp;
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {
        xmlhttp = false;
      }
    }
  @else
  xmlhttp = false;
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  return xmlhttp;
}
var http = getHTTPObject();

Somente uma passagem rápida por ela, definimos a nova função, e veja o detalhe, se você utilizar alguma IDE para o desenvolvimento dessas páginas, é bem provavel que identificará parte do código como um comentário, mas não é, não apague ;)

Depois de fazer toda a verificação, a função é chamada e passada seu valor à variável global http.

Agora acabou?!
Técnicamente sim, mas como criar a página para retornar os resultados? Bom, agora entra nosso amigão PHP. Como vimos, cada registro precisa ser separado por ",", e a apresentação do value deve ser separado por "|".

<?php
$con = mysql_connect("localhost", "usuario", "senha");
mysql_select_db("base_dados");

$categoria = addslashes($_GET["id"]); // pegamos o id passado pelo select
$consulta = mysql_query("SELECT * FROM subcategoria WHERE categoria = '$categoria'"); // selecionamos todas as subcategorias que pertencem à categoria selecionada
while( $row = mysql_fetch_assoc($consulta) )
{
  echo $row["nome"] . "|" . $row["codigo"] . ","; // apresentamos cada subcategoria dessa forma "NOME|CODIGO,NOME|CODIGO,NOME|CODIGO,...", exatamente da maneira que iremos tratar no JavaScript
}
?>

Belezinha pessoas? Essa seria a página consultar.php, agora vejamos como ficaria a nossa página principal completa:

<?php
$con = mysql_connect("localhost", "usuario", "senha");
mysql_select_db("base_dados");
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script language="javascript">
function pesquisar_dados( valor )
{
  http.open("GET", "consultar.php?id=" + valor, true);
  http.onreadystatechange = handleHttpResponse;
  http.send(null);
}

function handleHttpResponse()
{
  campo_select = document.forms[0].subcategoria;
  if (http.readyState == 4) {
    campo_select.options.length = 0;
    results = http.responseText.split(",");
    for( i = 0; i < results.length; i++ )
    { 
      string = results[i].split( "|" );
      campo_select.options[i] = new Option( string[0], string[1] );
    }
  }
}

function getHTTPObject() {
  var xmlhttp;
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {
        xmlhttp = false;
      }
    }
  @else
  xmlhttp = false;
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  return xmlhttp;
}
var http = getHTTPObject();
</script>
</head>

<body>
<form name="formulario" method="post" action="">
<p><select name="categoria" onchange="pesquisar_dados( this.value )">
	<option></option>
<?php
$consulta = mysql_query("SELECT * FROM categorias ORDER BY nome ASC");
while( $row = mysql_fetch_assoc($consulta) )
{
echo "<option value=\"{$row['codigo']}\">{$row['nome']}</option>\n";
}
?>
</select></p>
<p><select name="subcategoria"></select>
</p>
</form>
</body>
</html>

E se eu não quiser um select, mas sim, um texto?
Simples, teriamos que alterar somente a função para tratar o retorno:

function handleHttpResponse()
{
  campo_text = document.forms[0].subcategoria;
  if (http.readyState == 4) {
    campo_text = http.responseText;
    
  }
}

Dessa forma, o campo <textarea> ou quaisquer outros campos, ou tags, receberiam o valor retornado pela consulta, bastando somente tratar todos os textos na consulta.

===============-===============

Dedicatória
A todos vocês e principalmente a minha mamãe pelo Dia das Mães :)
Mesmo tendo a certeza que ela não vai ler esse tutorial, mas:

Mommy, I love you! :)

Attached Files


Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#2 LucasMS

LucasMS

    Super Veterano

  • Usuários
  • 2076 posts
  • Sexo:Não informado

Posted 06/05/2005, 14:26

Nossa, muito bom o tutorial, não conhecia esse recurso do JS não ! Valeu Balala ;) !!!

#3 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 06/05/2005, 15:42

Só alguns testes quanto a Compatibilidade, feito pelo Paulo Freitas:

Mozilla 1.7.7: OK
Mozilla Firebird 0.7: OK
Mozilla Firefox 1.0.3: OK
MSIE 6.0 SP2: OK
Netscape 7.02: OK
Opera 7.54: Sem suporte
Opera 8.0: OK
Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#4 enthroned

enthroned

    eh noizeh!

  • Usuários
  • 257 posts
  • Sexo:Não informado

Posted 06/05/2005, 17:44

maluco.....mto bom o tutorial, vai me ajudar em muito nao soh essa parte ai, mas como os eskeminha de cat e sub huehuehe mto bom!! :D
=]

#5 Klaus

Klaus

    @ ubuntu jaunty

  • Ex-Admins
  • 7924 posts
  • Sexo:Masculino
  • Localidade:127.0.0.1

Posted 06/05/2005, 18:11

Tô sem mySQL aqui... Balala, quando você puxa a Maçã, a acentuação vem corretamente?

Eu fiz alguns testes aqui para CEP (um outro exemplo que eu estava testando) e, São Paulo não queria aparecer acentuado corretamente mesmo com o charset em ISO-8859-1...
Klaus Paiva
Conheça também: Taperás

#6 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 06/05/2005, 20:13

É, tem que fazer uns esquema utilizando COLLATION e CHARSET no select. O MySQL novo está vindo com esses upgrades...

O que pode fazer é gravar a codificação html na tabela.
Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#7 Klaus

Klaus

    @ ubuntu jaunty

  • Ex-Admins
  • 7924 posts
  • Sexo:Masculino
  • Localidade:127.0.0.1

Posted 06/05/2005, 21:47

Não, tentei direto, tipo dá um echo "Maçã,blablabla..." e tenta puxar com acentuação...

Tentei <meta> no HTML, header no PHP e não vai...

Eu tentei jogar com htmlentities(), mas ao exibir num form, aparecem os códigos, tipo: &acedil;
Klaus Paiva
Conheça também: Taperás

#8 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 06/05/2005, 21:49

No próprio INSERT ele já grava com os caracteres bagunçados, até se consultar pelo console do MySQL vem tudo zoniado...
Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#9 Klaus

Klaus

    @ ubuntu jaunty

  • Ex-Admins
  • 7924 posts
  • Sexo:Masculino
  • Localidade:127.0.0.1

Posted 06/05/2005, 22:16

:D Com um pouco de Google + DOM + XML, tá aí:

A página .html está em anexo...

<?php

  header ("Content-Type: text/xml;");

echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>";

?>

<foo>
<cidade>São Caetano</cidade>
<estado>São Paulo</estado>
</foo>

Attached Files

  • Attached File  cep.html   1.84KB   656 downloads

Klaus Paiva
Conheça também: Taperás

#10 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 06/05/2005, 22:19

Mato o problema :)

O que o UTFG não pode resolver?!
Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#11 Guilherme Blanco

Guilherme Blanco

    Loading...

  • Conselheiros
  • 891 posts
  • Sexo:Masculino
  • Localidade:São Carlos - SP/Brasil
  • Interesses:Programação Web e minha namorada (Maria Camila).

Posted 06/05/2005, 23:56

Rapidaum... vou reescrever a função getHTTPObject para ajudar na compatibilidade...

function getHTTPObject() {
	var req;

	try {
  if (window.XMLHttpRequest) {
  	req = new XMLHttpRequest();

  	if (req.readyState == null) {
    req.readyState = 1;
    req.addEventListener("load", function () {
    req.readyState = 4;

    if (typeof req.onReadyStateChange == "function")
    	req.onReadyStateChange();
    }, false);
  	}

  	return req;
  }

  if (window.ActiveXObject) {
  	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];

  	for (var i = 0; i < prefixes.length; i++) {
    try {
    	req = new ActiveXObject(prefixes[i] + ".XmlHttp");
    	return req;
    } catch (ex) {};
  	}
  }
	} catch (ex) {}

	alert("XmlHttp Objects not supported by client browser");
}


A idéia é adicionar algum suporte que os browsers Gecko não possuem à propriedade readyState e ao evento onReadyStateChange.


Pelo que li, a idéia é basicamente à de um AJAX... caso tenham interesse, poderíamos discutir isto... =)


[]s,
<script language="WebFórum">
// Dados:
Nome("Guilherme Blanco");
Localidade("São Carlos - SP/Brasil");
Cargo("Manutenção");
</script>

#12 Balala

Balala

    What you want for yourself?

  • Ex-Admins
  • 3357 posts
  • Sexo:Não informado
  • Localidade:Jaraguá do Sul - SC
  • Interesses:http://forum.wmonline.com.br/index.php?showtopic=5792

Posted 07/05/2005, 09:47

Não so muito dos times Holandeses, mas poderiamos criar uma discussão sobre isso sim... :rolleyes:

O maior problema está na interpretação do request à diversos browsers.
Balala - Admin Geral Webfórum - Retired
Twitter
Stop Spreading Lies!
Posted Image

#13 Paulo Freitas

Paulo Freitas

    ××××××× LRU #456504 ××××××× ××××××× LRM #364686 ×××××××

  • Ex-Admins
  • 5612 posts
  • Sexo:Masculino
  • Localidade:Campinas - SP

Posted 07/05/2005, 15:02

Opa ... ;)

Vamos tentar deixar este magnífico código cross-platform e cross-browser ... :rolleyes:

Seguinte, vamos à teoria ... :P

Em navegadores Mozilla (o próprio Mozilla, o antigo Firebird, o Firefox ... ), ActiveX não é suportado por padrão, à não ser que se instale um plugin à parte.

Ah ... mas então o usuário do meu site irá se ferrar? Não! :)

É o seguinte ... se não me engano, em todas versões dos Mozillas, foi implementado sob o JavaScript um objeto global chamado new XMLHttpRequest() ... :) ... o que já reduz-se os códigos de verificações dos elementos ActiveX ...

Mas porquê isso? :blink:

Simples, a organização Mozilla que está cuidando do JavaScript versão 1.5, e, em seus navegadores, ele é incluído ... :rolleyes: ... já o IE, em sua última versão 6.0 SP2, usa JavaScript versão 1.3 !!! <_<

Para o IE(ca), temos que usar elementos ActiveX, que para piorar a situação, tem mais de um ProgID (identificador) utilizado e só IE 5.0 ou acima suporta ... :(

Ah, e já ia me esquecendo ... há um outro problema, navegadores como o Opera... O Opera é um navegador "misto", em que se pode navegar com UserAgents diferentes ... :blink: ... esse irá ser um problema à parte ... :unsure:

Vejam este trecho do changelog da versão 8.0 do Opera ...

• Support for XmlHttpRequest giving full Gmail support

... sem comentários ... :unsure:

Voltando aos elementos ActiveX do IE(ca), sobre os ProgID's existentes ... andei vendos estes links ...

http://support.micro...b/269238/EN-US/
http://www.codecomme...5-4-464965.html
http://www.perfectxml.com/msxmlRef.asp
http://webfx.eae.net.../xmlextras.html

E vi que o MSXML tem versões diferentes dependendo do IE(ca) utilizado (5.0, 5.5 ou 6.0) ... :unsure:

Mas, o código do GB é o mais completo, pois não existem outros ProgID's além destes ... :)

Resumindo, o problema está em navegadores "mistos" como o Opera e os IE(ca) de versões abaixo da 5.0 ... :unsure: ... até o momento, não achei solução alguma para eles ... :huh:

Mas é isso aí ... (y) ... já temos a faca, só falta achar o queijo ... :P

Flw's, T+V! :DAté mais

#14 Goku Jr

Goku Jr

    Nilson

  • Usuários
  • 3757 posts
  • Sexo:Masculino

Posted 12/05/2005, 16:21

:wacko: meu deus e eu q pensei q já sabia programar... :(

estou laskado :lol:

bom vejo q ainda irei continuar com os códigos q verifica os navagadores e se não for compativel não irá deixar o cara entrar, ou até deixar, mas irá ficar meio zoneado (n)

T+ !
-----------------------------------------------------------------------
PALMEIRAS - Primeiro campeão do mundo em 1951

#15 RMA

RMA

    Turista

  • Usuários
  • 36 posts
  • Sexo:Não informado

Posted 31/05/2005, 16:23

Desculpe ressucitar o Tópico, mas é que achei esse Tutorial Excelente, bem o q eu tava precisando. Porém, estou com uma dúvida em uma alteração que desejo fazer.

Como eu posso fazer para que esta função seja Genéria, ou seja, para que eu não precise específicar direto na Função qual o meu alvo (input, select, Div...)????

Nesta função vc definiu qual seria o select da subcategoria aqui:

campo_select = document.forms[0].subcategoria;


Eu tentei fazer da seguinte forma:

function pesquisar_dados( valor , alvo )

  http.open("GET", "consultar.php?id=" + valor, true);
  http.onreadystatechange = handleHttpResponse (alvo);
  http.send(null);
}


function handleHttpResponse( alvo )
{
  campo_select = document.getElementById(alvo);
  .
  .
  .
}


Ai, no evento OnChange do Select Categorias, eu colocaria lá OnChange = "pesquisar_dados (this.value , 'subcategoria')"

Porém, ele não faz nada se eu colocar o :

http.onreadystatechange = handleHttpResponse (alvo);



Como devo fazer essa alteração??

Edição feita por: RMA, 31/05/2005, 16:30.





2 user(s) are reading this topic

0 membro(s), 2 visitante(s) e 0 membros anônimo(s)

IPB Skin By Virteq