Olá pessoal!
Dando manutenção em um sistema java web com interface jsp precisei usar uma treeview para apresentar as categorias de produtos para o usuário. Vou relatar aqui a experiência.
As categorias estão modeladas no banco em uma tabela com autorelacionamento.
No oracle para consultar uma table com autorelacionamento podemos utilizar a seguinte query:
select id, LEVEL, SYS_CONNECT_BY_PATH(nome, '@') as caminho
from categoria CONNECT BY parent_id = PRIOR id START WITH id = categoria_inicial
A categoria_inicial é a primeira categoria de uma árvore, nesse sistemas existem várias árvores de categorias.
O resultado fica assim para a categoria_inicial igual a 30:
id level caminho
30 1 @Material de escritório
31 2 @Material de escritório@Informática
34 3 @Material de escritório@Informática@Tinta
55 4 @Material de escritório@Informática@Tinta@Tinta Impressoras
60 3 @Material de escritório@Informática@Armazenamento
63 4 @Material de escritório@Informática@Armazenamento@DAT/DLT/DVD/DDS
64 4 @Material de escritório@Informática@Armazenamento@Disquetes
92 3 @Material de escritório@Informática@Teste
93 4 @Material de escritório@Informática@Teste@Teste1
113 4 @Material de escritório@Informática@Teste@Teste2
120 4 @Material de escritório@Informática@Teste@Test3
Ai no java criei uma classe para representar a estrutura da categoria, ficou assim:
public class CategoriaTreeView {
public String id;
public int level;
public String path;
public CategoriaTreeView(String id, int level, String path){
this.id = id;
this.level = level;
this.path = path;
}
}
Como essa classe vai ser utilizada somente como uma estrutura de dados para representar o dado que será exibido na tela ela não tem gets e sets. Nem toda classe java precisa ter gets e sets. Gets e sets aqui são desnecessários e não acresentam nada. Acredite. Mas isso é assunto para outro post.
Também tenho um DAO que acessa o banco e entrega um List com os objetos CategoriaTreeView.
Antes disso fiz uma pesquisa na internet sobre como criar uma treeview no jsp (ou html) e encontrei o jQuery plugin: Treeview que transforma uma lista não ordenada do html <ul> em uma árvore.
Agora o problema é transformar a minha coleção de CategoriaTreeView em uma lista não ordenada com <ul> e <li>. Para isso eu criei a seguinte função recursiva que retorna uma String que será utilizada dentro do html:
private String processa(int atual, List<CategoriaTreeView> lista){
if(lista == null) return "";
String out = "";
if(lista.size() == 0) {
if(atual > 0){
out += "</li>\n";
out += "</ul>\n";
out += processa(atual - 1, lista);
}
}else if(lista.size()>0){
CategoriaTreeView item = lista.remove(0);
if(item.level == atual){
out += "</li>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level > atual){
out += "<ul>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level < atual){
out += "</li>\n";
out += "</ul>\n";
// adiciono o cara de volta na lista pois ainda não foi processado. estou voltando um nivel na árvore.
lista.add(0, item);
out += processa(atual - 1, lista);
}
}
return out;
}
Também temos a função para retornar a categoria de dentro do caminho:
private String subString(int i, String s){
String[] ss = s.split("@");
return ss[i];
}
Dentro do meu servlet eu tenho o seguinte código:
ArrayList categorias = dao.categorias(categoria_inicial);
String treeView = processa(0, categorias);
treeView = treeView.replaceFirst("<ul>", "<ul id=\"browser\">");
request.setAttribute("treeView", treeView);
Para exibir a treeview no jsp eu utilizei o exemplo simple.html que vem no download do jQuery plugin: Treeview. A única mudança foi que eu fiz o download do jquery ao invés de usar o link direto do ajax.googleapis.com.
Adicionei o seguinte ao jsp:
<link rel="stylesheet" href="../jquery.treeview.css" />
<link rel="stylesheet" href="../red-treeview.css" />
<link rel="stylesheet" href="screen.css" />
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script src="../lib/jquery.cookie.js" type="text/javascript"></script>
<script src="../jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#browser").treeview({control: "#treecontrol", animated:"normal", persist: "cookie"});
});
</script>
<%
String s = (String)request.getAttribute("treeView");
if(s != null && !s.trim().equals("")){
%>
<tr>
<td>
<br>
<div id="treecontrol">
<a title="Collapse the entire tree below" href="#">Fechar Tudo</a>
<a title="Expand the entire tree below" href="#">Abrir Tudo</a>
</div>
</td>
</tr>
<tr>
<td>
<br>
<div><%= s %></div>
</td>
</tr>
<%
}
%>
O resultado fica parecido com esse demo que está no site.
Abraços, Rodrigo Alencar.
segunda-feira, 24 de agosto de 2009
sábado, 23 de maio de 2009
Cursor with parameters in PL/SQL
Ver este post em Portugûes
Here I'm gonna show another technique to work with cursors in PL/SQL. I had to do something at work where it was very useful: cursor that take arguments.
The biggest advantages of parametrized queries is that the server doesn't have to pass through the parse and plan phases ever again (after the first time, of course) and the compile-time checking for syntax errors (when we use string queries we only know any syntax errors in runtime).
That said let's go to examples:
cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;
Nice, isn't it? It's like a procedure in terms of syntax. And opening the cursor is like this:
open ProductCursor('A%');
It'll open the cursor with all the products which name starts with 'A'.
We can create a rowtype based var from this cursor:
prod ProductCursor%rowtype;
Now I'm gonna join it all in a script:
declare
-- Cursor
cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;
-- Simple loop
prod ProductCursor%rowtype;
-- bulk collect loop
type Tprods is table of ProductCursor%rowtype;
prods Tprods;
i integer;
begin
-- simple loop
open ProductCursor('A%');
loop
fetch ProductCursor into prod;
exit when ProductCursor%notfound;
DBMS_OUTPUT.put_line(prod.nome);
-- other commands
end loop;
close ProductCursor;
-- bulk collect loop
open ProductCursor('A%');
fetch ProductCursor bulk collect into prods;
for i in prods.first .. prods.last loop
DBMS_OUTPUT.put_line(prods(i).nome);
-- another commands using prods(i)
end loop;
close ProductCursor;
end;
Cool, isn't it? See you next time.
Cursor com parâmetros em PL/SQL
View this post in English
Aqui vou mostrar outra técnica para trabalhar com cursores em PL/SQL. Eu tive que fazer um trabalho recentemente onde isso foi muito útil: Cursores que aceitam argumentos.
As maiores vantagem de usar queries parametrizadas no banco de dados é que o servidor não precisa fazer o parse e traçar um plano de execução (ele só faz isso na primeira vez que a query é executada) e ela fica certa em tempo de compilação (ao contrário das queries em string que nós só sabemos se há um erro de sintaxe em tempo de execução).
Dito isso vamos a um exemplo:
cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;
Legal, não? A sintaxe fica muito parecida com uma procedure. E o método de abrir o cursor também é legal:
open ProdutoCursor('A%');
Aqui vai abrir o cursor trazendo todos os produtos onde o nome começa com a letra 'A'.
Podemos ainda criar um rowtype a partir deste cursor:
prod ProdutoCursor%rowtype;
Agora vou criar um script para juntar tudo:
declare
-- Cursor
cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;
-- Para loop simples
prod ProdutoCursor%rowtype;
-- Para loop com bulk collect
type Tprods is table of ProdutoCursor%rowtype;
prods Tprods;
i integer;
begin
-- Loop simples
open ProdutoCursor('A%');
loop
fetch ProdutoCursor into prod;
exit when ProdutoCursor%notfound;
-- comandos a serem executados com o registro prod
DBMS_OUTPUT.put_line(prod.nome);
end loop;
close ProdutoCursor;
-- Loop com bulk collect
open ProdutoCursor('A%');
fetch ProdutoCursor bulk collect into prods;
for i in prods.first .. prods.last loop
-- comandos a serem executaos com o registro prods(i)
DBMS_OUTPUT.put_line(prods(i).nome);
end loop;
close ProdutoCursor;
end;
Muito legal, né? Até a próxima.
Generics - A great addition to .Net
Ver este post em Portugûes
Hello. In this post I'll show something very nice about .Net: Generics.
First, I'll show a simple struct in order to explain the feature:
struct Person {
public string Name;
public string Address;
public string Zip;
}
We have here a classic example of a data struct. Here we define fields with their respective data types (we're talking here about a strongly typed language). That means we have to provide the data type of the attributes at compile time. But, what if we could let the (struct's) user define what type s/he wants to use in their struct? How so? e.g.: A struct, two fields and their data type is open to the user to specify and set the attribute, making it "appear" a weakly typed language, but with the advantage of type checking at compile time.
Let's take a look at an example:
struct Pair<TClass1, TClass2>
where TClass1 : class
where TClass2 : class {
public TClass1 obj1;
public TClass2 obj2;
}
Here comes the generics: We define a struct, asking the user to provide which clases will will represent the TClass1 and TClass2, which we are defining that have to inherit the class object and it automatically defines what data type that fields inside will accept
The nice part is when we start to use this structure. Let's see another code block:
class Customer {
public int ID;
public string Name;
public override string ToString() {
return string.Format("Customer ID = {0}, Name = {1}", ID, Name);
}
}
class Product {
public int ID;
public string Name;
public override string ToString() {
return string.Format("Product ID = {0}, Name = {1}", ID, Name);
}
}
struct Pair<TClass1, TClass2>
where TClass1 : class
where TClass2 : class {
public TClass1 obj1;
public TClass2 obj2;
}
class Program {
static void Main(string[] args) {
var c = new Customer { ID = 1, Name = "Felipe" };
var p = new Product { ID = 1, Name = "Caneta BIC" };
var pair = new Pair<Customer, Product>() { obj1 = c, obj2 = p };
Console.WriteLine(pair.obj1.ToString());
Console.WriteLine(pair.obj2.ToString());
}
}
The braces after the new instanct are a new notation of C# that allows us to create new instances of classes and set values to public fields in the same instruction.
In the progem we create instances of Customer and Product and define these types as the relevant types for the struct Pair. Note that, after we define the struct with these types we can only inform instances of these types for the specific fields. The compiler doens't let us inform any other value; and even the IntelliSense indicates correctly.
I hope you all liked this post and again, sorry for my english, as I am no native English speaker. Thank you very much and see you next time.
Artigo completo (View Full Post)
Generics - Uma Grande adição a .Net
View this post in English
Olá a todos. Neste post vou mostrar algo muito legal a respeito da .Net: Generics.
Primeiro vou preparar o terreno para explicar o recurso: Vamos ter como exemplo uma estrutura básica:
struct Pessoa {
public string Nome;
public string Endereco;
public string CEP;
}
Nós temos aqui um exemplo clássico de uma estrutura de dados. Nela nós definimos campos com os tipos definidos de dados (claro, numa linguagem fortemente tipada). Isso significa que nós temos que fornecer os tipos de dados na hora em que a criamos. Mas, E se pudéssemos criar uma estrutura de dados onde o usuário (da estrutura, claro) escolha os tipos de dados dos atributos? Como assim? A estrutura possui dois atributos e o usuário diz de que tipo de dados são estes atributos antes de definir seus valores, tendo "aparência" de linguagem de tipagem fraca, mas com a vantagem de checagem de tipos em tempo de compilação.
Nada melhor para explicar do que um exemplo prático:
struct Par<TClasse1, TClasse2>
where TClasse1 : class
where TClasse2 : class {
public TClasse1 obj1;
public TClasse2 obj2;
}
Aqui vem o uso dos genéricos: Definimos uma estrutura, pedido que o usuário forneça dois tipo, TClasse1 e TClasse2, que dizemos abaixo que elas devem ser descendentes de object (ou object) e isso vira uma classe para ser referenciada dentro da struct.
A parte legal vem na hora em que começamos a utilizar esta estrutura. Abaixo tem mais um bloco de código:
class Cliente {
public int ID;
public string Nome;
public override string ToString() {
return string.Format("Cliente ID = {0}, Nome = {1}", ID, Nome);
}
}
class Produto {
public int ID;
public string Nome;
public override string ToString() {
return string.Format("Produto ID = {0}, Nome = {1}", ID, Nome);
}
}
struct Par<TClasse1, TClasse2>
where TClasse1 : class
where TClasse2 : class {
public TClasse1 obj1;
public TClasse2 obj2;
}
class Program {
static void Main(string[] args) {
var c = new Cliente { ID = 1, Nome = "Felipe" };
var p = new Produto { ID = 1, Nome = "Caneta BIC" };
var par = new Par<Cliente, Produto>() { obj1 = c, obj2 = p };
Console.WriteLine(par.obj1.ToString());
Console.WriteLine(par.obj2.ToString());
}
}
As chaves depois da nova instância das classes é uma facilidade do C# que nos permite criar uma nova instância de uma classe e atribuir valores aos membros públicos naquele momento.
Dentro do programa nós criamos instâncias das classes Cliente e Produto e definimos como atributos da nossa estrutura para usarmos depois. O detalhe é que, assim que nós definimos que as classes da estrutura são Cliente e Produto, o compilador não deixa nenhum outro valor; até o IntelliSense indica corretamente.
Espero que que vocês tenham gostado deste post e o assunto tenha despertado em vocês o interesse que despertou em mim. Muito obrigado e até a próxima.
Artigo completo (View Full Post)
Você já isntalou o IE8?
Como o título já diz: eu já. A microsoft colocou o Internet Explorer 8 como atualização crítica para o Windows XP e cá estamos nós usuários deste maravilhoso sistema operacional atualizando.
O navegador é muito bonitinho: A interface é boa, tem depurador de Javascript (já dava para fazer isso anteriormente, mas agora está incorporado no navegador), etc. Mas um problema assola alguns usuários (como minha digníssima que ainda usa muito o Internet Explorer): o teclado.
Alguns usuários têm notado que no IE 8 o teclado não responde legal. Na minhma máquina acontece isso Neste link [forum.clubedohardware.com.br] há uma discussão do problema e possíveis causas e soluções.
Alguns males vêm para bem: Agora minha patroa já está começando a usar o querido por todos Firefox para navegar, graças as minhas insistentes investidas. Ha ha. Aproveitei essa hora para trazê-la ao lado da luz.
Abraços e até a próxima!
sexta-feira, 15 de maio de 2009
JclStrings - StrPadRight, StrPadLeft
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses jclStrings, Math;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
ZnDt, ZnNum: String;
ADay, AMonth, AYear: Word;
begin
DecodeDate(Date, AYear, AMonth, ADay);
ZnDt := Format('%s%s%s', [ StrPadLeft(IntToStr(ADay), 2, '0'),
StrPadLeft(IntToStr(AMonth), 2, '0'), IntToStr(AYear)]);
Self.Canvas.TextOut(12, 32, ZnDt);
Randomize;
ZnNum := IntToStr(RandomRange(0, 50000));
ZnNum := StrPadRight(ZnNum, 6, 'X');
Self.Canvas.TextOut(12, 52, ZnNum);
end;
Por falar me Bozo, lembrei de uma coisa (rsrsrs)..... Esse exemplo com datas, não foi uma boa idéia!?!?!?!??!?!
Na verdade ... esse exemplo com datas foi ótimo! Para demonstrarmos como não fazer ... uma coisa que provavelmente todo desenvolvedor, em algum momento, vai precisar fazer (rsrsrs).
Por favor, não façam assim (concatenar zeros a direita do dia e do mês).
Por isso, preste a tenção para substituir o código da linha 35 ...
ZnDt := Format('%s%s%s', [ StrPadLeft(IntToStr(ADay), 2, '0'),
StrPadLeft(IntToStr(AMonth), 2, '0'), IntToStr(AYear)]);
Por
ZnDt := Format('%.2d%.2d%.4d', [ADay, AMonth, AYear]);
Bem melhor agora!!!!!!!
Se você veio procurar "StrPadLeft" para trabalhar com datas, se deu bem! Use o "Format('%.2d%.2d%.4d, [ADay, AMonth, AYear])".
O Malta, mais uma vez, nos emprestou o conhecimento dele.
Grato!
Artigo completo (View Full Post)
quarta-feira, 29 de abril de 2009
Controle de Versão - "Seus problemas acabaram!"
Você é aquele cara que, pra controlar as versões do seu sistema, zipa os fontes e nomeia com o número da versão? Ou paga um software caríssimo de controle de versão? Ou toma uma coça pra instalar um controlador gratuito? SEUS PROBLEMAS ACABARAM!!!
Apresento-lhes os dois softwares que vão resolver todos os seus problemas: VisualSVN + TortoiseSVN.
O primeiro é um servidor Windows de Subversion, um controlador de versões gratuito muito bom. Muito simples de instalar, esquema Windows: next, next, next, finish.
Muito fácil também de manusear. Basta criar os repositórios e os usuários que acessam esses repositórios.
Então aqui vai o link do VisualSVN: http://www.visualsvn.com/server/
O segundo é um cliente de Subversion muito, muito bom mesmo. Integra-se ao Windows Explorer e é super simples de usar também. Basicamente, você deve criar uma pasta que apontará para o repositório do VisualSVN. Depois do TortoiseSVN instalado, quando você clicar com o botão direito sobre a pasta pelo Windows Explorer, vai aparecer uma opção chamada "SVN Checkout...".
Colocou arquivos/diretórios novos dentro da pasta, "Add". Quer subir os fontes? "Commit". Quer atualizar seus fontes? "Update".
No próximo post sobre o assunto, eu vou dar uma passada mais detalhada sobre esta ferramenta.
Chega de blá, blá, blá. Lá vai o link: http://tortoisesvn.net/
Então é isso. Abraço a todos e até o próximo post!
sábado, 25 de abril de 2009
Ajax/JSON & Delphi technologies– Webbrocker, Intraweb (ISAPI), IWTemplateProcessorHTML com CSS
O objetivo deste artigo é documentar uma solução desenvolvida para atender um cliente.
Vamos criar um serviço de consulta que deverá fornecer dados para um requisição Ajax. Para isso construiremos uma aplicação servidora (Delphi/Webbrocker) a qual acessará uma base de dados MS SQL Server (especificamente o banco de dados para exemplos “Northwind”), para executarmos uma consulta parametrizada (valor que virá na requisição cliente) cujo os dados retornados serão devidamente formatados para Json (Wik) (Não vou usar XML). Ou seja, como resposta a requisição mencionada, a aplicação servidora retornará os dado que serão consumidos pelo Ajax/Json.
Não sei, ou sei muito pouco sobre o que vc esta falando, Gerson. Então veja:
Pesquisa 1
Pesquisa 2
Marco Cantù AJax XML/DOM
Neste artigo o Cantù mostra como aproveitar o XMLData do TClientDataSet no DOM/XML (mto legal para delpheros).
Marco Cantù Artigo Ajax
Json
Mãos à Obra, Estação ZN!
Server-Side development

A tecnologia de service web que vamos usar será API do IIS (ISAPI). No WebModule1 adicione os componentes de acesso a dados: TADOConnetion, TADODataSet, TDataSetProvider, TClientDataSet. No editor de string de conexão (Edit Connection String) do ADOConnection, configure a conexão com o SQL Server e em seguida associe os Datasets (Como Associar? veja no Estação ZN). O Comando SQl que definiremos no ADODataSet1 será:
select * from Customers
where CompanyName like :CompanyName

Evento OnAction da Action “ZnConsClientes”:

uses
Math, StrUtils;
procedure TWebModule1.WebModule1ZnConsClientesAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
const
ZnTag = '%s:%s';
var
StrStatment: String;
i, CodRetorno: Integer;
begin
with ClientDataSet1 do
begin
Params[0].AsString := '%' + Request.QueryFields.Values['znNomeCli']+ '%';
try
Open;
CodRetorno := IfThen(IsEmpty, -1, 1);
StrStatment := StrStatment +
Format(ZnTag, ['codretornoZn',
IntToStr(CodRetorno)]);
if CodRetorno = 0 then Exit;
for i := 0 to Pred(FieldCount) do
begin
StrStatment := StrStatment + ','+
Format(ZnTag, [LowerCase(ClientDataSet1.Fields[i].FieldName),
IfThen((ClientDataSet1.Fields[i].AsString = ''), QuotedStr('-'),
QuotedStr(ClientDataSet1.Fields[i].AsString))]);
end;
finally
Close;
Response.Content := Format('{%s}',[StrStatment]);
end;
end;
end;
Para usar as versões sobrecarregadas da função “IfTehn” precisamos, para este exemplo, declarar (fazer uses das ...) as units “Math” e “StrUtils” (observe na linha 2 do trecho acima).
Pronto, acabamos essa primeira parte! Antes de compilar, garanta que o ADOCOnnection esteja desconectado. Propriedade “Connected” igual a “false”. Agora sim!!! Compile a aplicação servidora para gerar a dll a qual faremos deploy no IIS (Deploy de uma dll ISAPI). Vou criar o diretório virtual no IIS com o nome de “ajaxjsonzn”.
Após ter tido sucesso em realizar o deploy, vamos testar.
Para isso digitar no browser "http://localhost/ajaxjsonzn/?znNomeCli=Cactus" para se emocionar ao ver o que acabamos de criar.

Veja a string retornada pela nossa aplicação servidora Webbrocker:
{codretornoZn:1,customerid:'CACTU',companyname:'Cactus Comidas para llevar',contactname:'Patricio Simpson',
contacttitle:'Sales Agent',address:'Cerrito 333',city:'Buenos Aires',region:'-',
postalcode:'1010',country:'Argentina',phone:'(1) 135-5555',fax:'(1) 135-4892'}
Cliente-Side development
Portanto, antes de qualquer coisa execute seu editor preferido de páginas htm e Javascript e bola pra frente. Abaixo, segue o código dá pagina que desenvolvi para este exemplo:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<style type="text/css">
<!--
.AreaTexto {
font-family: "Comic Sans MS", "Courier New", Georgia;
width: 420px;
height:540px;
background-color:#FFFF38;
}
-->
</style>
<script type="text/javascript">
var ZnXmlAjaxHttpObj;
function ZnGetClienteWsAjx(ZnMyName) {
alert('estou na função!');
if (typeof XMLHttpRequest != "undefined"){ZnXmlAjaxHttpObj = new XMLHttpRequest();}
else{
ZnXmlAjaxHttpObj = new ActiveXObject('Msxml2.XMLHTTP');
if (!ZnXmlAjaxHttpObj){ZnXmlAjaxHttpObj = new ActiveXObject('Microsoft.XMLHTTP');}
}
alert(ZnMyName.value);
var ZnSpan = document.getElementById("IWLABEL1");
ZnSpan.innerHTML = "Estaçaõ Zn: Buscando dados do Cliente pelo nome fornecido: " + ZnMyName.value + " ....";
var url = "http://localhost/ajaxjsonzn/?znNomeCli="+ ZnMyName.value;
ZnXmlAjaxHttpObj.open("GET", url, true);
ZnXmlAjaxHttpObj.onreadystatechange = ZnDynProcessaReqBuscaCliente;
ZnXmlAjaxHttpObj.send(null);
}
function ZnDynProcessaReqBuscaCliente() {
var ZnSpan2 = document.getElementById("IWLABEL2");
var ZnElement = document.getElementById("IWEDIT1");
ZnSpan2.innerHTML = 'Processando ..................';
if (ZnSpan2.innerHTML.indexOf("buscando dados",0) >= 0){ZnSpan2.innerHTML = "Processando ...";}
else {ZnSpan2.innerHTML = "<b>buscando dados do Cliente: </b>" + ZnElement.value + " ....";}
if (ZnXmlAjaxHttpObj.readyState == 4) {
if (ZnXmlAjaxHttpObj.status == 200) {
processJsonEstacaoZn(ZnXmlAjaxHttpObj.responseText);
}
}
else return false;
}
function processJsonEstacaoZn(obj1) {
var ObjLandjah;
eval('ObjLandjah = ' + obj1);
var Aux =
" <br /> customerid: "+ ObjLandjah.customerid +
" <br /> contactname: "+ ObjLandjah.contactname +
" <br /> contacttitle: "+ ObjLandjah.contacttitle +
" <br /> companyname: "+ ObjLandjah.companyname +
" <br /> country: "+ ObjLandjah.country +
" <br /> CEP/postal code: " + ObjLandjah.postalcode +
"<br /> Região: " + ObjLandjah.region +
"<br /> Cidade: " + ObjLandjah.city +
"<br />Logradouro: " + ObjLandjah.address +
" <br /> fax: " + ObjLandjah.fax +
" <br /> phone: "+ ObjLandjah.phone;
alert(Aux);
document.getElementById("cj").innerHTML += '- <b>Ninguém vai subir #@#@%#@%#%@ ... vai ficar todo mundo quietinho ae.</b>';
document.getElementById("cj").innerHTML += Aux;
document.getElementById("IWMEMO1").innerHTML += ' \n <b>100% Quatorze? </b>';
document.getElementById("IWMEMO1").innerHTML += ' \n ************************************';
//****************************************************
var insertData = "<b> Resultado Consulta www.estacaozn.blogspot.com:</b>";
try {
//alert('Cod Retorno: ' + ObjLandjah.codretornoZn);
switch (ObjLandjah.codretornoZn * 1) {
case 1:
document.getElementById("IWMEMO1").innerHTML += ' \n - Cavera meu Capitão. ';
document.getElementById("IWMEMO1").innerHTML += ' \n ************************************';
insertData += " <br /> customerid: "+ ObjLandjah.customerid +
" <br /> contactname: "+ ObjLandjah.contactname +
" <br /> contacttitle: "+ ObjLandjah.contacttitle +
" <br /> companyname: "+ ObjLandjah.companyname +
" <br /> country: "+ ObjLandjah.country +
" <br /> CEP/postal code: " + ObjLandjah.postalcode +
"<br /> Região: " + ObjLandjah.region +
"<br /> Cidade: " + ObjLandjah.city +
"<br />Logradouro: " + ObjLandjah.address +
" <br /> fax: " + ObjLandjah.fax +
" <br /> phone: " + ObjLandjah.phone;
//alert("Case, estou aqui");
// Abaixo, veja como atribuir valor do JavaScript Object Notation ao IWMemo e aos IWEdits
document.getElementById("IWMEMO1").innerHTML += ' \n ************************************';
document.getElementById("CEP").value = ObjLandjah.postalcode;
document.getElementById("CEP").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n CEP: " + ObjLandjah.postalcode;
document.getElementById("CONTACTNAME").value = ObjLandjah.contactname;
document.getElementById("CONTACTNAME").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n Contato: " + ObjLandjah.contactname;
document.getElementById("CONTACTTITLE").value = ObjLandjah.contacttitle;
document.getElementById("CONTACTTITLE").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n Contato: " + ObjLandjah.contacttitle;
document.getElementById("CIDADE").value = ObjLandjah.city;
document.getElementById("CIDADE").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n Cidade: " + ObjLandjah.city;
document.getElementById("BAIRRO").value = "Bla!";
document.getElementById("BAIRRO").disabled = true;
document.getElementById("FAX").value = ObjLandjah.fax;
document.getElementById("FAX").disabled = true;
document.getElementById("IWMEMO1").innerHTML += "\n Fax: " + ObjLandjah.fax;
document.getElementById("LOGRADOURO").value = ObjLandjah.address;
document.getElementById("LOGRADOURO").disabled = true;
document.getElementById("IWMEMO1").innerHTML += "\n Logradouro:" + ObjLandjah.address;
document.getElementById("COMPANYNAME").value = ObjLandjah.companyname;
document.getElementById("COMPANYNAME").disabled = true;
document.getElementById("IWMEMO1").innerHTML += "\n Nome da Empresa:" + ObjLandjah.companyname;
document.getElementById("COUNTRY").value = ObjLandjah.country;
document.getElementById("COUNTRY").disabled = true;
document.getElementById("IWMEMO1").innerHTML += "\n Pais:" + ObjLandjah.country;
document.getElementById("UF").value = ObjLandjah.region;
document.getElementById("UF").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n Região: " + ObjLandjah.region;
document.getElementById("PHONE").value = ObjLandjah.phone;
document.getElementById("PHONE").disabled = true;
document.getElementById("IWMEMO1").innerHTML += " \n Tel: " + ObjLandjah.phone;
document.getElementById("IWMEMO1").innerHTML += '\n ************************************';
break;
case -1: insertData += "Cliente não encontrado!"; break;
case -2: insertData += "Valor digitado inválido!"; break;
case -3: insertData += "Ta com nojinho 02?."; break;
case -4: insertData += "AH ESSA ALTURA DO CAMPEONATO VC TA SEM AH BANDOLEIRA ??!"; break;
default: "PEDE PRA SAIR 01. Pede pra sair.";
}
}
catch(Error) {
insertData = "<br> <font color=#FF0000> eRrO. TIRA ESSA ROUPA PRETA QUE VC NÃO É CAVEIRA. </font> As Landjhas de mirandjas!!!"
}
document.getElementById("IWLABEL2").innerHTML += insertData;
document.getElementById("IWLABEL1").innerHTML += " <br /><b> Os senhores estão bem? Os senhores estão feridos? Algum dos senhores estão baleados? " +
" Então, no próximo post vcs vão aprender a carregar corpos!!! </b>"
document.getElementById("IWMEMO1").innerHTML += ' \n ';
}
</script>
</head>
<body>
<form id="form1" name="form1" method="post" action="">
<div id="PosControles" style="position: absolute; top: 32px; left: 12px; width: 887px; height: 92px; background-color: #3399CC;
font-size:16px; font-weight:400" align="justify"><br />Digite o Nome do Cliente: {%IWEdit1%} | {%IWButton1%}
<br>
{%Logradouro%}{%Bairro%}{%Cidade%} {%UF%}{%CEP%} {%CompanyName%}
{%ContactName%}
{%ContactTitle%}
{%Phone%}
{%Fax%}
{%Country%}
{%IWLink1%} <a href="http://localhost/estacaozncliente">Reload Page</a></div>
<div id="PosSpan" style="position: absolute; top: 128px; left: 12px; width: 440px; height: 580px; background-color: #99FF99;">
{%IWLabel1%} {%IWLabel2%}
<span id="cj">
</span>
</div>
<div id="PosMemo" style="position: absolute; top: 128px; left: 458px; width: 440px; height: 580px; background-color: #99FF99;"
align="center"><p>
{%IWMEMO1%}
testando!!
</div>
</form>
</body>
</html>

Adicione no IWForm1 os seguintes componentes:
IWTemplateProcessorHTML1: TIWTemplateProcessorHTML;
IWLabel1: TIWLabel;
IWEdit1: TIWEdit;
IWButton1: TIWButton;
IWMemo1: TIWMemo;
CEP: TIWEdit;
UF: TIWEdit;
Bairro: TIWEdit;
Logradouro: TIWEdit;
Cidade: TIWEdit;
IWLabel2: TIWLabel;
CompanyName: TIWEdit;
ContactName: TIWEdit;
ContactTitle: TIWEdit;
Phone: TIWEdit;
Fax: TIWEdit;
Country: TIWEdit;
No evento OnCreate do IWForm1 codifique conforme ilustrado abaixo:
procedure TformMain.IWAppFormCreate(Sender: TObject);
begin
Self.TemplateProcessor := IWTemplateProcessorHTML1;
IWTemplateProcessorHTML1.Templates.default := 'ZnPageAjaxJsonIntraweb.html';
IWLabel1.Caption := ' ';
IWMemo1.Font.Enabled := False;
IWMemo1.Font.CSSStyle := 'AreaTexto';
CEP.Width := 80;
UF.Width := 40;
Cidade.Width := 120;
Logradouro.Width := 180;
Bairro.Width := 90;
IWButton1.ExtraTagParams.Add('onClick=ZnGetCLienteWsAjax(IWEDIT1)');
IWMemo1.Lines.Add(' ');
IWEdit1.Text := 'Cactus Comidas para llevar';
end;
Observe na linha 7, estou atribuindo dinamicamente ao IWMemo1 uma classe CSS (“'AreaTexto'”) a qual está definida na página HTML que criamos anteriormente.
Ok, muito bem, meus amigos e minhas amigas, a parte referente a aplicação cliente termina aqui!! Isso é mto bom! Agora, é chegado o momento do bom e velho amigo deploy. Para isso, um “build all” na aplicação Intraweb (alt, p, b) é bem vindo, ela será compilada e a dll para deploy será gerada. So .. next step ... enjoy yourself ...
O nome do diretório virtual que vou criar será “estacaozncliente”.
Testando Aplicação cliente IntraWeb/ISAPI.

Conclusão
Usar a tecnologia Ajax nos seus sistemas web, sites, ou serviços traz, além de um ganho de performance, escalabilidade e interoperabilidade. Isso porque a solução Ajax é independente da tecnologia que esteja sendo utilizada no client-side. Pretendo, para o próximo post documentar um exemplo da mesma solução desenvolvida neste arquivo, sendo que a camada cliente desenvolverei em Java com o Netbeans.
O uso do JavaScript Object Notation (Json) descomplica muito a desenvolvimento de uma solução baseada em Ájax.
Um ponto muito importante neste artigo é o emprego do componente processador de “templates” o IWTemplateProcessorHTML. Ele permite que seu form Intraweb seja construído em cima de um arquivo HTML criado separadamente. Dessa forma um leque de possibilidades se abre. No momento a que eu mais quero destacar é que com isso é possível modularizar seu projeto colocando toda a parte de layout, disign, bem como o processamento client-side. Com isso, todo o Javascript que trabalhamos nos artigos anteriores pode ser definido na página web. Igualzinho é feito por webmasters, inclusive usando a tag “src” para códigos Javascript que ficam em arquivos separados.
Javascript placement: o Código JavaScript pode estar fisicamente disposto em um diretório específico para este fim, num arquivo “.js” separado da página HTML. Isso melhora inda mais a modularização do seu sistema, site, portal, etc...
O arquivo fonte do Javascript em questão é referenciado na página HTML usando a tag “script” o atributo "src" com o nome do arquivo e o path definidos como valor.
<head>
<script language="JavaScript" src="ZnJavaScriptFile.js"></script>
</head>
Portanto, de agora em diante, sugiro que você cuide para que, imperativamente, o Javascript fique separado da aplicação Delphi. Para isso temos basicamente dois caminhos a tomar: O primeiro seria usar o “IWTemplateProcessorHTML”. Uma segunda opção seria usar um “LoadFromFile”, ou seja ler dinamicamente arquivos com as funções Javascript. Se você optar por usar o IwTemplateProcesso, implementar desta forma, o “js” na página HTML, é uma ação intuitiva. Como fazer isso está demostrado neste artigo. Caso negativo, uma idéia, proposta pelo Malta, que eu gostei bastante, seria do Delphi, fazer um “LoadFromFile” de um arquivo, onde estaria com código JavaScript parametrizado (semelhante a um parâmetro de um comando SQL). A idéia é usar, ao invés de parâmetros de “FormatString (%s)” uma sintaxe como nome de parâmetros (:nome) e fazer substituição por pares (nome, valor). Deixe-me explicar melhor:
Veja num dos artigos anteriores: O Código Javascript que defini não tem “%s” para usar na função Format? Então, substitua todos o “%s” por uma sintaxe própria, que estaríamos criando, que represente o nome de um parâmetro. Por exemplo: ..... :par1 ... :idade ... :cidade... :idade. A exemplo de um comando SQL num TSQLQurey. Para trabalhar em conjunto, criaríamos uma função para substituir os parâmetros por valores em runtime, por exemplo: “function ZnReplaceParams(const znParmName, znParamValue: String)”. A chamada seria: “ReplaceParams('idade', '18');”. De cara podemos citar como vantagens melhor legibilidade do código Javascript, além de não fica dependente de posição (como é o caso do “Format(%s)”). Dentro da função caixa preta “ZnReplaceParams”, um StringReplace pode dar conta do recado, com rfReplaceAll e rfIgnoreCase. O que inclusive facilita quando você precisa repetir o mesmo valor várias vezes no mesmo script bastaria repetir o nome da "macro" ou parâmetro. Boa Malta, Estação Zn agradece! Tks!!
Uma outra abordagem seria usar argumentos na própria função Javascript, a qual vai estar definida num arquivo “.txt”, ou “.js”, que seja, e no Delphi atribuir as definições das chamadas a essas funções nos eventos “Javascript”, nas propriedades “ExtragParams”, ou “ScriptEvent”. Como exemplifiquei no artigo sobre validação de CIC.
Aconselho ao desenvolvedor que decidir usar o Delphi/Intraweb ter muita atenção na hora de referenciar os objetos, inputs, submits, selects, criados pelo Intraweb, no que tange a caixa do nome dos controles definidos no Delphi. Isso pq o Delphi não é case sensitive, conseqüentemente o desenvolvedor delphi não deverá, a pricípio, estar acostumado com essa restrição. Portanto, cuidado com comandos do tipo “document.getElementById("IWMEMO1")”, porque todo componente Intraweb é criado na página html com o nome em CAIXA ALTA. A função “getElementById” é sensível a caixa.
Programar em Javascript exige muita atenção a questões extra-intelectuais, pois você não vai poder contar com code insight, nem auto-complemento de código (code complete) e ainda existe o overhead de atenção na questão do case sensitive sem contar que as mensagens de erro não são tão amigáveis. Uma ferramenta que pode ajudar neste sentido são os plugins para desenvolvimento web do Fire Fox.
Outro ponto adverso é desenvolver um script client-side compatível com todos os browsers. Isso exige bastante de quem está desenvolvendo. Entretanto os bônus adquiridos em usar enfaticamente Javascript acaba compensando todos os ônus listados. Além disso, com o tempo o desenvolvedor ganha prática nesta abordagem e esses fatores negativos acabam perdendo sua força.
A tecnologia Json ainda é bem nova, nas minhas pesquisas encontrei muito pouca gente usando. Mas pra minha surpresa um número razoável de pessoas, blogs, falando sobre. Dei uma pesquisada no google trends http://www.google.com/trends sobre as buscas sobre Json.


Abaixo, código completo das units Delphi:
unit IWUnit1;
{PUBDIST}
interface
uses
IWAppForm, IWApplication, IWTypes, IWCompMemo, IWCompButton, IWCompEdit,
Controls, IWControl, IWCompLabel, Classes, IWLayoutMgr,
IWTemplateProcessorHTML, IWHTMLControls;
type
TformMain = class(TIWAppForm)
IWTemplateProcessorHTML1: TIWTemplateProcessorHTML;
IWLabel1: TIWLabel;
IWEdit1: TIWEdit;
IWButton1: TIWButton;
IWMemo1: TIWMemo;
CEP: TIWEdit;
UF: TIWEdit;
Bairro: TIWEdit;
Logradouro: TIWEdit;
Cidade: TIWEdit;
IWLabel2: TIWLabel;
CompanyName: TIWEdit;
ContactName: TIWEdit;
ContactTitle: TIWEdit;
Phone: TIWEdit;
Fax: TIWEdit;
Country: TIWEdit;
procedure IWAppFormCreate(Sender: TObject);
public
end;
implementation
{$R *.dfm}
uses
ServerController, IWForm;
//ajaxconcorretor
procedure TformMain.IWAppFormCreate(Sender: TObject);
begin
Self.TemplateProcessor := IWTemplateProcessorHTML1;
IWLabel1.Caption := ' ';
IWMemo1.Font.Enabled := False;
IWMemo1.Font.CSSStyle := 'AreaTexto';
CEP.Width := 80;
UF.Width := 40;
Cidade.Width := 120;
Logradouro.Width := 180;
Bairro.Width := 90;
IWButton1.ExtraTagParams.Add('onClick=return ZnGetClienteWsAjx(IWEDIT1);');
IWMemo1.RawText := True;
IWMemo1.Lines.Add(' ');
IWEdit1.Text := 'Cactus Comidas para llevar';
end;
end.
unit Unit1;
interface
uses
SysUtils, Classes, HTTPApp, DBClient, Provider, DB, ADODB;
type
TWebModule1 = class(TWebModule)
ADOConnection: TADOConnection;
ADODataSet1: TADODataSet;
DataSetProvider1: TDataSetProvider;
ClientDataSet1: TClientDataSet;
ClientDataSet1CustomerID: TWideStringField;
ClientDataSet1CompanyName: TWideStringField;
ClientDataSet1ContactName: TWideStringField;
ClientDataSet1ContactTitle: TWideStringField;
ClientDataSet1Address: TWideStringField;
ClientDataSet1City: TWideStringField;
ClientDataSet1Region: TWideStringField;
ClientDataSet1PostalCode: TWideStringField;
ClientDataSet1Country: TWideStringField;
ClientDataSet1Phone: TWideStringField;
ClientDataSet1Fax: TWideStringField;
procedure WebModule1ZnConsClientesAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.dfm}
uses
Math, StrUtils;
procedure TWebModule1.WebModule1ZnConsClientesAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
const
ZnTag = '%s:%s';
var
StrStatment: String;
i, CodRetorno: Integer;
begin
with ClientDataSet1 do
begin
Params[0].AsString := '%' + Request.QueryFields.Values['znNomeCli']+ '%';
try
Open;
CodRetorno := IfThen(IsEmpty, -1, 1);
StrStatment := StrStatment +
Format(ZnTag, ['codretornoZn',
IntToStr(CodRetorno)]);
if CodRetorno = 0 then Exit;
for i := 0 to Pred(FieldCount) do
begin
StrStatment := StrStatment + ','+
Format(ZnTag, [LowerCase(ClientDataSet1.Fields[i].FieldName),
IfThen((ClientDataSet1.Fields[i].AsString = ''), QuotedStr('-'),
QuotedStr(ClientDataSet1.Fields[i].AsString))]);
end;
finally
Close;
Response.Content := Format('{%s}',[StrStatment]);
end;
end;
end;
end.
Artigo completo (View Full Post)
quarta-feira, 22 de abril de 2009
Navegar? Pois é, eu preciso ...

Artigo completo (View Full Post)