Sie sind auf Seite 1von 441

SIGUENOS EN:

LIBROS UNIVERISTARIOS Y SOLUCIONARIOS DE


MUCHOS DE ESTOS LIBROS GRATIS EN
DESCARGA DIRECTA

VISITANOS PARA DESARGALOS GRATIS.


preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página II
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página III

AJAX
Web 2.0 para profesionales

Maximiliano R. Firtman
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página IV
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página V

AJAX
Web 2.0 para profesionales

Maximiliano R. Firtman

Buenos Aires • Bogotá • México DF • Santiago de Chile


preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página VI

Datos catalográficos
Firtman, Maximiliano
Ajax. Web 2.0 para profesionales
Primera Edición
Alfaomega Grupo Editor, S.A. de C.V., México
ISBN: 978-970-15-1328-6
Formato: 17 x 23 cm Páginas: 440

Ajax. Web 2.0 para profesionales


Maximiliano Firtman
Derechos reservados ©Alfaomega Grupo Editor, S.A. de C.V., México

Primera edición: Alfaomega Grupo Editor, México, noviembre 2007

© 2008 Alfaomega Grupo Editor, S.A. de C.V.


Pitágoras 1139, Col. Del Valle, 03100, México D.F.

Miembro de la Cámara Nacional de la Industria Editorial Mexicana


Registro No. 2317

Pág. Web: http://www.alfaomega.com.mx


E-mail: libreriapitagoras@alfaomega.com.mx

ISBN: 978-970-15-1328-6

Derechos reservados:
La información contenida en esta obra tiene un fin exclusivamente didáctico y, por lo tanto,
no está previsto su aprovechamiento a nivel profesional o industrial. Las indicaciones
técnicas y programas incluidos, han sido elaborados con gran cuidado por el autor y
reproducidos bajo estrictas normas de control. ALFAOMEGA GRUPO EDITOR, S.A. de
C.V. no será jurídicamente responsable por: errores u omisiones; daños y perjuicios que se
pudieran atribuir al uso de la información comprendida en este libro, ni por la utilización
indebida que pudiera dársele.

Edición autorizada para venta en México y todo el continente americano.

Impreso en México. Printed in Mexico.

Empresas del grupo:


México: Alfaomega Grupo Editor, S.A. de C.V. – Pitágoras 1139, Col. Del Valle, México, D.F. – C.P. 03100.
Tel.: (52-55) 5089-7740 – Fax: (52-55) 5575-2420 / 2490. Sin costo: 01-800-020-4396
E-mail: libreriapitagoras@alfaomega.com.mx
Colombia: Alfaomega Colombiana S.A. – Carrera 15 No. 64 A 29 – PBX (57-1) 2100122
Fax: (57-1) 6068648 – E-mail: scliente@alfaomega.com.co
Chile: Alfaomega Grupo Editor, S.A. – General del Canto 370-Providencia, Santiago, Chile
Tel.: (56-2) 235-4248 – Fax: (56-2) 235-5786 – E-mail: agechile@alfaomega.cl
Argentina: Alfaomega Grupo Editor Argentino, S.A. – Paraguay 1307 P.B. “11”, Capital Federal,
Buenos Aires, C.P. 1057 – Tel.: (54-11) 4811-7183 / 8352, E-mail: info@alfaomegaeditor.com.ar
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página VII

A mis padres, los mentores de mi persona, a mi fa-


milia, a mi hermano y a Ani, mi compañera de vida.
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página VIII

Maximiliano R. Firtman
Es profesional en sistemas, docente y desarrollador web desde 1996. Es fundador y director del
instituto ITMaster Professional Training, donde también es docente de tecnologías móviles y
web, entre ellas, AJAX, Flex, Java ME y ASP.NET. En su carrera profesional publicó artículos en
diversas revistas técnicas y trabajó en distintos medios especializados.
Fue reconocido finalista en el premio Sadosky 2006 a la inteligencia argentina aplicada en
la sociedad de la información. Creó el portal de contenidos para móviles entupalma.com y fue
reconocido como uno de los más destacados desarrolladores móviles del mundo en el pro-
grama Forum Nokia Champion.
También es autor de los libros Programación para celulares con Java, ASP.NET, Desarro-
llos móviles con .NET y ASP.NET 2.0.
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página IX

Índice
C01. Web 2.0. La nueva web Wikis ........................................................ 29
Comunidades ............................................ 30
La nueva web................................................ 1 Interoperabilidad ............................................ 30
Qué es la Web 2.0 .......................................... 1 LinkBack.................................................... 30
Historia ...................................................... 2 Redes de favoritos .................................... 30
Qué no es la Web 2.0 ................................ 3 Gadgets y Widgets .................................... 32
Web 1.0 .................................................... 3
En ejemplos .............................................. 5 Estándares .................................................... 33
El nuevo modelo de trabajo ............................ 33
Rich Internet Applications............................ 6 XHTML ...................................................... 33
Qué son.......................................................... 6 CSS .......................................................... 34
Características................................................ 8 JavaScript.................................................. 35
Tipos de aplicación .................................... 10 XML .......................................................... 36
Ventajas ........................................................ 12 Separación en capas ...................................... 36
Desventajas.................................................... 13
Capacidad de uso ...................................... 13
El botón Atrás del navegador...................... 13
2da Guerra de los browsers ...................... 13
C02. Comenzando con AJAX
Indexación de buscadores.......................... 14 Herramientas ................................................ 43
Favoritos o marcadores.............................. 15 Entorno de trabajo...................................... 43
Manejo de errores...................................... 16 Adobe Dreamweaver.................................. 43
Complejidad de desarrollo.......................... 16 Microsoft Expression Web .......................... 43
Plataformas disponibles.................................. 16 JSEclipse .................................................. 44
AJAX.......................................................... 16 Visual Web Developer ................................ 49
Adobe Flash .............................................. 17 Navegadores y utilitarios ................................ 53
Adobe Flex ................................................ 18 Internet Explorer ........................................ 53
OpenLaszlo ................................................ 20 Firefox ...................................................... 55
Microsoft Silverlight .................................. 21 Opera ........................................................ 57
Java Webstart ............................................ 22 Servidor Web .................................................. 58
El sentido de la web .................................... 23 Cassini ...................................................... 60
La Web semántica .......................................... 23 Internet Information Server ........................ 60
Microformats ............................................ 24 Apache ...................................................... 60
Web mashups ................................................ 25 HTTP Proxies ............................................ 62
Web services y API ........................................ 26 El objeto XMLHttp ........................................ 62
Red social .................................................... 27 Origen ............................................................ 63
Etiquetado ...................................................... 27 Modo de uso .................................................. 63
Modelos ........................................................ 28 Instanciación .................................................. 65
Blogs y derivados ...................................... 28 En Internet Explorer.................................... 65

IX
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página X

Maximiliano R. Firtman

En otros navegadores ................................ 65 Constructores ............................................ 95


Patrón Factory............................................ 66 Prototipado ................................................ 96
Métodos más utilizados .................................. 67 Herencia .................................................... 96
open .......................................................... 67 Buenas prácticas ............................................ 97
send .......................................................... 68 Nomenclatura ............................................ 97
abort.......................................................... 69 Documentación.......................................... 98
Propiedades .................................................. 69 JSON ............................................................ 100
readyState ................................................ 69 Qué es............................................................ 100
status ........................................................ 70 Sintaxis .......................................................... 100
statusText .................................................. 71 Ventajas ........................................................ 102
responseText ............................................ 71 JSON con funciones ...................................... 103
responseXml.............................................. 72 Usos ............................................................ 103
onreadystatechange .................................. 72 Librerías para otros lenguajes ........................ 104
Otros métodos ................................................ 73 PHP .......................................................... 105
setRequestHeader...................................... 73 .NET .......................................................... 105
getResponseHeader .................................. 73 Java .......................................................... 106
getAllResponseHeaders ............................ 74
Métodos y propiedades no estándar .............. 75 Prototype ...................................................... 106
Qué es............................................................ 106
Primer Proyecto AJAX .................................. 75 Instalación...................................................... 106
Hola AJAX ...................................................... 75 Utilitarios ........................................................ 106
Parámetros GET.............................................. 79 $ ............................................................ 106
?clave=valor&clave2=valor2...................... 79 $$ ............................................................ 108
LeerArchivo.ASPX ...................................... 79 $F ............................................................ 108
Parámetros POST .......................................... 80 $w ............................................................ 108
clave=valor&clave2=valor2........................ 80 Try.these .................................................... 109
LeerArchivoPost.aspx ................................ 80 Otros.......................................................... 109
leerArchivoPost.html .................................. 81 Agregados a objetos ...................................... 110
Reemplazando contenido................................ 82 Strings............................................................ 110
XHR.js........................................................ 83 Arrays ........................................................ 111
reemplazandoDIV.html .............................. 83 Elementos DOM ........................................ 113
Event ........................................................ 113
Form.......................................................... 113
C03. JavaScript avanzado formulario.html .......................................... 115
Técnicas avanzadas .................................... 87 formulario.js .............................................. 116
Try-Catch ...................................................... 87 Objeto AJAX .............................................. 116
Generando errores .................................... 88 Ajax.Request(url, opciones) ........................ 116
For in ............................................................ 89 Ajax.Updater(elemento, url, opciones).......... 116
Manejo de funciones ...................................... 90 Ajax.PeriodicalUpdater(elemento, url,
Parámetros opcionales .............................. 90 opciones) ................................................ 116
Sobrecarga de parámetros por tipo ............ 91 Otros agregados ........................................ 118
Parámetros como variables........................ 91 Model View Controller .................................. 120
Parámetros múltiples ................................ 93 Qué es............................................................ 120
Programación orientada a objetos .................. 93 Estructura ...................................................... 120
Objeto Object ............................................ 93 Técnicas ........................................................ 121
Recorriendo el objeto ................................ 94 index.html (Vista) ...................................... 121
Creando clases .......................................... 95 index.js (Controlador) ................................ 122

X
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XI

Índice

modelo.js (Modelo) .................................... 122 Eventos...................................................... 152


ajax.js (Modelo).......................................... 123 Parámetros .................................................... 153
El código ........................................................ 155
Usando la librería ........................................ 161
C04. Document Object Model Sitio estático versión AJAX.............................. 161
Qué es............................................................ 125 index.html.................................................. 162
Estructura ...................................................... 125 estilos.css.................................................. 163
Objetos .......................................................... 125 quienes.html.............................................. 165
Métodos y propiedades .................................. 127 clientes.html .............................................. 165
Documento DOM........................................ 127 servicios.html ............................................ 166
Atributos de los nodos................................ 127 contacto.html ............................................ 166
Métodos de los nodos ................................ 128 Aviso de cargando .................................... 168
Ejemplo .................................................... 129 Aplicando efectos ...................................... 170
Propiedades útiles en XHTML ........................ 130 Lector RSS .................................................... 171
this ............................................................ 131 lector.html.................................................. 172
disabled .................................................... 131 estilos.css.................................................. 173
Estilos CSS ................................................ 131 lector.js...................................................... 175
Ejemplos ........................................................ 131 tecnología.xml .......................................... 177
Efecto rollover............................................ 131 Actualizando periódicamente .................... 178
Creando una tabla dinámica ...................... 132 Proxy PHP ...................................................... 180
Script.aculo.us.............................................. 136 proxyrss.php .............................................. 180
Qué es............................................................ 136
Instalación...................................................... 137
Efectos visuales.............................................. 138 C06. Formulario de registro AJAX
Efectos de núcleo ...................................... 138 Objetivo ........................................................ 183
Efectos combinados .................................. 141 Arquitectura.................................................... 183
Toggle........................................................ 142 Tablas ............................................................ 184
Ejemplos.................................................... 142 Usuarios .................................................... 184
mostrarVentana.html.................................. 145
mostrarVentana.css .................................. 145 Creando el formulario .................................. 186
mostrarVentana.js...................................... 146 XHTML .......................................................... 186
Builder............................................................ 146 formulario.html .......................................... 187
formulario.css............................................ 189
Autocompletar .............................................. 189
C05. Creando una librería de trabajo Qué es............................................................ 189
Objetivo .......................................................... 149 Cuándo aplicarlo ............................................ 190
Características................................................ 150 Autocompletar local........................................ 191
$Ajax ........................................................ 150 Opcionales ................................................ 197
Opciones.................................................... 150 Autocompletar remoto .................................... 198
Opción url (Obligatorio) ............................ 150 BD.php ...................................................... 200
Opción método .......................................... 150 Buscador de localidades ............................ 203
Opción tipoRespuesta ................................ 151 Categorías con niveles en cascada ............ 206
Opción parámetros .................................... 151 Completar países............................................ 207
Opción cache ............................................ 151 Problemas con la codificación.................... 209
Opción avisoCargando .............................. 152 Completar provincias...................................... 211
Opción id .................................................. 152
Controles ricos ............................................ 217

XI
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XII

Maximiliano R. Firtman

Slider ............................................................ 217 Generar URL en forma automática ............ 270


Script.aculo.us slider.................................. 220 Periodic Refresh ............................................ 271
Atributos opcionales .................................. 223 MultiStage Download ................................ 275
Implementando Nivel Educativo ................ 224 Predictive Fetch ........................................ 276
DatePicker...................................................... 228 Prefetch cliente.......................................... 278
Yahoo UI ........................................................ 228 Prefetch servidor........................................ 279
Calendar .................................................... 231 Local Cache.................................................... 280
Funciones avanzadas ................................ 235 Submission Throttling .................................... 280
NumericTextBox ............................................ 236 Implementación ........................................ 281
NumericUpDown........................................ 236 Peticiones que se sobreescriben ................ 282
SortableList .................................................... 238
Consultando los cursos .............................. 238
RichTextBox .................................................. 242 C08. Comercio electrónico con AJAX
Validación activa .......................................... 244 Introducción ................................................ 285
existeusuario.php .................................... 244 Estructura ...................................................... 285
Enviando el formulario ................................ 245 Lenguaje de servidor.................................. 285
Mostrando una alerta ................................ 247 Base de datos ............................................ 286
Clases de conexión .................................... 287
Diseño Web .................................................... 289
C07. Patrones de diseño para RIA Comportamiento inicial .............................. 292
Index.js ...................................................... 297
Qué son ........................................................ 249 Resultados de búsqueda ................................ 298
Los patrones como ley.................................... 250 categoria.aspx ............................................ 299
Patrones GoF .................................................. 250 buscar.aspx (fig. 8-6) .................................. 300
Su uso en AJAX .............................................. 251 Detalle de producto ........................................ 305
Patrones generales ...................................... 252 Producto.aspx ............................................ 307
Factory .......................................................... 253 Agregando al canasto ................................ 311
Abstract Factory ........................................ 254 Mostrando el canasto ................................ 312
Observer ........................................................ 255 Quitando del canasto ................................ 315
Command ...................................................... 257 Modificando cantidades ............................ 316
Memento .................................................. 259 Arrastrar y soltar .......................................... 318
Value Object .................................................. 260 Introducción .................................................. 318
Patrones exclusivos de RIA.......................... 261 Draggables .................................................... 319
Guesstimate .................................................. 261 Droppables .................................................... 321
On-Demand JavaScript .................................. 263 Uso avanzado ................................................ 323
Código dinámico con JSON ........................ 263 Aplicación .................................................. 323
Código dinámico con XHTML...................... 264 Arrastrando al canasto .............................. 323
home.js (Controlador ya cargado) .............. 265 Arrastrando a la basura.............................. 329
corrector.js (módulo cargado con Finalizando la compra.................................. 330
ulterioridad) .............................................. 265 Guardado automático .................................... 337
Cargador de scripts.................................... 266
Cross Domain Proxy ...................................... 267 Código completo .......................................... 338
Heartbeat ...................................................... 267 index.html .............................................. 338
Unique URLs .................................................. 269 estilos.css .............................................. 340
Generar URL bajo demanda........................ 270 index.js .................................................. 345

XII
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XIII

Índice

C09. AJAX avanzado Google Gears .................................................. 391


Ejemplo .......................................................... 393
Técnicas ...................................................... 353
Historial.......................................................... 353 AJAX en el móvil .......................................... 394
Pasos a seguir .......................................... 354 Aplicaciones para iPhone................................ 395
Métodos .................................................... 355
Ejemplo .................................................... 355
Almacenando en el cliente.............................. 358 C10. Librerías y frameworks
Cambio de URL .......................................... 358 Librerías de cliente ......................................397
Datos a futuro ............................................ 358 Adobe Spry ....................................................
397
Datos masivos .......................................... 360 Spry Widgets..............................................
398
No esperemos las imágenes .......................... 360 XML DataSets ............................................
400
Reproducir sonido .......................................... 362 Efectos Spry ..............................................
403
Comprimiendo y ocultando el código .............. 362 Microsoft AJAX Library.................................... 404
Dojo ShrinkSafe ........................................ 365 jQuery........................................................
405
Javascript Chaos Engine ............................ 366 Dojo Toolkit ....................................................
407
Compilar la lógica de negocios .................. 371 Dijit............................................................
408
Comprimiendo el XHTML ................................ 372 Módulos ....................................................
410
Pruebas unitarias............................................ 375 Otras librerías ................................................
410
xUnit .......................................................... 376 Moo.fx – moofx.mad4milk.net.................... 412
Conexión con Google.................................... 379 OAT Framework – oat.openlinksw.com ........ 412
Google Code .................................................. 379 Aflax – aflax.org ......................................
412
Servicios disponibles ................................ 380 Rico – openrico.org ..................................
412
Frameworks y formatos ............................ 382 Number Formatting Library - xaprb.com ...... 412
Google KLM ............................................ 382 Mochikit – mochikit.com .......................... 412
Google Data ............................................ 382 Librerías para PHP........................................ 412
Google Web Toolkit .................................. 382 SAJAX ............................................................ 412
Google Gears .......................................... 382 XAJAX ............................................................ 414
Google Open Source .................................. 382 PAJAX ............................................................ 414
API Key .......................................................... 382
Google Maps API ............................................ 384 Librerías para ASP.NET ................................ 415
Objetos de la API........................................ 384 Ajax.NET Professional .................................... 415
mapa.js .................................................. 385 Microsoft ASP.NET AJAX Extensions .......... 417
Controles .................................................. 418
Conexión con Microsoft Live........................ 385 Control Toolkit ............................................ 419
Windows Live Dev .......................................... 385
Otros lenguajes ............................................ 421
Conexión con Yahoo! .................................... 387 Java .......................................................... 421
Yahoo! Developer Network.............................. 387 ColdFusion ................................................ 421
Conexión con Amazon.................................. 387 .NET .......................................................... 421
AWS ............................................................ 387 Python ...................................................... 421
Aplicaciones desconectadas ...................... 389 PHP .......................................................... 421
Adobe AIR ...................................................... 389 Ruby .......................................................... 421

XIII
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XIV
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XV

Prólogo
Es llamativo observar cómo la mayoría de nosotros se acostumbra al paradigma vigente, al que
se llega a considerar totalmente normal, y cómo, cuando nos muestran de repente un paradigma
nuevo, nos damos cuenta de que en realidad el que teníamos hasta ahora era mucho peor. ¡Y
no nos habíamos dado cuenta! En política esto sucede muy a menudo. No obstante, también
nos pasó a nosotros, los desarrolladores web.
Todos nos habíamos acostumbrado a las limitaciones del HTML y el protocolo HTTP, entre
ellas, la más notable, la eterna espera entre una página y la siguiente. Asimismo, el usuario de
Internet terminó por aceptarlo como algo imposible de superar. Hasta los chistes decían que
WWW en realidad significaba Wait, Wait, Wait (esperar, esperar, esperar). Y de golpe, alguien
nos abrió el panorama y nos mostró un nuevo paradigma. Probablemente no fue el primero, ni
el mejor, pero fue el que más difusión le dio. Me refiero a Google, con sus primeros servicios
Web 2.0: Gmail y Google Maps.
De pronto nos dimos cuenta de que había otra forma de hacer las cosas y que parecía
mucho mejor para el usuario. Las esperas se reducían, el tráfico al servidor era menor y la in-
terfaz de usuario se mantenía estable durante el 100% de la estadía del usuario en el sitio web.
No más interfaces que hacen esperar al usuario.
Por supuesto, la industria acompañó… Los navegadores empezaron a soportar esta nueva
técnica y los desarrolladores, que queríamos ser como los de Google, comenzamos a investi-
gar y crear aplicaciones utilizando la misma técnica. Hasta le dimos nombre: AJAX.
Durante casi 10 años nos basamos en la misma técnica base: HTML y vínculos. Podíamos
utilizar banners en Flash o algún otro tipo de objeto más avanzado, que fueron incorporándose
durante los años, pero el fondo real siempre se trataba de peticiones que hacían esperar al
usuario hasta que se descargue la próxima página. Asimismo, durante casi 10 años nos pare-
ció casi normal repetir el menú, el logo, los banners y el pie de página en todas las páginas
HTML, con la consecuente redundancia de datos transferidos. Y cuando todos pensaban que
JavaScript era un lenguaje casi muerto, apareció AJAX y el lenguaje tomó un nuevo vuelo im-
pensado hace unos años. Ahora tenemos que volvernos expertos en JavaScript para lograr
técnicas complejas y compatibles con todos los navegadores; debemos empezar a aplicar pa-
trones de diseño y técnicas de orientación a objetos que antes eran impensadas e innecesarias.
Bienvenidos al nuevo mundo del desarrollo web. Bienvenidos a AJAX.
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XVI

Alfaomega e ITMaster Professional Training te dan la posibilidad de


que certifiques tus conocimientos y experiencia adquiridos como lec-
tor de este libro por medio de un examen gratuito. Su aprobación te
permitirá obtener los certificados de Introducción a Web 2.0, JavaS-
cript Avanzado y AJAX en ITMaster Professional Training.
Luego de la obtención del certificado podrás continuar tu forma-
ción en la carrera corta de especialización Rich Internet Applications,
que agrega a tu capacitación AJAX las herramientas de Adobe Flex,
Microsoft Silverlight y Microsoft Expression Blend, OpenLaszlo y/o
Adobe Integrated Runtime (AIR), para completar tu conocimiento en
todas las plataformas de generación de aplicaciones ricas de Internet.
La capacitación podrás realizarla en forma presencial en las
sedes habilitadas o de manera no presencial a través de Internet, en
cualquier ciudad del mundo donde te encuentres.
Para dar el examen de certificación y continuar tu capacitación,
ingresa en la dirección correspondiente a tu país, donde recibirás más
información e instrucciones. Para realizar cualquier consulta adicional,
se detalla la dirección de correo electrónico que corresponde a tu país:

España http://ajax.itmaster.es info@itmaster.es


México http://ajax.itmaster.com.mx info@itmaster.com.mx
Argentina http://ajax.itmaster.com.ar info@itmaster.com.ar
Otro país http://ajax.itmaster.la info@itmaster.la
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XVII

Introducción
En este libro se cubrirán todos los temas básicos y avanzados relacionados con el mundo de
la nueva técnica, conocida como AJAX (Asynchronous Javascript and XML). Se presume un
cierto conocimiento inicial del lector en el uso de HTML y JavaScript, así como de algún len-
guaje de servidor. No obstante, un usuario recién ingresado en este mundo podrá seguir el
ritmo de a poco con ciertos repasos que se realizan a lo largo del libro.
En el primer capítulo se repasará el nuevo concepto de la Web 2.0, incluidas las aplica-
ciones ricas de Internet, la web semántica y los nuevos conceptos de redes sociales en la web.
También se fundamentará el uso de estándares y la nueva metodología de diseño con CSS. Ya
en el segundo capítulo se comenzará a analizar en qué consiste técnicamente AJAX y el ob-
jeto XMLHttpRequest con los primeros ejemplos sencillos.
A partir del capítulo 3 se entrará en el uso de técnicas avanzadas de JavaScript, meto-
dologías de trabajo y herramientas del lenguaje que pocas veces se usaron antes del ingreso
de AJAX en el mundo del desarrollo web. En el capítulo siguiente se analizarán en detalle el Do-
cument Object Model (DOM) y las bases de la creación dinámica de contenido en una página
XHTML. También se comenzará el trabajo con librerías de uso común en AJAX, como Prototype
y Script.aculo.us.
La creación de una librería de múltiples propósitos para AJAX es el tema fundamental que
se irá entretejiendo en el capítulo 5. También se implementará un lector de noticias completa-
mente realizado con las nuevas técnicas AJAX. En el capítulo siguiente se realizará un formu-
lario web utilizando técnicas ricas, validaciones activas y controles ricos, y una forma de
autoguardado por medio de AJAX contra un desarrollo PHP en el servidor.
Se seguirá el camino por los patrones de diseño sobre aplicaciones AJAX, con el objetivo de
solucionar problemas comunes en el mundo de las aplicaciones ricas de Internet y crear un vo-
cabulario común entre los desarrolladores. Aplicando lo expuesto y la librería de trabajo creada
antes, en el capítulo 8 se realizará un sitio completo de comercio electrónico utilizando ASP.NET
como desarrollo en el servidor. Allí se llevarán a cabo técnicas de arrastrar y soltar, búsquedas de
productos sin refrescar la página y servicios ricos en un sitio web.
Entre las técnicas avanzadas que se verán en el capítulo 9 se podrá tener un manejo del
historial del navegador web, la compresión y el ocultamiento del código JavaScript y la crea-
ción de aplicaciones que puedan funcionar de manera desconectada de Internet. En el último
capítulo se hará un repaso por decenas de librerías adicionales para aplicaciones JavaScript y
para crear aplicaciones AJAX desde PHP y ASP.NET.
preliminares.qxd:Project Ajax4.1.qxd 10/18/07 8:26 PM Página XVIII
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 1

Web 2.0
La nueva web 1
La nueva web
La World Wide Web, como se la conoce en el presente, nació a principios de la década
de 1990 y en sus inicios sólo ofreció contenido textual agrupado en los famosos hi-
pervínculos o links. En esa época se habló mucho del nacimiento del hipertexto como
concepto y de la navegación por la web.
No obstante, en la actualidad, estamos lejos de aquella época; basta con visitar
cualquiera de nuestros sitios web favoritos para darnos cuenta. Los sitios web ya no
son sólo texto e hipervínculos. Son imágenes, animaciones Flash, publicidades que
tapan la lectura, ventanas desplegables, videos, juegos y aplicaciones completas.
La información ya no tiene la exclusividad en el mundo de Internet, en el presente
la usamos también para comprar, mantener nuestra vida social, administrar nuestra
hoja de cálculos o publicar nuestros videos.
Es por eso que la web como la conocíamos hasta la actualidad está cambiando.
Aparece una nueva web, la Web 2.0.

Qué es la Web 2.0

Con sinceridad, no hay un concepto claro que la defina. Wikipedia, la famosa enciclo-
pedia online mantenida por la propia comunidad y participante de la Web 2.0, la define
así: “Se refiere a la transición percibida en Internet desde las webs tradicionales a apli-
caciones web destinadas a usuarios”.
Otros la definen como un nuevo movimiento social en Internet, algunos como una
nueva ola de servicios y, los más técnicos, como la posibilidad de evadir las limitacio-
nes del HTML.

1
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 2

Maximiliano R. Firtman

La verdad es un poco de todo eso y mucho más. Es un concepto abierto que


abarca tres grandes conceptos, los ampliaremos de a poco:
1. Aplicaciones ricas de Internet.
2. Web semántica.
3. Redes sociales.

Historia
El término Web 2.0 tiene un origen claro: fue utilizado por primera vez por O’Reilly
Media (empresa conocida por su editorial de libros de tecnología) en una conferencia
en octubre de 2004. Meses después fue Tim O’Reilly, fundador de la empresa, quien
definió el concepto y lo hizo conocido en la comunidad. Incluso antes de que el término
se hiciera de uso común, O’Reilly lo había registrado como marca, lo que luego dio al-
gunos dolores de cabeza a otras empresas que intentaron usarlo (fig. 1-1).

Fig. 1-1. Diagrama de conceptos que se asocian a Web 2.0. Este diagrama se distribuye bajo la licencia
Creative Commons, muy común en el mundo de la Web 2.0.

En ese momento la definición de O’Reilly incluía:


• La web como plataforma.
• Efectos de red en una arquitectura de participación.
• Innovación y desarrolladores independientes.
• Pequeños modelos de negocio capaces de publicar servicios y contenidos.
• Datos abiertos.
• El perpetuo beta.

2
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 3

AJAX. Web 2.0 para profesionales

De esta forma vemos cómo alrededor del término se agrupan muchos conceptos,
y cada uno posee su parte de verdad. Al finalizar el capítulo tendremos una idea más
compleja de ellos (fig. 1-2).

Fig. 1-2. Diagrama que agrupa en forma más estructurada distintos conceptos relativos a la Web 2.0.

Qué no es la Web 2.0


Si bien resulta complejo definir rápidamente la Web 2.0, es factible enunciar qué no
es, respecto de términos que podrían confundirse.
Web 2.0 no es Internet 2. Este último concepto es una red paralela nueva de alta
velocidad por el momento utilizada por universidades. Web 2.0 funciona sobre la misma
red de Internet que todos conocemos.
Tampoco es un nuevo lenguaje de programación.
Web 2.0 no es un cambio radical de tecnología. Veremos que seguimos utilizando
HTTP, HTML, JavaScript y muchas de las tecnologías con las que veníamos traba-
jando; aunque las usaremos de otro modo.
Tampoco es sólo AJAX, ni RSS.

Web 1.0
De esta forma, aparece una Web 1.0 que hasta ahora era la única que conocíamos y
que, si bien había evolucionado desde 1995 durante 10 años, seguía utilizando la
misma base. Incluso en términos económicos en el presente a la Web 1.0 se la cata-
loga como la que falló en la conocida burbuja de Internet, a fines del milenio pasado,
en la que cientos y miles de empresas punto com debieron cerrar sus puertas luego de
millones de dólares invertidos.

3
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 4

Maximiliano R. Firtman

Fig. 1-3. Recopilación de marcas web 2.0 publicadas en el blog Imperfect World en shafiur.i-edit.net.

Fig. 1-4. En Archive.org se puede observar cómo eran los sitios web años atrás y analizar las diferen-
cias con las versiones actuales.

4
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 5

AJAX. Web 2.0 para profesionales

En el cuadro 1-1, en el que se comparan ambos paradigmas, se facilita la com-


prensión del concepto.

Concepto Cómo es en la Web 1.0 Cómo es en la Web 2.0

Quiénes publican Los productores de los sitios Tanto los productores


web como los mismos usuarios

Distribución de la información Centralizada en un sitio web Dispersa en miles de sitios


a través de interconexiones

Publicidad en la web Sólo para grandes Cualquiera puede


presupuestos y con campañas publicar y organizar su
cerradas propia campaña

Dueños de la información El sitio web Los usuarios

Tecnología reinante HTML 4.0 XHTML y CSS

Disponibilidad de nuevos Cuando estaban finalizados Se liberan en modalidad


servicios web luego de años de trabajo Beta apenas tienen alguna
funcionalidad

Posibilidad de utilizar Ninguna Los sitios ofrecen API abiertas


servicios de otros sitios para que otros se conecten

Cuadro 1-1. Comparación entre los paradigmas de la Web 1.0 y la Web 2.0

En ejemplos
Si se coloca el cuadro anterior en sitios web, en el cuadro 1-1 se observan los ejem-
plos principales que muestran con claridad la diferencia entre una y otra web.
Si visitamos los sitios catalogados en el cuadro 1-2 como Web 1.0, veremos que
muchos de ellos se actualizaron, pero en su momento fueron el ícono de la diferencia
con sus pares 2.0.
También es de destacar que en la segunda columna aparecen muchos servicios
de Google. Pues bien, esta empresa ha sido pionera en el uso de los servicios web 2.0
y, ya sea por desarrollo propio o por comprar otras empresas, se ha convertido en uno
de los íconos de la Web 2.0 y en el que más promovió esta nueva concepción de In-
ternet en los usuarios. Tanto Yahoo! como Microsoft ingresaron un tiempo después al
concepto, lo que dejó mucho margen a Google para captar mercado.

5
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 6

Maximiliano R. Firtman

Concepto Cómo es en la Web 1.0 Cómo es en la Web 2.0

E-mail Hotmail Gmail

Publicidad DoubleClick Google AdWords

Mapas MapQuest Google Maps

Fotografías Ofoto Yahoo! Flickr

Publicación por parte GeoCities Blogger


de los usuarios

Buscador Altavista Google

Enciclopedia Encarta Wikipedia

Información Slashdot Digg

Paquete de oficina - Google Docs

Compras Amazon GAP

Cuadro 1-2. Ejemplos de sitios que muestran las diferencias entre las dos webs.

Rich Internet Applications


Qué son

Las aplicaciones ricas de Internet pueden ser el término más fuerte de la Web 2.0 para
los diseñadores y desarrolladores. Sin embargo, es sólo uno de los conceptos de la
Web 2.0 y no deben confundirse como sinónimos.
Entonces, una aplicación rica de Internet es un cruce entre las aplicaciones web
y las de escritorio, que deriva en cierto comportamiento hacia el cliente, que se co-
munica con el servidor sólo en casos necesarios. Además, implica superar las limita-
ciones de HTML, por lo que se puede ofrecer todo tipo de controles ricos y una nueva
experiencia al usuario (fig. 1-5).
El término lo designó en 2002 la empresa Macromedia, en la actualidad Adobe,
creadora de la herramienta Flash. En ese momento, Macromedia anunciaba que con
su plataforma Flash era posible crear una nueva experiencia de uso en los sitios web
que no era posible con HTML y promovió el uso de este nuevo concepto. Tuvieron que
pasar varios años antes de que realmente se empezaran a utilizar estos conceptos y
su plataforma Flash se volviera una de las actuales rivales en el mercado.

6
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 7

AJAX. Web 2.0 para profesionales

Fig. 1-5. Esquema de los participantes en el mundo RIA.

Si se engloban las características de los conocidos como clientes ricos (aplicaciones


de escritorio, como Microsoft Excel o Adobe Photoshop) y las de los denominados
clientes livianos (aplicaciones web tradicionales) quedan conjuntos que se observan en
la figura 1-6.
El objetivo de las aplicaciones ricas de Internet es tomar las ventajas de los clien-
tes ricos y los clientes livianos para formar un conjunto nuevo que las englobe (fig. 1-7)

A B

Complicadas de Fáciles de
Distribuir y Actualizar Distribuir y Actualizar

Experiencia Rica para el Usuario Demoras y Esperas al Uso

Productividad del Programador Limitada Experiencia de Usuario

Respuesta Rápida al Usuario Complejo Desarrollo

Trabajo Fuera de Línea 100% En Línea

Aplicaciones Ricas Aplicaciones Web


(Escritorio) Antiguas

Fig. 1-6. Conjuntos A y B, características de las aplicaciones ricas y aplicaciones web.

7
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 8

Maximiliano R. Firtman

Aplicaciones Ricas
de Internet
A C B

Experiencia Rica para el Usuario Demoras y Esperas


al Uso
Complicadas de Fáciles de Distribuir y Actualizar
Distribuir y
Actualizar Productividad del Programador Limitada
Experiencia
Las Aplicaciones Ricas de Internet de Usuario
usan lo Mejor de los dos Mundos
No son
Multiplataforma Respuesta Rápida del Usuario Complejo
Desarrollo
Trabajo Fuera de Línea

Multiplataforma 100% En Línea

Aplicaciones Ricas Aplicaciones web


(Escritorio) Antiguas

Fig. 1-7. Conjuntos A, B y C.

Características

De esta forma, como se vio antes, las RIA, como se las suele conocer en forma abre-
viada, engloban las características siguientes:
• Experiencia rica del usuario. Implica hacer uso de nuevos conceptos en la
web, como controles ricos de ingreso (selectores de fecha, deslizadores, in-
greso de texto con formato), servicios de drag and drop y evitar demoras al
usuario en el uso del sitio web.
• Capacidad offline. Permite que una aplicación web siga funcionando aunque
se haya perdido conectividad con el servidor o con Internet. Por supuesto,
esto será posible en algunos casos; asimismo, si la conexión se retoma,
seguiría su uso normal (fig. 1-8).
• Productividad alta del desarrollador. ¡Enhorabuena! Se acordaron de
nosotros, y los entornos de trabajo y las herramientas para desarrollar aplica-
ciones web evolucionaron hasta encontrarse en la actualidad cercanas a la
productividad en una aplicación de escritorio. Tendremos capacidades drag
and drop, desarrollo rápido de aplicaciones, capacidad de debugging, refac-
toring y otras soluciones que permitirán el desarrollo de sitios web de manera
más eficiente.

8
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 9

AJAX. Web 2.0 para profesionales

Fig. 1-8. Google Spreadsheets al pasar a modo offline. Recordemos que sigue siendo una página
web.

• Respuesta. Se acabaron las esperas para el usuario, las aplicaciones web res-
ponden con rapidez y es posible interactuar con la aplicación aun cuando se
espera una respuesta del servidor.
• Flexibilidad. Los nuevos sitios web permiten una interfaz flexible con la posi-
bilidad de modificar la apariencia, el contenido y los servicios disponibles de
una manera sencilla y rápida.
• Fácil de distribuir y actualizar. Actualizar una aplicación RIA es tan simple
como publicar los nuevos archivos en el servidor. Incluso, hasta se podría ac-
tualizar con cientos de usuarios conectados.
• Fácil de administrar. No hay metodologías de instalación complejas, DLL ni
instaladores; asimismo, la complejidad de las metodologías de instalación no
es mucho mayor que la de cualquier aplicación web normal.

9
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 10

Maximiliano R. Firtman

El cliente adquiere un uso más intensivo, ahora no sólo sirve para pequeñas validacio-
nes. El browser también administrará el flujo de la aplicación, los módulos y la interac-
ción con el servidor. Todas las comunicaciones al servidor no serán invocadas en forma
directa por el clic del usuario, sino por el código de cliente. Estas peticiones al servidor
se harán detrás de escena, o sea, el usuario no será consciente de la petición, a no ser
que se active de manera explícita un cartel que indica Cargando (fig. 1-9).

Fig. 1-9. Modelo clásico vs. modelo de aplicación rica de Internet.

Tipos de aplicación
Hay dos tipos de aplicaciones ricas de Internet: las conocidas como full RIA y las RIA
embebidas.
Las primeras son aplicaciones en las que se utiliza por completo el nuevo modelo
RIA. Manejan una o dos direcciones (URL o unique resource location) para todo el sitio
web. Escapan al clásico concepto de página web, para convertirse en aplicación web.
Las RIA embebidas en realidad son una mezcla entre las aplicaciones clásicas y
las web 2.0. Siguen comportándose como páginas web normales, con hipervínculos
interconectados hasta llegar a un punto en el que, por funcionalidad, se convierten en
una RIA, mejorando la experiencia del usuario en ese punto (figs. 1-10 y 1-11).

10
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 11

AJAX. Web 2.0 para profesionales

Fig. 1-10. Una aplicación full RIA mantiene todo el sitio web bajo un mismo concepto y URL.

Fig. 1-11. GAP es un ejemplo de RIA embebido en el que recién al llegar al listado de productos se
encuentra disponible la posibilidad de trabajar con controles ricos en el canasto de compras.

11
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 12

Maximiliano R. Firtman

Ventajas

Las ventajas son muchas y algunas de ellas ya se mencionaron. La más importante es


la posibilidad de ofrecerle al usuario una experiencia más rica con el sitio web. Es fac-
tible ofrecer controles de trabajo y servicios nuevos, como la posibilidad de autoguar-
dar la información. ¿Quién no escribió alguna vez un e-mail durante 20 minutos para
que se cierre la página, se apague el equipo o al enviarlo el servidor indique que se
cerró la sesión y se debe empezar de nuevo? En el presente, con las aplicaciones ricas
de Internet, se puede ofrecer el servicio que hizo famoso a Microsoft Word, la posibi-
lidad de autoguardar lo que se va escribiendo cada algunos segundos.
También, se puede elegir la manera en que se desea realizar una acción en el sitio
web, mediante un clic en un vínculo, presionando un atajo de teclado o arrastrando y
soltando un objeto (fig. 1-12).

Fig. 1-12. En Google Calendar, aplicación RIA, es posible crear una cita nueva en nuestra agenda uti-
lizando el vínculo, el atajo de teclado Control-N, seleccionando el rango de horas en la grilla o hasta
enviando un e-mail con los datos.

12
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 13

AJAX. Web 2.0 para profesionales

Además, se redujo la transferencia de datos desde el servidor hacia el cliente, lo


que ahorra tiempo de carga de la página, cantidad de bytes transferidos y tiempo de
navegación total.
Es así que está comprobado que la tasa de conversión aumenta en grado nota-
ble cuando se trabaja con aplicaciones ricas. ¿A qué se llama tasa de conversión? Se
trata de una acción del usuario que implica un hito en el sitio web, por ejemplo, una sus-
cripción, una compra o el registro del usuario en el sitio web. Hasta se comenta a modo
de chiste (con su parte de verdad) que el usuario ahora tiene menos tiempo para arre-
pentirse.

Desventajas

Las desventajas de las RIA son menos conocidas que las ventajas, pero es importante
tenerlas presentes.

Capacidad de uso
El usuario hace por lo menos 10 años que navega por Internet y eso implica que sabe
cómo utilizar un sitio web 1.0 sin problemas. Sabe que debe ir haciendo clic en hiper-
vínculos, que debe esperar cada recarga, sabe completar un formulario con campos de
texto y listas de selección y está acostumbrado al famoso botón Enviar. Ahora bien,
¿sabrá utilizar el nuevo sitio web 2.0 enriquecido?
Es necesario hacer un estudio de capacidad de uso mucho más extensivo que
antes o, incluso, educar al usuario acerca de cómo utilizar la aplicación (fig. 1-13).

El botón Atrás del navegador


Todos conocemos el concepto de historial del navegador. Con cada clic se puede re-
troceder con el botón correspondiente, y volver de a una página. Sin embargo, ahora
ya no se halla la unidad página, sino que cada clic en realidad puede conllevar cual-
quier tipo de acción en el sitio o la aplicación web, como abrir un menú o borrar una
foto, y siempre nos encontramos en la misma página o URL si lo pensamos con el viejo
sistema de trabajo.
Es así que en los primeros sitios RIA el botón de atrás hacía salir al usuario de la
aplicación a pesar de que hubiera realizado 100 clics o más en la misma URL. Esto es
un problema pero, con ciertos recaudos, más adelante en el libro veremos cómo po-
demos solucionarlo.

2da Guerra de los browsers


Así como en la década de 1990 existió la guerra de los browsers entre Netscape e In-
ternet Explorer por la compatibilidad, este nuevo tipo de aplicaciones ricas trae la ver-
sión actualizada de la guerra, con Internet Explorer por un lado y los navegadores

13
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 14

Maximiliano R. Firtman

alternativos por otro (Firefox, Opera, Safari). Si bien algunas plataformas (como Flash
o Flex) son más compatibles entre navegadores, hay ciertas incompatibilidades de las
que tenemos que estar conscientes a la hora de desarrollar RIA.

Fig. 1-13. Algunos sitios web recurren a ayudas visuales para enseñar al usuario a utilizar la interfaz rica.

Indexación de buscadores
Una de las preguntas clásicas de un cliente, además del costo final del diseño de su
próxima página web, es: ¿cómo aparezco primero en los buscadores? La verdad es
que las aplicaciones ricas de Internet tienen cierto problema aquí y es un desafío para
los buscadores encontrarle una solución.
En general una aplicación rica presenta una sola URL y con un contenido inicial
(leído por el buscador). El contenido restante ya no son páginas aparte, sino que son
pequeñas zonas que se actualizan directamente en el cliente según la interacción del
usuario. Esto implica que el buscador sólo indexará la página inicial.
Esto se debe a que ahora los sitios web se convierten en aplicaciones y no en una
mera revista online.

14
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 15

AJAX. Web 2.0 para profesionales

Favoritos o marcadores
El uso de favoritos y marcadores se hizo muy común entre los usuarios y nos permite
agregar cualquier información que vemos a nuestra lista. Ahora bien, cuando ingresa-
mos de nuevo en ese favorito, pretendemos ver la misma información que teníamos en
pantalla cuando lo agregamos. ¿Pero si siempre es la misma URL?
Este problema también tiene consecuencias cuando queremos enviarle la direc-
ción de lo que vemos a un amigo por e-mail o mensajería instantánea. Nuestra intui-
ción de usuarios Web 1.0 indica que alcanza con copiar y pegar la dirección que vemos
en el navegador. En Web 2.0 parece que no, o por lo menos no al principio. Luego ve-
remos cómo se puede solucionar este problema con AJAX (fig. 1-14).

Fig. 1-14. Google Maps posee el vínculo Enlazar con esta página, que genera en el momento una
URL única con exactamente la vista actual en el mapa.

15
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 16

Maximiliano R. Firtman

Manejo de errores
Otra de las costumbres (malas, por cierto) que trajo la Web 1.0 fue recibir los errores
del servidor, 404 cuando la página no existe, 500 cuando el servidor tiene un problema
interno, etc. No obstante, si ahora las peticiones al servidor se hacen detrás de es-
cena, y los usuarios no ven su resultado directamente, ¿cómo se enteran de que se
produjo un error?
Ahí viene nuestro trabajo como programadores para capturar y actuar ante errores
que surjan en el servidor, que antes, feliz y lamentablemente, no podíamos manejar.

Complejidad de desarrollo
Por más que en la actualidad los entornos son más amigables y permiten mayor efi-
ciencia, la verdad es que desarrollar aplicaciones ricas lleva un trabajo extra respecto
de las aplicaciones tradicionales para la web. Son más complejas de depurar, mante-
ner y actualizar. Sin embargo, esto ha llevado a la aparición de herramientas cada vez
más poderosas en este sentido. En el próximo capítulo se analizarán muchas de estas
herramientas.

Plataformas disponibles

En los últimos tiempos surgieron muchas plataformas para la creación de RIA, incluso
muchos entornos que en realidad generan código para alguna de las plataformas clá-
sicas (como AJAX o Flash). A continuación se detallan las más utilizadas en el mer-
cado.

AJAX
En esta plataforma estará centrado el resto del libro. Es la única de las plataformas basada
en estándares y que no posee dueño. AJAX es la sigla de Asynchronous JavaScript And
Xml (JavaScript asincrónico con XML) y es un término creado en 2005 por Jesse James
Garret para darle un nombre al conjunto de técnicas al escribir un artículo. El término
se hizo muy conocido y logró imponerse en el mercado, mientras que el mismo Jesse,
que no es programador, declaró que nunca programó un sitio en Ajax pero que parti-
cipa de manera activa en proyectos web. El concepto creado por Jesse no era una
mera cuestión de JavaScript, era toda una nueva concepción en el desarrollo de apli-
caciones en Internet (fig. 1-15).
La verdad es que AJAX no es nuevo y antes se conocía con otros nombres, pero
no fue muy popular hasta que Google, gracias a sus excelentes servicios e interfaz, per-
mitió que se hiciera conocido entre los usuarios y los desarrolladores. Desde Internet
Explorer 5.0 (1999) Microsoft incorporó un objeto conocido como XMLHTTP que per-
mitía hacer lo que en ese momento se conoció como Remote Scripting, pero nadie le
vio el potencial hasta 6 años después. Sólo Microsoft lo utilizaba en su Outlook Web
Access, su versión web incluida con Exchange.

16
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 17

AJAX. Web 2.0 para profesionales

Fig. 1-15. Hasta hace pocos años una búsqueda acerca de AJAX sólo nos traía el equipo de fútbol
holandés o un jabón para lavar la ropa.

AJAX usa XHTML y CSS como lenguaje de estructura y diseño, JavaScript como
lenguaje de programación, el modelo DOM (Document Object Model) para trabajar con
la estructura del sitio y XML como uno de los formatos de transporte de datos desde
y hacia el servidor (aunque no el único). Un lenguaje de servidor aún es necesario (como
PHP, ASP o Java) para la lógica de servidor y el acceso a bases de datos.
Todos los servicios de Google, salvo pequeños usos de Flash, están desarrollados
bajo esta tecnología. Tanta fue la fe de Google en esta plataforma, que ha creado y
lanzado a la comunidad su plataforma de desarrollo para Java que crea automática-
mente el código AJAX necesario, conocido como Google Web Toolkit (GWT).
AJAX se hizo tan conocido, que los demás browsers, encabezados por Mozilla
Firefox, implementaron una versión clon del objeto XMLHTTP para que las aplicaciones
AJAX funcionen en todos ellos (para los lectores impacientes, ya entraremos en detalles).
El entorno se conoce tanto, que hasta navegadores instalados en teléfonos celu-
lares ya soportan esta plataforma. En la actualidad la W3C, organización encargada
de los estándares, trabaja en la estandarización formal de la plataforma.

Adobe Flash
Todos conocemos Flash. Banners, animaciones y sitios web enteros están desarrolla-
dos bajo esta tecnología. Incluso, de todas las tecnologías fuera de XHTML, Flash es
la más distribuida entre los browsers de todo el mundo.

17
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 18

Maximiliano R. Firtman

Macromedia, entonces dueña del producto, fue la creadora del concepto y de las
palabras Rich Internet Application con esta plataforma. El mayor inconveniente de re-
alizar aplicaciones RIA bajo Flash es que requiere buenas prácticas, creación de con-
troles web de cero (cajas de texto y otros controles ricos) y trabajar con código.
Hay muchos desarrolladores Flash que han creado sus propios frameworks de
trabajo para crear aplicaciones ricas fácilmente bajo esta plataforma, gracias a la po-
tencia y la flexibilidad del lenguaje. No obstante, Flash es un producto más asociado
al diseño y a la animación y siempre le costó entrar en el mundo de los programado-
res, a pesar de todos los esfuerzos realizados en el producto Flash Professional y en
el lenguaje ActionScript 2.0 por hacerlo más querido para los desarrolladores.
Macromedia, consciente de que le costaba llegar a este público, creó Flex, plata-
forma que en el presente es la recomendada por la empresa para la creación de apli-
caciones ricas.

Adobe Flex
Ahora ya producto de Adobe, Flex es una herramienta que permite generar aplica-
ciones RIA basadas en la plataforma Flash, pero con un entorno de trabajo y un mo-
delo pensados de manera específica para este tema y no para el mundo de la
animación.
Es así que Adobe Flex, que tomó fuerza recién a partir de la versión 2.0, contiene
más de 50 controles prearmados para los usos comunes de las aplicaciones RIA y di-
seño visual y drag and drop (fig. 1-16). Flex en realidad es el nombre de la tecnología,
y forman parte los productos siguientes:
• Flex Builder: entorno de desarrollo comercial basado en Eclipse.
• Flex SDK: compilador gratuito que toma el código fuente y lo convierte a SWF.
• Flex Data Services: servidor de aplicaciones basado en Java que provee ser-
vicios a las aplicaciones RIA desarrolladas en Flex. Posee una versión Express
gratuita y otra comercial.
• Flex Chart Components: componentes adicionales que generan gráficos es-
tadísticos (de barras, de torta, etc.) con una interfaz gráfica excelente.
Flex se basa en un lenguaje XML que define la interfaz gráfica y los compo-
nentes de forma declarativa, conocido como MXML, junto a un código en lenguaje
ActionScript 3.0. Este último deriva de ECMAScript (al igual que JavaScript) y en esta
versión se convirtió en un competidor digno de cualquier lenguaje orientado a obje-
tos; es estricto y posee todas las cualidades de un lenguaje como Java o C#. Estas
aplicaciones se compilan en archivos SWF (al igual que los de Flash) y requieren el
Flash Player 9 instalado en el browser.

18
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 19

AJAX. Web 2.0 para profesionales

Fig. 1-16. Flex Builder en acción; no sólo ayuda en la codificación, sino también en el diseño visual
de la aplicación.

Flex es sólo una herramienta de cliente y puede trabajar en dos modos: utilizando
Flex Data Services (un servidor de aplicaciones basado en Java) o contra cualquier
tecnología de servidor (p. ej., PHP, .NET o Java) por medio de servicios web o archi-
vos XML (fig. 1-17).
Adobe le pone mucha fuerza al producto, pero no lo quiere confrontar con AJAX,
sino que lo presenta como un complemento. Por ello, provee herramientas y clases
para interactuar desde AJAX hacia una aplicación Flex y al revés (Flex-Ajax Bridge);
incluso es posible hacer una aplicación AJAX que haga uso de servicios ofrecidos por
las clases del Flash Player, superiores a los aportados por el browser por sí solo. Esto
sin necesidad de hacer una interfaz visual en Flex.
Adobe también tiene su propia librería para AJAX, conocida como Adobe Spry
que forma parte integral de Dreamweaver CS3.

19
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:56 PM Página 20

Maximiliano R. Firtman

Fig. 1-17. Un ejemplo de RIA con Flex que permite comparar productos y agregarlos al canasto de
compras arrastrando y soltando.

OpenLaszlo
OpenLaszlo es una plataforma Open Source mantenida por la empresa Laszlo Sys-
tems, que genera aplicaciones RIA a partir de un lenguaje de marcado XML, conocido
como LZX y código ECMAScript compatible.
Hasta la versión 4, este producto compilaba directamente para la plataforma
Flash, como Flex pero, a partir de la versión 4 compila, a decisión del programador, a
Flash o DHTML (o sea, una aplicación AJAX). También será posible, según un proyecto
activo, compilar aplicaciones RIA para teléfonos celulares.
Es un proyecto interesante, con mucho potencial y se pueden desarrollar aplicacio-
nes RIA con mucha flexibilidad. Por el momento, el único entorno que hay es un plugin
para Eclipse, llamado IDE4Laszlo, que no tiene herramientas de diseño visual ni drag
and drop; tampoco presenta ayuda en la codificación, lo que dificulta un poco su uso.
OpenLaszlo puede trabajar en una modalidad conocida como S.O.L.O. contra un ser-
vidor PHP, ASP, .NET u otro a través de servicios web o XML, o en modalidad servidor por
un servidor de aplicaciones Java, que agrega otras posibilidades de conexión (fig. 1-18).

20
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 21

AJAX. Web 2.0 para profesionales

Fig. 1-18. Aplicación completa realizada en OpenLaszlo con su código fuente disponible. Hay versio-
nes iguales bajo Flash y bajo AJAX con la misma funcionalidad.

Microsoft Silverlight
Microsoft llegó un poco tarde al mundo de las RIA, pero no por eso podemos desme-
recer su plataforma. Junto con el lanzamiento de su sistema operativo Windows Vista,
Microsoft lanzó un subsistema (compatible también con XP y 2003) llamado Windows
Presentation Foundation (WPF). Es un modelo nuevo de desarrollo de aplicaciones de
escritorio basado en un lenguaje de marcado conocido como XAML (se lee zamel) y
código .NET.
Al momento de escribir este libro, Microsoft recién lanzaba al mercado la tecnolo-
gía Silverlight, que equivale a la mencionada antes, pero pensada para la web. Esto im-
plica la presencia de un plugin para los browsers más conocidos (IE y Firefox incluidos)
que permita correr este tipo de aplicaciones (algo similar al Flash Player). Este player in-

21
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 22

Maximiliano R. Firtman

cluye una versión reducida del .NET Framework y permite crear aplicaciones interac-
tivas vectoriales en 2D y 3D utilizando JavaScript (u otro lenguaje de cliente como
VBScript).
Dado que emplea el mismo motor JavaScript provisto por el browser, Silverlight
no genera ningún adicional a lo que provee AJAX. O sea, utiliza el mismo modelo de
AJAX, sólo que agrega un formato y un sistema de manejo gráfico y de interfaz nue-
vos (fig. 1-19).

Fig. 1-19. Uno de los editores XAML oficial de Microsoft, Expression Blend.

Java Webstart
Si bien existe hace tiempo, la posibilidad de crear aplicaciones de Internet con el uso
de Java del lado del cliente ha quedado muy relegada luego del lanzamiento de Flash.
Java Webstart permite generar aplicaciones de Internet del mismo modo que si fueran
de escritorio. Éstas requieren tener instalada la Java Virtual Machine en el equipo del
cliente y pueden ser invocadas desde un vínculo en una página web.
Estas aplicaciones son autoactualizables y descargan los módulos que necesitan
antes de ejecutarse.
Quienes se quieran dedicar a más de una plataforma RIA tienen una gran ventaja:
hay muchos puntos en común. La mayoría usa un lenguaje derivado de ECMAScript y
un lenguaje declarativo XML similar.

22
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 23

AJAX. Web 2.0 para profesionales

Fig. 1-20. En una aplicación RIA el usuario puede mantener actividad constante con el sitio web.

El sentido de la web
No hay que creer que la Web 2.0 es sólo AJAX. Está naciendo un concepto nuevo para
la web y se relaciona con el sentido o el significado del contenido. Relacionado con el
nuevo concepto de diseño separado en capas, aparecen los conceptos que se men-
cionarán a continuación. No se profundizará en demasiados detalles técnicos, más
que los necesarios para entender el concepto y comenzar a aplicarlos en nuestros de-
sarrollos AJAX.

La Web semántica

La web semántica es el concepto más fuerte en este sentido y el objetivo es que la in-
formación en la web posea metadatos acerca del significado de los datos que se mues-
tran. Esto implica incluir información adicional en los sitios web, que no será vista por
el usuario y que se expresará en un lenguaje formal (p. ej., basado en un esquema
XML) que pueda ser estandarizado y comprendido por herramientas automatizadas,
como un motor de búsqueda (fig. 1-21).
Es así que cuando indiquemos en un motor de búsqueda pintores europeos del
siglo XVII, éste podrá comprender el argumento temporal que buscamos (siglo XVII), el
argumento geográfico (Europa) y la categoría (pintores), y así encontrar sitios web rela-
cionados sin necesidad de que incluyan las palabras buscadas. Nuestros sitios deberán
indicar, en estos lenguajes formalmente definidos, la información para que esto suceda.

23
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 24

Maximiliano R. Firtman

Fig. 1-21. Nuestro diagrama al concepto de Web semántica.

Incluso será de utilidad para identificar precios, categorías, marcas y demás in-
formación parametrizada de los productos a la venta en un sitio de e-commerce, para
utilizar búsquedas cruzadas, como hace www.froggle.com, un servicio de Google que
intenta emular una web semántica trabajando con la web clásica.
En este modelo, los formatos que se estandarizan son RDF (Resource Description
Framework) y OWL (Web Ontology Language), que añaden características adicionales.
En la web encontraremos mucha información y ejemplos del uso de este concepto nuevo.
Se espera una madurez de la web semántica para los próximos años y su asen-
tamiento sería la base de la ya proclamada Web 3.0.

Microformats
Incluso, bajo el concepto de la web semántica se puede hablar también de los mi-
croformats. Básicamente, la idea es generar formatos de contenido con el XHTML vá-
lido en la actualidad utilizando las propiedades del lenguaje, como pueden ser class,
rel o rev.
Por ejemplo, el famoso formato para administración de contactos de una agenda
vCard tiene su versión en microformato, que equivaldría a algo similar a esto:

<div class=”vcard”>
<div class=”fn”>Maximiliano R. Firtman</div>
<div class=”org”>ITMaster</div>
<div class=”tel”>111-555-1234</div>
<a class=”url” href=”http://www.itmaster.es”>http://www.itmaster.es</a>
</div>

24
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 25

AJAX. Web 2.0 para profesionales

Esta información podría detectarse de manera automática e incorporarse, por


ejemplo, en la agenda del equipo o de un teléfono celular. Éste es un concepto toda-
vía no muy utilizado, pero es bueno tenerlo en mente.

Web mashups

Junto con todos los conceptos que estamos comentando aparecen las web mashups,
algo así como una web mezcla que básicamente implica el concepto de sitios web que
no tienen contenido por sí solos, sino que son mezcla de otros. Reciben información
desde distintas fuentes a través de RSS, servicios web y API abiertas.
En general, el usuario decide qué y cómo quiere ver, como una forma de centra-
lizar información de distintas fuentes y verlas bajo un mismo concepto (fig. 1-22).

Fig. 1-22. Netvibes es un sitio que permite recibir información y servicios de variados orígenes de
datos desde una misma interfaz web.

25
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 26

Maximiliano R. Firtman

En www.webmashup.com hay un catálogo completo de sitios de esta índole. In-


cluso servicios abiertos, como Google Maps o Yahoo Maps, permitieron que surjan
miles de sitios web que toman información de un origen (p. ej., de tráfico, venta de in-
muebles) y la vuelquen sobre los mapas de los sitios mencionados antes, todo sin que
estos sitios sean origen de ninguno de los servicios. No obstante, por medio de la
mezcla permiten crear un servicio nuevo que antes no existía. Un buen ejemplo es go-
oglemapsmania.blogspot.com encontraremos muchos de estos sitios, la mayoría de
ellos bajo tecnología AJAX (fig. 1-23).

Fig. 1-23. BeerMaping es un ejemplo en el que se muestra sobre Google Maps dónde se puede ir a
tomar una buena cerveza en distintos lugares del mundo.

Web services y API

Otro punto para Google. Cuando comenzó la ola de la Web 2.0, fue el primero en ofre-
cer una interfaz de aplicación, una API, abierta y gratuita para que cualquier usuario pu-
diera conectarse con sus servicios, ya sea de búsqueda, mapas o noticias. En el

26
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 27

AJAX. Web 2.0 para profesionales

presente tiene más de 20 API disponibles, incluidas AdWords, AdSense y Hojas de


Cálculo, en las que es factible acceder a las hojas almacenadas de un usuario para
leer y escribir información. De esta forma, es posible crear un servicio nuevo montado
en los servicios de terceros.
Servicios web es uno de los estándares en este aspecto que involucra dos siste-
mas desarrollados en cualquier lenguaje (.NET, Java, PHP, etc.) que quieren comuni-
carse datos e invocar servicios remotos transfiriendo objetos que se convierten en
nativos en el receptor, no importa la plataforma origen. Esto se logra gracias al formato
SOAP, basado en XML.
API es un nombre más genérico que permite la interconexión entre sistemas bajo
cualquier protocolo. En el mundo de la web se hicieron famosas las peticiones vía con-
ceptos de AJAX, los servicios web e incluso el formato RSS de publicación de nove-
dades. Este último es el más rudimentario de todos.
Algunos ejemplos de las empresas web grandes que ofrecen sus API abiertas son Yahoo
(developer.yahoo.com), Google (code.google.com/apis), Microsoft Live
(msdn.microsoft.com/live) y Amazon (aws.amazon.com).

Red social
Uno de los fenómenos de la Web 2.0 es la revolución social adquirida por medio de los
nuevos servicios en colaboración de la red. Si bien no son parte del aspecto técnico
de una aplicación AJAX, por ejemplo, es importante conocer la terminología utilizada,
ya que es parte del mundo Web 2.0. Hay cientos de términos nuevos aplicados a este
mundo, pero vamos a abocarnos a los más difundidos.
La colaboración entre todos los usuarios de la red es parte fundamental de este
hecho y es así que surgieron miles de sitios que ofrecen nuevos servicios en colabo-
ración, que comparten fotos, favoritos, RSS, blogs y música.

Etiquetado

Uno de los pilares de este trabajo es el llamado folksonomy que, sin intentar encontrarle
una traducción, implica la categorización mediante etiquetas (tags) de información,
webs, imágenes, videos y todo tipo de contenido.
Basados en estas etiquetas o tags, surgieron las nubes de etiquetas (tag clouds)
o etiquetas por peso, que es una lista de tags con tamaños de tipografía distintos según
la importancia o la cantidad de veces que aparece cada una. El precursor de este mo-
delo fue Flikr y luego lo copiaron miles de sitios web (fig. 1-24).

27
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 28

Maximiliano R. Firtman

Fig. 1-24. Temáticas más consultadas en un foro de discusión a través de una nube de etiquetas.

Modelos

Blogs y derivados
Técnicamente un blog o weblog no es más que una base de datos de artículos orde-
nados de manera cronológica en modo inverso. Lo que los hizo tan famosos fue la fa-
cilidad de uso para un usuario normal que no tiene idea alguna de diseño web, HTML
o alojamiento web. Equivale a una bitácora o diario personal donde el dueño ingresa
texto, adjuntos y links, y otros usuarios pueden dejar comentarios.
A partir de los blogs se hizo conocido el formato RSS como solución al problema
de no saber cada cuánto el dueño actualiza su blog. Por ello, se difundió este formato
que a la vista del usuario avisa cuándo un sitio publica algo nuevo. Sobre este servicio
luego aparecieron los podcast y videocast que equivalen a programas de radio y TV
creados por personas independientes desde sus casas, fomentando un concepto
nuevo de web creada por los usuarios independientes y no sólo por grandes produc-
tores de contenido.
A partir del éxito de los blogs, aparecieron los flogs o fotologs donde los usuarios
suben a diario fotos de su vida a la web o desde el celular, así como los videologs con
el mismo concepto aplicado al contenido multimedia.

28
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 29

AJAX. Web 2.0 para profesionales

Wikis
Un wiki es un sitio web que permite que sus propios usuarios editen, agreguen y eli-
minen su contenido. Por lo general estos sitios no requieren un registro por parte del
usuario y se basan en la misma comunidad para que no permita abusos al cambiar in-
formación. Es el máximo exponente de una autoría en colaboración, donde todos son
autores del contenido (fig. 1-25).

Fig. 1-25. Wikipedia es lo máximo en concepto de wikis, ya que es una encliclopedia en varios idio-
mas completamente creada y actualizada por los usuarios.

Incluso los wikis son creados y diseñados con el mismo formato y estilo CSS para
lograr uniformidad en su manejo y visualización. En muchos de ellos se guarda todo el
historial de versiones del contenido, por si es necesario volver atrás por algún acto de
vandalismo.

29
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 30

Maximiliano R. Firtman

Comunidades
A partir de estos modelos surgieron miles de sitios web que tienen como objeto la co-
laboración y la publicación de contenido por parte de los usuarios, desde sus equipos
de escritorio y hasta desde sus teléfonos móviles.
YouTube fue el más famoso de todos ellos al ser adquirido por Google, y no es
más que un sitio de publicación gratuita de videos caseros etiquetados por los propios
usuarios. Simple y muy efectivo.
YouTube fue creado por tres jóvenes y en menos de un año fue declarado invento
del Año 2006 por la revista TIME. A fines de ese año fue adquirido por Google por la
suma de 1.650 millones de dólares luego de 21 meses de vida.
Esto habla mucho de qué es Web 2.0 y por qué la nueva red social que surgió
tiene tanta importancia en nuestro trabajo como desarrolladores. No debemos quedar
ajenos a este concepto nuevo.

Interoperabilidad

La interoperabilidad entre los sitios comunitarios se volvió muy común y, si vamos a de-
sarrollar un sitio Web 2.0, debemos tenerlo en cuenta.

LinkBack
Un LinkBack es un acuse de recibo que le llega al dueño de un sitio web o blog cuando
otro hace un link a él. Se ha hecho muy común en el mundo de los sitios comunitarios.
Para ello se crearon tres subformatos: RefBack, TrackBack y PingBack.
Los RefBack son los más simples, e implican incluir un hipervínculo hacia el sitio
original desde donde se obtuvo la información. El sitio receptor deberá utilizar la ca-
becera HTTP para reconocer que se trata de un LinkBack.
Los TrackBack son básicamente dos scripts estándar en el emisor y el receptor.
Cuando un usuario quiere declarar que obtuvo información de otro sitio, ingresa su
URL en un sistema de TrackBack y este último le informa por una petición POST al
servidor original que deberá tener un script preparado para recibir esa información.
Los PingBack se parecen a los RefBack, dado que implican un hipervínculo hacia
el sitio original, pero requieren la instalación de un script en ambos sitios que tienen una
comunicación para confirmar el LinkBack y evitar posibles SPAM o links ficticios.

Redes de favoritos
Es común encontrar en muchos sitios web varios links con distintos íconos de colores
que permiten agregar nuestro sitio web a distintas redes de favoritos comunitarios. Las
más utilizadas son: Digg, del.icio.us, Technorati, Furl y Meneame (en español).

30
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 31

AJAX. Web 2.0 para profesionales

Dentro de cada sitio encontraremos detalles de cómo generar un botón para agre-
gar nuestro sitio a alguna de esas redes. Si los usuarios nos agregan a éstas podrán
sernos de utilidad para mejorar nuestra posición en los motores de búsqueda.
Si además queremos que nuestro sitio forme parte de algún sitio web mashup, debe-
mos ofrecer contenido para publicación (o sindicación) en distintos formatos, entre ellos
RSS y Atom. Éstos son formatos basados en XML que estandarizan las noticias de nues-
tro sitio web, y luego éstas son leídas automáticamente por los browsers o lectores de RSS.
A continuación se observa un ejemplo de archivo RSS de noticias.

<?xml version=”1.0” encoding=”iso-8859-1”?>

<rss version=”2.0”>
<channel>
<title><![CDATA[ELPAIS.com - RSS - Última Hora]]></title>
<link><![CDATA[http://www.elpais.com/loultimo/]]></link>
<description><![CDATA[ELPAIS.com - RSS - Última Hora]]></description>
<language>es-es</language>
<image>
<url>http://www.elpais.com/im/tit_logo.gif</url>
<title>ELPAIS.com - RSS - Última Hora</title>
<link>http://www.elpais.com</link>
</image>

<item>
<title><![CDATA[Paisley y el Sinn Fein avanzan claramente en las eleccio-
nes del Ulster]]></title>

<link><![CDATA[http://www.elpais.com/articulo/internacional/Paisley/Sinn/Fein/avan
zan/claramente/elecciones/Ulster/elpepuint/20070509elpepuint_4/Tes]]></link>

<description><![CDATA[El Partido Democrático Unionista de Ian Paisley, y


el Sinn Fein, brazo político del IRA, están igualados a 20 escaños cuando se han
adjudicado 53 de los 108 que componen la Asamblea legislativa norirlandesa. Las dos
formaciones confirman los pronósticos y ganan terreno con respecto a las pasadas
elecciones. De momento, el recuento está suspendido. Se retomará mañana a las 9
horas aunque los resultados definitivos no se conocerán hasta después del medio-
día.]]></description>
<author><![CDATA[AGENCIAS <elpais@elpais.com>]]></author>
<pubDate><![CDATA[Fri, 9 May 2007 01:58:00 +0100]]></pubDate>
</item>

...

</channel>
</rss>

31
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 32

Maximiliano R. Firtman

En la figura 1-26 se observa un RSS como el anterior.


Algunos sitios mashups permiten generar formatos más avanzados, por lo gene-
ral basados en XML y JavaScript.

Fig. 1-26. Así muestra el Internet Explorer 7.0 un RSS como el que se ve antes. Al suscribirnos, ante
cualquier nueva noticia nos avisará con un alerta.

Gadgets y Widgets
Por último, vamos a analizar un nuevo concepto que comenzó a aparecer también junto
con la Web 2.0 y tiene a los desarrolladores como la base de su trabajo. Algunas em-
presas los llaman Widgets (como Yahoo! y Mac OS X) y otras Gadgets (como Google
y Microsoft). Son aplicaciones pequeñas (ejecutables o web) que se pueden incluir en
el escritorio de nuestro equipo o en la página principal de un sitio web.
Ejemplos de sitios web donde podemos incluir este tipo de aplicaciones son la pá-
gina personalizada de Google (www.google.com/ig) o Netvibes.com. En la mayoría de
los casos constan de un archivo de configuración XML, una página XHTML y código
JavaScript utilizando técnicas AJAX (fig. 1-27).

32
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 33

AJAX. Web 2.0 para profesionales

Fig. 1-27. Página personalizada de Google donde es posible insertar sitios RSS y Gadgets creados
por programadores independientes que ofrecen distintos servicios.

Estándares
El nuevo modelo de trabajo

Sí, amigos. Lamento informarles que deberán dejar de trabajar como lo hacían hasta
la actualidad. A partir de ahora se hará necesario utilizar los últimos estándares y se-
parar el trabajo en capas y archivos distintos. El esfuerzo vale la pena y ganaremos en
menos trabajo duplicado y facilidad de uso, desarrollo y modificación en el futuro.

XHTML
HTML era (nótese el uso de pasado en el verbo) un lenguaje muy caótico. Usábamos
etiquetas y propiedades que no eran compatibles con todos los browsers y podíamos

33
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 34

Maximiliano R. Firtman

olvidarnos de cerrar una etiqueta que nada grave sucedía. Esto nos llevaba a trabajar
de forma muy desprolija y a no poder realizar pruebas de calidad sobre nuestros de-
sarrollos.
Por ello surgió XHTML, la versión estricta de HTML. Si bien por el momento se pa-
recen bastante, en versiones futuras comenzarán a diferir, por lo que es conveniente ir
acostumbrándose.
Para empezar, XHTML es estricto. Etiquetas y propiedades deben escribirse en mi-
núscula y sus valores, encerrarse entre comillas. Toda etiqueta debe cerrarse, incluso
la que parece no tener cierre, como <br>. De allí la existencia de <br />, una versión
que cierra la etiqueta en la apertura.
La verdad es que usar <br/> alcanza (nótese que no tiene un espacio antes de la
barra). No obstante, para hacer que el código sea compatible con navegadores muy an-
tiguos que no reconocen XHTML, se puede agregar el espacio.
Usar XHTML permite trabajar con estándares, atenerse a ellos y realizar páginas
más simples, con código más legible y la posibilidad de verificar la validez del mismo.
Incluso deberían dejar de utilizarse las etiquetas FONT, B, I, y otras de formato,
aunque cueste hacerlo. En los capítulos siguientes se profundizará en el tema de
XHTML.

CSS
Todos conocen las hojas de estilo en cascada o CSS, pero no todos saben usarlas
como corresponde a la Web 2.0. Las CSS son un método que surgió para definir el es-
tilo visual de los elementos en un documento XML o derivado.
Comenzaron a hacerse conocidas en el mundo del diseño web porque brindaban una
solución para eliminar los subrayados de los links; toda una novedad para la época. Sin em-
bargo, las CSS son mucho más potentes que eso; no sólo permiten definir el estilo visual
de los elementos en un documento, sino también su disposición (layout) dentro de él.
Es así que desde los comienzos de la Web 2.0 se habla del diseño sin tablas, o
table-less, una metodología que permite diseñar toda una página web por medio de DIV
y CSS que indican la disposición de los elementos en la página. A todos los que dise-
ñaron con tablas por muchos años les cuesta acostumbrarse, pero una vez que se
comprende por completo el sistema, se advierten los beneficios y la simplicidad que
se logran (fig. 1-28).
En aplicaciones AJAX, CSS se torna fundamental para reducir el tráfico al servi-
dor (al no transmitir etiquetas de formato) y para lograr efectos, diseños y ocultamiento
de módulos en la página web. Es muy recomendable profundizar en el mundo de CSS
para trabajar con más comodidad en aplicaciones AJAX.

34
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 35

AJAX. Web 2.0 para profesionales

Elemento HTML XHTML+CSS

Tablas 30Kb 0Kb!

GIFs Espaciadores 12Kb 0Kb!

Peso de página 38Kb 28kb


HTML

TOTAL: 28Kb

Fig. 1-28. Una página web con tablas que ocupa 80 Kb se reduce a menos de 30 Kb cuando se la di-
seña con CSS.

JavaScript
Si bien hubo intentos de destronar este lenguaje en el lado del cliente, como el caso de
VBScript en Internet Explorer, lo cierto es que JavaScript se convirtió en el lenguaje de
script predilecto para muchos aspectos, entre ellos la ejecución de código en el browser.
Su uso en aplicaciones AJAX aumentó en grado notable el conocimiento que los
desarrolladores web teníamos de este lenguaje y que, en las próximas páginas, abor-
daremos con mayor detenimiento.
Convertido en el estándar ECMAScript, promete seguir evolucionando, como lo
hizo ActionScript 3.0, derivado del lenguaje (fig. 1-29).

Fig. 1-29. Árbol genealógico del lenguaje JavaScript hasta el presente.

35
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 36

Maximiliano R. Firtman

XML
Este metalenguaje se convirtió en el estándar de transmisión de información estructu-
rada en la web. Las aplicaciones AJAX lo usarán mucho, ya sea mediante la aplicación
de sus conceptos al trabajar con el Document Object Model (DOM), la transmisión de
información desde y hacia el servidor o el almacenamiento de datos.
Un archivo XML no es más que un archivo de texto con una sintaxis y una es-
tructura predefinidas, que se puede validar y recorrer por medio de distintos métodos.
Los servicios web que permiten interconectar sistemas en la web usan a XML de fondo,
y éste es un tema fundamental que todo desarrollador de aplicaciones ricas debe co-
nocer a fondo.

Separación en capas

Hasta el presente una página web constaba de un archivo HTML que contenía:
• La estructura del documento.
• Información acerca del documento (Meta Data).
• Diseño gráfico del documento.
• Datos e información que debe mostrar.
• Código de cliente a ejecutar.
Todo mezclado dentro del código HTML y sin ninguna estructura fácil de com-
prender. Para ejemplificarlo, en el siguiente código fuente HTML de una página web 1.0,
¿dónde está el precio del producto? ¿Podemos automatizar de alguna forma la ex-
tracción de ese precio? ¿Y cuál es el título principal de la página?

Producto.htm
<table width=”457” border=”0” cellspacing=”0” cellpadding=”0” align=”center”>
<tr> <td><font color=”red”>GUIA PARA HACERSE RICO SIN CANCELAR SUS TARJETAS DE
CREDITO</font></td>
</tr>
<tr><td height=”15”> <hr size=”1” width=”457” class=”linkschicos”
noshade></td></tr></table>
<table width=”457” border=”0” cellspacing=”0” cellpadding=”0”>
<tr>
<td width=”100” valign=”top”><img src=”/covers/98/70/40/61/22.gif” border=0></td>
<td width=”7”>&nbsp;</td>
<td width=”340” valign=”top”>
<table width=”340” border=”0” cellspacing=”0” cellpadding=”0” align=”center”>
<tr><td width=”203” valign=”top” class=”textos”>ISBN 9870406122<br>
Autor KIYOSAKI ROBERT T.<br>

36
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 37

AJAX. Web 2.0 para profesionales

LECHTER SHARON L.<br>


Editorial AGUILAR<br>
Peso 0,15 Kg.Edici&oacute;n 2007,en R&uacute;stica<br>
136 p&aacute;ginas<br>
<b>Idioma Espa&ntilde;ol</b></span></td>
<td width=”7” valign=”top”>&nbsp;</td>
<td width=”120” valign=”top” align=”center”>
<table width=”130” border=”0” cellpadding=”2” cellspacing=”0”>
<tr> <td align=”center”><img src=”/img/varias/1x1_transp.gif” width=”10”
height=”4”></td></tr>
<tr> <td align=”center”>
<table width=”90” border=”0” cellspacing=”0” cellpadding=”2” bgcolor=”#CED6EF”>
<tr align=”center”> <td width=”50%” class=”preciolibro”>
<table width=”88” border=”0” cellspacing=”0” cellpadding=”0” bgcolor=”#FFFFFF”>
<tr> <td class=”preciolibro” align=”center”>$ 27,00</td>
</tr></table>
</td></tr>
</table>

Ahora comparémoslo con el código siguiente separado en tres archivos que re-
flejaría un sitio web muy similar al anterior. Rápidamente notaremos el cambio.

Producto.htm
<div id=”contenedor”>
<h1>Libros Recomendados</h1>

<div id=”libro”>
<div id=”titulo”>

</div>

<div id=”otrosDatos”>

</div>

<div id=”precio”>

</div>
</div>

</div>

37
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 38

Maximiliano R. Firtman

Producto.xml
<producto>
<titulo>

GUIA PARA HACERSE RICO SIN CANCELAR SUS TARJETAS DE CREDITO

</titulo>
<precio>$27,00</precio>
<isbn>9870406122</isbn>
<autores>

<autor>KIYOSAKI ROBERT T.</autor>

<autor>LECHTER SHARON L.</autor>

</autores>

</producto>

Producto.css

body,#contenedor,div {
padding: 0px; margin: 0px;
}
#contenedor {
width: 457;
}
h1 {
color: red;
font-family: Arial;
font-size: 15px;
}
#precio {
text-align: center;
float: left;
width: 50%;
}
#otrosDatos {
font-size: small;
float: right;
width: 50%;
}

38
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 39

AJAX. Web 2.0 para profesionales

Por la etiqueta XHTML estándar h1 se sabe con claridad cuál es el título, y me-
diante los datos en XML es muy sencillo trabajar con ellos para separar el precio o
cualquier otro dato. Estamos usando XHTML para definir la estructura jerárquica del
sitio y no su disposición o su diseño.
Esto es la base de la separación en capas. A partir de ahora, nuestro proyecto
web deberá separarse en capas de manera correcta lo que nos dará grandes ventajas,
entre ellas:
• Facilidad de actualización y modificación de datos, diseño y estructura.
• Reutilización de código al máximo.
• Reducción del tamaño de los archivos, con el aumento consecuente de la ve-
locidad.
• Simplicidad en el código fuente.
• Mejora del rendimiento de indexación en los buscadores.
• Excelente disponibilidad para trabajar en equipo.
En el esquema de la figura 1-30 se observa cómo podría quedar ahora nuestro
sitio web separado en capas.
Incluso el código JavaScript que se verá más adelante también se separará en capas,
pero no nos adelantemos. Empecemos primero con nuestro primer proyecto AJAX.

Fig. 1-30. Es preciso acostumbrarse a trabajar separando el diseño y la disposición de la estructura


y el código.

39
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 40

Maximiliano R. Firtman

Concepto AJAX Flash Flex Laszlo Silverlight Java

Lenguaje XHTML Ninguno MXML LZX XAML Ninguno


declarativo

Lenguaje de JavaScript ActionScript ActionScript JavaScript JavaScript Java


script y .net

Requerimientos Objeto Flash Flash Player Flash Silverlight Java Virtual


en el browser XMLHTTP Player 6+ 9+ Player 7+ o Player y Objeto Machine
XMLHTTP XMLHTTP

Porcentaje de
penetración en 98% 98% 65% 90% 1% 86%
los browsers a
inicios de 2007

IDE Ninguno Flash Flex Builder IDE4Laszlo Expression NetBeans/


propio Professional Blend Eclipse

Entorno visual No posee Bueno Muy bueno Regular Muy bueno Bueno

Facilidad de
desarrollo Baja Baja Alta Media Media Media
rápido

Propietario Estándar Adobe Adobe / Laszlo / Microsoft Sun /


compatible Open Source Open Source Open Source

Simplicidad
para el usuario Excelente Buena Buena Buena Regular Regular
actual

Simplicidad para
el desarrollador Excelente Regular Buena Buena Buena Regular
JavaScript
actual

Integración con
desarrollos Muy buena Regular Buena Buena Buena Sin integración
Web 1.0

Requerimientos
de servidor Ninguno Ninguno Flex Data Laszlo Server Ninguno Java Server
Services (para algunas
(para algunas funciones)
funciones)

40
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 41

AJAX. Web 2.0 para profesionales

Concepto AJAX Flash Flex Laszlo Silverlight Java

Formato de XML / Texto / XML / Texto / XML XML / Texto XML / Texto / Cualquiera
datos JSON Binario JSON

Protocolos HTTP HTTP / AMF HTTP / AMF HTTP HTTP HTTP

Acceso a Web No Limitada Sí (sólo con Sí (sólo con No Sí


Services servidor) servidor)

Acceso a
servidores de No Bajo permisos Bajo permisos No No Sí
terceros
directamente

Acceso a objetos
remotos No No Java Java No Java

Experiencia en Muy buena Buena Regular Regular Ninguna Muy bajo


el mercado RIA

Acceso a
ejemplos Excelente Bueno Muy bueno Regular Regular Bueno
y librerías

Tecnología de
servidor con la Cualquiera (PHP / ASP / .NET / Java) Java
que trabaja
Cuadro 1-3. Cuadro comparativo entre plataformas RIA

En el próximo capítulo se comenzará a analizar en qué consiste técnicamente


AJAX y el objeto XMLHttpRequest con los primeros ejemplos sencillos.

41
C01.qxd:Project Ajax4.1.qxd 10/18/07 7:57 PM Página 42
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 43

Comenzando con AJAX


2
Herramientas
Para el desarrollo de aplicaciones web en AJAX necesitaremos cambiar un poco nues-
tros hábitos como desarrolladores web. Lo más probable es que estemos acostum-
brados a entornos como Adobe Dreamweaver o incluso a utilizar algún editor de texto
(como EditPlus o Notepad++) y a probar nuestros sitios en Internet Explorer.
No es que ahora no podemos seguir con esta metodología, pero la complejidad
de las aplicaciones que desarrollaremos hace que necesitemos mayor cantidad de he-
rramientas que nos ayuden en el trabajo. Veamos algunas de ellas.

Entorno de trabajo

Adobe Dreamweaver
No es que las herramientas clásicas de desarrollo, como Dreamweaver, ya no nos sean
de utilidad. Por lo menos hasta la versión CS3 del producto la ayuda que nos puede
proporcionar en la codificación de JavaScript es insuficiente, incluso también para có-
digo de servidor se torna algo rudimentario.
Esto no significa que no necesitemos dicho software, de hecho para diseño
XHTML con CSS de nuestra aplicación, seguramente sigamos precisando esta herra-
mienta excelente (fig. 2-1).

Microsoft Expression Web


Siguiendo con la línea de Dreamweaver, esta nueva herramienta de Microsoft permite
generar los sitios web XHTML con CSS de una forma simple y con un entorno similar
a los que nos tiene acostumbrados Microsoft.

43
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 44

Maximiliano R. Firtman

Fig. 2-1. Seguiremos utilizando Dreamweaver para el diseño, la disposición y la arquitectura del sitio
web.

Si trabajamos con ASP.NET del lado del servidor, este entorno ayudará con la
parte de diseño del sitio web (fig. 2-2).

JSEclipse
Aquí llegamos a la primera herramienta específicamente preparada para aplicaciones
AJAX. Se recomienda el uso de esta herramienta, todavía desconocida para la mayo-
ría de los desarrolladores web.
Eclipse es un entorno integrado gratuito creado para el desarrollo de aplicaciones
Java y luego liberado para la creación de cualquier tipo de aplicación por medio de un
sistema de plugins. Es así que ahora es posible desarrollar aplicaciones en C++, PHP,
Flex, Laszlo y muchos otros.
JSEclipse es un plugin, gratuito al momento de escribir este libro, propiedad de
Adobe, luego de que esta empresa adquiriera Interakt, empresa creadora del producto.
Este plugin permite tener uno de los primeros entornos creados de manera espe-
cífica para desarrollar aplicaciones bajo JavaScript, y soporta la mayoría de las libre-
rías de AJAX disponibles en el mercado.

44
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 45

AJAX. Web 2.0 para profesionales

Fig. 2-2. Expression Web es una alternativa propuesta por Microsoft para el diseño del sitio web con
XHTML y CSS.

Entre las características que posee se pueden mencionar:


• Compleción de código en objetos y nombres de variables.
• Atajos de teclado específicos de JavaScript.
• Revisión automática de sintaxis y errores mientras se codifica.
• Navegación rápida por funciones.
• Ayuda al estilo JavaDoc sobre el código JS de terceros e incluso sobre nuestro
código si se comenta utilizando el estándar JsDoc.
• Soporte para las librerías de AJAX: Dojo, Prototype, Yahoo UI!, Quooxdoo y li-
brerías propias.

45
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 46

Maximiliano R. Firtman

En el momento de escribir este libro, Eclipse puede descargarse en forma gratuita


desde www.eclipse.org, y JSEclipse desde labs.adobe.com/technologies/jseclipse.
Es posible que en el futuro sea parte de los productos finalizados de Adobe (fig. 2-3).

Fig. 2-3. JSEclipse se tornará fundamental para ayudarnos a desarrollar aplicaciones AJAX dadas sus
características propias de un IDE.

Eclipse no requiere instalación y sólo es necesario descomprimir el ZIP en una


carpeta de nuestro disco. Una vez hecho esto se puede ejecutar el archivo eclipse.exe
para abrir el entorno. La falta de requerimiento de instalación puede hacerlo parecer un
poco desorganizado, sin embargo, es excelente para tener más de una versión del en-
torno (con distintas configuraciones y plugins) en distintas carpetas, cada una con su
propio ejecutable (fig. 2-4).

46
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 47

AJAX. Web 2.0 para profesionales

Fig. 2-4. El entorno de Eclipse abierto. Es importante ir acostumbrándose a sus ventanas y a su forma
de trabajar.
Una vez abierto el entorno, debemos instalar JSEclipse siguiendo estos pasos
(fig. 2-5):
1. Ir al menú Help > Software Updates.
2. Marcar la opción Select New Features to Install.
3. Presionar el botón New Archived Site.
4. Buscar y elegir el archivo ZIP descargado desde el sitio de Adobe con el JSE-
clipse.
5. Pulsar siguiente.
6. Aceptar el contrato de usuario.
7. Reiniciar el entorno.

Si trabajamos con Java en el servidor, el entorno ya trae todo lo necesario, por lo


que sólo basta con crear un proyecto nuevo de tipo JSP. Cada vez que abramos un ar-
chivo con extensión .js (JavaScript), JSEclipse entrará en funcionamiento.

47
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 48

Maximiliano R. Firtman

Fig. 2-5. Eclipse permite actualizar los plugins instalados o agregar otros nuevos, como en nuestro caso.

Si nuestro proyecto es de tipo PHP o .NET y no tenemos plugin alguno para estas
plataformas, basta con crear un proyecto de tipo Simple Project y apuntarlo a la car-
peta donde se encuentren los archivos y el servidor web esté configurado. Ante cual-
quier archivo de tipo .js será JSEclipse el que lo maneje.
Además, Eclipse viene con soporte para la creación y la validación de código
XHTML (sin vista de diseño), de archivos XML (en código y vista diseño) y decenas de
otros formatos (fig. 2-6).
Si trabajamos con PHP como plataforma en el servidor, además, es recomenda-
ble utilizar el plugin creado por Zend (los creadores de PHP), llamado PHP Development
Tools (PDT), que se puede descargar de zend.com/pdt. Con ello, tendremos una nueva

48
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 49

AJAX. Web 2.0 para profesionales

perspectiva (configuración del entorno) en Eclipse para crear proyectos PHP. De esta
manera, podremos detectar errores de sintaxis en el momento de escribir el código,
tendremos disponibles opciones de refactoring, ayuda durante la codificación y hasta
posibilidad de debugging de PHP junto a la configuración de Apache. Es posible ins-
talar JSEclipse sobre la instalación de PDT.
Si bien hay otros IDE creados de manera específica para JavaScript, éste es el
más completo de todos, con el soporte de una gran empresa, como es Adobe, y el
respaldo de un entorno de desarrollo conocido en el mercado, como es Eclipse.

Fig. 2-6. Se observa Eclipse al editar un archivo XML en vista Diseño. Si se trabaja con un esquema
de validación o DTD, Eclipse validará el documento en forma automática y dará ayuda de código
según el contexto.

Visual Web Developer


Visual Studio 2005, el entorno de desarrollo de Microsoft, tiene una amplia trayectoria
en el mercado de creación de aplicaciones. A partir de la versión 2005 posee un nuevo
motor para el desarrollo de sitios web, conocido como Visual Web Developer, que in-

49
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 50

Maximiliano R. Firtman

cluye una versión gratuita express, que no tiene mucho que envidiarle a su versión co-
mercial.
Además de ser el entorno por excelencia para crear aplicaciones en ASP.NET 2.0,
será de utilidad también para la codificación y la depuración de código JavaScript (JS-
cript según la nomenclatura de Microsoft) (fig. 2-7).

Fig. 2-7. Visual Web Developer es un entorno gratuito que será de utilidad para crear código AJAX.

Esto incluye el sistema de Intellisense para completar código mientras se escribe


(aunque no es tan completo como el de JSEclipse) y un poderoso sistema de debugging
de código JavaScript en conjunto con Internet Explorer.
Para poder utilizarlo, es preciso crear un nuevo proyecto ASP.NET (aunque no se
haga uso de este lenguaje) y luego crear los archivos XHTML, CSS y JavaScript nece-
sarios de nuestro proyecto. Se podrá editar y validar cada uno de ellos utilizando el
mismo entorno (fig. 2-8).
Es el mejor entorno para depurar nuestras aplicaciones AJAX dentro de Internet
Explorer, y si se quiere utilizar esta característica, es preciso seguir los pasos que si-
guen (fig. 2-9):

50
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 51

AJAX. Web 2.0 para profesionales

Fig. 2-8. Con VWD es posible validar nuestro código en distintos estándares, como HTML 4.0, HTML
para Internet Explorer 6 o XHTML Transicional y Estricto.

Fig. 2-9. Casillas que se deben desactivar en Internet Explorer para depurar código JavaScript.

51
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 52

Maximiliano R. Firtman

En Internet Explorer 6 o 7, ir a Herramientas -> Opciones de Internet.


En Avanzadas, dentro de Navegación, desactivar las casillas que digan algo simi-
lar a Deshabilitar la depuración de secuencia de comandos (Internet Explorer) y Des-
habilitar la depuración de secuencia de comandos (Otros), (fig. 2-9).
Una vez hecho esto, y con el código abierto en el Visual Web Developer, se debe
ir al menú Debug (depurar) y elegir la opción Start Debugging (comenzar depuración).
Para acceder a esta función también es posible utilizar la tecla F5 (o el botón de Play).
Si es la primera vez que lo hacemos, nos pedirá confirmación para crear un archivo
web.config que permitirá configurar la depuración. Una vez que esto se realizó, Visual
Web Developer abrirá un nuevo servidor web apuntando a la carpeta de nuestro pro-
yecto y luego el Internet Explorer apuntando vía HTTP al archivo HTML que se estaba
creando con la opción de depuración activada. Ante algún breakpoint o error en el có-
digo JavaScript, la ejecución se detendrá (figs. 2-10 y 2-11).

Fig. 2-10. Cuando se produzca un error, o se llegue a un breakpoint en el código, Internet Explorer pa-
rará la ejecución y VWD permitirá que se vea la línea donde paró y el estado de todos los objetos y
variables, y se podrá seguir ejecutando línea por línea o en forma continua.

52
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 53

AJAX. Web 2.0 para profesionales

Fig. 2-11. Con Visual Web Developer se podrán editar varios tipos de archivos, entre ellos XHTML (Html
Page), CSS (Style Sheet), XML, XSLT, bases de datos SQL Server y código JavaScript (JScript File).

Navegadores y utilitarios

Internet Explorer
Si trabajamos bajo entorno Windows, seguro que ya estará instalada alguna versión de
este navegador de Internet. Es recomendable tener instalada la versión 6 y, si es posi-
ble, es mejor contar con un equipo alterno con Internet Explorer 5.5.
Respecto de la última versión, Internet Explorer 7, también es útil tenerla instalada,
a pesar de que se espera que su distribución tarde un poco dado que sólo viene con
Windows Vista o se puede descargar teniendo el Windows XP con una licencia válida.
En caso de que ya se tenga instalada la versión 7 del navegador, Microsoft ofrece
a los desarrolladores, en forma gratuita, la descarga de una imagen para su producto
Virtual PC (también gratuito) con Windows XP con Internet Explorer 6. Esto propor-
ciona una instalación de XP que funcionará sobre la nuestra (sea Vista o XP) y nos per-
mitirá probar nuestras aplicaciones en la versión anterior del navegador. La imagen
puede descargarse de microsoft.com/downloads buscando por Internet Explorer 6
Application Compatibility VPC Image.

53
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 54

Maximiliano R. Firtman

Esta técnica de utilizar imágenes de computadoras virtuales es excelente para


probar nuestras aplicaciones no sólo en distintas versiones de navegadores, sino tam-
bién en diferentes sistemas operativos (como Linux o Mac).
Con el navegador solo no alcanza. Por eso, desde microsoft.com/downloads es
posible descargar la herramienta gratuita de Microsoft, Internet Explorer Developer
Toolbar (fig. 2-12). Ésta incorpora una barra de herramientas en el navegador que per-
mite acceder a funciones útiles para los desarrolladores, que se tornan fundamenta-
les para depurar y trabajar con aplicaciones XHTML, CSS y AJAX dentro de este
navegador.

Fig. 2-12. Developer Toolbar en acción sobre Internet Explorer.

Entre las funciones con las que se dispone se encuentran:


• Explorar y modificar el DOM en forma dinámica.
• Ubicar y elegir elementos dentro de la página.
• Desactivar ciertas funciones (JavaScript, CSS, etc.).
• Ver información útil sobre los elementos: nombre de clase, ids, access keys,
etc.
• Ver los bordes de tablas, celdas, imágenes y divs.
• Validar HTML, CSS y RSS.

54
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 55

AJAX. Web 2.0 para profesionales

• Ver información acerca de las dimensiones de cada imagen, sus tamaños y


texto alternativo.
• Ver una regla que permitirá verificar la alineación y las medidas de los ele-
mentos.
• Encontrar qué reglas CSS se aplican para cada elemento.
• Ver el código fuente que actualmente está generado de manera dinámica.

Firefox
Este navegador se volvió bastante popular en los últimos tiempos y le quitó algo de
mercado al Internet Explorer. Este último todavía es el más difundido, pero para los
desarrolladores Firefox será un aliado mucho más poderoso.
Lo ideal será tener instaladas varias versiones de Firefox, como 1.0, 1.5 y 2.0, a la
vez. Este proceso es mucho más sencillo que con Internet Explorer; no se precisará re-
currir a máquinas virtuales, simplemente se puede tener la última versión instalada en
el equipo y, por medio de lo que se conoce como versiones portables, es posible con-
seguir las versiones anteriores en distintas carpetas sin necesidad de instalarlas y que
tengan conflictos con las otras. Para descargar las versiones portables se puede visi-
tar el sitio web www.portableapps.com.
Firefox viene con un motor de XHTML y CSS llamado Gecko (incluido también en
otros navegadores) que sigue los estándares de forma más estricta que Internet Explorer,
pero que en muchos casos no es compatible con este último. Por eso se deben depurar
todas las aplicaciones y es preciso probarlas en cada uno de ellos.
Su motor JavaScript también es un poco más poderoso e incluye mejoras sobre
el lenguaje y sus objetos, así como un manejo de errores más organizado.
Desde sus inicios, Firefox fue uno de los precursores del uso de adicionales y plugins
dentro del navegador, y en lo que respecta a nosotros, los plugins recomendados para
instalar son Web Developer y Firebug.
El primero tiene una funcionalidad similar a la del que se describió antes para In-
ternet Explorer, con algunos adicionales e interfaz más sencilla de utilizar. Se puede
descargar gratis de addons.mozilla.org/firefox/60.
Por otro lado, Firebug es fundamental para nuestras aplicaciones AJAX. Su sitio
web es www.getfirebug.com y, entre otras funciones, permite ver y depurar las peti-
ciones XmlHttpRequest que una aplicación AJAX hace al servidor. Por el lado del có-
digo JavaScript, facilita su depuración y seguimiento, así como obtener estadísticas en
línea (profiling) para detectar problemas de rendimiento o tamaños de memoria utiliza-
dos por nuestro código (fig. 2-13).
Firebug permite que se vean los errores de JavaScript con un detalle extensivo de
éste, observar la pila de llamadas de funciones y acceder con rapidez al código fuente
donde se produjo el error. Además, trae soporte de breakpoints que permite que el có-
digo JavaScript pare en cierto lugar que defina el desarrollador y, a partir de allí, se

55
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 56

Maximiliano R. Firtman

Fig. 2-13. Firebug analizando las peticiones XHR que hizo la aplicación AJAX de Google Maps.

pueda ejecutar paso por paso analizando el valor que tienen todas las variables y los
objetos en memoria (figs. 2-14 y 2-15).
Para sintetizar, las funciones que permitirá realizar Firebug son:
• Inspeccionar y editar HTML.
• Optimizar los estilos CSS en vivo.
• Visualizar métricas CSS (márgenes, bordes, rellenos, etc.).
• Monitorear actividad de red al descargar archivos, imágenes, plugins y peti-
ciones AJAX.
• Depurar código JavaScript.
• Encontrar errores y hacerles un seguimiento.
• Explorar el DOM.
• Ejecutar código JavaScript nuevo en vivo.

56
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 57

AJAX. Web 2.0 para profesionales

Fig. 2-14. Los detalles de un error JavaScript aportados por Firebug permiten que el problema se en-
cuentre y se detecte con facilidad.

Fig. 2-15. Motor de depuración (debug) de Firefox ejecutando código JavaScript línea por línea.

Opera
Éste es uno de los navegadores con mayor cantidad de funciones incluidas, pero no es
uno de los más utilizados. Su uso decayó ante la salida de Firefox y, según sus creado-
res, es el más rápido del mercado. Opera no sólo desarrolla navegadores para equipos
de escritorio, sino también para teléfonos celulares (como Opera Mobile y Opera Mini),
televisores y otros dispositivos.
Junto al navegador de Mac OS, Safari, es el tercero en distribución de navega-
dores en el mundo. Si bien el porcentaje de penetración del navegador es bajo (menor
que el 2%) es bueno probar las aplicaciones en él.

57
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 58

Maximiliano R. Firtman

Desde la versión 9.20, Opera incluye un módulo para desarrolladores que se pa-
rece bastante al plugin Firebug de Firefox. Con él será posible navegar por el DOM de
una página web, ver y modificar los estilos CSS y analizar las peticiones XmlHttpRequest
que una aplicación AJAX hace hacia el servidor (fig. 2-17).

Fig. 2-16. Se observa una aplicación AJAX de Google que no es compatible con el navegador Opera.
En estos casos Google recomienda utilizar Internet Explorer o Firefox.

Servidor Web

¿Es necesario un servidor web para AJAX? En principio, AJAX no requiere un len-
guaje de servidor, dado que puede leer XML y archivos de texto estáticos sin nece-
sidad de generarse dinámicamente con algún lenguaje como ASP o PHP. No
obstante, el problema que se va a presentar en el entorno de desarrollo es que, por
seguridad, la mayoría de los navegadores no permite hacer peticiones AJAX si se
está trabajando con el sistema de archivos local, o sea, levantando el archivo XHTML
desde el disco (fig. 2-18).

58
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 59

AJAX. Web 2.0 para profesionales

Fig. 2-17. A partir de Opera 9.20 se dispone de una herramienta para desarrolladores que permite de-
purar aplicaciones.

Fig. 2-18. Error de Internet Explorer cuando se intenta ejecutar una aplicación AJAX desde el disco local.

59
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 60

Maximiliano R. Firtman

Firefox es uno de los navegadores que sí permite trabajar en el disco local, pero
el código AJAX que se usará en la web y en el disco local no es exactamente el mismo,
por lo que tampoco sirve probarlo de esta forma.
Entonces es obligatorio montar un servidor de pruebas, o utilizar un servidor web
real, para probar las aplicaciones AJAX aunque no hagan uso de script de servidor al-
guno.

Cassini
Cassini es el nombre que posee el servidor web que viene integrado con Visual Web
Developer, cuya descripción ya se detalló en páginas anteriores. Si bien es posible
prender este servidor sin necesidad del entorno, lo recomendable es hacerlo desde el
IDE, dado que ya lo prepara y lo configura para funcionar con la carpeta de nuestro pro-
yecto.
Este servidor se activa en un puerto al azar, por lo que la URL de nuestras aplica-
ciones serán del tipo http://localhost:9999/nombre_carpeta. Además, servirá si traba-
jamos en el servidor con ASP 3, ASP.NET (Visual Basic o C#) o ASP.NET Phyton.

Internet Information Server


El servidor web IIS de Microsoft también es un favorito cuando trabajamos con Windows
XP o Vista en el equipo de desarrollo, dado que viene incluido con las versiones Pro-
fessional y Business de ambos sistemas operativos.
Sólo es necesario instalarlo desde el panel de control y configurar la carpeta donde
se encuentran los archivos por medio de una carpeta virtual (fig. 2-19).
Entonces, al prender este servidor, nuestra URL será http://localhost/nombre_car-
peta. También podremos reemplazar localhost por el nombre de nuestro equipo o la di-
rección IP en la red.
Con IIS se podrá trabajar con ASP, ASP.NET, Phyton y PHP, entre otros.

Apache
Apache es el servidor web favorito en el mundo y el que mejor se lleva con el entorno
y el lenguaje PHP. Si bien es posible instalarlo y configurarlo en forma manual, lo re-
comendable (dado que estamos en un entorno de desarrollo) es instalar alguna de las
distribuciones que hay en el mercado que configuran de manera automática Apache,
PHP y MySQL, como XAMPP (apachefriends.org) o EasyPHP (easyphp.org) (fig. 2-20).
Si se utiliza Java del lado del servidor, un Apache Tomcat será suficiente, al igual
que cualquier otro servidor web que permita levantar los archivos de nuestro sitio me-
diante una URL web.

60
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 61

AJAX. Web 2.0 para profesionales

Fig. 2-19. Consola de IIS que se encuentra en el panel de control y que permitirá crear una nueva car-
peta virtual.

Fig. 2-20. XAMPP es una distribución simple y completa que incluye todo lo necesario para trabajar
con aplicaciones AJAX que usen PHP en el servidor.

61
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 62

Maximiliano R. Firtman

HTTP Proxies
Cuando se trabaja con algún navegador que no soporta ningún plugin que permita ana-
lizar el tráfico detrás de escena que administra una aplicación AJAX, es necesario recu-
rrir a una herramienta que permita analizar el tráfico HTTP que circula en nuestro equipo.
Los recomendados para aplicaciones AJAX son Charles Web Debugging Proxy
(www.xk72.com) y Microsoft Fiddler (www.fiddlertool.com). Este último permite, ade-
más de ver el tráfico, modificar las peticiones antes de enviarlas a un servidor, y cam-
biar las respuestas antes de devolverlas al navegador (fig. 2-21).

Fig. 2-21. Se observa todo el tráfico HTTP entre nuestro equipo e Internet. Incluso se puede ver el trá-
fico que consumen los plugins del navegador, como la Google Toolbar.

El objeto XMLHTTP
Por fin llegamos al corazón de AJAX: el objeto XMLHttp. Veamos de qué se trata y
cómo se utiliza para generar peticiones detrás de escena hacia el servidor.

62
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 63

AJAX. Web 2.0 para profesionales

Origen

Alrededor de 1998, Microsoft liberó una tecnología conocida como Remote Scripting
que permitía, por medio de un applet Java, realizar peticiones desde JavaScript al ser-
vidor sin que el usuario lo note ni que se cambie la URL del sitio web, mientras se hace
esperar al usuario.
Al año siguiente la empresa de Redmond lanzó el Internet Explorer 5.0 y allí in-
corporó, bajo la tecnología ActiveX, un objeto llamado XMLHttp que reemplazaba fun-
cionalmente al applet Java antes descripto. De esta forma, era posible utilizar esta
tecnología conocida como Remote Scripting sin necesidad de que el usuario tenga
instalada una Java Virtual Machine, lo que además aumentaba la velocidad de las apli-
caciones de este tipo.
El uso de esta solución no tuvo mucha difusión y sólo fue utilizada por el mismo
Microsoft para algunos de sus productos web.
Sin embargo, 5 años después algunas empresas (lideradas por Google tal vez) re-
tomaron el concepto y comenzaron a aplicarlo en sus sitios web para lograr interfaces
ricas, nunca vistas antes en sitios HTML. Así, y gracias a las interfaces limpias y la in-
formación excelente de Google (como los mapas satelitales de todo el mundo), hicie-
ron que la tecnología se hiciera conocida y muchos otros desarrolladores quieran
implementarla; allí nació el concepto de AJAX.
Es así que el objeto XMLHttp es el corazón de toda aplicación AJAX, dado que es
el que técnicamente permite realizar una petición con el servidor en forma asincrónica
y sin cambiar de URL.
Dada la cantidad de sitios que comenzaron a utilizar esta técnica, los navegado-
res competencia de IE implementaron un clon del objeto, lo llamaron XMLHttpRequest.
Este objeto es nativo de JavaScript (como window o document) e implementa los mis-
mos métodos y propiedades que el ActiveX de Microsoft.
A partir de la versión 7 de Internet Explorer, Microsoft también implementó el ob-
jeto XMLHttpRequest en forma nativa, a la vez que mantuvo por compatibilidad el Ac-
tiveX (fig. 2-22). El objeto nativo permite que las aplicaciones AJAX funcionen en
configuraciones donde por seguridad se desactivó el uso de ActiveX.
El objeto ahora está implementado en Firefox 1.0 o superior, Netscape 7.1 o su-
perior, Opera 8 o superior, Safari 1.2 o superior, Konqueror, Opera Mobile y Nokia Web
Browser para S60.

Modo de uso

Para hacer una petición al servidor desde código JavaScript (aunque técnicamente
también se podría hacer desde VBScript y JScript en IE) es necesario seguir los pasos
siguientes:

63
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 64

Maximiliano R. Firtman

Fig. 2-22. Dentro de las propiedades de Internet Explorer 7 se encuentra la posibilidad de desactivar
el uso del objeto nativo XMLHttpRequest.

1. Instanciar el objeto.
2. Configurar y abrir la petición.
3. Definir una función de JavaScript que se encargue de administrar la evolución
de la petición (dada su asincronía).
4. Enviar la petición y los datos al servidor.
5. En la función definida antes, manipular el estado de la petición y, en el caso
correcto, recibir los datos y actuar en consecuencia con ellos, según lo que hu-
biera que hacer.

64
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 65

AJAX. Web 2.0 para profesionales

Instanciación

En Internet Explorer
En Internet Explorer 5.5 y 6.0 la instanciación de cualquier objeto ActiveX se realiza de
la siguiente manera:

objeto = new ActiveXObject(”nombreClase”);

En nuestro caso, el objeto XMLHttp lleva distintos nombres de clase, según la ver-
sión del sistema operativo. Algunos posibles son:

objeto = new ActiveXObject(”Microsoft.XMLHttp”);


objeto = new ActiveXObject(”MSXML2.XMLHttp”);
objeto = new ActiveXObject(”MSXML2.XMLHttp.3.0”);
objeto = new ActiveXObject(”MSXML2.XMLHttp.4.0”);
objeto = new ActiveXObject(”MSXML2.XMLHttp.5.0”);

La única forma de saber cuál debemos utilizar es, lamentablemente, probarlos


todos, en orden de mayor probabilidad, y el que no genere una excepción (que pode-
mos capturarla con un try-catch) será el que funciona en nuestro navegador.
Entonces, podemos crearnos un vector con todos los posibles nombres de ins-
tanciación e intentar con cada uno, como el siguiente código:

// Definimos un vector con las distintas posibilidades


var vectorVersiones = [”MSXML2.XMLHttp.5.0”, ”MSXML2.XMLHttp.4.0”,
”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”, ”Microsoft.XMLHttp”];

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
if (!requerimiento) {
requerimiento = new ActiveXObject(vectorVersiones[i]);
}
}
} catch (e) {}
}

En otros navegadores
Tanto en Internet Explorer 7 como en el resto de los navegadores, la instanciación se
realiza de la siguiente forma:

65
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 66

Maximiliano R. Firtman

objeto = new XMLHttpRequest();

A partir de allí, el objeto se puede usar de igual manera que el objeto ActiveX, sin
importar cuál de todos sea.

Patrón Factory
Dado que tenemos distintas formas de instanciar el objeto y, con el afán de mantener
un solo código reutilizable para hacerlo, se hace necesaria la aplicación de una sim-
plificación del patrón de diseño Factory (o fábrica), que será el encargado de decidir
cuál es la forma adecuada de instanciar el objeto y devolverla. De este modo se abs-
trae nuestro código principal del método que se usó.
Para ello, vamos a hacer uso de dos propiedades del lenguaje JavaScript:
1. Cualquier objeto, si no existe o no está definido, devuelve undefined, que lógi-
camente equivale a false. Si el objeto existe, lógicamente equivale a true.
2. Se puede hacer uso de la sentencia try-catch en JavaScript, desde sus últimas
versiones (la utilizada en los navegadores compatibles con AJAX). Todo el
código encerrado en la sentencia try será ejecutado y, en caso de que se pro-
duzca algún error, se ejecutará el código encerrado en la sentencia catch. Esta
última recibe un parámetro (en general llamado e) con información acerca del
error, si nos interesa utilizarla.

try {
// Código a intentar ejecutar
} catch (e) {
// Código a ejecutar cuando ocurrió un error en el try
}

Así podemos llegar al siguiente método para instanciar un objeto XMLHttp en sus
diferentes formas:

function obtenerXHR() {
req = false;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
if (ActiveXObject) {
// Definimos un vector con las distintas posibilidades
var vectorVersiones = [”MSXML2.XMLHttp.5.0”,
”MSXML2.XMLHttp.4.0”, ”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”, ”Micro-
soft.XMLHttp”];

66
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 67

AJAX. Web 2.0 para profesionales

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
req = new ActiveXObject(vectorVersiones[i]);
return req;
} catch (e) {}
}
}
}
return req;
}

De esta manera, esta función devuelve un objeto XMLHttp válido (no importa su
forma de instanciación) o el valor lógico false que podrá utilizarse en nuestro código
principal como sinónimo de navegador que no soporta AJAX.
Su uso entonces sería el siguiente:

var peticion;
peticion = obtenerXHR();

Métodos más utilizados

open
El método open, a pesar de lo que uno podría suponer por el nombre, no abre la co-
nexión con el servidor, sino que sólo configura la petición y la deja lista para enviarla.
Sus parámetros son los siguientes:

Método Es un string con alguno de los métodos HTTP con los que haremos la
petición. Los que podremos usar aquí son GET o POST.

URL Es un string con la URL que queremos invocar en el servidor. Puede


ser relativa al documento actual (p. ej., datos.txt) o absoluta
(http://www.dominio.com/datos.txt). Si vamos a enviar datos vía GET
debemos adjuntarlos a la URL.

Asincronismo Es un valor lógico que indica si queremos que la petición sea


asincrónica (true) o sincrónica (false). Una aplicación AJAX, por
definición, es siempre asincrónica.

Usuario Es un parámetro opcional, de tipo string, que define el nombre de


usuario con el que se debe identificar la petición en el servidor.

Contraseña Es obligatorio si definimos el usuario, y define la contraseña asignada.

67
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 68

Maximiliano R. Firtman

En general, el código que utilizaremos será el siguiente:

peticion.open(GET, ”url”, true);

Si bien parece que el usuario y la contraseña pueden dar un nivel mayor de se-
guridad, recordemos que estamos escribiendo un código de script que puede leer cual-
quier usuario en el código fuente. Por este motivo, la autenticación HTTP a menudo no
se utiliza en las peticiones AJAX.
Cuando definimos en true, el asincronismo, la petición se realizará en background,
o sea, el código JavaScript se seguirá ejecutando y cuando lleguen los datos del ser-
vidor nos avisará. En el caso de definirlo en false, el código JavaScript quedará con-
gelado hasta tanto llegue la petición del servidor. Recordemos que la primera “A” de
AJAX se refiere al uso de la asincronía (fig. 2-23).

Fig. 2-23. La figura muestra la diferencia entre usar una petición asincrónica y una sincrónica.

send
Éste es el método que finalmente se encarga de enviar una petición al servidor, una vez
que se configuró con el método open. Tiene un solo parámetro opcional que repre-
senta los datos que enviaremos en la petición, en el caso de enviar datos vía POST. Si
bien es opcional, por compatibilidad con algunos navegadores siempre se acostum-
bra incluir el parámetro, en caso de no enviar dato alguno al servidor o hacerlo vía GET
en la URL, se puede usar el valor especial null para definirlo. El código sería entonces:

68
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 69

AJAX. Web 2.0 para profesionales

peticion.send(null)

abort
Este método aborta una petición en curso, luego de haber invocado al método send.
Abortar la petición implica que ya no se nos avisará cuando lleguen los datos y en el
navegador se suspenderán todas las acciones que se estaban utilizando para enviar
datos al servidor y recibirlos.
Su uso no es muy común, pero es simple:

peticion.abort()

Propiedades

readyState
Los métodos analizados sirven para preparar y enviar la petición, pero no alcanzan
para administrarla. La propiedad de sólo lectura readyState devuelve un código nu-
mérico entre 0 y 4 inclusive, que indica en qué estado se encuentra la petición.
Los posibles estados son:

Código Estado Descripción

0 Sin inicializar El requerimiento sólo fue instanciado. Muchos


navegadores no manejan este código y utilizan
directamente el siguiente.

1 Cargando El requerimiento se configuró (con open) pero


todavía no se envió.

2 Cargado El requerimiento se envió o se está enviando,


aunque todavía no tenemos respuesta alguna
del servidor.

3 Interactivo El servidor ya respondió la petición, ya tenemos


disponibles las cabeceras pero el contenido todavía
se está descargando.

4 Completo La petición ya finalizó y el contenido está completo.

En general, salvo que se precise algún control mayor que el normal, sólo intere-
sará cuando la petición se encuentre en estado 4, por lo que este código, que luego
se verá dónde se ubica, comenzará a resultarnos familiar.

69
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 70

Maximiliano R. Firtman

if (peticion.readyState==4) {
// La petición terminó
}

status
Es muy importante no confundir esta propiedad con la anterior. Si bien parecen simila-
res, la propiedad status devuelve el código HTTP que nos devolvió el servidor. Estos có-
digos hasta ahora nunca los administrábamos en una Web 1.0, aunque como usuarios
los conocemos: entre ellos están el 404 (recurso no encontrado) o el 500 (error interno
del servidor).
Dado que ahora es nuestro código, y no es el navegador el que administra inter-
namente la petición, es nuestra responsabilidad capturar estos errores y actuar en con-
secuencia con el usuario. Si recibimos un error del servidor por una petición AJAX, el
navegador no mostrará nada al usuario acerca de ese error.
Algunos de los códigos que serán de utilidad son:

Código Descripción

200 La petición se pudo procesar en forma correcta.

404 La URL que peticionamos no existe en el servidor.

500 Error interno del servidor. Puede indicarnos que el servidor está
saturado o que hay algún error en el script ejecutado en el servidor.

400 La petición enviada al servidor es errónea. Hay algún inconveniente


con las cabeceras o con la información POST enviada.

403 No tenemos permiso de acceder al recurso en el servidor.


405 No se acepta el método. Hay un problema al definir los métodos POST o GET.

414 La URL pedida es muy larga. Puede producirse cuando se envían


muchos datos por GET. En este caso, se debe cambiar el método a POST.

503 El servidor está temporalmente no disponible.

Entonces, el código que se debe esperar de una petición correcta será 200, y en el
caso de recibir algún error en el servidor, es factible utilizar alguna de las herramientas ya
descriptas, que permiten analizar la petición XMLHttpRequest, como Firebug (fig. 2-24).
Ahora la condición que se analizó antes se agranda de la siguiente forma:

70
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 71

AJAX. Web 2.0 para profesionales

if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Los datos llegaron bien y están disponibles
}
}

Fig. 2-24. Se observa cómo Firebug permite que se vea el detalle de un error que se produjo en un
código de servidor que de otra manera no sería posible analizar.

statusText
Es una propiedad de sólo lectura no muy utilizada que devuelve un texto descriptivo
del status visto con anterioridad. Así, recibiremos un string que contiene OK cuando el
status sea 200. Esta propiedad no devuelve el mismo valor en todos los navegadores
web, por lo que no es posible utilizarla para saber cómo resultó la operación.

responseText
Esta propiedad de sólo lectura devuelve un string con el contenido del cuerpo devuelto
por el servidor ante la petición. Sólo se tiene seguridad de que estos datos están co-
rrectos cuando readyState sea 4 y status sea 200.
Esta propiedad se utiliza para recibir del servidor tanto información textual, como
(x)HTML, código JavaScript u objetos JSON (ya veremos esta modalidad un poco más
adelante).

71
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 72

Maximiliano R. Firtman

Si bien la X de AJAX implica el uso de XML, mediante esta opción no se estaría


utilizando este lenguaje y, a pesar de lo que se pueda creer a estas alturas, el empleo
de XML no es tan usual en aplicaciones AJAX y ya veremos por qué.

responseXML
Como se indicó, XML hizo originalmente a AJAX. Si la respuesta del servidor es un
XML válido entonces se puede utilizar esta propiedad de sólo lectura para recibir el
objeto XML nativo en JavaScript y luego procesarlo por los métodos de DOM (Docu-
ment Object Model), como si se tratara de la misma página XHTML. Más adelante ve-
remos ejemplos del uso de XML y las ventajas y desventajas que tiene respecto del
empleo de responseText.

onreadystatechange
De todas las propiedades descriptas hasta ahora, ésta es la única que se utiliza antes
de enviar la petición. Todos conocemos el modelo de eventos de JavaScript que per-
mite, por ejemplo, ejecutar código al momento de que la página se cargue (onload) o
cuando se acciona un botón (onclick) definiendo una función que se encargará de eje-
cutar código cuando el evento se produzca (event handler).
El objeto XMLHttpRequest posee un solo evento, que se puede (y se debe) cap-
turar para procesar la petición, dado que, recordemos, se está tratando con una peti-
ción asincrónica donde el objeto se encarga de avisarnos cuando la petición llega.
Este aviso se realiza sobre la base de una función o un método que se debe desig-
nar como el encargado de procesar la petición. La propiedad onreadystatechange, en-
tonces, debe asignarse a una función que se ejecutará de manera automática cada vez
que la propiedad readyState cambie su valor (entre 0 y 4, como se mencionó antes).
De esta forma, cuando el estado llegue a 4, ya estaremos listos para leer los datos
del servidor y actuar en consecuencia. A esta propiedad se le puede asignar una fun-
ción de dos maneras: indicando el nombre de la función (sin paréntesis) o designando
una función en línea. A continuación se observan estos dos ejemplos.

// Opción 1
(...)
// Es importante no incluir los paréntesis de llamada () al asignar
la función
peticion.onreadystatechange = procesarPeticion;
peticion.send(null);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Los datos llegaron bien y están disponibles
}
}
}

72
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 73

AJAX. Web 2.0 para profesionales

// Opción 2
peticion.onreadystatechange = function() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Los datos llegaron bien y están disponibles
}
}
}

peticion.send(null);

Esta propiedad deberá definirse antes o después del método open y antes del
send para que el código funcione de manera correcta.

Otros métodos

setRequestHeader
Permite definir un parámetro en el encabezado HTTP en la petición que irá al servidor. Por
ello, debe definirse antes del send, y desde el script de servidor será posible leer este valor.
En general esta modalidad la usaremos para definir valores relativos a la petición
(codificación, protocolo, etc.) y no para enviar parámetros al servidor (p. ej., informa-
ción para agregar a una base de datos). Para esta última opción se utilizan los pará-
metros GET o POST.
Su sintaxis es la siguiente:

peticion.setRequestHeader(clave, valor)

Por ejemplo:

Peticion.setRequestHeader(”Content-Type”, ”text/xml”);

getResponseHeader
Así como podíamos enviar valores en el encabezado de la petición saliente, podemos
leer los valores recibidos en la petición HTTP entrante, o sea, en la respuesta del ser-
vidor. Para ello, debemos conocer el nombre o la clave del valor que se quiere leer. Por
ejemplo,

73
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 74

Maximiliano R. Firtman

if (peticion.getResponseHeader(”Content-Type”)==”text/html”) {
// La respuesta recibida es un HTML
}

getAllResponseHeaders
Este método permite recibir en un string todos los valores recibidos en la cabecera
HTTP de la respuesta del servidor. Podemos convertirlo a un vector utilizando la fun-
ción split, propia de un string, para recorrerlo. Para ello podemos utilizar una expresión
regular (\r?\n) que permite separar los distintos valores por saltos de línea. Entonces,
por ejemplo, se puede hacer una lista de todas las cabeceras recibidas (fig. 2-25) y
mostrarlas en el navegador de la siguiente forma:

var peticion = obtenerXHR();


peticion.open(”GET”, ”traerdatos.aspx”, true);
peticion.onreadystatechange = procesarPeticion;
peticion.send(null);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos las cabeceras (y no el contenido)
var headers =
peticion.getAllResponseHeaders().split(/\r?\n/);
var mensaje = ””;
for (var i in headers) {
mensaje += headers[i] + ”\n\r”;
}
alert(mensaje);
}
}
}

Fig. 2-25. En una ventana de alerta se observan las cabeceras recibidas en una petición AJAX.

74
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 75

AJAX. Web 2.0 para profesionales

Métodos y propiedades no estándar

Internet Explorer y Firefox agregaron algunos métodos al objeto XMLHttpRequest que


no son parte del original y del estándar de facto que se creó. Debemos tener cuidado al
utilizarlos, dado que sólo podremos hacerlo si hay seguridad de que se trata de este na-
vegador.
Por ejemplo, en Internet Explorer se encuentran las propiedades responseBody (la
respuesta se obtiene como un array de bytes) y responseStream (los bytes se obtienen
a medida que llegan del servidor como un flujo de datos), pero su uso no es recomen-
dable por incompatibilidades.
El motor de Mozilla, incorporado en Firefox, agrega algunos eventos (onprogress,
onerror y onload) y ciertos métodos, como overrideMimeType que permite que el na-
vegador no tome en cuenta el tipo de datos MIME enviado por el servidor para proce-
sar el archivo (figs. 2-26 y 2-27).

Fig. 2-26. Visual Web Developer mientras hace una depuración de código AJAX y analiza el objeto pe-
tición junto a sus métodos y propiedades.

Primer Proyecto AJAX


Hola AJAX

Vamos a crear entonces un primer proyecto que reciba un texto desde un archivo TXT
y lo mostremos en una alerta como primer ejemplo funcionando de AJAX.

75
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 76

Maximiliano R. Firtman

Fig. 2-27. El mismo objeto petición analizado desde Firebug.

<!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>
<title>Primer Ejemplo</title>

<script type=”text/javascript”>

function obtenerXHR() {
req = false;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
if (ActiveXObject) {
// Definimos un vector con las distintas posibilidades
var vectorVersiones = [”MSXML2.XMLHttp.5.0”,
”MSXML2.XMLHttp.4.0”, ”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”,
”Microsoft.XMLHttp”];

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
req = new ActiveXObject(vectorVersiones[i]);
return req;
} catch (e) {}
}
}
}

76
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 77

AJAX. Web 2.0 para profesionales

return req;
}

var peticion = obtenerXHR();


peticion.open(“GET”, “primertexto.txt”, true);
peticion.onreadystatechange = procesarPeticion;
peticion.send(null);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos el texto en una alerta
alert(peticion.responseText);
}
}
}

</script>

</head>
<body>

</body>
</html>

En este ejemplo, al cargarse la página se ejecutará una segunda petición al servi-


dor detrás de escena que traerá el contenido de un archivo de texto, y, cuando llegue
en forma correcta y completa, se mostrará en una alerta. Nuestro primer ejemplo AJAX
es funcional por completo.
Si quisiéramos hacerlo sincrónico (recordemos que no sería AJAX estrictamente) en-
tonces no necesitaríamos definir una función que maneje el evento readystatechange, ya
que una vez que termine de ejecutar el método send los datos ya habrán llegado. Recor-
demos que esto no es común, el código JavaScript se queda congelado mientras llega la
petición del servidor y sólo podría servir en algunos casos muy particulares.

Fig. 2-28. Nuestro primer ejemplo AJAX funcionando de manera correcta en Internet Explorer 6, In-
ternet Explorer 7, Opera y Firefox.

77
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 78

Maximiliano R. Firtman

<!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>
<title>Primer Ejemplo</title>

<script type=”text/javascript”>

function obtenerXHR() {
req = false;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
if (ActiveXObject) {
// Definimos un vector con las distintas posibilidades
var vectorVersiones = [”MSXML2.XMLHttp.5.0”,
”MSXML2.XMLHttp.4.0”, ”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”,
”Microsoft.XMLHttp”];

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
req = new ActiveXObject(vectorVersiones[i]);
return req;
} catch (e) {}
}
}
}
return req;
}

var peticion = obtenerXHR();


peticion.open(”GET”, ”primertexto.txt”, false);
peticion.send(null);

// La petición terminó
if (peticion.status==200) {
// Mostramos el texto en una alerta
alert(peticion.responseText);
}

</script>

</head>
<body>

</body>
</html>

78
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 79

AJAX. Web 2.0 para profesionales

Parámetros GET

El envío de parámetros de tipo GET al servidor es uno de los más simples de imple-
mentar. Sólo se deben adjuntar, a la URL de la petición, los parámetros en el formato.

?clave=valor&clave2=valor2
Así, el ejemplo siguiente invoca en el servidor a un script dinámico ASP.NET que lee el
archivo que se le pasa por parámetro. Este ejemplo se propone a los fines de ir pro-
bando distintos métodos de comunicación en AJAX, pero no debe utilizarse en pro-
ducción, ya que podría traer problemas de seguridad (p. ej., que alguien pueda leer
nuestro código fuente).
Entonces, tenemos un script ASPX (podría ser PHP o cualquier otro lenguaje) que
sólo lee un archivo de texto y devuelve ese archivo al cliente, y una página HTML (den-
tro del mismo servidor) que, al cargarse, pide leer uno de esos archivos (fig. 2-29).

Fig. 2-29. Esquema de funcionamiento del ejemplo de lectura de archivos.

LeerArchivo.ASPX

<%@ Page Language=”VB” %>


<script runat=”server”>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
Dim texto As String
texto = My.Computer.FileSystem.ReadAllText(
Server.MapPath(Request.QueryString(”archivo”)))
Response.Write(texto)
End Sub
</script>

79
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 80

Maximiliano R. Firtman

En la página HTML del primer ejemplo sólo se cambiará el código JavaScript por
el siguiente:

Var peticion = obtenerXHR();


peticion.open(”GET”, ”leerArchivo.aspx?archivo=primertexto.txt”, true);
peticion.onreadystatechange = procesarPeticion;
peticion.send(null);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos el texto en una alerta
alert(peticion.responseText);
}
}
}

Nótese que lo único que se cambió es la URL que se invocó, enviando el pará-
metro GET archivo con el valor primertexto.txt. Este tipo de ejemplos se pondrá más
interesante en los próximos capítulos.

Parámetros POST

El método POST es útil cuando tenemos mucha información que enviar al servidor, así
como cuando queremos enviar información binaria o, incluso, un XML. Por el momento
vamos a enviar parámetros al estilo usual y que el servidor pueda leer las variables recibi-
das por esta metodología, por ejemplo, con $_POST en PHP o con Request.Form en ASP.
Para ello, se deben enviar los parámetros en el mismo formato URL que se indicó
antes, pero sin el símbolo de interrogación, o sea:

clave=valor&clave2=valor2
Estos valores deberán enviarse como parámetros en el método send del objeto
XMLHttpRequest y, por último, será preciso definir una cabecera HTTP para indicar al
servidor que se envían parámetros en formato URL (fig. 2-30).
Entonces el código quedaría así:

LeerArchivoPost.aspx
<%@ Page Language=”VB” %>
<script runat=”server”>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)

80
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 81

AJAX. Web 2.0 para profesionales

Dim texto As String


texto = My.Computer.FileSystem.ReadAllText( Server.MapPath(Re-
quest.Form(”archivo”)))
Response.Write(texto)
End Sub
</script>

leerArchivoPost.html
<!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>
<title>Envío de Parámetros vía POST</title>

<script type=”text/javascript”>

function obtenerXHR() {
// (...) Aquí va la misma función antes realizada
}

var peticion = obtenerXHR();


peticion.open(”POST”, ”leerArchivoPost.aspx”, true);
peticion.onreadystatechange = procesarPeticion;

// Definimos cabecera obligatoria para enviar POST


peticion.setRequestHeader(”Content-Type”,
”application/x-www-form-urlencoded”);

// Enviamos los parámetros


var parametros = ”archivo=primertexto.txt”;
peticion.send(parametros);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos el texto en una alerta
alert(peticion.responseText);
}
}
}

</script>

</head>
<body>

</body>
</html>

81
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 82

Maximiliano R. Firtman

Fig. 2-30. Con los agregados para AJAX en los navegadores se podrán ver y analizar las peticiones
XHR realizadas al servidor, así como los parámetros POST que se enviaron.

Reemplazando contenido

Hasta ahora realizamos varios ejemplos de peticiones AJAX enviando datos vía GET y
vía POST, pero siempre utilizamos una alerta para mostrar la respuesta del servidor.
Si bien esta modalidad puede ser útil para ver la respuesta con rapidez, en un sitio
AJAX esto no tiene mucha utilidad. Entonces, una de las formas más sencillas de im-
plementar una aplicación AJAX es reemplazar contenido dentro de la página web por
la respuesta recibida en modo texto o HTML por parte del servidor.
Para esto, es preciso tener zonas de contenido (por lo general DIV) con un iden-
tificador único para JavaScript (la propiedad id) al que se le puede cambiar la propie-
dad innerHTML con el nuevo contenido que se desea poner. De esta forma es factible
insertar contenido nuevo o reemplazar el viejo con texto, HTML e incluso código Ja-
vaScript que llegó con ulterioridad por medio de peticiones AJAX.
Para ello se deben tener en cuenta dos cosas muy importantes que es preciso
cambiar en los ejemplos que se venían exhibiendo:
1. La petición AJAX hay que hacerla cuando se tiene seguridad absoluta de que
todo el HTML de la página fue cargado y que nuestro DIV ya está disponible
para su uso. Si se desea ejecutar la petición cuando la página se cargue, se
debe usar el método load del body.
2. El objeto XMLHttpRequest debe definirse como una variable global dentro de
la página, dado que si no es así no se podrá leer el texto recibido del servi-
dor, porque ahora crear la petición y procesarla se realizarán en funciones
distintas.

De paso, puede ser buen momento para sacar la función obtenerXHR a un Ja-
vaScript externo, dado que ya nos percatamos de que la usaremos en forma cons-
tante, y, por ahora, esta función nunca cambia.

82
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 83

AJAX. Web 2.0 para profesionales

Si vamos a leer directamente archivos HTML del disco debemos asegurarnos de


que estos HTML no poseen las etiquetas <html>, <head> o <body>, sino el contenido
que queremos insertar. Si fuera así, tendríamos un problema, ya que no es válido tener
un html dentro de un div (figs. 2-31 y 2-32).
Así, nuestro código podría ser el siguiente:

XHR.js
// Instancia un nuevo objeto XMLHttpRequest

function obtenerXHR() {
req = false;
if (XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
if (ActiveXObject) {
// Definimos un vector con las distintas posibilidades
var vectorVersiones = [”MSXML2.XMLHttp.5.0”,
”MSXML2.XMLHttp.4.0”, ”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”,
”Microsoft.XMLHttp”];

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
req = new ActiveXObject(vectorVersiones[i]);
return req;
} catch (e) {}
}
}
}
return req;
}

reemplazandoDIV.html
<!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>
<title>Envío de Parámetros vía POST</title>
<script type=”text/javascript” src=”XHR.js”></script>
<script type=”text/javascript”>

// Defino Variables Globales


var peticion;

function enviarPeticion() {
peticion = obtenerXHR();
peticion.open(”POST”, ”leerArchivoPost.aspx”, true);

83
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 84

Maximiliano R. Firtman

peticion.onreadystatechange = procesarPeticion;

// Definimos cabecera obligatoria para enviar POST


peticion.setRequestHeader(”Content-Type”,
”application/x-www-form- urlencoded”);

// Enviamos los parámetros


var parametros = ”archivo=primerhtml.txt”;
peticion.send(parametros);

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos el texto dentro del DIV
var div = document.getElementById(”contenido”);
div.innerHTML = peticion.responseText;
}
}
}

</script>

</head>
<body onload=”enviarPeticion()”>

<div id=”contenido”>
</div>

</body>
</html>

Fig. 2-31. Si bien parece una página normal, todo el HTML que se ve en la figura fue traído vía XMLHtt-
pRequest y no es parte del HTML original.

84
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 85

AJAX. Web 2.0 para profesionales

Fig. 2-32. Mediante Web Developer de Firefox se puede ver el código HTML generado, que es el que
realmente estamos viendo en pantalla aunque haya sido generado de manera dinámica.

En el capítulo 3 se entrará en el uso de técnicas avanzadas de JavaScript, meto-


dologías de trabajo y herramientas del lenguaje.

85
C02.qxd:Project Ajax4.1.qxd 10/18/07 7:55 PM Página 86
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 87

JavaScript avanzado
3
Técnicas avanzadas
Antes de comenzar a realizar acciones más avanzadas con AJAX, es preciso ver y
aprender algunas técnicas poco conocidas en JavaScript que ayudarán a escribir un
código mejor y más limpio.

Try-Catch

Si bien ya se mencionó algo en el capítulo anterior, es necesario abordar esta senten-


cia de manera más detallada. Disponible desde JavaScript 1.4, la sentencia try permite
ejecutar cierto código JavaScript que es susceptible de generar algún error y de esta
manera capturarlo. Esta instrucción forma parte de casi todos los lenguajes moder-
nos, como Java, Visual Basic, C# y PHP. Su sintaxis en JavaScript es la siguiente:

try {
// Código a Intentar
} catch (e) {
// Código a ejecutar si dio error el anterior
} finally {
// Código a ejecutar siempre
}

Si se tienen tres líneas de código en el try y la segunda genera un error, entonces


la tercera nunca se ejecutará y el hilo de ejecución se moverá hacia el código incluido
en el catch (capturar en inglés). Este último recibe un parámetro que, por convención,

87
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 88

Maximiliano R. Firtman

se llama e de error o excepción (fig. 3-1). Este parámetro es un objeto que expone las
siguientes propiedades:
• name: tipo de error.
• message: mensaje detallado del error.
• lineNumber: línea donde se produjo el error.

Por último, la sentencia try puede contener una sentencia finally, en la que se in-
cluye código que se ejecutará siempre, tanto en los casos en que el código try dé error
y se prosiga con el catch, como cuando el código se ejecute de manera correcta.
La captura de errores permite:
• No exponer al usuario a errores de JavaScript que implicarían que se cuelgue
la aplicación RIA.
• Capturar posibles errores cuando se reciba código vía AJAX desde el servidor.
• Enviar una petición AJAX al servidor con los detalles del error JavaScript (y los
datos del navegador) para que en el servidor, por ejemplo, se envíe un e-mail
al administrador con el detalle.

Fig. 3-1. Objeto e con el detalle del error producido.

Generando errores
En la programación orientada a objetos también es común no sólo capturar errores
sino generarlos. ¿Generar errores? Sí, es posible que nuestro código genere un error

88
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 89

AJAX. Web 2.0 para profesionales

(o excepción, como se lo conoce) a propósito con un mensaje particular, para que


luego éste pueda ser capturado por un try en otro momento del código. Esto permite
que se mantenga un manejo de error interno consistente con el sistema de errores pro-
pio del lenguaje.
El código para generar una excepción es el siguiente:

throw(”Mensaje de Error”);

Si se desea que el objeto recibido en el catch tenga las mismas propiedades que
los clásicos errores, se puede hacer lo siguiente:

throw({name: ”Error Interno”, message: ”Mensaje de Error”});

For in

Todos conocen la clásica sentencia for:

for (var i=0; i<array.length; i++) {


alert(array[i]);
}

Nótese primero el uso de var i. Si no se lo había hecho hasta ahora es momento


de recordarlo. Es imprescindible colocar var i y no sólo i en el for. Si no se incluye el var,
la variable i se considerará global a todo el código e interferirá con otros ciclos for que
hubiera, y cuando el código JavaScript es grande (como en una aplicación AJAX), se
puede tornar muy difícil encontrar un error como éste cuando la aplicación no res-
ponde como deseamos.
No obstante, lo que nos convocaba en esta parte del libro era otra instrucción, la
conocida como for in. Ésta es una instrucción particular de JavaScript que permite ite-
rar entre todos los elementos de una colección (como un vector o array), sea su índice
numérico o alfanumérico. Su sintaxis es la siguiente:

for (var i in coleccion) {


alert(coleccion[i]);
}

89
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 90

Maximiliano R. Firtman

Esta sentencia permite que se itere entre los elementos de un vector con menos
código que el clásico for visto antes y con el mismo resultado. Es preciso no confun-
dir la sentencia for in con la for each encontrada en muchos lenguajes (como C#, PHP
o Java). Esta última itera entre los elementos de la colección, mientras que for in lo
hace sobre el índice.
Si se va a usar la librería conocida como Prototype (que se analizará en párrafos
posteriores) no se puede utilizar for in cuando se trata de vectores. Más adelante ve-
remos por qué y su solución.

Manejo de funciones

Lo primero que se nos ocurre al leer el título es, ¿qué se puede indicar acerca de las
funciones que no se sepa? Bueno, veremos que hay mucho más de las funciones en
JavaScript de lo que uno conoce.

Parámetros opcionales
En JavaScript los parámetros de las funciones pueden no enviarse al momento de eje-
cutar la función sin que esto implique un error, en primera instancia. Por ejemplo, una
función que recibe un parámetro puede invocarse sin él. Ahora bien, según lo que haga
la función adentro, es factible que tal vez el código termine en un error.
No obstante, esta característica se puede aprovechar para crear funciones que
hacen operaciones distintas (o la misma de manera diferente), según la cantidad de
parámetros que se reciban, emulando la sobrecarga de funciones existentes en len-
guajes tipados. Si se tienen numerosos parámetros, sólo es posible no invocar a los úl-
timos. Por ejemplo, la función siguiente:

function multiplesParametros(a, b, c) {

puede invocarse enviando ningún parámetro, el parámetro a, el a y el b, o todos. No


es posible enviar sólo b o sólo c, dado que se entendería como a.
Cuando un parámetro no se envía al momento de la invocación, posee el valor
especial undefined.
Por ejemplo, se puede armar la función siguiente que muestra un mensaje de error:

function mostrarError(texto) {
if (texto==undefined) {

90
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 91

AJAX. Web 2.0 para profesionales

texto = ”Ha ocurrido un error. No se dispone de detalles”;


}
alert(texto);
}

Sobrecarga de parámetros por tipo


Si bien no es una característica de JavaScript, si se quiere emular el funcionamiento de
la sobrecarga de parámetros en funciones, o sea, tener una función con el mismo nom-
bre, pero que según el tipo del parámetro haga cosas distintas, se puede hacer uso del
operador lógico typeof. Por ejemplo,

function mostrar(dato) {
// Si es un array muestro todos los elementos, si no sólo el dato
if (typeof dato == ”object”) {
for (var i in dato)
alert(i);
} else {
alert(dato);
}
}

JavaScript podrá devolver object, string, number, boolean, function o undefined al


usar typeof.

Parámetros como variables


Léase la frase siguiente dos veces: una función en JavaScript es una variable. ¿Una va-
riable? Así es. De esta forma, cuando se hace:

function imprimirNombre() {
alert(”Soy JavaScript”);
}

es equivalente a:

var imprimirNombre;
imprimirNombre = function() {
alert(”Soy JavaScript”);
}

91
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 92

Maximiliano R. Firtman

ya sea que se defina de la primera o de la segunda forma, ambas se invocan de la


misma manera: imprimirNombre().
Ahora que se sabe que las funciones en realidad son variables, pueden operarse
como tales; por ejemplo, es factible enviar funciones por parámetro o asignar funcio-
nes a otras variables.
Por ejemplo, si se hace:

var imprimirApellido = imprimirNombre;


imprimirApellido ();

se estaría ejecutando la función nombre original. Nótese (y tendremos que volver a in-
sistir con esto) que cuando se asignan las funciones no se le incluyen los paréntesis a
imprimirNombre. Si se hiciera imprimirNombre(), se la estaría ejecutando y no asig-
nando.
Cada elemento del documento (X)HTML posee propiedades que son de tipo fun-
ción, más conocidas como eventos. Por ejemplo, el onclick, el onload, el onchange.
Esto significa que, desde código JavaScript se puede leer y definir qué código se quiere
ejecutar en esos eventos sin incrustar ese código dentro del HTML.
Veamos cómo se haría al viejo estilo:

<input type=”button” value=”Haz clic” onclick=”alert(‘Gracias por


hacer clic’)” />

Ahora veamos cómo se puede cambiar por código. Recuérdese que la propie-
dad XHTML que se debe usar en el tag script es type=”text/javascript” y no más
language=”javascript”.

<input type=”button” value=”Haz clic” id=”btn1” />

<script type=”text/javascript”>

document.getElementById(”btn1”).onclick = apretar; // Sin paréntesis

function apretar() {
alert(‘Gracias por hacer clic’);
}
</script>

92
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 93

AJAX. Web 2.0 para profesionales

Aunque, dado que son variables, también se les podría asignar algo así como una
función literal, sin necesidad de ponerle nombre a la variable/función. Este método
también se llama función inline o función anónima:

<input type=”button” value=”Haz clic” id=”btn1” />

<script type=”text/javascript”>

document.getElementById(”btn1”).onclick = function() {
alert(‘Gracias por hacer clic’);
}
</script>

Si bien por el momento parece que se escribe más código, se verá cómo esto nos
ayudará a ser más prolijos con nuestro trabajo y a realizar efectos muy simples con
muy poco código, sin ensuciar el HTML.

Parámetros múltiples
Es posible que una función no tenga definida una cantidad mínima de parámetros y que
ésta sea dinámica. Para leer los parámetros en forma dinámica, podemos no definir pa-
rámetro alguno y luego leer la propiedad especial arguments. Esta propiedad es un
objeto que contiene todos los argumentos recibidos en la función. Entonces, podrá
convertirse a Array y recorrerse como cualquier vector; cada posición tendría cada ar-
gumento recibido.

Programación orientada a objetos

Si bien JavaScript es un lenguaje orientado a objetos, no es común que los programa-


dores desarrollen clases o moldes de objetos en JavaScript. Esto es, primero porque
hasta el presente no era necesario y, segundo, porque la sintaxis que tiene JavaScript
es un poco extraña comparada con lenguajes más conocidos orientados a objetos.

Objeto Object
El primer caso, más simple, es crear un objeto de la clase genérica Object. Para instan-
ciar (crear) un objeto de una clase determinada, se usa la instrucción new. Ahora bien,
¿cómo es posible dar propiedades (variables) o métodos (funciones) a ese objeto? Muy
simple, se asignan después. Recuérdese que JavaScript es un lenguaje no estricto.

// instanciamos
var persona = new Object();
// definimos propiedades

93
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 94

Maximiliano R. Firtman

persona.nombre = ”Juan”;
persona.apellido = ”Pérez”;
// definimos métodos
persona.imprimir() = function() {
alert(this.nombre + “ “ + this.apellido);
}

persona.imprimir();

Nótese el uso de this, como objeto especial que permite acceder desde adentro
de código del objeto a sus propiedades. Este código ejecuta lo que uno espera que
haga, como se ve en la figura 3-2.

Fig. 3-2. Se pueden crear métodos de manera dinámica una vez que el objeto está instanciado.

Recorriendo el objeto
Ahora que se ve que un objeto puede tener cualquier propiedad definida de manera di-
námica, ¿cómo se sabe, dado un objeto recibido, qué propiedades tiene? Todos los ob-
jetos en JavaScript permiten acceder a las propiedades (recuérdese que las funciones
también son propiedades) por medio de notación de array; por ejemplo, persona.nom-
bre también puede accederse como persona[”nombre”].
De esta manera, es factible iterar entre todas las variables simplemente con un for in.

for (var propiedad in persona) {


alert(propiedad + “ tiene “ + persona[propiedad]);
}

94
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 95

AJAX. Web 2.0 para profesionales

Creando clases
Qué sucede si se quiere crear un molde para desarrollar objetos nuevos, o sea, definir
clases. La solución es un poco difícil de leer al principio, pero veamos un ejemplo:

function Curso() {
this.nombre = ””;
this.precio = ””;
this.alumnos = []; // vector vacío
}

¿Una función? Sí, una clase se define como una función que puede tener propie-
dades (representadas con el objeto this) y también otras funciones adentro. De esta
manera, si se ejecuta

Curso();

se está considerando como función, y si se ejecuta

ajax = new Curso();

se está considerando como una clase y se está creando una nueva instancia de esa
clase. De esta forma se le pueden agregar métodos a la clase:

function Curso() {
this.nombre = ””;
this.precio = ””;
this.alumnos = []; // vector vacío
this.inscribir = function(alumno) {
// Agrega el alumno al curso
this.alumnos.push(alumno);
}
}

ajax = new Curso();


ajax.nombre = ”AJAX”;
ajax.precio = 100;
ajax.inscribir(”Raúl”);
ajax.inscribir(”José”);

Constructores
El concepto de constructor tiene que ver con el código insertado dentro de la clase/fun-
ción, por ejemplo:

95
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 96

Maximiliano R. Firtman

function Curso(nombre, precio) {


this.nombre = nombre;
this.precio = precio;
this.alumnos = []; // vector vacío
this.inscribir = function(alumno) {
// Agrega el alumno al curso
this.alumnos.push(alumno);
}
}
ajax = new Curso(”AJAX”, 100);

De esta forma, al instanciar el objeto, le estamos ejecutando código.

Prototipado
Una de las grandes ventajas de JavaScript a la hora de trabajar con objetos es la po-
sibilidad de modificar en forma dinámica, y a futuro, clases ya definidas por nosotros,
por otras librerías, o por el propio motor de JavaScript. De esta forma, es posible agre-
garle comportamiento (métodos) a todos los arrays o a todos los objetos FORM de
nuestra página.
Así muchas librerías logran incorporar nueva funcionalidad al lenguaje JavaScript.
Esta posibilidad se conoce como prototype y su sintaxis es muy sencilla, por ejemplo:

// le agregamos una función a todos los objetos Persona


// luego de definir la clase
Persona.prototype.calcularTotal = function() {
var total = 0;
for (var i in this.alumnos)
total += this.alumnos[i];
return total;
}

Herencia
JavaScript no soporta de manera directa el concepto de herencia, aunque se puede
emular. No nos introduciremos en este tema, porque es difícil que tengamos que hacer
uso de él en aplicaciones AJAX. Muchas librerías de cliente incorporan a JavaScript
metodologías más sencillas para lograr herencia en los objetos.

96
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 97

AJAX. Web 2.0 para profesionales

Buenas prácticas

Nomenclatura
Es una buena práctica tener una nomenclatura estándar para usar, dado que en aplica-
ciones AJAX habrá mucho código JavaScript. Esto ayudará a reducir la cantidad de erro-
res. Una sugerencia utilizada por el mismo lenguaje en varias oportunidades es la siguiente:
• Utilizar notación camello minúscula en variables y funciones. Esto es, la
primera letra de todas las variables y funciones debe ser minúscula, y todas las
palabras siguientes que forman el nombre deben comenzar con mayúscula.
Por ejemplo: imprimir(), imprimirNombreCompleto(), cantidadAcumulada.
• En clases utilizar notación camello mayúscula. Esto es, todas las palabras
que forman parte del nombre deben comenzar con mayúscula. Por ejemplo:
String, ListaDeEmpleados.
• En propiedades de tipo función (eventos) utilizar minúscula. Por ejemplo:
onclick, onreadystatechange, onfinishshopping.
• En constantes utilizar mayúsculas y guion bajo para separar palabras. Por
ejemplo: PI, MENSAJE_ERROR.
• Prefijos. Si bien hay técnicas para utilizar prefijos en todas las variables (p. ej.,
si n fuera para números, nTotal sería el nombre correcto), lo ideal en JavaScript
es utilizar prefijos cuando su uso realmente valga la pena, por ejemplo, para
diferenciar vectores de variables simples. En general se puede utilizar a o v
como prefijo.
• Prefijos en Ids. Es muy útil utilizar prefijos en los Ids de los elementos XHTML.
De esta manera, se pueden identificar y encontrar elementos en el DOM con
rapidez. Algunas sugerencias son:

TAG Prefijo Ejemplo

A lnk lnkPróximo

INPUT type=”button” btn btnGuardar

INPUT type=”text” txt txtDirección

INPUT type=”checkbox” chk chkAceptoCondiciones

INPUT type=”radio” rd rdTipoDocumento

SELECT lst lstPaises

SPAN lbl lblTítulo

DIV div divContenido

TABLE tbl tblClientes

97
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 98

Maximiliano R. Firtman

Documentación
Si bien se sabe que es conveniente documentar todo proyecto, hay un estándar en el
mercado, conocido como xDoc (JavaDoc para Java, NDoc para .NET, PHPDoc para
PHP, etc.), que permite documentar variables, clases y funciones de una manera es-
tándar que posibilita a los IDE entender para brindar ayuda cuando se escribe código.
Además, existen utilitarios que buscan nuestro código por este tipo de docu-
mentación y generan ayuda en formato HTML o Windows Help para brindar la docu-
mentación del proyecto en forma automática.
En el caso de JavaScript, JSEclipse soporta esta nomenclatura, y hay utilitarios,
como JSDoc, que permiten que se genere el documento de ayuda (fig. 3-3).

Fig. 3-3. JSEclipse ayuda en la generación de la documentación JSDoc.

No obstante, ¿qué sucede con la seguridad de nuestro código? ¿Conviene dejar


comentarios en nuestro JavaScript? La respuesta es sí y no. Veamos: es necesario do-
cumentar nuestro proyecto por la salud del código a los fines de desarrollo. Asimismo,

98
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 99

AJAX. Web 2.0 para profesionales

es preciso no generar comentarios en el código final para enviar archivos más peque-
ños y no entregar información confidencial sobre el uso de la aplicación. De esta ma-
nera, se hace necesario pensar que vamos a tener un código en modo desarrollo y,
cuando ya tengamos todo funcionando, la versión que publicamos en producción será
una versión de los archivos .js sin documentación.
Se puede descargar una versión de JSDoc de jsdoc.sourceforge.net, que lee todo
comentario que se haya generado con doble asterisco y lo asigna a la definición de la
línea siguiente. Se puede descargar otra versión de code.google.com/p/jsdoc-2.
Por ejemplo:

/** Es el nombre completo del alumno */


var nombreCompleto;

Cuando se trata de una función, el mismo comentario JSDoc tiene ciertos pará-
metros que ayudarán a confeccionar la documentación (fig. 3-4).

Fig. 3-4. Ejemplo de cómo quedaría un archivo de documentación generado con JSDoc a partir del
código fuente.

99
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 100

Maximiliano R. Firtman

Veamos un ejemplo sencillo:

/** Suma dos números


/* @returns entero con la suma
/* @param {number} a primer sumando
/* @param {number} b segundo sumando
*/
function suma(a, b) {
return a+b;
}

JSON
Qué es

JSON significa JavaScript Object Notation, o notación de objetos de JavaScript, y se


pronuncia como el nombre inglés Jason. No es más que una forma muy potente y poco
conocida de crear e instanciar objetos, que tomó un significado nuevo a partir de las
aplicaciones AJAX.
Su notación es tan sencilla que en la actualidad se utiliza en muchos lenguajes para
transporte liviano de objetos.

Sintaxis

Un objeto JSON está encerrado entre llaves {} y contiene propiedades separadas por
comas, cuyos nombres deberían estar encerrados entre comillas (aunque la mayoría de
las implementaciones los acepta sin ellas). Cada propiedad tiene un valor separado
por dos puntos (:) y cada valor puede ser:
• Un string literal encerrado entre comillas.
• Un número.
• Un array.
• Una función.
• Otro objeto JSON.

Veámoslo mejor en un ejemplo,

{
nombre: ”John”,
apellido: ”Doe”,
edad: 25
}

100
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 101

AJAX. Web 2.0 para profesionales

El estándar estricto indica que los nombres de las propiedades deben estar en-
cerrados entre comillas, aunque a esta altura de la evolución de los browsers se puede
prescindir de ellas:

{
”nombre”: ”John”,
”apellido”: ”Doe”,
”edad”: 25
}

Es probable que esta sintaxis nos recuerde la utilizada en las hojas de estilo CSS.
Es similar, sólo que las propiedades se separan por comas y no por punto y coma, y
además no se coloca la última coma.
Un vector se puede enunciar con rapidez entre corchetes [] con sus elementos
separados por coma. Por ejemplo:

{
nombre: ”John”,
apellido: ”Doe”,
edad: 25,
hijos: [”Mary”, ”Sean”]
}

Asimismo, una propiedad puede contener otro JSON, por ejemplo:

{
nombre: ”John”,
apellido: ”Doe”,
edad: 25,
hijos: [”Mary”, ”Sean”]
pareja: {
nombre: ”Lisa”
}
}

Todos los espacios, las tabulaciones y los saltos de línea son opcionales, pero
simplifican la lectura.
A veces también se considera JSON cuando se define sólo un vector, por ejemplo:

var paises = [”Argentina”, ”México”, ”España”];

101
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 102

Maximiliano R. Firtman

Asimismo, cada elemento de un vector en un JSON puede ser otro JSON.

var carreras = [{nombre: ”Mobile”, duracion: 4},


{nombre: ”Flash”, duracion: 5}
];
alert(carreras[0].nombre); // Imprime Mobile

Ventajas

Las ventajas son muchas, es sencillo y rápido de escribir, su lectura es comprensible


y se puede navegar por el objeto con notación de punto, como cualquier otro objeto
JavaScript (fig. 3-5).

var cliente = {
nombre: ”John”,
apellido: ”Doe”,
edad: 25,
hijos: [”Mary”, ”Sean”]
pareja: {
nombre: ”Lisa”
}
};
alert(“El cliente “ + cliente.nombre + “ tiene “ +
cliente.hijos.length + “ hijos y su pareja se llama “ +
cliente.pareja.nombre);

Fig. 3-5. Ventana de alerta con todos los datos obtenidos del JSON.

102
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 103

AJAX. Web 2.0 para profesionales

Un JSON, como todo objeto JavaScript, puede recorrerse con un for in para saber
todas las propiedades que posee.

JSON con funciones

Un JSON, como no podía ser de otra manera, también puede contener funciones, que
pueden transportarse como cualquier otra variable:

var cliente = {
nombre: ”Juan”,
limpiar: function() {
this.nombre = ””;
}
}

cliente.limpiar();

Usos

En el presente, JSON se utiliza para:


• Definir enumeraciones o constantes para evitar problemas de escritura, por
ejemplo:

var tipoCliente = {
EMPRESA: 1,
PARTICULAR: 2,
INSTITUCION: 3
}

c = new Cliente(tipoCliente.PARTICULAR);

• Transportar objetos entre el cliente y el servidor a través de AJAX, en reem-


plazo de XML. Para ello, se recibe el objeto como string, como se indicó en el
capítulo anterior por medio de la propiedad responseText del XMLHttpRequest.
Para hacer que JavaScript interprete al JSON como tal y no sólo como string,
hace falta ejecutar el código siguiente que evalúa el JSON:

// ...
var objeto = eval( “(“ + xhr.responseText + “)“ );

103
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 104

Maximiliano R. Firtman

Antes de hacer el eval, es necesario estar seguros de que es un JSON válido, si


no generará una excepción (que se puede capturar con try) o ejecutará código Java
Script si lo fuera.
• Reemplazar a XML en el concepto de Web Services para simplificar los datos
enviados. Google o Yahoo! ofrecen muchos de sus servicios públicos en for-
mato JSON, además del clásico XML.
• Definir parámetros opcionales cuando se crean objetos. Ya se verán ejemplos
de esto más adelante.

Librerías para otros lenguajes

El sitio web www.json.org ofrece un listado de librerías que permiten convertir objetos na-
tivos de cada lenguaje hacia un JSON y viceversa. También ofrece una función JavaScript
que se encarga de recibir un string e indicar si es un JSON válido o no (fig. 3-6).

Fig. 3-6. Desde el sitio web de JSON se pueden descargar librerías de JSON para PHP, .NET, ActionScript,
Java y muchos otros lenguajes.

104
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 105

AJAX. Web 2.0 para profesionales

PHP
Hay varias librerías para PHP que permiten importar y exportar objetos nativos PHP a
formato JSON, pero desde la versión 5.2 de PHP una de ellas ya se incorporó en el len-
guaje sin necesidad de instalar nada más.
Esta extensión agrega a PHP dos funciones: json_decode y json_encode, que
convierten un string a objeto PHP y viceversa, respectivamente. Por ejemplo:

<?
$json = ‘{”nombre”:”Juan,”edad”:23}‘;

$persona = json_decode($json);

echo $persona->nombre . “ tiene “ . $persona->edad . ” años”;


?>

<?
// Este código envía al Javascript un JSON
$arr = array (‘nombre’=>’Juan’,‘edad’=>23);

echo json_encode($arr);

?>

El uso de las otras implementaciones para PHP que figuran en json.org es muy si-
milar.

.NET
En la actualidad en .NET hay dos librerías estándar con JSON: Jayrock (jayrock.berlios.de)
y Json.NET (newtonsoft.com). Ambas son gratuitas y tienen la misma funcionalidad. Ve-
amos un ejemplo utilizando Json.NET:

// Serializando un objeto a JSON en C#


Cliente c = new Cliente();
c.Nombre = ”Microsoft”;
c.Website = ”http://www.microsoft.com”;
c.Productos = new string[] { ”Windows”, ”.NET”, ”Office” };

string Json = JavaScriptConvert.SerializeObject(c);

// Para recibir un JSON como string y convertirlo a objeto de clase


//cliente
Cliente c = (Cliente)JavaScriptConvert.DeserializeObject(json, ty-
peof(Cliente));

105
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 106

Maximiliano R. Firtman

En próximas versiones de .NET, se incorporarán clases que podrán convertir JSON


a objetos .NET y viceversa, directamente en el framework.

Java
Java es una de las plataformas con mayor cantidad de librerías para convertir JSON.
Sólo en el sitio json.org hay más de 12 librerías distintas. Su uso es muy similar a los
propuestos antes en PHP y .NET, por lo que no vale la pena ejemplificarlos de nuevo.

Prototype
Qué es

Prototype es una librería Open Source creada para extender las funcionalidades de Ja-
vaScript y reducir la tarea de codificación a los programadores. Tiene la gran ventaja
de distribuirse en un solo archivo .js, es muy liviana y en los últimos tiempos se con-
virtió en un estándar de facto en el mercado. Muchas otras hacen uso de Prototype,
por lo que en numerosos casos se la considerará un requisito obligatorio en aplicacio-
nes AJAX.

Instalación

Su instalación es muy sencilla. Sólo basta con visitar el sitio web www.prototypejs.org
y descargar la última versión, que no es más que un archivo prototype.js que se debe
incorporar en nuestro proyecto y, luego, incluirlo en un tag script (fig. 3-7).
En el sitio web se puede consultar toda la documentación de las API que incorpora la
librería. A continuación se detallarán los agregados más utilizados.

Utilitarios

$
Dentro de la gama de utilitarios, hay muchos y muy útiles. El primero que se va a ana-
lizar es el signo $. Aunque hasta el presente no se usaba para mucho, es posible que
una variable (y, por lo tanto, también una función) en JavaScript comience con el signo
$, incluso que su nombre sea sólo ese símbolo. Es por eso que Prototype ha creado
una función llamada $ que reemplaza a una de las funciones más utilizadas en una
aplicación AJAX: document.getElementById. Es así que con hacer:

$(”divContenido”)

106
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 107

AJAX. Web 2.0 para profesionales

Fig. 3-7. Sitio web oficial de la librería Prototype.

se estaría recibiendo un objeto que represente al elemento XHTML que tenga id div-
Contenido. Queda muy simple y sencillo de leer, además de la obvia reducción de có-
digo a escribir y a transferir desde el servidor al cliente. De esta forma, si se quiere
cambiar el color de fondo de una celda que posee id, se podría hacer:

$(”celda1”).bgColor = ”red”;

o si se quiere definir la función onclick de un botón:

$(”btnEnviar”).onclick = function() { alert(”Gracias por presio-


narme”) };

no obstante, la función $ no es sólo una mera traducción de document.getElement ById.


La función recibe un número dinámico de parámetros y, cuando se envía más de uno,

107
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 108

Maximiliano R. Firtman

lo que se obtiene es un vector cuyas posiciones son cada uno de los elementos pedi-
dos. Por ejemplo:

$(”btnEnviar”, ”btnCancelar”, ”btnSalir”)

Este código devolvería un vector de 3 posiciones con tres objetos de tipo botón, con
los ids solicitados.

$$
La función $$ recibe uno o más selectores de tipo CSS (de clase, de etiqueta o de id)
y devuelve un vector con todos los elementos que cumplen con el o los selectores
dados. Hay combinaciones completas que se pueden hacer para encontrar con facili-
dad y rapidez elementos HTML que cumplan con alguna condición. Ejemplos:

// Devuelve todos los divs


$$(”div”);

// Devuelve todos los span de clase titulo


$$(”span.titulo”);

// Devuelve todos los links que abran en ventana nueva


$$(”a[target=’_blank’]”);

// Devuelve todos los td y th de la tabla clientes


$$(”#clientes td”, ”#clientes th”);

$F
Devuelve el valor (la propiedad value) del elemento HTML dado, por lo general una eti-
queta de formulario (un textbox, o un select).

var nombre = $F(”txtNombre”);


var país = $F(”lstPaises”);

$w
Copiada del lenguaje Ruby, esta función recibe un string con palabras separadas por
espacio y devuelve un vector con cada palabra.

var arrayPaises = $w(”Argentina Brasil Chile Uruguay”);

108
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 109

AJAX. Web 2.0 para profesionales

Try.these
Esta función recibe una lista de funciones por parámetro y devuelve el resultado de la
primera de ellas que no genere una excepción (error). Por ejemplo, se podría mejorar
nuestra librería de AJAX cuando se instancia el objeto XMLHttpRequest evitando ifs:

function obtenerXHR() {
return Try.these(
function() { return new XMLHttpRequest() },
function() { return new ActiveXObject(‘Msxml2.XMLHTTP’) },
function() { return new ActiveXObject(‘Microsoft.XMLHTTP’) }
) || false;
}

Otros
Hay otros utilitarios menos usados, como $R, $A y $H. El primero permite generar un
objeto ObjectRange, el segundo, convertir cualquier objeto enumerable a un Array y el
último, cualquier objeto a un HashTable (array asociativo). Dejamos para revisar en la
documentación oficial de Prototype su uso y ejemplos. $R permite obtener una se-
cuencia de objetos de tipo enumerables, por ejemplo, para recibir una lista con los nú-
meros 1 a 1000, se puede hacer $R(1, 1000) y las letras del alfabeto $R(‘a’, ‘z’). Si se
quieren convertir esos objetos a Array, sólo resta aplicarle también $A (fig. 3-8).

Fig. 3-8. La documentación de Prototype incluye ejemplos de cada función y está disponible en la web,
en PDF y en formato Ayuda de windows.

109
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 110

Maximiliano R. Firtman

Agregados a objetos

Cuando importamos prototype.js en nuestra página web, de manera instantánea mu-


chos objetos adquieren características nuevas, como propiedades y métodos agrega-
dos por la librería.

Strings

Todos los strings ahora poseen, entre otros, los métodos siguientes:

Método Descripción

blank Devuelve true si el string está vacío o sólo contiene espacios

camelize Devuelve una versión en formato camello del string en cuestión. Por ejemplo: nombre-
cliente devuelve nombreCliente

capitalize Pone la primera letra en mayúscula

desherize Reemplaza todos los guiones bajos (_) por medios (-)

empty Devuelve true si el string está vacío por completo (no tiene ni siquiera espacios)

endsWith Recibe una cadena e indica si el string finaliza con ella. Por ejemplo, es útil para
comprobar extensiones de nombre de archivo

escapeHTML Convierte caracteres especiales a HTML

evalJSON Evalúa el string como un JSON y devuelve un objeto. Recibe un parámetro lógico opcional
e indica si queremos comprobar que no sea código malicioso

evalScripts Ejecuta todos los tag SCRIPT que hubiera en el string

startsWith Recibe una cadena e indica si el string comienza con ella

strip Elimina todos los espacios antes y después del texto (equivalente a un Trim en otros
lenguajes)

stripScripts En caso que el string fuera HTML, elimina todos los tags script que hubiera

stripTags En caso que el string fuera HTML elimina todos los tags (aunque no el texto que tuvieran
dentro)

110
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 111

AJAX. Web 2.0 para profesionales

Método Descripción

times Recibe un parámetro numérico y devuelve una versión con el string repetido n veces.

toArray Convierte el string a un array de caracteres.

toJSON Convierte el string a un JSON compatible.

toQueryParams En caso que el string tuviera un formato estilo QueryString (clave=valor&clave2=valor2)


devuelve un objeto con las propiedades clave y clave2.

truncate Recibe una cantidad y un sufijo opcional. Trunca el string a la cantidad dada e incorpora
el sufijo al final. Por defecto el sufijo es “...”. Permite mostrar textos largos en espacios
reducidos.

underscore Convierte un string en notación camello a separado por guiones bajos.

unescapeHTML Devuelve una versión en texto normal de un string con caracteres en formato Escape
HTML.

También aparece una nueva clase en JavaScript llamada Template, que permite
definir cierta plantilla y un objeto estilo JSON, así como reemplazar cada propiedad
del objeto en la plantilla en las ocurrencias que se indiquen. Por ejemplo:

// ésta es la plantilla
var plantilla = new Template(‘El curso de #{curso} es dictado por
#{profesor}.’);

// los datos a reemplazar


var cursoAjax = {
curso: ‘AJAX y JS Avanzado’,
profesor: ‘Maximiliano R. Firtman’
};
// aplica la plantilla
alert(plantilla.evaluate(cursoAjax));

Arrays
Todos los arrays reciben los métodos siguientes. Cuando el objeto que tenemos no es
estrictamente un array, sino una colección (p. ej., document.getElementsByTagName)
podemos convertirlo a array en forma explícita para tener estos métodos utilizando $A.

111
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 112

Maximiliano R. Firtman

Método Descripción

clear Limpia todo el array.

clone Devuelve una copia exacta del array.

compact Devuelve una versión comprimida del array, eliminando todas las posiciones nulas
o indefinidas.

each Ejecuta una función recibida por parámetro en cada posición del array. Equivale
a un for que recorra todo el array y ejecute la función a cada elemento.

first Devuelve el primer elemento.

flatten En el caso de un vector multidimensional (p. ej., una matriz), lo convierte a una sola
dimensión.

indexOf Devuelve la posición de la primera ocurrencia de un elemento recibido por


parámetro, o -1 si no existe.

last Devuelve el último elemento.

reduce Si el array contiene una sola posición, devuelve el único elemento.

reverse Invierte la posición de los elementos.

toJSON Convierte el vector a un string estilo JSON.

without Recibe una lista de valores y devuelve el vector, pero sin los valores recibidos.

Si trabajamos con Prototype, debemos dejar de utilizar for in para recorrer los vec-
tores. Sin entrar en demasiados detalles técnicos, los métodos que Prototype tienen
problemas con el for in. La solución es cambiar el código siguiente:

for (var i in vector) {


alert(vector[i]);
}

por el que sigue:

vector.each(function(item) {
alert(ítem)
}

112
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 113

AJAX. Web 2.0 para profesionales

También aparecen métodos nuevos que se pueden aplicar a todos los elementos
que sean enumerables, que los podemos ver en la documentación. Algunos de estos
métodos son en realidad muy útiles.

Elementos DOM
Cuando se acceda a un elemento DOM por medio de las funciones propias de Prototype,
como $ o $$, entonces se estará accediendo a un elemento nodo extendido, que posee
más propiedades y métodos. Más adelante en este capítulo se introduce el tema de
DOM y se agregan estos elementos de Prototype.

Event
Prototype incorpora a JavaScript un manejo de eventos algo superior al clásico que trae
el estándar del lenguaje. Con Prototype se puede hacer uso del patrón de diseño Ob-
server para agregar o eliminar un observador a un evento de un elemento HTML. Esto
permite una forma más sencilla de agregar y eliminar funciones que escuchan a que
cierto evento ocurra.
Para ello, hay una clase Event que posee los métodos observe y stopObserving.
Veamos un ejemplo:

Event.observe(window, ‘load’, function() {


Event.observe(‘btnEnviar’, ‘click’, mostrarMensaje);
});

function mostrarMensaje() {
alert(”Gracias”);
// Dejamos de ”observar” el click del botón
Event.stopObserving(‘btnEnviar’, ‘click’, mostrarMensaje);
// El próximo click no ejecutará esta función
}

Form
Si a un formulario HTML le incluimos un ID (p. ej., ”form1”) y lo accedemos a través de
$(”form1”), tendremos los métodos siguientes:

Método Descripción

disable Desactiva de manera funcional todos los elementos que están dentro del formulario.

enable Vuelve a activar en forma funcional todos los elementos.

findFirstElement Devuelve el primer control que esté activado y no sea de tipo hidden.

113
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 114

Maximiliano R. Firtman

Método Descripción

focusFirstElement Pone el foco en el primer control del formulario.

getElements Devuelve una colección con todos los controles de ingreso del formulario.

getInputs Devuelve una colección con todos los controles INPUT. Es posible restringir cuáles
queremos mediante los parámetros.

reset Limpia todo el formulario.

serialize Devuelve todos los controles en formato string URL para enviarlos en una
petición AJAX vía GET o POST.

serializeElements Devuelve una serie de controles enviados por parámetro en formato string URL.

Así, si se desea convertir un clásico formulario a un formulario AJAX, sólo se debe


realizar la petición al servidor, enviando los parámetros recibidos del método serialize.
Además, se debe cambiar el botón de Enviar de tipo submit por uno de tipo button, si
no lo estaremos enviando al viejo estilo (fig. 3-9). Veamos un ejemplo:

Fig. 3-9. Se puede transformar cualquier formulario para que envíe los datos vía AJAX sin refrescar la
página.

114
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 115

AJAX. Web 2.0 para profesionales

formulario.html

<!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>Formulario de Envío</title>
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”ajax.js”></script>
<script type=”text/javascript” src=”formulario.js”></script>
</head>

<body>
<form id=”form1” name=”form1”>
<p>Nombre:
<input name=”txtNombre” type=”text” id=”txtNombre” />
</p>

<p>Apellido:
<input name=”txtNombre2” type=”text” id=”txtApellido” />
</p>

<p>Direcci&oacute;n:
<input name=”txtNombre3” type=”text” id=”txtDireccion” />
</p>

<p>Pa&iacute;s:
<select name=”lstPaises” id=”lstPaises”>
<option value=”AR”>Argentina</option>
<option value=”ES”>Espa&ntilde;a</option>
<option value=”MX”>M&eacute;xico</option>
</select>
</p>

<p>
<input type=”button” onclick=”enviarPost()” value=”Bot&oacute;n”
/>
</p>
</form>

</body>
</html>

115
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 116

Maximiliano R. Firtman

formulario.js

function enviarPost() {
var peticion = obtenerXHR();
peticion.open(”POST”, ”recibirDatos.php”, true);
peticion.onreadystatechange = procesarPeticion;

// Definimos cabecera obligatoria para enviar POST


peticion.setRequestHeader(”Content-Type”, ”application/x-www-form-
urlencoded”);

// Enviamos los parámetros del formulario a través de Prototype


var parametros = $(”form1”).serialize();
peticion.send(parametros);
}

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Mostramos el texto en una alerta
alert(peticion.responseText);
}
}
}

Objeto AJAX
Prototype provee su propio mecanismo para realizar peticiones AJAX que nos abstrae
de los problemas de incompatibilidad entre browsers, entre otras cosas.
Para ello, provee los objetos siguientes que se deben instanciar:

Ajax.Request(url, opciones)
Permite realizar una petición AJAX a la url indicada, definiendo distintos parámetros
opcionales para partir del segundo parámetro, que se envía en formato JSON.

Ajax.Updater(elemento, url, opciones)


Realiza una petición AJAX, y el contenido recibido como texto HTML lo utiliza como
contenido para reemplazar en el elemento DOM enviado por parámetro (p. ej., un DIV).

Ajax.PeriodicalUpdater(elemento, url, opciones)


Realiza una petición AJAX periódicamente y, sin mediar ningún otro código reemplaza
el contenido del elemento recibido por parámetro (p. ej., un DIV) con el texto HTML re-
cibido por la url en la petición.

116
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 117

AJAX. Web 2.0 para profesionales

Además, por medio de Ajax.Responders es posible registrar funciones que se eje-


cutarán cada vez que una petición AJAX de Prototype pase por cierto estado.
En todos los métodos expuestos las opciones en formato JSON pueden ser:

Opción Valor por defecto Descripción

asynchronous true Define si se usa una petición asincrónica o


sincrónica

contentType ‘application/x-www-form-urlencoded’ Define la cabecera que se enviará al servidor con


el tipo de contenido que estamos enviando

encoding ‘UTF-8’ La codificación de la petición

method ‘post’ Puede ser get o post

parameters ‘’ Recibe los parámetros a enviar en la petición.


Se puede enviar un string tipo URL, o un
objeto (p. ej., un JSON)

postBody null En caso que se envíe vía post se puede definir


aquí el cuerpo de la petición enviada

requestHeaders Headers por defecto Se puede enviar un objeto (p. ej., JSON) o un
vector con los headers que se quieren enviar

También los tres tipos de peticiones en las opciones permiten definirle los even-
tos siguientes que podrán ser capturados por una función:

Propiedad Descripción

onComplete Se ejecuta cuando la petición termina

onException Se ejecuta cuando se produce cualquier tipo de error al definir la petición

onFailure Se ejecuta cuando hubo algún error en el servidor (status != 200)

onSuccess Se ejecuta cuando la petición termina bien (equivaldría a cuando


readyState==4 y status==200). Este evento recibe la respuesta recibida
por parámetro (que tiene las propiedades responseText y responseXml)

on999 Siendo 999 algún código HTTP (p. ej., on404). Se ejecuta cuando ese código HTTP
se produce en la petición

117
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 118

Maximiliano R. Firtman

Por ejemplo, para enviar una petición al servidor y actualizar un DIV con el conte-
nido de un archivo html, el código sería el siguiente:

new Ajax.Updater(‘divContenido’, ‘contenido.html’, {


onFailure: { alert(‘Ocurrió un error’) },
method: ‘get’
});

Si se desea reemplazar nuestro ejemplo anterior de un formulario POST utilizando


el objeto Ajax de Prototype se cambiaría el formulario.js por el siguiente:

function enviarPost() {
new Ajax.Request(”recibirDatos.php”, {
onSuccess: function(respuesta) {
// En respuesta tenemos la devolución del servidor
alert(respuesta.responseText);
}
parameters: $(“form1”).serialize();
}
}

Como se puede apreciar, el código para hacer la petición AJAX se simplifica


mucho. No obstante, siempre se debe recordar que igualmente la librería está haciendo
lo mismo que hacíamos nosotros antes. De esta forma, ya no sería necesario utilizar
nuestro ajax.js, aunque todavía no nos desharemos de él.
Incluso si se envía desde el servidor un encabezado que indique algún tipo MIME
de tipo JSON (p. ej., application/javascript), Prototype convertirá en forma automática
la respuesta a JSON y se recibirá como segundo parámetro del evento onSuccess (fig.
3-10).

Otros agregados
Prototype también agrega comportamiento a los objetos siguientes:
• Class. Aparece un método Class.create que devuelve una función al estilo de-
finición de clases en el lenguaje Ruby.
• Date. Aparece el método toJSON que convierte la fecha.
• Enumerable. Aparecen varios métodos nuevos en todos los objetos que sean
enumerables (colecciones).
• Function. Aparecen los métodos bind y bindAsEventListener, que permiten
enlazar las funciones cuando hay problemas con el ámbito (scope) de éstas.

118
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 119

AJAX. Web 2.0 para profesionales

Fig. 3-10. Objeto respuesta recibido en el evento onSucess. Cada evento tiene sus propios atributos.

• Hash. Permite trabajar de mejor forma cuando se trata con objetos de tipo
Hash (o vectores asociativos).
• Number. Contiene algunas funciones útiles para números, como times –que
ejecuta una función n cantidad de veces– o toPaddedString –que devuelve el
número con ceros a la izquierda–.
• Object. La librería agrega métodos a todos los objetos, entre ellos extend –que
permite heredar del mismo– o toJSON –que lo convierte a un string con nota-
ción JSON–.
• PeriodicalExecuter. Permite ejecutar una función en forma periódica. Lo que
hace es encapsular el funcionamiento de setInterval y clearInterval propios de
JavaScript.

119
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 120

Maximiliano R. Firtman

Model View Controller


Qué es

El Model View Controller (modelo–vista–controlador) o MVC es un patrón de diseño


que permite separar en capas nuestra aplicación para lograr un menor acoplamiento
entre el código. Es una solución que sirve en todo tipo de aplicaciones, no sólo las de
tipo ricas de Internet.

Estructura

El patrón de diseño sugiere que dividamos nuestra aplicación en tres capas (fig. 3-11):
Modelo: es el que contiene la lógica de negocios de nuestra aplicación y el que toma
decisiones sobre el estado de los objetos dentro del sistema. Sabe cómo hay que eje-
cutar un cambio en la aplicación, aunque nunca le muestra nada al usuario.
Vista: es la encargada de mostrar información al usuario y recibir su interacción.
Controlador: es el que recibe el aviso de la interacción del usuario y decide qué es lo
que hay que hacer. No se encarga de hacerlo, dado que para eso invoca al Modelo.
Dentro de una aplicación AJAX una metodología de aplicación del patrón MVC es
separar nuestro desarrollo en:
• Vista: es el archivo XHTML junto al CSS que define la estructura de los ele-
mentos que el usuario ve junto con un identificador (id) a cada elemento con
el que se quiere interactuar. El XHTML no contendrá código JavaScript alguno,
ni siquiera la definición de un onclick.
• Controlador: es un archivo JavaScript que controla a la Vista mencionada
antes, por lo general con el mismo nombre que el archivo XHTML, que al car-
garse inicializará todo el comportamiento inicial de la aplicación y se encargará
de administrar la interacción entre la vista y el modelo.
• Modelo: son distintos archivos JavaScript invocados desde el controlador.
Son los que mantienen la lógica del negocio, los que se comunican con el ser-
vidor cuando sea necesario y los que le avisan al controlador de los cambios
en el estado.

El uso de esta técnica permite, además, que diseñadores y programadores tra-


bajen por separado y en forma simultánea sin temor a problemas entre sí, dado que el
programador AJAX sólo trabajará con el controlador y el modelo (archivos .js), y el di-
señador con los XHTML y CSS. Mientras el diseñador mantenga los ids necesarios, la
aplicación RIA seguirá funcionando sin problemas.

120
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 121

AJAX. Web 2.0 para profesionales

Fig. 3-11. El patrón MVC y la interacción entre sus capas.

El uso de MVC en el mundo del desarrollo web no se circunscribe sólo al nave-


gador, también es posible aplicar el patrón de diseño en el servidor, según la plata-
forma con la que se trabaje. Por ejemplo, en ASP.NET el archivo ASPX es la vista, el
code-behind (.aspx.vb o .aspx.cs) es el controlador y una capa de clases es el mo-
delo. En Java, podrían ser JSF, JSP y una capa de clases, y en PHP se puede hacer
uso de algún sistema de plantillas, como Smarty.

Técnicas

Veamos un ejemplo donde se lee un archivo de texto del servidor, como en el capítulo
pasado, pero aplicando el modelo MVC:

index.html (Vista)

<!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>
<title>Ejemplo de MVC</title>
<script type=”text/javascript” src=”index.js”></script>
<script type=”text/javascript” src=”xhr.js”></script>
<script type=”text/javascript” src=”modelo.js”></script>

</head>

<body>
<input type=”button” id=”btnLeer” value=”Leer” />
<div id=”divContenido”>

</div>
</body>
</html>

121
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 122

Maximiliano R. Firtman

Como se puede notar, el HTML no contiene nada de código JavaScript, sólo ele-
mentos identificados con un id y una llamada a un archivo JS externo con el mismo nom-
bre (el controlador). También se acepta incluir otros archivos JS necesarios, aunque
asimismo es posible que el propio controlador cargue el resto de los JS necesarios.
El controlador, entonces, deberá definir el comportamiento que tendrá nuestra pá-
gina web a través del evento window.onload (que equivale al onload del body), o sea,
cuando la página se carga. Se puede pensar en esta función como las clásicas fun-
ciones main de lenguajes como C.

index.js (Controlador)

window.onload=function() {
// Definimos todo el comportamiento inicial de la vista
document.getElementById(”btnLeer”).onclick = traerArchivo;
}

function traerArchivo() {
leerArchivoServidor(”primertexto.txt”, recibirArchivo);
}

Function recibirArchivo(texto) {
document.getElementById(”divContenido”).innerHTML = texto;
}

modelo.js (Modelo)

var peticion = obtenerXHR();


var funcionRetornoControlador;

function leerArchivoServidor(archivo, funcionRetorno) {


peticion.open(”GET”, ”leerArchivo.aspx?archivo=” + archivo, true);
peticion.onreadystatechange = procesarPeticion;
peticion.send(null);
// Guardo la función de retorno del controlador para uso future
functionRetornoControlador = funcionRetorno;
}

function procesarPeticion() {
if (peticion.readyState==4) {
// La petición terminó
if (peticion.status==200) {
// Llamo a la función del controlador
funcionRetornoControlador(peticion.responseText);
}
}
}

122
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 123

AJAX. Web 2.0 para profesionales

ajax.js (Modelo)

function obtenerXHR() {
req = false;
if (XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
if (ActiveXObject) {
// Definimos un vector con las distintas posibilidades
var vectorVersiones = [”MSXML2.XMLHttp.5.0”,
”MSXML2.XMLHttp.4.0”, ”MSXML2.XMLHttp.3.0”, ”MSXML2.XMLHttp”, ”Micro-
soft.XMLHttp”];

// Lo recorremos e intentamos instanciar cada uno


for (var i=0; i<vectorVersiones.length; i++) {
try {
req = new
ActiveXObject(vectorVersiones[i]);
return req;
} catch (e) {}
}
}
}
return req;
}

En el capítulo 4 se analizarán en detalle el Document Object Model (DOM) y las


bases de la creación dinámica de contenido en una página XHTML. También se co-
menzará el trabajo con librerías de uso común en AJAX, como Prototype y
Script.aculo.us.

123
C03.qxd:Project Ajax4.1.qxd 10/18/07 8:00 PM Página 124
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 125

Document Object Model


4
Qué es

El famoso DOM, o Document Object Model, es un estándar definido por la W3C que
permite manipular cualquier documento XML (aunque HTML no lo era, también era po-
sible utilizarlo). Define una interfaz común para procesar y navegar una estructura je-
rárquica de tipo XML, y en el presente se puede usar en JavaScript, Java, PHP y
muchos otros lenguajes. Todos ellos implementan los mismos métodos y propieda-
des, como indica el estándar.
En JavaScript se puede utilizar el DOM para manipular y recorrer el documento
(X)HTML a través del objeto window.document (más conocido como document sola-
mente). También será posible recorrer cualquier XML que se cree en forma manual o
que se reciba vía AJAX (fig. 4-1).

Estructura

La estructura de un documento DOM es jerárquica y se asemeja a un árbol genealó-


gico, en el que se incluyen conceptos como hijos, padres, hermanos (fig. 4-2).

Objetos

Hay dos clases de objetos que existen en un documento DOM, la que representa a
todo el documento en sí y la que representa a cada uno de los nodos (o etiquetas) de
la estructura jerárquica (fig. 4-3).

125
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 126

Maximiliano R. Firtman

Fig. 4-1. Ejemplo de estructura jerárquica de un XHTML cuando se lo analiza como un documento DOM.

Fig. 4-2. Un documento DOM puede representarse como un árbol genealógico.

126
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 127

AJAX. Web 2.0 para profesionales

Fig. 4-3. Se observan los conceptos que existen dentro de cada nodo (etiqueta, valor, atributos, id).

Métodos y propiedades

Documento DOM
El objeto documento en sí representa a todo el DOM y encapsula todo su contenido.
Este objeto no se debe confundir con el nodo raíz (o etiqueta principal).
Básicamente, tiene todos los métodos que cualquier nodo, y además incorpora la
propiedad documentElement, que devuelve el objeto nodo raíz del XML.

Atributos de los nodos


Todos los nodos poseen los atributos o las propiedades siguientes:

childNodes Devuelve un vector con todos los nodos hijos (directos)


firstChild Devuelve el primer hijo, equivalente a childNodes[0]
lastChild Devuelve el último hijo
nextSibing Devuelve el “hermano” siguiente en la estructura jerárquica
previousSibing Devuelve el “hermano” anterior en la estructura jerárquica
tagName Representa el nombre de la etiqueta del nodo
nodeValue Representa el texto que existe dentro de la etiqueta (entre la apertura
y el cierre). Cuando se trata de XHTML, los atributos innerText e
innerHTML reemplazan a nodeValue
parentNode Devuelve el nodo padre (que lo contiene)

127
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 128

Maximiliano R. Firtman

Métodos de los nodos


Respecto de los métodos (o las funciones) disponibles en cada nodo, se pueden men-
cionar:

setAttribute (atributo, valor) Define un atributo en el nodo


getAttribute (atributo) Devuelve el valor de un atributo
removeAttribute (atributo) Elimina el atributo del nodo
getElementById (id) Devuelve el nodo descendiente del actual que posea el id especificado
getElementsByTagName (tag) Devuelve un vector con todos los nodos descendientes del actual que
sean de la etiqueta proporcionada
createElement (etiqueta) Instancia un objeto nodo de la etiqueta especificada
appendChild (nodo) Agrega como hijo nuevo del nodo actual, el nodo recibido por
parámetro, al final
insertBefore (nodo1, nodo2) Inserta como hijo nuevo del nodo actual, el nodo recibido por
parámetro, pero antes que el otro parámetro

Además, la librería Prototype antes mencionada agrega los siguientes métodos,


entre otros, a todos los nodos:

getElementsByClassName (clase) Devuelve un vector con todos los elementos que posean una clase
CSS en particular, por medio del atributo class
getElementsBySelector (selector) Devuelve un vector con todos los elementos que cumplan con una
condición CSS y sean descendientes del actual (similar a $$)
addClassName (clase) Agrega una clase CSS a las clases que ya posee el elemento
ancestors () Devuelve los “ancestros” del elemento en la estructura jerárquica,
esto es: el padre, el abuelo, etc.
classNames () Devuelve un vector con todas las clases CSS aplicadas al elemento
cleanWhitespace () Elimina todos los espacios vacíos y saltos de línea que estén dentro
del elemento. Esto permite asegurarse de no tener “hijos” vacíos
descendants () Devuelve un vector con todos los descendientes del elemento
getDimensions () Devuelve un objeto con las propiedades height (alto) y width (ancho)
en pantalla
hide () Oculta el elemento HTML y no lo muestra en la pantalla
remove () Elimina el elemento HTML del DOM
removeClassName () Elimina una clase CSS aplicada al elemento

128
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 129

AJAX. Web 2.0 para profesionales

scrollTo () Envía el desplazamiento de la página a la altura del elemento en


cuestión
show () Muestra un elemento que está oculto
visible () Devuelve true, si el elemento está visible, o false, si está oculto

Ejemplo
Supongamos que tenemos el documento XML siguiente cargado en una variable lla-
mada xml.

1 <?xml version=”1.0” ?>


2 <clientes>
3 <cliente id=”1” nombre=”Pepsi” />
4 <cliente id=”2” nombre=”Coca Cola”>
5 <marca>Coca Cola Zero</marca>
6 <marca>Coca Cola Light</marca>
7 </cliente>
8 </clientes>

Recibiríamos los siguientes resultados si aplicamos:

Ejecutando Recibimos

var c = xml.documentElement; El nodo clientes (2)

c.childNodes; Un vector que contiene 3 y 4

c.firstChild.tagName cliente

c.firstChild.getAttribute(“nombre”) Pepsi

c.lastChild.getAttribute(“precio”) undefined

c.childNodes[1].childNodes Un vector que contiene 5 y 6

var cc = c.getElementById(“2”); El nodo cliente (4)

cc.childNodes[0].nodeValue Coca Cola Zero

El ejemplo anterior es cierto, aunque a continuación se detallarán algunas dife-


rencias que podemos tener en determinados browsers.

129
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 130

Maximiliano R. Firtman

Los browsers que no son Internet Explorer entienden de forma distinta los dos
ejemplos siguientes:

<clientes>
<cliente>Coca Cola</cliente>
</clientes>

<clientes><cliente>Coca Cola</cliente></clientes>

Para Internet Explorer, en ambos casos la etiqueta clientes tiene un solo hijo (child-
Nodes). Sin embargo, para Firefox, Opera y Safari, entre otros, el primer ejemplo tiene
3 nodos hijos y el último, sólo uno. ¿Por qué sucede esto? Debido a que estos brow-
sers entienden que los espacios y los saltos de línea entre etiquetas son un nodo más,
que tiene tagName con valor undefined.
Para resolver esta incompatibilidad podemos preguntar si tagName es distinto de
undefined antes de procesarlo, o eliminar todos los espacios antes de recorrer child-
Nodes. La librería Prototype incorpora el método cleanWhitespace para eliminar los
espacios.

Propiedades útiles en XHTML

Cuando se utiliza DOM dentro del (X)HTML, o sea, con el objeto window.document, hay
ciertas “ventajas” que no se encuentran al usar DOM sobre cualquier XML.
La primera de ellas es poder leer y asignar atributos sin usar getAttribute o setAt-
tribute, sino directamente con el nombre de la propiedad (siguiendo notación camello,
salvo en las funciones). Por ejemplo:

document.getElementById(”tblClientes”).cellSpacing = 10;
document.getElementById(”tblClientes”).width = ”100%”;

La única excepción es la definición del atributo class, que permite definir el nom-
bre de una regla CSS de clase (las que comienzan con punto). Como class es una pa-
labra reservada de JavaScript (aunque no usada), JavaScript reemplazó esta propiedad
por className, cuando se lo accede por medio de propiedades.

document.getElementById(”txtNombre”).className = ”txtError”;

Recuérdese que se puede reemplazar document.getElementById, por $ si se usa


Prototype.

130
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 131

AJAX. Web 2.0 para profesionales

this
Cuando se escribe alguna función que responde a un evento de un nodo XHTML, como
onclick, se puede hacer referencia a un objeto especial llamado this que representa el
nodo actual.

disabled
JavaScript también permite desactivar cualquier nodo XHTML del documento mediante
la propiedad lógica disabled. Si se pone en true se estará apagando un elemento
XHTML; esto implica que el usuario no puede utilizarlo (si fuera un botón o un campo
de texto).
En el ejemplo siguiente se apaga un botón luego de ser presionado por el usuario:

<input type=”button” id=”btnPresionar” onclick=”this.disabled=true” />

Recuérdese que también podríamos (y deberíamos) separar nuestro código y de-


finir el evento onclick desde código JavaScript:

$(”btnPresionar”).onclick = function() {
this.disabled = true;
}

Estilos CSS
Desde JavaScript también es posible acceder a un atributo especial de todos los nodos
XHTML, se trata de style, que permite definir un estilo CSS inline. JavaScript representa
los estilos CSS de un elemento con un objeto con notación de punto. Así, todas las pro-
piedades CSS tienen su contraparte JavaScript con un ligero cambio de sintaxis. En CSS
hay propiedades, como text-align, que llevan guion; éstas se transforman en textAlign.

Ejemplos

Efecto rollover
Hay un efecto clásico conocido como rollover que cambia el color de fondo de una
celda (o cualquier otro elemento) cuando el usuario posa el cursor sobre el elemento y
lo vuelve a su color original al salir de él.
Para aplicar este efecto se puede recurrir a la propiedad XHTML bgColor, aunque
no sería aplicando CSS, y ya se sabe que todo lo relacionado con el estilo de un ele-
mento se debe hacer por CSS.

131
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 132

Maximiliano R. Firtman

Entonces se puede aplicar el siguiente código compatible con CSS a una celda
que tenga el id celda:

$(”celda1”).onmouseover = function() {
this.style.backgroundColor = ”yellow”;
}
$(”celda1”).onmouseout = function() {
this.style.backgroundColor = ””;
}

Ahora bien, lo bueno de esta forma de trabajar, y aquí se ve su gran potencial, es


cómo se hace para aplicar este mismo efecto a todas las celdas de una tabla de 1000
filas por 10 columnas. Ponerle un id a cada una parece un código suicida, entonces,
¿por qué no pensar en DOM? Hay un método llamado getElementsByTagName que de-
vuelve un vector con todos los elementos de una etiqueta determinada, entonces, ha-
gamos lo siguiente:

var todosTD = document.getElementsByTagName(”td”);


for (var i in todosTD) {
// todosTD[i] es cada nodo celda
todosTD[i].onmouseover = function() {
this.style.backgroundColor = ”yellow”;
}
todosTD[i].onmouseout = function() {
this.style.backgroundColor = ””;
}
}

¡Listo! Se creó un efecto de rollover sobre 10 000 celdas (o las que fueran) sin du-
plicar código HTML ni JavaScript (figs. 4-5 y 4-6).

Creando una tabla dinámica


Para ejemplificar la creación dinámica de XHTML, algo muy común en el mundo de
una aplicación AJAX (recordemos que la interfaz de usuario se modifica por el mismo
JavaScript), se va a detallar una pequeña actividad que genere una tabla HTML en
forma dinámica por medio de código. Para ello hay dos métodos, cada uno con sus
ventajas y desventajas.
Ambos generan el mismo resultado, uno lo hace de forma más desprolija, pero
probablemente sea más rápido de ejecutar, y el otro utiliza todas las ventajas de DOM
para desempeñarse con mayor prolijidad.
Veamos primero la versión que no usa DOM en su totalidad.

132
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 133

AJAX. Web 2.0 para profesionales

Fig. 4-5. El efecto rollover permite cambiar el color de una celda al posarse sobre ella.

Fig. 4-6. Si bien el código fuente original no tenía el efecto aplicado, al ver el código fuente generado
(con Developer Toolbar) se puede observar que ahora cada celda tiene su código.

133
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 134

Maximiliano R. Firtman

Imagínese un XHTML con el código siguiente:

<body>
<div id=”divTabla”>

</div>
</body>

Se desea que, al cargarse la página, se genere una tabla de 100 columnas por
100 filas. Lo primero en que se piensa es en definir el evento onload del body, o sea:

<body onload=”crearTabla()”>
<div id=”divTabla”>

</div>
</body>

Este código no está mal, pero ya se vio que uno de los objetivos del patrón MVC
es eliminar por completo el código JavaScript del XHTML para no tener todo mez-
clado, entonces, en el XHTML se podría incluir el siguiente código JS externo:

<html>
<head>
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”crearTabla.js”></script>
</head>
<body>
<div id=”divTabla”>

</div>
</body>
</html>

Asimismo, el archivo crearTabla.js tendrá el código que sigue (fig. 4-7):

// Ejecutamos código en el evento onload del body


window.onload = function() {
crearTabla();
}

134
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 135

AJAX. Web 2.0 para profesionales

function crearTabla() {
// Crea la tabla
var html = ”<table style=’width:100%‘>”;
for (var i=0; i<100; i++) {
// Crea la fila
html += ”<tr>”;
for (var j=0; j<100; j++) {
// Crea la celda
html += ”<td>” + i + ”-” + j + ”</td>”;
}
html += ”</tr>”;
}
html += ”</table>”;
// Agrega la tabla creada al div
$(”divTabla”).innerHTML = html;
}

Fig. 4-7. Toda una tabla creada en forma dinámica sin que exista en el código fuente original.

135
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 136

Maximiliano R. Firtman

¿Cómo sería lo mismo pero en versión “prolija” usando DOM?

// Ejecutamos código en el evento onload del body


window.onload = function() {
crearTabla();
}

function crearTabla() {
// Crea la tabla
var tabla = document.createElement(”table”);
tabla.style.width = ”100%”;
for (var i=0; i<100; i++) {
// Crea la fila
var tr = document.createElement(”tr”);
for (var j=0; j<100; j++) {
// Crea la celda
var td = document.createElement(”td”);
td.innerHTML = i + ”-” + j;
// Agregamos la celda a la fila
tr.appendChild(td);
}
// Agregamos la fila a la tabla
tabla.appendChild(tr);
}
// Agrega la tabla creada al div
$(”divTabla”).appendChild(tabla);
}

Script.aculo.us
Qué es

Script.aculo.us es una librería gratuita para la creación de aplicaciones ricas de Inter-


net utilizando JavaScript, que necesita Prototype para ejecutar su funcionalidad. Es
una de las librerías más sencillas y más utilizadas para crear controles ricos (fig. 4-8).
Dentro de las funcionalidades que agrega se pueden destacar:
• Framework de animación
• Soporte de Drag and Drop
• Controles Ajax (como Autocomplete)
• Más utilidades DOM, además de las de Prototype
• Testing de Unidad

136
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 137

AJAX. Web 2.0 para profesionales

Fig. 4-8. El sitio web de Script.aculo.us es un buen punto de inicio para encontrar ejemplos y docu-
mentación.

Instalación

Desde el sitio web de la librería (http://script.aculo.us) se puede descargar la última


versión en formato ZIP. Dentro de este archivo comprimido en la carpeta lib se encon-
trará la última versión de Prototype y en la carpeta src, los archivos .js de la librería.
Esta librería presenta 7 archivos .js partiendo como base de scriptaculous.js. Este
mismo JavaScript es el que carga el resto de los scripts.
Se deben instalar todos los js en la misma carpeta donde se tendrán los HTML y
los JavaScript, y si se desea insertarlos en otra subcarpeta, se debe modificar pro-
totype.js con el camino relativo hasta llegar a ellos.
Para la utilización primero es necesario que se incluya Prototype, por ejemplo:

<script src=”javascripts/prototype.js” type=”text/javascript”></script>


<script src=”javascripts/scriptaculous.js”
type=”text/javascript”></script>

137
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 138

Maximiliano R. Firtman

Si se desean limitar las funcionalidades disponibles y así reducir la cantidad de Ja-


vaScript que se cargarán, se puede utilizar la sintaxis siguiente:

<script src=”scriptaculous.js?load=lista”
type=”text/javascript”></script>

donde lista es una secuencia separada por comas de alguno de los módulos siguien-
tes: builder, effects, dragdrop, controls, slider.

Efectos visuales

Uno de los agregados más potentes en Script.aculo.us es la posibilidad de generar


efectos visuales muy atractivos y con muy poco código. Para ello, sólo hace falta uti-
lizar la sintaxis siguiente:

new Effect.NombreEfecto(id_elemento, opcionales);

De esta forma, se puede aplicar un efecto a un DIV, o a cualquier otro elemento


del DOM. Cuando se instancie el efecto, éste se generará en pantalla (fig. 4-9).
Los efectos disponibles se dividen en:
• Efectos de núcleo: contiene efectos de base.
• Efectos combinados: contiene efectos visuales producto de la combinación
de efectos de núcleo.
• Librería de efectos: es una lista de efectos generados a partir de los anterio-
res por la comunidad de usuarios disponibles en wiki.script.aculo.us/scripta-
culous/show/EffectsTreasureChest.

Efectos de núcleo
Los Core Effects o efectos de núcleo disponibles son los siguientes:
• Opacity: cambia la opacidad (transparencia) del elemento.
• Scale: cambia el tamaño del elemento.
• Morph: cambia una propiedad CSS del elemento.
• Move: mueve el elemento en la página.
• Highlight: genera una animación de resaltado del fondo del elemento.
• Parallel: ejecuta un conjunto de efectos en paralelo.

138
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 139

AJAX. Web 2.0 para profesionales

Fig. 4-9. La API de efectos de Script.aculo.us es muy completa y en la web encontraremos ejemplos
de cada uno.

Los parámetros opcionales se ingresan en formato de objeto JSON y los que se


comparten entre todos los efectos de núcleo son:

Propiedad Valor por defecto Descripción

duration 1 Duración del efecto en segundos, es posible utilizar valores reales,


por ejemplo: 2, 0.5
fps 25 Cantidad de cuadros refrescados por segundo
transition Define una función que modifica el punto de animación
from 0 Valor entre 0 y 1 que define el punto de origen del efecto
to 1 Valor entre 0 y 1 que define el punto destino del efecto
queue Permite definir, en modo avanzado, dónde aplicar el efecto en
una cola de efectos
delay 0 Segundos de espera desde ahora antes del comienzo de la animación

139
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 140

Maximiliano R. Firtman

En la documentación de la librería es factible encontrar sobre qué elementos se


puede aplicar cada efecto para tener compatibilidad con todos los browsers. En ge-
neral, a los DIV se les pueden aplicar todos los efectos.
Algunas propiedades específicas de cada efecto son:

Efecto Propiedad Descripción

Scale scaleX Valor lógico que define si se debe escalar en sentido horizontal.
Scale scaleY Valor lógico que define si se debe escalar en sentido vertical.
Scale scaleContent Define si también se debe escalar el contenido del elemento.
Scale scaleFromCenter Define si se escala desde el centro.
Scale scaleMode Puede ser ‘box’ o ‘contents’.
Morph style Define un objeto JSON con los valores CSS nuevos que debe
tener el elemento.
Move x Especifica la coordenada x del destino.
Move y Especifica la coordenada y del destino.
Move mode Puede ser ‘absolute’ (considera píxeles reales) o ‘relative’ (mueve
el elemento desde donde está n cantidad de píxeles).
Highlight startcolor Color inicial del efecto.
Highlight endcolor Color final del efecto.
highlight restorecolor Valor lógico que indica si se debe devolver el color original al elemento.

Así, por ejemplo, con el código siguiente se puede crear un efecto que apaga de
a poco un botón al ser presionado:

<input type=”button” value=”Apagar” id=”btnApagar” onclick=”new Ef-


fect.Opacity(‘btnApagar’, {from: 1, to: 0, duration: 2})” />

Las transiciones permiten modificar el modo en que se aplica el efecto. Es reco-


mendable probarlas todas para entender sus diferencias. Las opciones disponibles
(mediante el atributo transition) son:
• Effect.Transitions.sinoidal (valor por defecto)
• Effect.Transitions.linear
• Effect.Transitions.reverse

140
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 141

AJAX. Web 2.0 para profesionales

• Effect.Transitions.wobble
• Effect.Transitions.flicker

El único distinto es Parallel, que recibe un vector de efectos que se deben apli-
car, por ejemplo:

new Effect.Parallel( [ new Effect.Move(‘btn1’, {x: 0, y:0}),


new Effect.Opacity(‘btn1’) ] );

Por último, se expondrán las propiedades de tipo función (Eventos) disponibles


para administrar mejor el efecto animado:

Evento Descripción

beforeStart Se ejecuta antes de comenzar el efecto.


beforeUpdate Se ejecuta antes de que se realice cada redibujo del efecto (depende de la cantidad.
de frames por segundo –fps– y de la duración).
afterUpdate Se ejecuta después de actualizar cada redibujo.
afterFinish Se ejecuta al finalizar toda la animación.

En todas estas funciones se recibirá un objeto por parámetro, que contendrá pro-
piedades útiles para saber el estado del efecto, entre ellas element (referencia el ele-
mento que se anima), currentFrame (el cuadro actualmente dibujado), startOn
(milisegundos pasados desde el inicio) y finishOn (milisegundos restantes).

Efectos combinados
Los efectos combinados ofrecen una funcionalidad mayor y más simple, así como más
atractivos. Los disponibles son:
• Appear
• Fade
• Puff
• DropOut
• Shake

141
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 142

Maximiliano R. Firtman

• SwithOff
• BlindDown
• BlindUp
• SlideDown
• SlideUp
• Pulsate
• Squish
• Fold
• Grow
• Shrink

En wiki.script.aculo.us/scriptaculous/show/CombinationEffects se encontrará un
detalle y una descripción de cada uno, junto con las opciones adicionales de las que
se pueden disponer en cada uno de ellos.

Toggle
Hay un efecto especial llamado Toggle que permite prender o apagar un elemento con
rapidez (según su estado actual), aplicando algún tipo de efecto entre appear, blind o
slide.
Por ejemplo:

<a href=”javascript:new Effect.Toogle(‘divContenido’,


‘blind’)”>Titulo</a>

<div id=”divContenido”>Contenido</div>

Ejemplos
Veamos un ejemplo en el que al presionar un botón aparece en pantalla una especie
de ventana que estaba oculta, que tiene una opción para cerrarse. Las operaciones
de abrir y cerrar se realizan con una animación, y al finalizar el cierre aparece una alerta
(figs. 4-10 a 4-13).

142
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 143

AJAX. Web 2.0 para profesionales

Fig. 4-10. Nuestra página web recién abierta. Nótese que el divVentana no se muestra.

Fig. 4-11. Al utilizar el link “Abrir Ventana”, ésta se abre con un efecto de transición y el resultado es éste.

143
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 144

Maximiliano R. Firtman

Fig. 4-12. Al cerrar se ve cómo se aplica un efecto de cierre y se abre una alerta al terminar el efecto.

Fig. 4-13. Utilizar overflow:auto permite que un div con ancho y alto definidos tenga su propia barra
de desplazamiento si el contenido no cabe.

144
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 145

AJAX. Web 2.0 para profesionales

mostrarVentana.html

<!DOCTYPE html PUBLIC ”-//W3C//DTD HTML 4.01 Transitional//EN”


”http://www.w3.org/TR/html4/loose.dtd”>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html;
charset=ISO-8859-1”>
<title>Abrir Popup Interno</title>
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript”
src=”scriptaculous.js?load=effects”></script>
<script type=”text/javascript” src=”mostrarVentana.js”></script>
<link rel=”stylesheet” type=”text/css” href=”mostrarVentana.css”
/> </head>
<body>

<a id=”lnkMostrar”>Mostrar Ventana</a>

<div id=”divVentana”>
<a id=”lnkCerrar”>Cerrar Ventana</a>
<br />
<br />
Veamos un ejemplo en el que al presionar un botón aparece
en pantalla una especie de ventana que estaba oculta, que tiene una
opción para cerrarse. Las operaciones de abrir y cerrar se realizan
con una animación y al finalizar el cierre aparece una alerta.
</div>

</body>
</html>

mostrarVentana.css

#divVentana {
width: 400px;
height: 200px;
position: absolute;
top: 20px;
right: 100px;
background-color: yellow;
border: 1px red solid;
margin: 15px;
overflow: auto;
}

145
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 146

Maximiliano R. Firtman

mostrarVentana.js

window.onload = function() {
$(”divVentana”).hide();
$(”lnkMostrar”).href=”javascript:abrirVentana()”;
$(”lnkCerrar”).href=”javascript:cerrarVentana()”;
}

/** Abre una ventana (div) con un efecto de aparición


*
*/
function abrirVentana() {
new Effect.Appear($(”divVentana”));
}

/** Cierra la ventana (div) con un efecto


* y muestra una alerta cuando éste termina
*/
function cerrarVentana() {
new Effect.Fold($(”divVentana”), {
afterFinish: function() {
alert(”Se terminó de cerrar la ventana”);
}
});
}

Builder

Además del framework de efectos, Script.aculo.us agrega soporte de arrastrar y sol-


tar (drag and drop), autocomplete, testing y otros controles que se verán más adelante
en el libro.
Lo que se puede analizar ahora es un utilitario DOM adicional conocido como
Builder.
Builder.node es una metodología rápida y sencilla para crear objetos de tipo
DOM (tablas, divs, etc.) y definir sus propiedades con rapidez en cambio de utilizar
document.createElement.
Su sintaxis es la siguiente:

var nodo = Builder.node(”etiqueta”);


var nodo = Builder.node(”etiqueta”, atributos);
var nodo = Builder.node(”etiqueta”, arrayHijos);
var nodo = Builder.node(”etiqueta”, atributos, arrayHijos);

146
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 147

AJAX. Web 2.0 para profesionales

En la versión más simple es el equivalente a document.createElement.


Los atributos se definen en un formato de objeto JSON, por ejemplo:

var tabla = Builder.node(‘table’, {width:’100%‘, cellpadding:’3’,


cellspacing:’0’});

Los nombres de las propiedades del JSON equivalen a los de HTML, salvo class,
que se utiliza className y for, que se utiliza htmlFor.
La variable tabla ahora se puede usar para anexarla a otro element DOM, por
ejemplo:

$(”divContenido”).appendChild(tabla);

El parámetro arrayHijos es un vector de otros nodos que se insertarán como hijos


del elemento que se está creando. Por ejemplo, se crea un DIV con un link dentro:

$(”div1”).appendChild(Builder.node(”div”,
[ Builder.node(”a”,{id: ”link1”})]);

La creación de una librería de múltiples propósitos para AJAX es el tema funda-


mental que se irá entretejiendo en el capítulo 5. También se implementará un lector de
noticias completamente realizado con las nuevas técnicas AJAX.

147
C04.qxd:Project Ajax4.1.qxd 10/18/07 8:04 PM Página 148
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 149

Creando una librería de trabajo


5
Objetivo

Cuando se trabaja haciendo desarrollos web o de otro tipo de software, siempre se


debe tener una frase en mente: no reinventemos la rueda. Muchos proyectos tienen si-
militudes y características en común, y no vale la pena pensar de nuevo todos los pro-
blemas cada vez que nos aparece. Entonces, la solución es armar una librería o una
biblioteca de trabajo que se pueda reutilizar en nuestros proyectos.
También se podría pensar para qué armar nuestra propia librería si ya hay algunas,
como Prototype. La respuesta es que una cosa no quita la otra. Uno de los problemas
de utilizar una librería de terceros (como Prototype, Spry, Rico, etc.) es que estamos
acoplando nuestro proyecto 100% a ella. ¿Y si dentro de unos meses o años quere-
mos migrar a otra librería porque descubrimos mayores funciones o mejor rendimiento?
La solución tampoco es armar una librería de trabajo 100% de cero, sino implementar
una interfaz propia, y utilizar nuestro framework favorito actual, como puede ser Prototype.
Esto nos permite extender la librería con funciones nuevas y cambiar de framework en el
futuro sin alterar todo el código JavaScript del modelo y de los controladores.
Por supuesto, algunas cuestiones serán muy específicas de un framework y en cada
caso será necesario decidir si usar directamente el framework u ofrecer una interfaz a la
librería (fig. 5-1).

Fig. 5-1. Nuestra librería actuará como una capa intermedia entre el código de la aplicación, el código
de la librería y las llamadas a otros frameworks.

149
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 150

Maximiliano R. Firtman

Características

En primer lugar, queremos que nuestra librería encapsule el funcionamiento de las pe-
ticiones XMLHttpRequest para simplificarnos la tarea desde nuestras aplicaciones.
Para esto, queremos poder hacer peticiones, abstraernos de las cuestiones inhe-
rentes al objeto XHR, y solicitar distintas propiedades y opciones desde nuestro código.

$Ajax

De esta manera es factible crear una función que puede llamarse de cualquier forma
pero, dado que se desea escribir lo menos posible, una buena sugerencia es $Ajax. El
uso del signo $ permite pensar en una sintaxis estilo Prototype y, además, evita tener
problemas con otras posibles variables que puedan tener el mismo nombre.

Opciones
El objetivo final es que a esta función podamos enviarle las opciones que siguen y al-
gunos valores por defecto.

Opción url (Obligatorio)


Especifica la dirección URL (absoluta o relativa) donde enviar la petición.

Opción método
Especifica el método que se va a utilizar para enviar la petición AJAX (entre POST y
GET). En principio, uno podría suponer que se puede enviar un string, por ejemplo,
get. El problema que esto conlleva es la posibilidad de equivocarse sin notar el error al
ser un literal, y que se pueden tener algunos inconvenientes con las mayúsculas o las
minúsculas. Una solución posible es utilizar un JSON como enumerador de opciones.
Ejemplo:

var $metodo = {
GET: ”get”,
POST: ”post”
}

de esta forma, directamente se especifica $metodo.GET o $metodo.POST y se evita


el uso de literales tipo string. Además, los entornos de desarrollo, como JSEclipse brin-
dan ayuda contextual y completan el código usando este método.

150
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 151

AJAX. Web 2.0 para profesionales

Una decisión para tomar es si por defecto se desea usar POST o GET, en caso de
que el programador de nuestra librería no nos indique un método explícito. Una primera
apreciación podría indicar que GET es una buena opción, dado que permite leer cual-
quier archivo estático sin problemas.

Opción tipoRespuesta
Si bien ya se indicó cómo recibir Texto, JSON o XML desde una petición AJAX, la idea
sería abstraernos de cómo se hace esto (incluso hasta podríamos olvidarnos). Por ello
sería muy importante que nuestra librería se abstraiga de esto y podamos indicarle qué
tipo de respuesta deseamos al momento de hacer la petición. Como se hizo con el
método, se podrían especificar los posibles tipos como un JSON:

var $tipo = {
TEXTO: 0,
JSON: 1,
XML: 2
}

utilizar $tipo.TEXTO como valor por defecto es la mejor opción si no nos especifican
nada.

Opción parámetros
Si se envían parámetros en formato GET, se sabe que hay que agregarlos a la URL, pero
si se envían parámetros en formato POST es necesario recibirlos al momento de ge-
nerar la petición. De esta manera, nuestra librería recibiría los parámetros en dos for-
matos posibles:
• String: en este caso se supone que los parámetros ya vienen formados en tipo
URL.
• Object: en este caso se supone que es un objeto tipo Hash (p. ej., un JSON)
con cada una de las propiedades que se van a enviar.

También se podría decidir que si se reciben los parámetros y el método es GET,


se generará el string y se lo anexará a la URL.
Si hay parámetros POST por enviar, se debe enviar la cabecera Content-type con
el valor application/x-www-form-urlencoded.

Opción cache
Esta opción se puede definir como valor lógico (true o false), donde el programador
indique si desea que en la petición actual se haga caché o no. Por el momento nues-

151
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 152

Maximiliano R. Firtman

tra actividad se limitará a agregar un parámetro aleatorio a la URL si el usuario no


quiere caché de la petición. Esto obliga a que el navegador no utilice versiones guar-
dadas de la URL a pedir. Más adelante se implementará un patrón de diseño que per-
mitirá mantener un caché local y que se puede anexar a la librería sin perder
compatibilidad.
Por defecto se podría suponer que no se quiere caché. Ésta es la primera opción
que se agrega aún no disponible en Prototype, por lo que su implementación depende
por completo de nosotros.

Opción avisoCargando
Esta opción, si está definida, dará el identificador (id) de un elemento en la página web
que se quiere usar como aviso o cartel de cargando o loading. Esto permite que se
pueda activar un aviso o no con facilidad, según cada tipo de petición. Si no se indica
esta propiedad, entonces no se producirá el efecto de aviso.
La idea sería que la librería prenda el elemento HTML en cuestión al enviar la pe-
tición y la apague al recibirla.

Opción id
Este parámetro opcional permitiría definirle a cada petición un identificador (de cual-
quier tipo), que se usará para enviarlo junto con los datos recién llegados. Esto permi-
tiría utilizar una sola función que reciba los datos para muchas peticiones, y pueda
identificar a cada una por medio de su id.

Eventos
Así como podemos definir opciones, también vamos a querer, por lo menos, recibir los
datos de la petición que se realiza. Para eso se pueden implementar al menos dos
eventos (funciones) simples:
onfinish: se ejecutaría cuando los datos llegaron de manera correcta desde el servidor
y recibiría dos parámetros, los datos (en formato JSON, Texto o XML, según la opción
tipoRespuesta) y un segundo parámetro opcional con el identificador de la petición
(opción id). Si bien este evento parece obligatorio, no se va a tratar como tal, porque
hay algunos casos en los que sólo se quieren enviar datos y no interesa recibir la res-
puesta.
onerror: se ejecutaría cuando se produjo algún error, ya sea en la petición, al conver-
tir los datos a XML o a JSON, o en el servidor. Esta función recibiría un código numé-
rico de error y un objeto opcional con mayor información. Este evento se podría separar
según el tipo de error que fuera, pero por el momento no tiene mayor uso.

152
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 153

AJAX. Web 2.0 para profesionales

Parámetros

Hemos analizado que nuestra librería tendrá muchos parámetros, y algunos de ellos
son opcionales. Según lo visto, el único obligatorio es la url, y el resto puede definirse
o no. De esta manera, podemos crear nuestra función con la interfaz pública siguiente:

function $Ajax(url, opciones) {

Las opciones se pueden trabajar como un objeto JSON que puede no enviarse;
si se envía, puede contener uno, algunos o todos los eventos y las opciones expues-
tos antes.
Veamos algunos ejemplos concretos de cómo queremos invocar nuestra función:

$Ajax(”texto.txt”, {onfinish: function(texto) { alert(”texto”); });

$Ajax(”clientes.json”, {
metodo: $metodo.GET,
tipoRespuesta: $tipo.JSON,
cache: true,
avisoCargando: ”divCargando”,
id: 3,
onfinish: recibirClientes;
onerror: function() {
// Control de errores
}
});

function recibirClientes(clientes) {
clientes.each(function(cliente) {
alert(cliente.nombre);
});
}

$Ajax(”enviar.php”, {metodo: $metodo.POST, parametros: $(”form1”).


serialize() });

de esta manera se ve que se simplifica mucho el uso de AJAX en nuestro código Ja-
vaScript al abstraernos de los problemas de implementación.

153
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 154

Maximiliano R. Firtman

Respecto de las opciones que llegan por parámetro a la función $Ajax, en mu-
chas ocasiones hay un inconveniente por resolver. Cada vez que se desea preguntar
por una opción, por ejemplo, opciones.tipoPeticion, puede ocurrir lo siguiente:
• Que el segundo parámetro (opciones) directamente no se haya definido, para
lo cual el código en cuestión daría directamente error.
• Que opciones esté definido, pero justo la propiedad que se desea (p. ej., tipo-
Peticion) no lo esté. Esto dará undefined, y se debe recurrir al valor que se su-
pone por defecto.
• Que opciones esté definido, así como opciones.tipoPeticion. En ese caso, se
debe usar este valor.

Dado que en nuestra librería la consulta de un parámetro se va a efectuar con asi-


duidad, se puede crear una función que, dada la colección de opciones, el nombre de
una opción particular y el valor por defecto, devuelva lo correcto.

function __$P(coleccion, parametro, defecto) {


if (coleccion==undefined) {
// No se definió ninguna opción
return defecto;
} else {
if (coleccion[parametro]==undefined) {
// No se definió la opción deseada
return defecto;
} else {
return coleccion[parametro];
}
}
}

Para entender esta función es preciso recordar que escribir opciones.tipoPeticion


es equivalente a opciones[“tipoPeticion”]. Así, cada vez que se necesite preguntar por
una de las opciones se usará el código siguiente:

var metodo = __$P(opciones, ”metodo”, $metodo.GET);

De esta manera, si el método no se definió como una opción, entonces se recibirá


$metodo.GET por defecto (fig. 5-2).

154
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 155

AJAX. Web 2.0 para profesionales

$Ajax (url, opciones)

Si no quiere caché
Agrega random a la URL

Definir tipo de petición


POST o GET URL Parámetros

Guardar valores para uso futuro


Tipo de respuesta Eventos onfinish y onerror Id Aviso de cargando
(XML, JSON o texto)

Hacer petición vía Prototype


Enviar parámetros de Definir onSuccess como Prender cartel de
Prototype función interna cargando

Cuando se ejecuta onSuccess de Prototype


Leer texto, JSON o XML Apagar cartel de cargando Llamar a la función
la respuesta onfinish si existe
enviando de la respuesta

Fig. 5-2. Diagrama de flujo con la funcionalidad que posee nuestra librería.

El código

Por fin se llegó al código completo de la primera versión de nuestra librería para hacer
y manipular peticiones Ajax, con el sustento de Prototype para garantizar compatibili-
dad. Veámoslo:

/**
*
* Librería AjaxLib v 1.0
*
* Realiza peticiones AJAX de manera sencilla y automática.
*
* @author Maximiliano R. Firtman firt@itmaster.es
*
*/

/** Especifica opciones para tipoRespuesta


*/
var $tipo = {
XML: 0,
TEXTO: 1,
JSON: 2
}

155
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 156

Maximiliano R. Firtman

/** Especifica opciones para método


*/
var $metodo = {
GET: ”GET”,
POST: ”POST”
}

/**
* Realiza un nuevo requerimiento AJAX a la url especificada
* con las opciones definidas
* @param {String} url La URL donde realizar la petición
* @param {Object} opciones Un objeto JSON con los atributos opcionales
que queremos definirle.
*
* opciones disponibles:
* id: Un identificador interno para ser recibido junto a los datos
* metodo: $metodo.POST o $metodo.GET
* tipoRespuesta: $tipo.TEXTO, $tipo.JSON o $tipo.XML
* parametros: un string en formato URL o un objeto Hash
* cache: true o false
* avisoCargando: define el id de un elemento que queremos usar
* como cartel de ”Cargando” mientras la petición se hace
* onfinish: función a ejecutarse cuando se reciban los datos.
* Esta función recibirá el Texto, JSON o XML recibido y el
id de la petición.
* onerror: función a ejecutarse cuando se produzca un error.
* Esta función recibe un objeto con detalles del error y
el id de la petición
*/
function $Ajax(url, opciones) {
// Preguntamos si no quiere Caché
if (__$P(opciones, ”cache”, true)==false){
// Agregamos un parámetro random a la URL
// Ponemos ? o & según la presencia de parámetros anteriores
var caracter = ”?”;
if (url.indexOf(”?”)>0) caracter = ”&”;
url += caracter + Math.random();
}
var metodo = __$P(opciones, ”metodo”, $metodo.GET);
var parametros = __$P(opciones, ”parametros”);

// Genera JSON de propiedades necesarias para Prototype


// En un futuro puede ser reemplazado por otra librería
var protoOpc = {
method: metodo,
onSuccess: __$AjaxRecibir.bind(this, opciones),
onException: __$AjaxError.bind(this, opciones),
onFailure: __$AjaxError.bind(this, opciones)
}

156
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 157

AJAX. Web 2.0 para profesionales

// Si se definieron los parámetros los agregamos


if (parametros!=undefined) {
protoOpc.parameters = parametros;
}

// Genera la nueva petición vía Prototype


var peticion = new Ajax.Request(url, protoOpc);

// Prende el cartel de Cargando, si existiera


if (__$P(opciones, ”avisoCargando”)!=undefined) {
__$AjaxCargando(opciones.avisoCargando, true);
}

/**
* Función interna que se encarga de recibir la petición lista
* desde Prototype y ejecutar el evento onfinish de la petición
*/
function __$AjaxRecibir(opciones, xhr) {
// Si se ejecuta este método estamos seguros de que
// readyState==4 y status==200

// Apagamos cartel de Cargando si existiera


if (__$P(opciones, ”avisoCargando”)!=undefined) {
__$AjaxCargando(opciones.avisoCargando, false);
}

// Traemos la función onfinish si fue definida


var funcionRetorno = __$P(opciones, ”onfinish”);
// Traemos el identificador de la petición si fue definido
var id = __$P(opciones, ”id”);

if (funcionRetorno!= undefined) {
// Si el usuario indicó que quiere recibir la respuesta
// Suponemos TEXTO como tipo por defecto.
var tipoRespuesta = __$P(opciones, ”tipoRespuesta”,
$tipo.TEXTO);
switch(tipoRespuesta) {
case $tipo.TEXTO:
funcionRetorno(xhr.responseText, id);

break;
case $tipo.XML:
funcionRetorno(xhr.responseXML, id);

break;
case $tipo.JSON:
// Intentamos evaluar el JSON por si no es válido
var objeto;
try {
objeto = xhr.responseText.evalJSON();
} catch (e) {

157
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 158

Maximiliano R. Firtman

__$AjaxError(opciones, xhr, {code: -1,


message: ”JSON No válido” });
return;
}
funcionRetorno(objeto, id);
}
}

/**
* Función interna que se encarga de prender o apagar el cartel
* de Cargando, si existiera
*/
function __$AjaxCargando(cartel, prender) {
if (prender) {
$(cartel).show();
} else {
$(cartel).hide();
}
}

/**
* Función interna que se encarga de recibir la ejecución
* cuando se produzca algún error en la petición desde Prototype
*/
function __$AjaxError(opciones, xhr, excepcion) {
// Apagamos cartel de Cargando si existiera
if (__$P(opciones, ”avisoCargando”)!=undefined) {
__$AjaxCargando(opciones.avisoCargando, false);
}

// Cuando se trata de un error de servidor, no hay excepción


if (excepcion==undefined) {
// Supongo error de HTTP, genero mensaje propio
excepcion = {code: xhr.status, message: ”Error del servidor”}
}
// Consulto si estaba definido el evento onerror
var funcionError = __$P(opciones, ”onerror”);
if (funcionError!=undefined) {
funcionError(excepcion, __$P(opciones, ”id”));
}
}

/**
* Función interna que se encarga de entregar un parámetro opcional
* desde una colección tipo JSON, con un valor por defecto
*/
function __$P(coleccion, parametro, defecto) {
if (coleccion==undefined) {
return defecto;

158
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 159

AJAX. Web 2.0 para profesionales

} else {
if (coleccion[parametro]==undefined) {
return defecto;
} else {
return coleccion[parametro];
}
}
}

Primero, vemos que hay varias funciones que comienzan con doble guion bajo
(__). Esto se hace sobre funciones que se consideran privadas, o de uso interno de la
función pública $Ajax. El uso de __ implica que rara vez encontraremos esa función
para ejecutarla directamente y que las probabilidades de que se mezcle con otras del
mismo nombre son muy bajas. Para no tener estos problemas de conflictos entre fun-
ciones globales nuestro AjaxLib se podría reemplazar por una clase (como se analizó
en la parte de Programación Orientada a Objetos).
Luego se crea un objeto JSON con el formato de opciones que requiere Prototype,
convirtiendo el nuestro (en español y acorde con nuestras necesidades) al que nece-
sita Prototype.
A Prototype se le indica que nuestras funciones __$AjaxError y __$AjaxRecibir
serán las encargadas de manejar las respuestas de la petición y no directamente las
funciones onerror y onfinish que pidió el que llamó a la librería. Esto permite ofrecer
mayor funcionalidad que la de Prototype, por ejemplo, ya devolviendo Texto, JSON o
XML, según lo que se haya pedido originalmente.
Un aspecto que se debe tener en cuenta es que Prototype siempre captura con
un try catch internamente las llamadas a los métodos de onSucess. Esto implica que
si la petición estuvo correcta, pero nuestro método que recibe los datos tiene errores,
Prototype ejecutará el onerror. Hay que tener cuidado con este tema, para evitar dolo-
res de cabeza cuando no se encuentra dónde está el error.
En el futuro se pueden agregar funciones nuevas a nuestra librería con mucha fa-
cilidad (p. ej., una bitácora o log de todas las peticiones que se hacen, el tiempo que
demoran, etc., para luego tomar estadísticas de uso).
También se debe recordar que nuestro objetivo es que en el futuro podamos cam-
biar de Prototype a otra librería interna, sin necesidad de alterar nada en nuestro có-
digo de uso.
Una de las cosas extrañas que se pueden encontrar en nuestro código es el uso de:

onSuccess: __$AjaxRecibir.bind(this, opciones)

159
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 160

Maximiliano R. Firtman

Parece raro no haber utilizado:

onSuccess: __$AjaxRecibir

El problema es que JavaScript, por defecto, al asignar funciones que se ejecutan


luego, hace perder a la función ejecutada el ámbito donde se había originado. Esto es
perjudicial, dado que en nuestra función __$AjaxRecibir queremos leer, por ejemplo, las
opciones que el usuario de la librería definió para actuar en consecuencia, y si al eje-
cutarse pierde el ámbito (scope), no se tiene más acceso a esa variable.
Como solución se podría pensar en convertir en variable global a opciones. De
esta manera se podría acceder a ella en la función __$AjaxRecibir. Esto es correcto,
pero habría un gran inconveniente.
En la figura 5-3 se puede ver un esquema del problema. Si se hace una segunda
petición mientras la primera no finalizó, la segunda petición estaría reemplazando las
opciones de la primera y entonces habría un conflicto grave. Se necesita que cada pe-
tición tenga y mantenga sus propias opciones. Allí aparece el método bind agregado
por Prototype a todas las funciones. Este método permite asignar funciones pero con
la ayuda de definir un ámbito en particular y, además, indicarles parámetros (como op-
ciones) para que se los pase luego cuando realmente sean ejecutadas.
De esta forma, __$AjaxRecibir recibe como primer parámetro las opciones y, a
partir de allí, agrega todos los parámetros que realmente se enviaron en la invocación
real.
A continuación se desarrolla un ejemplo que muestra este concepto con mayor
claridad:

function imprimir() {
// Imprime todos los argumentos recibidos separados por espacio
alert($A(arguments).join(” ”));
}

// Agrega un primer parámetro ”*” a Imprimir


var imprimirConAsterisco = imprimir.bind(this, ”*”);

// Imprime: ”* AJAX con PHP”


imprimirConAsterisco(”AJAX con PHP”);

160
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 161

AJAX. Web 2.0 para profesionales

Fig. 5-3. Si se trabaja con variables globales, entrarán en conflicto peticiones simultáneas.

Usando la librería
Sitio estático versión AJAX

Imagínese un clásico sitio web estático de una empresa, con secciones de Quiénes
somos, Servicios, Clientes y Contacto. Ahora, supongamos que se desea hacerlo con
AJAX. De esta manera, el usuario ingresa en una sola URL y desde allí el menú sólo re-
carga una zona central con peticiones AJAX a archivos HTML (fig. 5-4).

Fig. 5-4. Ésta es la estructura de nuestro sitio ficticio.

Este ejemplo no requiere ningún lenguaje de servidor, con sólo HTML ya es total-
mente funcional. La única desventaja de usar esta herramienta en un sitio estático por
completo es que los motores de búsqueda no podrán indexar en forma correcta todos
los contenidos.

161
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 162

Maximiliano R. Firtman

Veremos cómo solucionar este problema.


Para ello, se diseñará la Página Principal como plantilla inicial y menú. Se va a di-
señar el sitio web usando CSS en lugar de tablas, y para eso se recibirá la ayuda de
Adobe Dreamweaver CS3 creando una nueva página HTML elástica de 2 columnas con
encabezado y pie de página. Esto genera ya el CSS compatible con todos los browsers,
aunque también es posible armarlo en forma manual sin mayores inconvenientes.
Los archivos AjaxLib.js y prototype.js son los mismos que utilizamos con anterio-
ridad (fig. 5-5).

Fig. 5-5. El uso de CSS en lugar de tablas permite tener un diseño atractivo con un XHTML muy sim-
ple y entendible.

index.html
<!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=utf-8” />
<title>Mi Sitio AJAX.com</title>
<link href=”estilos.css” rel=”stylesheet” type=”text/css” />
<script type=”text/javascript” src=”prototype.js”></script>

162
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 163

AJAX. Web 2.0 para profesionales

<script type=”text/javascript” src=”AjaxLib.js”></script>


<script type=”text/javascript” src=”index.js”></script>
</head>

<body class=”twoColElsLtHdr”>

<div id=”container”>

<div id=”header”>
<h1>MiSitioAJAX.COM</h1>
<!— end #header —>
</div>

<div id=”sidebar1”>
<!— usamos H3 para crear cada menú —>
<h3 id=”home”>Página principal Page</h3>
<h3 id=”quienes”>Quiénes Somos</h3>
<h3 id=”servicios”>Servicios</h3>
<h3 id=”clientes”>Clientes</h3>
<h3 id=”contacto”>Contacto</h3>
<!— end #sidebar1 —>
</div>

<div id=”mainContent”>
<h1> Bienvenidos </h1>
<p>MiSitioAJAX.com es una empresa dedicada a la creación y el diseño
de aplicaciones ricas de Internet utilizando la tecnología AJAX</p>
<!— end #mainContent —>
</div>

<br class=”clearfloat” />

<div id=”footer”>
<p>(C) 2007 - ITMaster Professional Training</p>
<!— end #footer —>
</div>

<!— end #container —>


</div>

</body>
</html>

estilos.css
body {
font: 100% Verdana, Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
text-align: center;
color: #000000;
background-color: #FFFFCC;

163
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 164

Maximiliano R. Firtman

}
#sidebar1 h3 {
cursor: pointer;
}

.twoColElsLtHdr #container {
width: 46em;
background: #FFFFFF;
margin: 0 auto;
border: 1px solid #000000;
text-align: left;
}
.twoColElsLtHdr #header {
background: #DDDDDD;
padding: 0 10px;
}
.twoColElsLtHdr #header h1 {
margin: 0;
padding: 10px 0;
}

.twoColElsLtHdr #sidebar1 {
float: left;
width: 12em;
background: #EBEBEB;
padding: 15px 0;
}
.twoColElsLtHdr #sidebar1 h3, .twoColElsLtHdr #sidebar1 p {
margin-left: 10px;
margin-right: 10px;
}

.twoColElsLtHdr #mainContent {
margin: 0 1.5em 0 13em;
}
.twoColElsLtHdr #footer {
padding: 0 10px;
background:#DDDDDD;
}
.twoColElsLtHdr #footer p {
margin: 0;
padding: 10px 0;
}

.fltrt {
float: right;
margin-left: 8px;
}
.fltlft { /

164
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 165

AJAX. Web 2.0 para profesionales

float: left;
margin-right: 8px;
}
.clearfloat {
clear:both;
height:0;
font-size: 1px;
line-height: 0px;
}

En nuestro controlador index.js, el primer paso es crear los vínculos necesarios


para el menú, que están representados con etiquetas H3 en lugar de links A. Con CSS
(cursor: pointer) ya se le dio aspecto de link al tener la clásica manito cuando el usua-
rio se posa sobre cada opción del menú.
Ahora queda recorrer todos los links utilizando el mismo selector CSS para el cur-
sor, empleando JavaScript y Prototype:

function crearLinks() {
// Recorro todos los H3 dentro de la Sidebar1
var opciones = $$(”#sidebar1 h3”);
opciones.each(function(opcion) {
// Genero la acción del clic por cada uno
opcion.onclick = function() {
// utilizo el id de cada h3 como nombre de sección
mostrarSeccion(opcion.id);
}
})
}

Entonces se va a utilizar el id de cada h3 como nombre de un archivo formado por


ese id y .html para traer la información. Estos archivos sólo deben contener el HTML a
incluir en la zona de contenido y no el body, el head, etc. Por ejemplo:

quienes.html

<h1> Quiénes Somos </h1>


<p>Somos una empresa moderna, con sede en Argentina, México y Es-
paña cuya misión es crear aplicaciones ricas de Internet con todas
las tecnologías posibles</p>

clientes.html
<h1> Clientes </h1>
<p>Algunos de los clientes más importantes son:
<ul>
<li>Coca Cola </li>

165
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 166

Maximiliano R. Firtman

<li>Pepsi</li>
<li>Fanta</li>
<li>7Up</li>
<li>Crush</li>
<li>Paso de los Toros</li>
</ul>
</p>

servicios.html
<h1> Servicios </h1>
<p>Entre los servicios prestados contamos con
<ul>
<li>Diseño Web</li>
<li>Usabilidad</li>
<li>Desarrollo PHP y ASP.NET</li>
<li>Desarrollo AJAX y Flex</li>
<li>Diseño de Base de Datos</li>
<li>Acompañante Terapéutico</li>
</ul>
</p>

contacto.html
<h1> Contacto </h1>
<p>Puedes contactarnos por las siguientes vías:
<ul>
<li>Postal: Av. Siempre Viva 123</li>
<li>Teléfono: 123-54874</li>
<li>E-mail: info@midominioajax.com</li>
</ul>
</p>

El código JavaScript controlador de nuestra aplicación queda muy sencillo y sim-


ple de comprender (fig. 5-6):

window.onload = function() {
crearLinks();
}

function crearLinks() {
// Recorro todos los H3 dentro de la Sidebar1
var opciones = $$(”#sidebar1 h3”);
opciones.each(function(opcion) {
// Genero la acción del clic por cada uno

166
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 167

AJAX. Web 2.0 para profesionales

opcion.onclick = function() {
// utilizo el id de cada h3 como nombre de sección
mostrarSeccion(opcion.id);
}
})
}

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
$(”mainContent”).innerHTML = html;
}
});
}

Fig. 5-6. En la figura se aprecia que se puede navegar por las secciones y se va refrescando sólo el
contenido principal. En Firebug se pueden ver todas las peticiones AJAX realizadas.

167
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 168

Maximiliano R. Firtman

Aviso de cargando
Debido a que los usuarios todavía no están muy acostumbrados a encontrarse con si-
tios AJAX, al hacer click en cada sección estarán esperando que la página entera se
recargue. Como eso no ocurrirá, se podría incluir un cartel de cargando para que el
usuario espere hasta que cada petición termine, antes de pensar que los links no fun-
cionan.
Ésta será, entonces, la primera oportunidad de probar nuestro pequeño framework
de aviso de carga por medio de la librería de Ajax. Para ello, sólo se debe crear un DIV
en el HTML que esté apagado por defecto como el siguiente:

<div id=”divCargando” style=”display: none”>


Por favor espere...
</div>

y definirle, mediante CSS las propiedades deseadas. También cambiaremos nuestra


petición Ajax con el siguiente código:

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
$(”mainContent”).innerHTML = html;
},
avisoCargando: ”divCargando”
});
}

Si se desea que el cartel de cargando se parezca a los clásicos carteles de los ser-
vicios de Google (que aparecen arriba a la derecha, en blanco sobre rojo), el CSS que
se debe aplicar es similar al siguiente (figs. 5-7 y 5-8):

#divCargando {
position: absolute;
top: 5px;
right: 5px;
background-color: red;
color: white;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
}

168
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 169

AJAX. Web 2.0 para profesionales

Fig. 5-7. Nuestro cartel de cargando en acción mientras se espera la petición AJAX. Con CSS se lo
puede ubicar visualmente donde se desee.

Fig. 5-8. En el sitio www.ajaxload.info se encontrará un generador de animaciones para los carteles
con modelos similares a los usados en muchos sitios AJAX.

169
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 170

Maximiliano R. Firtman

Aplicando efectos
Por último, se podría usar Script.aculo.us para generar un efecto al cambiar de sección.
Para ello se agregan todos los archivos scriptaculous.js y effects.js de la librería a nues-
tro proyecto y se la importa en el index.html después de Prototype, indicando que sólo
se desea usar los efectos:

<script type=”text/javascript”
src=”scriptaculous.js?load=effects”></script>

Una opción sería apagar con lentitud el contenido viejo y hacer aparecer el nuevo
con otro efecto. El código a cambiar en el index.js sería:

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
// Comienzo efecto de salida
new Effect.Fade(”mainContent”, {
duration: 1,
afterFinish: function() {
// Comienzo efecto de aparición de
//contenido
$(”mainContent”).innerHTML = html;
new Effect.Appear(”mainContent”);
}
});
},
avisoCargando: ”divCargando”
});
}

Otra opción de efecto válido sería hacer un Highlight de la zona modificada, en


este caso el “mainContent”. Esto permite mostrar un efecto amarillo al cambiar el con-
tenido, que se va yendo automáticamente en unos milisegundos. Esto obliga al usua-
rio a darse cuenta de que se acaba de cambiar el contenido. El código sería:

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
$(”mainContent”).innerHTML = html;
// Comienzo efecto de Highlight

170
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 171

AJAX. Web 2.0 para profesionales

new Effect.Highlight(”mainContent”);

},
avisoCargando: ”divCargando”
});
}

El único cuidado que se debe tener al usar el efecto Highlight es que, en Internet
Explorer, es necesario que el elemento al que se le aplica este efecto tenga estricta-
mente definida la propiedad background-color vía CSS, para así saber a qué color tiene
que volver cuando el efecto termina.

Lector RSS

Un buen ejemplo de cómo utilizar XML en peticiones AJAX es realizar un lector de ca-
nales RSS (Really Simple Syndication). Un RSS es un archivo en formato XML que per-
mite mostrar ciertas noticias o novedades en un formato estándar utilizado por muchos
lectores.
En este caso se hará una página AJAX que muestre el contenido de un archivo
RSS ubicado en nuestro servidor (recuérdense las restricciones de seguridad). No obs-
tante, se podría crear con facilidad un PHP o un ASP.NET que traiga un RSS de otro
servidor. Más adelante se verá cómo implementar esta funcionalidad.
El objetivo es tener la pantalla dividida en dos. En una primera columna se hace
una lista con los títulos de las noticias del RSS y en la segunda se coloca el contenido
de cada noticia seleccionada.
Un RSS tiene un formato jerárquico, como se indica en la figura 5-9.
Recuérdese que hay varios formatos de RSS y también existe ATOM. Si se desea
leer todos los formatos, habrá que adaptar nuestro código.
El objetivo del JavaScript será leer el XML, procesarlo y dibujar el contenido en el
HTML. Hay un botón para actualizar el RSS en forma manual y recargar su contenido.
Mientras se hace la petición, se apaga el botón para que no pueda utilizarse, se
muestra cartel de loading y se pone el fondo gris. Cada noticia (ítem) se exhibe en un
menú a la izquierda, y al hacer clic se muestra su detalle en la parte derecha. Para
todos los efectos visuales se utiliza CSS.
Veamos entonces nuestro lector.html y su CSS (fig. 5-10).

171
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 172

Maximiliano R. Firtman

Fig. 5-9. Estructura XML de un archivo RSS. Cada ítem representa a cada noticia.

Fig. 5-10. Nuestro lector RSS en funcionamiento.

lector.html
<!DOCTYPE html PUBLIC ”-//W3C//DTD HTML 4.01 Transitional//EN”
”http://www.w3.org/TR/html4/loose.dtd”>
<html>
<head>

172
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 173

AJAX. Web 2.0 para profesionales

<meta http-equiv=”Content-Type” content=”text/html; charset=ISO-


8859-1”>
<title>Lector de RSS</title>
<link href=”estilos.css” rel=”stylesheet” type=”text/css” />
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”AjaxLib.js”></script>
<script type=”text/javascript” src=”scriptaculous.js”></script>
<script type=”text/javascript” src=”lector.js”></script>
</head><body>

<div id=”divTitulo”></div>

<input type=”button” value=”Actualizar” id=”btnActualizar” />

<div id=”divContenedor”>

<div id=”divItems”>
</div>

<div id=”divDetalle”>
<div id=”lblTituloItem”></div>
<div id=”lblTextoItem”></div>
<div id=”lblFechaItem”></div>
<div id=”lblLinkItem”></div>
</div>

</div>

<div id=”divLoading”>
Por favor, espere...
</div>

</body>
</html>

estilos.css
body {
font: 100% Verdana, Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
text-align: center;
color: #000000;
background-color: #EEE;
}

#btnActualizar {
position: absolute;
top: 10px;
right: 10px;
background: white;

173
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 174

Maximiliano R. Firtman

color: black;
border: 1px gray solid;
}

#divTitulo {
width: 80%;
text-align: center;
padding: 15px;
font-size: 21px;
height: 50px;
background: #FFEEEE;
}

#divItems {
width: 30%;
float: left;
}

#divItems div {
font-size: 10px;
text-align: left;
padding: 10px;
cursor: pointer;
width: 200px;
}
#divItems div:hover {
color: red;
}
#divItems div.selected {
background-color: #abcefe;
color: blue;
font-weight: bold;
}

#divDetalle {
width: 500px;
padding: 25px;
float: left;
text-align: justify;
}

#lblTituloItem {
font-weight: bold;
font-size: 17px;
padding-bottom: 15px;
}

#lblFechaItem {
padding-top: 15px;
text-align: right;
color: gray;
}

174
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 175

AJAX. Web 2.0 para profesionales

#divLoading {
position: absolute;
top: 50px;
right: 50%;
background-color: red;
color: white;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
}

lector.js
window.onload = function() {
// Hace petición al servidor para traer Datos la primera vez
traerRSS();
$(”btnActualizar”).onclick = traerRSS;
}

function traerRSS() {
// Apaga el botón
$(”btnActualizar”).disabled = true;
// Pone el fondo del body en gris
$$(”body”)[0].style.background = ”#EEE”;
$Ajax(”tecnologia.xml”, {
cache: false, // No queremos que cachee al actualizar
cartelCargando: ”divLoading”,
tipoRespuesta: $tipo.XML,
onfinish: procesarRSS,
onerror: function() {
alert(”Ha ocurrido un error al recibir el RSS”)
}
});
}

// Guarda globalmente el RSS


var rss;

function procesarRSS(xml) {
rss = xml;
// Prende el botón
$(”btnActualizar”).disabled = false;
// Pone el fondo del body en blanco
$$(”body”)[0].style.background = ”white”;

// Proceso el RSS y voy completando los datos en el HTML


$(”divTitulo”).innerHTML = leerTextoEnTag(rss.getElementsByTag-
Name(”title”)[0]);

175
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 176

Maximiliano R. Firtman

// Limpia los ítems anteriores


$(”divItems”).innerHTML = ””;

var items = rss.getElementsByTagName(“item”);

// Recorro cada ítem (noticia o artículo)


for (var i=0; i<items.length; i++) {
// Creo un nuevo elemento div de menú en divItems
var div = document.createElement(”div”);
div.id = ”item_” + i;
div.onclick = function() { verItem(this) };
// Obtengo el título del ítem actual
div.innerHTML = leerTextoEnTag(items[i].getElementsByTag-
Name(”title”)[0]);
$(”divItems”).appendChild(div);
}
// Selecciona la primera
verItem($(”item_0”));
}

function verItem(elemento) {
// Le saca la clase ”seleccionado” al anterior
try {
$$(”div.selected”)[0].removeClassName(”selected”);
} catch(e) {}
// Le asigna una clase CSS a la seleccionada
$(elemento).addClassName(”selected”);
// Extrae el número dentro del ID
var id = elemento.id.substring(5);
var item = rss.getElementsByTagName(”item”)[id];

$(”lblTituloItem”).innerHTML = leerTextoEnTag(item.getElementsBy-
TagName(”title”)[0]);
$(”lblTextoItem”).innerHTML = leerTextoEnTag(item.getElementsBy-
TagName(”description”)[0]);
$(“lblFechaItem”).innerHTML = leerTextoEnTag(item.getElementsBy-
TagName(”pubDate”)[0]);

var link = ”<a href=’” + leerTextoEnTag(item.getElementsByTag-


Name(”link”)[0]) + ”‘ target=’_blank’>Ver Articulo</a>”;
$(”lblLinkItem”).innerHTML = link;

new Effect.Highlight(”divDetalle”, {duration: 0.3});


}

function leerTextoEnTag(elemento) {
if (elemento!=undefined)
return elemento.firstChild.nodeValue;
else
return ””;

176
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 177

AJAX. Web 2.0 para profesionales

tecnología.xml
<?xml version=”1.0” encoding=”UTF-8” ?>
<rss>
<channel>
<title>Maestros del Web</title>
<link>http://www.maestrosdelweb.com</link>
<description>Un espacio para los entusiastas del web</description>

<language>es</language>

<item>
<title>¿Realizas búsquedas en Internet desde tu
celular?</title>
<link>http://feeds.feedburner.com/~r/maestrosdel
web/~3/115748199/</link>
<pubDate>Fri, 11 Sep 2007 00:06:37 +0000</pubDate>

<category><![CDATA[Actualidad]]></category>

<description><![CDATA[Un teléfono móvil no es precisamente la


herramienta más usable para navegar en Internet, lo que está generando
interesantes iniciativas que se enfocan en mejorar la búsqueda de conte-
nidos en la red desde uno de estos dispositivos.
¿Has utilizado un buscador como Yahoo o Google desde
tu celular? Herramientas que son muy fáciles de [...]]]></description>
</item>

<item>
<title>Rebit: backup automático de tus datos</title>
<pubDate>Thu, 10 Sep 2007 18:44:32 +0000</pubDate>
<category><![CDATA[Actualidad]]></category>
<description><![CDATA[Es un simple aparato del tamaño de una
cámara digital compacta que realiza el backup de tu computadora de una
forma automática simplemente conectándola a través de un cable USB.
Rebit es un dispositivo que realiza tus backups de forma au-
tomática y actualizada. Creo que todos nos preocupamos por no perder la
información de nuestra computadora [...]]]></description>

</item>

<item>
<title>Xurrency: un conversor de monedas en línea</title>
<link>http://feeds.feedburner.com/~r/maestrosdel
web/~3/115656832/</link>
<pubDate>Thu, 10 Sep 2007 16:43:29 +0000</pubDate>

<category><![CDATA[Actualidad]]></category>
<description><![CDATA[Una nueva herramienta 2.0 muy útil para
los viajeros y las personas que constantemente necesitan realizar conver-
siones de monedas, Xurrency tiene los datos actualizados todo el tiempo.
Xurrency fue creada por el desarrollador de Cádiz, España, Alfonso Jimé-
nez, la cual según el sitio oficial es una herramienta 2.0 muy fácil de

177
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 178

Maximiliano R. Firtman

usar. El nombre se refiere [...]]]></description>


</item>
</channel>
</rss>

Para leer el texto inserto en una etiqueta XML, por ejemplo <title>Texto</title>, hay que
navegar hasta llegar al elemento title y tomar el valor de su primer hijo (firstChild.nodeValue)
(figs. 5-11 y 5-12).
Si se va a generar el XML desde algún lenguaje dinámico, como PHP o ASP.NET
es obligatorio enviar la cabecera correcta con el tipo MIME indicando que se trata de
un XML. En caso de que esto no se haga JavaScript dará un error al leer responseXML
por no tratarse de un XML válido.
En PHP se puede hacer (antes de enviar cualquier contenido):

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

En ASP o ASP.NET:

Response.ContentType = ”text/xml”);

Actualizando periódicamente
Si se deseara que las noticias se actualicen en forma automática cada n cantidad de
segundos o minutos sin que el usuario deba utilizar el botón recargar, sólo se debe
agregar el código siguiente a nuestro window.onload:

setInterval(”traerRSS()”, 120000);

Este código ejecutaría la función traerRSS que actualiza los datos cada 2 minu-
tos (2 x 60 x 1000). Sólo es preciso tener cuidado y no abrir siempre la primera noticia
al refrescar. Se debe pensar que si el usuario está leyendo una noticia justo en el mo-
mento de cargar de nuevo, se le cambiará de manera automática a la primera.
Esto se puede resolver si se guarda en una variable global la noticia que el usua-
rio está viendo para dejarla en el mismo lugar. En estos casos sería conveniente no
mostrar el aviso de cargando, dado que el usuario no activó en forma explícita la ac-
tualización y será molesto que cada 2 minutos vea un efecto de desactivación del con-
tenido.

178
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 179

AJAX. Web 2.0 para profesionales

Fig. 5-11. Mientras se carga o actualiza el RSS, la vista es la siguiente. El botón está desactivado.

Fig. 5-12. El mismo RSS observado en la Visión Diseño de Eclipse.

179
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 180

Maximiliano R. Firtman

Proxy PHP

Leer RSS de nuestro dominio es una buena idea para transportar noticias e informa-
ción en un formato estándar. No obstante, sería mejor si se pueden leer archivos RSS
de otros dominios, como los miles que existen en diversos lugares. Para ello, se ne-
cesita un proxy o intermediario en nuestro servidor por los problemas de seguridad
que hay en AJAX.
En PHP realizar un proxy es muy sencillo. Si se usa PHP en el servidor, se incluye
el archivo siguiente:

proxyrss.php

<?php

if (isset($_GET[‘url’])){
$url = ‘http://‘ . $_GET[‘url’];
header(”Content-type: text/xml”);
readfile($url);
}

?>

de esta manera, ahora sólo se debe cambiar la petición Ajax; en lugar de hacerla a un
xml, se haría al php enviando por parámetro GET la url del RSS a leer. Por ejemplo:

$Ajax(“proxyrss.php?url=www.developer.apple.com/rss/adcheadlines.rss”
, {

}

El PHP leerá en el servidor el RSS del servidor de Apple y nos lo entregará como
si estuviera localmente en nuestro servidor. El browser nunca se entera de que la pe-
tición se hizo a otro servidor, por lo que no muestra error de seguridad alguno.
La misma idea se puede migrar con facilidad a ASP.NET o Java del lado del ser-
vidor. Asimismo, con un poco de código se podrá crear un lector RSS donde el usua-
rio pueda tener guardado sus RSS favoritos y agregar nuevos (figs. 5-13 y 5-14).

180
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 181

AJAX. Web 2.0 para profesionales

Fig. 5-13. Ahora nuestro lector sirve para leer cualquier RSS de cualquier servidor.

Fig. 5-14. Google Reader es un lector RSS AJAX con la misma base que nuestro proyecto, pero con
mayor funcionalidad.

181
C05.qxd:Project Ajax4.1.qxd 10/18/07 8:07 PM Página 182
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:09 PM Página 183

Formulario de registro AJAX


6
Objetivo
La idea en este capítulo es realizar un ejercicio completo con los temas vistos hasta
ahora para confeccionar un formulario de registro en un sitio web, que podría modifi-
carse para su utilización en cualquier tipo de formulario.
El formulario contendrá las siguientes acciones:
• Se enviará vía POST en una petición AJAX mostrando el resultado en la misma
página.
• Realizará una validación activa de los datos; por activa se entiende que se re-
aliza de manera constante mientras el usuario ingresa el formulario.
• Tendrá dos campos de tipo autocompletar. Uno de ellos permitirá elegir op-
ciones de una lista reducida en posibles elementos y el segundo requerirá pe-
ticiones AJAX al servidor.
• Se implementará una lista desplegable en cascada que permite recorrer una
estructura de dos o más niveles (p. ej., País > Provincias > Ciudades) sin hacer
recargas al servidor.
• También se tendrán algunos controles ricos que se incorporarán al formulario.

Arquitectura

Se elige PHP 5 como plataforma del lado del servidor para ejemplificar el uso de la co-
municación cliente-servidor, pero los ejemplos pueden exportarse con rapidez a otras
plataformas, como ASP.NET, Java o Ruby.

183
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:09 PM Página 184

Maximiliano R. Firtman

Se utilizará MySQL como motor de base de datos y se empleará una clase pro-
pietaria sencilla para simplificar el acceso a la base de datos para realizar consultas.
El sistema permitirá registrarse en una página web donde se ofrecen cursos a dis-
tancia. El usuario se registrará y podrá seleccionar en qué fecha desea comenzarlos y
en qué orden los quiere cursar.
Para realizar muchos de los controles antes mencionados se utilizará la librería
Script.aculo.us.

Tablas

En la figura 6-1 se puede ver un diagrama entidad-relación con las tablas utilizadas y
sus relaciones.
Las tablas son:

Usuarios

Campo Tipo de datos Opciones

nombre_usuario varchar(20) Clave Primaria, NOT NULL


nombre varchar(50) NOT NULL
apellido varchar(50) NOT NULL
e-mail varchar(150) NOT NULL
direccion varchar(100)
localidad varchar(100)
provincia_id int Clave Foránea
password varchar(20) NOT NULL
edad int
nivel int
fecha_inicio datetime
fecha_alta datetime

Países

Campo Tipo de datos Opciones

id int Clave Primaria, NOT NULL, AutoIncrement


nombre varchar(50) NOT NULL

184
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:09 PM Página 185

AJAX. Web 2.0 para profesionales

Provincias

Campo Tipo de datos Opciones

id int Clave Primaria, NOT NULL,


AutoIncrement
nombre varchar(50) NOT NULL
país_id int Clave Foránea

Cursos

Campo Tipo de datos Opciones

id int Clave Primaria, NOT NULL,


AutoIncrement
nombre varchar(50) NOT NULL

Cursos_x_Usuario

Campo Tipo de datos Opciones

id_usuario varchar(20) Clave Primaria, NOT NULL


id_curso int Clave Primaria, NOT NULL
orden int

Fig. 6-1. Diagrama entidad-relación de nuestras tablas MySQL.

185
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:09 PM Página 186

Maximiliano R. Firtman

Creando el formulario
XHTML

El primer paso es crear la estructura básica del formulario. Se creará un clásico for-
mulario con dos columnas, pero sin usar tablas. Haciendo uso de DIV y CSS se puede
lograr el mismo efecto, incluso más personalizado. Usaremos nuestra librería AjaxLib,
Prototype y Script.aculo.us, por lo que ya agregamos estos JS a nuestro XHTML, ade-
más del archivo formulario.js controlador de nuestra página.
Nótese que algunos campos se dejan vacíos y se irán incorporando con funcio-
nalidad luego (fig. 6-2).

Fig. 6-2. Así se ve nuestro formulario en el navegador web.

186
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 187

AJAX. Web 2.0 para profesionales

formulario.html

<!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>Formulario de Registro ITMaster</title>
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”AjaxLib.js”></script>
<script type=”text/javascript” src=”scriptaculous.js”></script>
<script type=”text/javascript” src=”formulario.js”></script>
<link href=”formulario.css” rel=”stylesheet” type=”text/css” />
</head>

<body>

<form id=”formRegistro”>

<div class=”filaCampo”>
<div class=”etiqueta”>Nombre de Usuario: </div>
<div class=”campo”><input type=”text” id=”txtUsua-
rio” /></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Nombre: </div>
<div class=”campo”><input type=”text” id=”txtNom-
bre” /></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Apellido: </div>
<div class=”campo”><input type=”text” id=”txtApe-
llido”
/></div>
</div>
<div class=”filaCampo”>
<div class=”etiqueta”>Dirección E-mail: </div>
<div class=”campo”><input type=”text” id=”txtEmail”
/></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Dirección Postal: </div>
<div class=”campo”><input type=”text” id=”txtDirec-
cion” /></div>
</div>

187
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 188

Maximiliano R. Firtman

<div class=”filaCampo”>
<div class=”etiqueta”>Localidad: </div>
<div class=”campo”><input type=”text” id=”txtLoca-
lidad” /></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>País: </div>
<div class=”campo”><select id=”lstPais”></se-
lect></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Provincia: </div>
<div class=”campo”><select id=”lstProvincia”></se-
lect></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Edad: </div>
<div class=”campo”><input type=”text” id=”txtEdad”
/></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Nivel Educativo: </div>
<div class=”campo”><div
id=”nivelEducativo”></div></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Fecha de Inicio Deseada:
</div>
<div class=”campo”><input type=”text” id=”txtFe-
chaInicio” /></div>
</div>

<div class=”filaCampo”>
<div class=”etiqueta”>Cursos en Orden: </div>
<div class=”campo”><div id=”cursos”></div></div>
</div>

<input type=”button” id=”btnRegistrar” value=”Registrar


Usuario” />

</form>

</body>
</html>

188
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 189

AJAX. Web 2.0 para profesionales

formulario.css

body {
font-family: Arial, Helvetica, sans-serif;
}

input {
border: 1px #888 solid;
}

#formRegistro {
width: 500px;
border: 1px #666666 solid;
background: #eeb;
padding: 15px;
}

.filaCampo {
padding: 2px;
height: 25px;
}

.etiqueta {
width: 40%;
float: left;
}

.campo {
width: 60%;
float: right;
}

Autocompletar
Qué es

Un control de tipo autocompletado (autocomplete) o autosugerido (autosuggest) es


básicamente un campo de texto que, a medida que el usuario ingresa las letras, le su-
giere posibles opciones para que pueda elegir con el cursor o el teclado, y así evitar ter-
minar de insertar el texto en forma manual (fig. 6-3).

189
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 190

Maximiliano R. Firtman

Fig. 6-3. Google Suggest es una versión del buscador que va sugiriendo posibles opciones mientras
se ingresa texto. En la Google Toolbar también se incluye esta opción.

Si bien se podría armar desde cero, por medio de JavaScript y las acciones on-
keyup y onkeydown de un campo de texto, hay librerías que ayudan en este sentido y
Script.aculo.us es la más simple y potente de ellas (fig. 6-4).

Cuándo aplicarlo

Un control de tipo autocompletado debe aplicarse en campos de texto donde, si bien


el campo al que el usuario ingrese cualquier texto es abierto, es muy probable que en
él se inserte algún valor de una lista predefinida que nosotros ya tenemos. Un ejemplo
muy claro es cuando se escribe un e-mail en los campos de Para donde se pueden su-
gerir direcciones registradas en la libreta o usadas con anterioridad (fig. 6-5).

190
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 191

AJAX. Web 2.0 para profesionales

Fig. 6-4. En Yahoo! UI (developer.yahoo.com) existen sugerencias sobre cómo y cuándo aplicar dis-
tintos tipos de controles ricos.

Se debe aplicar en campos donde el usuario puede no estar seguro de qué in-
gresar (p. ej., un cuadro de búsqueda) o cuando podemos tener la lista de posibles va-
lores registrados con anterioridad.
Una variante de este control rico es ir completándole el campo al usuario mientras
escribe en lugar de mostrarle una lista de opciones posibles, aunque no es la más
común.
Existen dos tipos de autocompletar, uno local y uno remoto o AJAX.

Autocompletar local

El autocompletar local se aplica cuando la lista de posibles opciones que el usuario


puede utilizar es reducida en cantidad y además es estática (no se actualiza en vivo en
el servidor). De esta forma, la lista la tiene preincorporada el código JavaScript embe-
bido en un vector local que no requiere peticiones AJAX al servidor.

191
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 192

Maximiliano R. Firtman

Fig. 6-5. La mayoría de los webmail modernos, como Yahoo! Mail, GMail o Windows Live Mail, so-
portan autocompletado al redactar un e-mail.

Si bien podría crearse de cero, no se va a caer en escritura de código completa-


mente de cero, y se va a hacer uso de Script.aculo.us, que provee una forma sencilla
y rápida de crear controles de autocompletado (fig. 6-6).
Script.aculo.us ofrece un objeto llamado Autocompleter, que permite crear el con-
trol. Los pasos para hacerlo son los siguientes:
• Crear el campo de ingreso de texto (<input type=”text” />) y definirle un id para
que luego lo utilice el control, por ejemplo, txtDestinatario.
• Definir el campo de texto como autocomplete=”false”, como atributo XHTML.
Este atributo le indica al navegador web que no utilice técnicas de autocom-
pletado propias del mismo porque esto llevaría a una confusión, ya que el
usuario podría ver dos autocompletados, el nuestro y el del navegador.

192
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 193

AJAX. Web 2.0 para profesionales

Fig. 6-6. En el sitio developer.yahoo.com/ypatterns se puede encontrar una descripción sobre cómo
se debería programar y diseñar un autocomplete totalmente desde cero.

• Crear un div vacío en cualquier lugar del DOM (aunque es recomendable ha-
cerlo luego del input) y definirle un id. Este div será utilizado por Script.aculo.us
para crear la lista de opciones.
• Crear un vector de strings con todas las opciones que queremos que se utili-
cen como posibles.
• Instanciar un nuevo objeto con la siguiente sintaxis:

new Autocompleter.Local(id_textbox, id_div, vector_opciones, adicio-


nales);

Con el código anterior ya se tiene listo un simple y sencillo autocomplete funcio-


nando. Cuando el usuario comience a escribir en el campo de texto, se le desplegará

193
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 194

Maximiliano R. Firtman

una lista con sugerencias según los caracteres que ya fue ingresando. El usuario podrá
continuar ingresando texto, hacer clic en alguna de las sugerencias o navegar con las
flechas de cursor del teclado y seleccionar una de ellas.
A continuación se muestra un ejemplo simple:

<div class=”filaCampo”>
<div class=”etiqueta”>País: </div>
<div class=”campo”><select id=”lstPais”></select></div>
<div id=”autocompletePais”></div>
</div>

En el controlador formulario.js se agrega:

window.onload = function() {
var localidades = [”Alabama”, ”Brasilia”, ”Barcelona”, ”Buenos
Aires”, ”Colonia”, ”Córdoba”, ”Madrid”, ”Mendoza”, ”Mexico DF”];
new Autocompleter.Local(”txtLocalidad”, ”autocompleteLocalidad”,
localidades);
}

Ahora, cuando se ingresen una o más letras en el campo de Localidad, por ejem-
plo una “B”, se verá un listado de opciones que aparecerán en forma automática de-
bajo del campo, en nuestro caso, Brasilia, Barcelona y Buenos Aires (véase fig. 6-7).
También se puede apreciar que la o las letras que se vayan ingresando aparecerán re-
saltadas en negrita en el listado de sugerencias.
Al ver la figura 6-7 se comprende que las opciones de autocompletado aparecen,
pero sin demasiado estilo, al aplicar un formato de viñetas.
Lo que se debe hacer es aplicar estilos al div de autocompleteLocalidad por
medio de CSS. La misma librería script.aculo.us ofrece estilos CSS para lograr que el
control de autocompletado se vea como los que estamos acostumbrados a ver. Para
evitar tener que duplicar los estilos por cada autocomplete, se puede utilizar un estilo
de clase y agregar, desde XHTML o JavaScript, la clase al div, por ejemplo:

window.onload = function() {
var localidades = [”Alabama”, ”Brasilia”, ”Barcelona”, ”Buenos
Aires”, ”Colonia”, ”Cordoba”, ”Madrid”, ”Mendoza”, ”Mexico DF”];
$(”autocompleteLocalidad”).className = ”autocomplete”;
new Autocompleter.Local(”txtLocalidad”, ”autocompleteLocali-
dad”, localidades);
}

194
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 195

AJAX. Web 2.0 para profesionales

Fig. 6-7. Al ingresar un texto del que pueden surgir opciones, éstas aparecen debajo, aunque todavía
sin estilo.

Y en formulario.css se agregan los estilos CSS siguientes:

div.autocomplete {
position:absolute;
width:250px;
background-color:white;
border:1px solid #888;
margin:0px;
padding:0px;
}

div.autocomplete ul {
list-style-type:none;
margin:0px;

195
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 196

Maximiliano R. Firtman

padding:0px;
}
div.autocomplete ul li.selected {
background-color: #ffb;
}

div.autocomplete ul li {
list-style-type:none;
display:block;
margin:0;
padding:2px;
height:24px;
cursor:pointer;
}

De esta manera el código autocompletar tiene un estilo muy similar a los contro-
les de este tipo en aplicaciones de escritorio (figs. 6-8 y 6-9).

Fig. 6-8. Ahora se puede apreciar que las sugerencias de autocompletado se ven con un estilo más
acorde al tipo de solución buscada.

196
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 197

AJAX. Web 2.0 para profesionales

Fig. 6-9. Cuando aparecen las opciones podemos elegirlas con el puntero o movernos con las teclas
de cursor.

Opcionales
Además, es posible definir como cuarto parámetro del Autocompleter.Local los si-
guientes atributos opcionales en formato de JSON:

Opción Descripción

choices Indica la cantidad máxima de opciones a mostrar en el autocomplete

partialSearch Si se define en false sólo buscará coincidencias con el inicio de las


posibles opciones. En true (por defecto) mira en cualquier palabra
que esté dentro de la opción

197
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 198

Maximiliano R. Firtman

Opción Descripción

fullSearch Si se define en true, busca coincidencias con cualquier parte del string
de las opciones

minChars Indica la cantidad mínima de caracteres que se necesitan para


comenzar a mostrar sugerencias

partialChars Indica cuántos caracteres se ingresan antes de comenzar una


búsqueda parcial (en cualquier palabra)

frequency Indica cada cuántos segundos intenta sugerir opciones (por defecto 0.4)
updateElement Es una función que recibirá por parámetro la opción que el usuario elige

afterUpdateElement Es una función que se ejecuta después de que el usuario elige una op
ción y se cargó en el campo de texto

Por ejemplo, podríamos cambiar nuestro código por el siguiente:

new Autocompleter.Local(”txtLocalidad”, ”autocompleteLocalidad”, lo-


calidades, {frequency: 0.8, partialChars: 4, fullSearch: true});

Autocompletar remoto

Cuando las opciones que se le pueden sugerir al usuario son demasiadas, o dependen
de algún dato que varía de manera dinámica en el servidor, no es óptimo ni útil gene-
rar un vector con todas las opciones posibles. Imagínese, por ejemplo, el listado de
todas las ciudades del mundo. No sólo se enviaría información que nunca se usará,
sino que se sobrecargaría la memoria del browser y la transferencia de datos.
Por ello, hay una versión del autocompletar que funciona en forma remota. En
este caso, cuando el usuario comienza a escribir, la librería se encarga de emitir una pe-
tición al servidor con los caracteres que el usuario ingresó y el servidor deberá darle una
respuesta con las opciones que debe mostrar.
La respuesta debe tener formato XHTML utilizando listas desordenadas, esto es,
como en el ejemplo siguiente:

<ul>
<li>Opcion 1</li>
<li>Opcion 2</li>
</ul>

198
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 199

AJAX. Web 2.0 para profesionales

Automáticamente, entonces, la librería mostrará estas dos opciones como suge-


rencias de ingreso.
La idea sería que en el servidor se ejecute algún script (p. ej., PHP o ASP) que re-
ciba el texto ingresado hasta el momento, busque en una tabla y genere la lista de-
sordenada.
Recuérdese que esta versión del autocomplete genera peticiones al servidor y se
debe encontrar un equilibrio entre cantidad de peticiones y tiempo de espera para evi-
tar sobrecargar el servidor.
La sintaxis es la siguiente:

new Ajax.Autocompleter(id_textbox, id_div, url, opciones)

Como se ve, es similar al autocomplete local, sólo que es un objeto dentro de la


clase Ajax, clase que se había visto que provee Prototype. Asimismo, se reemplaza el
vector de opciones por la url del script, que se encargará de devolver las opciones.
Las opciones disponibles a enviar en formato JSON son:

Opción Descripción

paramName OBLIGATORIO. Este parámetro indica el nombre de la variable vía POST


donde se enviarán los caracteres ingresados por el usuario

minChars Indica la cantidad mínima de caracteres que se necesitan para


comenzar a mostrar sugerencias. Dado que se trata de peticiones al
servidor, es recomendable utilizar 2 o 3 caracteres mínimos

frequency Indica cada cuántos segundos intenta sugerir opciones (por


defecto 0.4). Es un valor para definir para lograr un equilibrio entre
servicio y cantidad de peticiones

indicator Si lo indicamos, define el nombre de un elemento del DOM que actuará


como cartel de cargando o loading mientras la petición se realiza.
Su uso no es muy recomendable para no marear al usuario

updateElement Es una función que recibirá por parámetro la opción que el usuario elige

afterUpdateElement Es una función que se ejecuta después de que el usuario elige una
opción y se cargó en el campo de texto

La petición AJAX se realizará automáticamente por Script.aculo.us. Reemplace-


mos nuestro autocomplete local por uno remoto. Primero se hace un script PHP que
consulte en la tabla de usuarios un listado de todas las localidades ya usadas con an-
terioridad por otros usuarios.

199
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 200

Maximiliano R. Firtman

Previamente debe hacerse una clase en PHP para manejar la base de datos y así
simplificar la tarea. Recuérdese que los archivos PHP sólo ejecutarán código y no ten-
drán HTML mezclado entre sí. Si ya se estaba usando JSEclipse se puede instalar PDT
(PHP Development Tools) para agregar soporte de PHP al mismo entorno.
Es preciso recordar que migrar este ejemplo a ASP.NET, Java, Ruby u otra plata-
forma es en realidad muy sencillo.

BD.php
Hagamos entonces una librería simple de PHP para manejar la base de datos. Esto
permitirá simplificar mucho más todos los scripts que se usarán a partir de ahora.
Siempre es recomendable utilizar una clase de este tipo para crear una capa de
datos y no hacer consultas directamente a los objetos de la base de datos. Esto per-
mite realizar aplicaciones más escalables en el futuro.
La clase tiene métodos (funciones) para distintas tareas, entre ellas:

Método Descripción

Execute Recibe una consulta SQL y devuelve un vector de registros con todos
los resultados

ExecuteRecord Recibe el nombre de una tabla y un filtro SQL para el where, y trae un
solo registro

ExecuteField Trae un vector con todos los valores que tiene un solo campo en cada
uno de los registros de la tabla indicada con un filtro particular

ExecuteTable Recibe el nombre de una tabla y un campo de orden y devuelve todos


los registros con todos sus campos

ExecuteScalar Muy útil, devuelve el resultado de una consulta que retorna un solo
valor. Por ejemplo, un COUNT(*)

RecordCount Recibe el nombre de una tabla y devuelve la cantidad de registros totales

BD.php
<?php

// ***
// *** Conexión a la Base de Datos ***
// ***

// Instanciamos un objeto global a todos los PHP que lo incluyan


$bd = new BD();

class BD {

200
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 201

AJAX. Web 2.0 para profesionales

// Reemplazar con los datos de la base MySQL


var $host = ”localhost”;
var $user = ”root”;
var $password = ””;
var $database = ”ajax”;
var $conn;

const ABIERTA = 1;
const CERRADA = 0;

var $status = CERRADA;

/**
* Abre la Base de datos
*/
public function open() {
$this->conn = mysql_connect($this->host, $this->user, $this->pass-
word) or die(mysql_error());
mysql_select_db($this->database, $this->conn) or die(mysql_error());

/**
* Cierra la Base de Datos
*
*/
public function close() {
mysql_close($this->conn);
}

/**
* Ejecuta una consulta que no devuelve resultados
*
* @param string $sql Consulta SQL
*/
public function ExecuteNonQuery($sql){
if ($this->status==BD::CERRADA) $this->open();
$rs = mysql_query($sql, $this->conn);
settype($rs, ”null”);
}

/**
* Ejecuta una consulta SQL
*
* @param string $query Consulta SQL
* @return un array de registros, cada uno siendo un array asocia-
tivo de campos
*/
public function Execute($query){

201
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 202

Maximiliano R. Firtman

if ($this->status==BD::CERRADA) $this->open();
//echo $query;
$rs = mysql_query($query,$this->conn);

// Paso el recordset a array asociativo


$registros = array();
while ($reg=mysql_fetch_array($rs)) {
$registros[] = $reg;
}
return $registros;
}

/**
* Ejecuta una consulta devolviendo una fila (registro) con todos sus
campos
*
* @param string $tableName Nombre de la Tabla
* @param string $filter Filtro SQL para el Where
* @return un array asociativo de campos
*/
public function ExecuteRecord($tableName, $filter) {
$todos = $this->Execute(“SELECT * FROM $tableName WHERE $filter
“);
return $todos[0];
}

/**
* Ejecuta una consulta devolviendo una columna (campo) con todos sus
registros
*
* @param string $tableName Nombre de la Tabla
* @param string $field Nombre del Campo a traer
* @param string $filtro Filtro del Where (por lo menos debe ser 1=1
* @return un array asociativo de valores de cada registro
*/
public function ExecuteField($tableName, $field, $filter) {
$todos = $this->Execute(”SELECT $field FROM $tableName WHERE $fil-
ter”);

$aux = array();
foreach ($todos as $uno) {
$aux[] = $uno[0];
}

return $aux;
}

/**
* Trae todos los registros de una tabla
*
* @param string $tableName Nombre de la Tabla
* @param string $orden Campo por el cual ordenar (opcional)

202
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 203

AJAX. Web 2.0 para profesionales

* @return un array de registros, cada uno un array asociativos


*/public function ExecuteTable($tableName, $orden = ””) {
if ($orden!=””)
return $this->Execute(”SELECT * FROM ” . $tableName . ” ORDER
BY ” . $orden);
else
return $this->Execute(”SELECT * FROM ” . $tableName);
}

/**
* Trae un solo valor de la base de datos
*
* @param string $query Consulta SQL (1x1)
* @return el valor devuelto por la consulta
*/
public function ExecuteScalar($query) {
if ($this->status==BD::CERRADA) $this->open();

$rs = mysql_query($query, $this->conn) or die(mysql_error());

$reg = mysql_fetch_array($rs);
return $reg[0];
}

/**
* Devuelve la cantidad de registros de una tabla
*
* @param string $tableName Nombre de la Tabla
* @return Cantidad de Registros
*/
public function RecordCount($tableName) {
return $this->ExecuteScalar(”SELECT COUNT(*) FROM ” . $tableName);
}

?>

Buscador de localidades
Ya que está lista la librería para la base de datos, se va a crear el script php, llamado
autocompleteloc.php, que reciba el parámetro desde nuestra aplicación AJAX, busque en
la tabla de localidades y devuelva la lista desordenada. Para ello se usa el operador lógico
LIKE de SQL que busca dentro de un campo de tipo texto para encontrar coincidencias.
Si se desea que pueda aparecer el texto en cualquier lugar, se puede hacer:

SELECT campo FROM tabla WHERE campo LIKE ‘%%palabra%%‘

203
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 204

Maximiliano R. Firtman

En ese caso, por ejemplo, si el usuario ingresa “an”, se daría como sugerencia
tanto Analía como Mariana.
En cambio, si se quiere que sólo aparezca como comienzo de la opción (en el
ejemplo anterior, Mariana no comienza con “an”) la consulta sería así:

SELECT campo FROM tabla WHERE campo LIKE ‘palabra%%‘

Recuérdese que la librería Script.aculo.us envía por POST el valor ingresado por
el usuario con el nombre de variable que se indicó en las opciones.
Nuestro PHP queda sencillo de la siguiente forma:

<?php
/***
* Autocomplete de Localidades
*/

include(”BD.php”);

$caracteres = $_POST[”caracteres”];

if ($caracteres != ””) {
// Lleva el nombre de la tabla, el campo y la instrucción WHERE
$aLocalidades = $bd->ExecuteField(”USUARIOS”, ”Localidad”,
” Localidad LIKE ‘%%$caracteres%%‘ ”);

$respuesta = ”<ul>”;

foreach ($aLocalidades as $localidad) {


// Le vamos concatenando a la respuesta cada opción
$respuesta .= ”<li>” . $localidad . ”</li>”;
}

$respuesta .= ”</lu>”;

echo $respuesta;
}
?>

El XHTML queda exactamente igual y se modifica su controlador formulario.js para


que funcione en modo Autocomplete Remoto.

window.onload = function() {
$(”autocompleteLocalidad”).className = ”autocomplete”;

204
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 205

AJAX. Web 2.0 para profesionales

new Ajax.Autocompleter(”txtLocalidad”, ”autocompleteLocalidad”,


”autocompleteloc.php”, {paramName: ”caracteres”});
}

Nótese que es obligatorio definir el parámetro adicional paramName con el nom-


bre de la variable POST que se quiere recibir en el PHP con $_POST. En ASP.NET se
leería con la colección Request.Form.
Al ejecutar nuestra página, ahora cuando se ingrese por lo menos un carácter (dado
que no se definió ningún minChars) se realizará una petición pasados 0.4 segundos de
escribir algo al PHP. El script buscará en la base de datos localidades similares a lo in-
gresado por el usuario y devolverá una lista desordenada que es utilizada por
Script.aculo.us para mostrarla como sugerencias de Autocomplete (figs. 6-10 y 6-11).

Fig. 6-10. A simple vista el Autocomplete funciona igual, pero se puede apreciar en Firebug que se fue-
ron realizando peticiones de manera constante.

205
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 206

Maximiliano R. Firtman

Fig. 6-11. Si en cada LI se pone HTML y se modifica el alto de cada uno por CSS, se pueden lograr
autocompletes más visuales.

Categorías con niveles en cascada


Un sistema de niveles en cascada se aplica cuando hay algún tipo de selección que
posee más de un nivel de datos. Ejemplos de este modelo son:
• Países -> Provincias
• Provincias -> Localidades
• Categorías -> Subcategorías
• Empresa -> Sucursales

Cuando el usuario elige una opción del primer nivel (p. ej., un país), la selección
de Provincias debería completarse sólo con las provincias del país seleccionado. Asi-

206
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 207

AJAX. Web 2.0 para profesionales

mismo, cuando se selecciona una provincia, por ejemplo, se puede completar otro lis-
tado de ciudades o localidades si hubiera una normalización de este dato.
En aplicaciones web 1.0 cada vez que el usuario elegía un país, por ejemplo, al re-
gistrarse en un webmail, se recargaba toda la página para traer las provincias del país
seleccionado, si las hubiera. Ahora es posible utilizar AJAX para esta función simple-
mente realizando una petición al servidor cuando el usuario cambia la selección de un
País.

Completar países

Si bien podríamos haber completado nuestra lista de países de manera dinámica


con PHP en el momento de generar el formulario.html, vamos a hacerlo vía AJAX, así
de paso se practica un poco más.
Como la lista de posibles países no depende de ningún otro valor, apenas se carga
la página, se comienza la petición a un script php que devolverá todos los países. Cada
país tiene un identificador (clave primaria) y su nombre, por lo que una estructura XML
o JSON suena muy acorde a la solución. Se va a utilizar JSON por practicidad.
La idea es que paises.php devuelva una respuesta similar a la siguiente:

[{id: 1, nombre: ”Argentina”}, {id: 2, nombre: ”España”}]

Para ello, se crea el siguiente paises.php

<?php
/***
* Devuelve una lista de Países en JSON
*/

include(”BD.php”);

// Lleva el nombre de la tabla y el campo por el cual vamos a ordenar


// Equivale a un SELECT * FROM PAISES ORDER BY NOMBRE
$aPaises = $bd->ExecuteTable(”PAISES”, ”Nombre”);

// Abrimos un vector
$respuesta = ”[”;

foreach ($aPaises as $pais) {


// Le vamos concatenando a la respuesta cada opción
$respuesta .= ”{id: ” . $pais[”id”] . ”, nombre: ‘” .
$pais[”nombre”] . ”‘},”;
}
// Nos queda una última coma que debemos eliminar
$respuesta = substr($respuesta, 0, strlen($respuesta)-1);

207
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 208

Maximiliano R. Firtman

// Cerramos el vector
$respuesta .= ”]”;

echo $respuesta;

?>

Si se ejecuta el PHP desde el browser y se ve el código fuente, se recibirá un


JSON válido como el de la figura 6-12.

Fig. 6-12. Si bien el objetivo no es abrir el PHP desde el browser, podemos verificarlo de esa manera.

Ahora sólo es preciso cargar en el onload de la página los países utilizando nues-
tra librería Ajax:

208
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 209

AJAX. Web 2.0 para profesionales

window.onload = function() {
$(”autocompleteLocalidad”).className = ”autocomplete”;
new Ajax.Autocompleter(”txtLocalidad”, ”autocompleteLocalidad”,
”autocompleteloc.php”, {paramName: ”caracteres”});

// Pide todos los países


$Ajax(”paises.php”, {onfinish: cargarPaises, tipoRespuesta:
$tipo.JSON});
}

function cargarPaises(paises) {
// El parámetro es un vector de objetos JSON país

// Agregamos una primera opción que dice ”Seleccione”


// y no tiene ningún value
var opcion = new Option(”Seleccione un País”, ””);
$(”lstPais”).options[$(”lstPais”).options.length] = opcion;

for (var i=0; i<paises.length; i++){


var pais = paises[i];
// Creo una opción con JavaScript con el texto y el valor
var opcion = new Option(pais.nombre, pais.id);
// Agrego la opción al SELECT de Paises
// Todos los select tienen un vector de opciones
try {
$(”lstPais”).options[$(”lstPais”).options.length] =
opcion;
} catch (e) {
alert(”Error interno”);
}
}
}

Si se observa la figura 6-13 se puede apreciar que algunos países como México
o España tienen caracteres extraños en los acentos y las eñes. Eso se debe a un pro-
blema de codificación.

Problemas con la codificación


Cuando el navegador web hace la primera petición al servidor web lee el archivo
XHTML con una codificación que permite leer todos los acentos y caracteres (ISO-
8859-1). Ahora, cuando el navegador web hace peticiones vía AJAX al servidor, ten-
dremos problemas con los acentos y las eñes, dado que la codificación que se usa no
es compatible por defecto (UTF-8).
Para solucionar el problema, se debe indicar al navegador la codificación con la
que se va a enviar el archivo de la siguiente manera como primera línea en cada PHP
que traiga datos vía AJAX:

209
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 210

Maximiliano R. Firtman

header(”Content-Type: text/text; charset=ISO-8859-1”);

El text/text puede modificarse por otro tipo MIME según qué contenido se esté en-
tregando (p. ej., text/html o text/xml).

Fig. 6-13. Luego de cargarse la página inicialmente se hace una petición para traer todos los países
que se completan en la lista.

En el caso de ASP o ASP.NET se puede utilizar la instrucción siguiente (fig. 6-14):

Response.Charset = ”ISO-8859-1”

210
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 211

AJAX. Web 2.0 para profesionales

Fig. 6-14. Al definir ISO-8859-1 como codificación en el PHP se pueden ver correctamente todos los
acentos y las eñes.

Completar provincias

Ahora hay que cargar las provincias cada vez que el usuario seleccione un país. El pri-
mer paso es apagar la lista de provincias hasta tanto el usuario seleccione un país,
para eso alcanza con sólo incluir la siguiente línea:

// Apagar select de provincias


$(”lstProvincia”).disabled = true;

El segundo paso es capturar la acción onchange del control lstPais. De esta ma-
nera, cada vez que el usuario elija un país nuevo habrá que actualizar la lista de pro-

211
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 212

Maximiliano R. Firtman

vincias, para lo que se realizará una nueva petición al servidor enviando como pará-
metro el país.
Primero veamos cómo queda el archivo provincias.php

<?php
/***
* Devuelve una lista de Provincias en JSON
*/

// Evita problemas con los acentos en AJAX


header(”Content-Type: text/text; charset=ISO-8859-1”);

include(”BD.php”);

// Leo el ID del país desde un parámetro GET


$pais = $_GET[”pais”];
if ($pais!=””) {
$aProvincias = $bd->Execute(”SELECT * FROM PROVINCIAS where
pais_id = $pais”);

// Abrimos un vector
$respuesta = ”[”;

foreach ($aProvincias as $prov) {


// Le vamos concatenando a la respuesta cada opción
$respuesta .= ”{id: ” . $prov[”id”] . ”, nombre: ‘” .
$prov[”nombre”] . ”‘},”;
}

// Nos queda una última coma que debemos eliminar


$respuesta = substr($respuesta, 0, strlen($respuesta)-1);
}
// Cerramos el vector
$respuesta .= ”]”;

echo $respuesta;

?>

El siguiente paso, entonces, es capturar la acción onchange y hacer la petición


AJAX a provincias.php enviando el parámetro país por GET, teniendo cuidado con la
primera opción de la lista de países. La primera opción es aquella que indica: Selec-
cione un País. Cuando el usuario seleccione esta opción, se debe limpiar la lista de
provincias y apagarla hasta que vuelva a elegir un país. Este código se puede definir
una sola vez en el window.onload, o en el código de cargarPaises (fig. 6-15).

212
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 213

AJAX. Web 2.0 para profesionales

Fig. 6-15. Cada vez que se elige un país de la lista se ve que se hacen las peticiones al servidor pi-
diendo las provincias de ese país.

$(”lstProvincia”).onchange = function() {
if (this.value==””) {
// Eligió ”Seleccione un país”
this.disabled = true;
// Limpia todas las provincias que hubiera de antes
this.options.length = 0;
} else {
// Eligió un país, busco las provincias
var url = ”provincias.php?pais=” + this.value;
$Ajax(url, {onfinish: cargarProvincias, tipoRespuesta:
$tipo.JSON});
}
}

213
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 214

Maximiliano R. Firtman

El último paso entonces es crear la función cargarProvincias que se encargue de


llenar las opciones de la lista de provincias según el objeto JSON que llegó desde el
servidor.

function cargarProvincias(provincias) {
// El parámetro es un vector de objetos JSON provincias
// Agregamos una primera opción que dice ”Seleccione”
// y no tiene ningún value
var opcion = new Option(”Seleccione una Provincia”, ””);
// Agrega la nueva opción al final del vector
$(”lstProvincia”).options[$(”lstProvincia”).options.length] =
opcion;

for (var i=0; i<provincias.length; i++){


var provincia = provincias[i];
// Creo una opción con JavaScript con el texto y el valor
var opcion = new Option(provincia.nombre, provincia.id);
// Agrego la opción al SELECT de Provincias
// Todos los select tienen un vector de opciones
try {
$(”lstProvincia”).options[$(”lstProvincia”).op-
tions.length] = opcion;
} catch (e) {
alert(”Error interno”);
}
}

// Activamos el SELECT para que el usuario lo pueda usar


$(”lstProvincia”).disabled = false;
}

Si ahora cuando cargamos la página se selecciona Argentina, por ejemplo, se


puede ver que se activa la lista de provincias y al listarlas se observan provincias de Ar-
gentina (fig. 6-16).
Ahora bien, cuando se selecciona otro país, como España, en la figura 6-17 se ob-
serva lo que ocurre.
¿Qué ha sucedido? Básicamente cada vez que se elige un nuevo país, se agre-
gan nuevas opciones a la lista de provincias, sin borrar las del país que estaba antes
seleccionado. Entonces, sólo es preciso agregar una línea que borre todas las opcio-
nes antes de comenzar a cargar (fig. 6-18):

214
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 215

AJAX. Web 2.0 para profesionales

Fig. 6-16. Vía AJAX se trajeron todas las provincias de Argentina para mostrarlas en la lista de selección.

Fig. 6-17. Al seleccionar España aparecen, pero, qué sorpresa, también están las de Argentina.

215
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 216

Maximiliano R. Firtman

function cargarProvincias(provincias) {
// El parámetro es un vector de objetos JSON provincias

// Primero eliminamos todas las provincias anteriores si hubiera


$(”lstProvincia”).options.length = 0;

// Agregamos una primera opción que dice ”Seleccione”


// y no tiene ningún value
var opcion = new Option(”Seleccione una Provincia”, ””);
// Agrega la nueva opción al final del vector
$(”lstProvincia”).options[$(”lstProvincia”).options.length] =
opcion;

for (var i=0; i<provincias.length; i++){


var provincia = provincias[i];
// Creo una opción con JavaScript con el texto y el valor
var opcion = new Option(provincia.nombre, provincia.id);
// Agrego la opción al SELECT de Provincias
// Todos los select tienen un vector de opciones
try {
$(”lstProvincia”).options[$(”lstProvincia”).op-
tions.length] = opcion;
} catch (e) {
alert(”Error interno”);
}
}

// Activamos el SELECT para que el usuario lo pueda usar


$(”lstProvincia”).disabled = false;
}

Fig. 6-18. Ahora, al seleccionar España aparecen sólo las provincias de ese país.

216
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 217

AJAX. Web 2.0 para profesionales

Otra opción sería utilizar XML en lugar de JSON. Los ejemplos son muy simila-
res, sólo que se torna un poco más complejo el código para recorrer las provincias,
moviéndonos entre los nodos del XML. No obstante, a los fines de la arquitectura de
la solución, es exactamente igual.
Una buena idea sería utilizar algún mecanismo de caché o memoria por el que si
el usuario elije, por ejemplo, dos veces el mismo país, el script no vaya dos veces al
servidor a buscar las provincias, porque van a ser las mismas. Más adelante se verá
cómo implementar un modelo de caché como el propuesto.
Implementar un tercer nivel de cascada (p. ej., la ciudad) es relativamente senci-
llo e implica seguir la misma idea de ir haciendo peticiones.

Controles ricos
La palabra rico de las aplicaciones ricas de Internet no sólo referenciaba la posibili-
dad de incorporar nuevos servicios (como puede ser la lista en cascada), sino también
la posibilidad de trabajar con nuevos controles gráficos que le permitan al usuario se-
leccionar opciones con mayor calidad gráfica y funcionalidad.
A continuación se verán algunos controles ricos que se pueden agregar a nues-
tro formulario como ejemplo para aplicar en cualquier aplicación RIA.

Slider

Un slider o deslizador permite que el usuario seleccione una opción o variable de tipo
numérica pero, en lugar de ingresar el valor numérico puede desplazar con el cursor
algún objeto y soltarlo en el valor deseado. Este control emula el funcionamiento del
volumen de algunos equipos de audio, por ejemplo, donde hay una perilla que se
puede subir o bajar hasta el nivel deseado.
Otra característica es que el valor buscado está en un rango acotado (p. ej., entre
1 y 10) y puede ser continuo (puede elegir cualquier valor intermedio) o discreto (puede
elegir sólo números pares).
Los sliders se pueden realizar en forma horizontal o vertical.
Uno de los primeros en utilizar sliders en páginas web AJAX fue Google Maps.
Todos seguramente lo reconoceremos como el nivel de zoom del mapa que estamos
viendo. Con el mouse se puede subir o bajar el nivel de zoom con facilidad (figs. 6-19
y 6-20).

217
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 218

Maximiliano R. Firtman

Fig. 6-19. Ejemplos de controles de tipo slider.

Fig. 6-20. Google Maps implementa un slider al seleccionar el nivel de zoom.

218
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 219

AJAX. Web 2.0 para profesionales

También es muy útil el doble slider en el que el usuario tiene dos controles para
arrastrar sobre un mismo eje con el objetivo de seleccionar un rango de valores. Por
ejemplo, si fuera una búsqueda de productos por precio, el usuario podría seleccionar
el rango que quiere buscar moviendo el slider inferior y el superior hasta lograr el rango
deseado (fig. 6-21).

Fig. 6-21. La búsqueda de diamantes de Amazon.com contiene distintos tipos de slider para elegir el
diamante deseado.

Si bien se puede crear un slider desde cero con JavaScript, lo ideal es utilizar una
librería para hacerlo con facilidad (fig. 6-22). Algunas librerías que incluyen controles
tipo Slider son:
• Script.aculo.us
• Microsoft AJAX Control Toolkit
• Yahoo UI! Library
• WebFX

219
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 220

Maximiliano R. Firtman

Fig. 6-22. WebFX Slider es una librería específica para crear este tipo de controles. Se puede descar-
gar de webfx.eae.net.

Script.aculo.us slider
En nuestro caso vamos a crear un control de tipo Slider para que el usuario pueda se-
leccionar el nivel educativo que posee. Para ello, se va a recurrir a Script.aculo.us, dado
que es una de las librerías que ya veníamos utilizando.
En el sitio web www.aldenta.com/examples/script.aculo.us/slider-standard.html
hay muchos ejemplos de sliders distintos utilizando la librería (fig. 6-23).
Para crear un slider en esta librería, se debe utilizar la sintaxis siguiente:

new Control.Slider(’id_slider_arrastable’, ’id_contenedor’, opcio-


nes);

220
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 221

AJAX. Web 2.0 para profesionales

Fig. 6-23. En la figura se observan distintos ejemplos de sliders creados con script.aculo.us.

Para el control entonces se necesitan por lo menos dos divs, uno para el conte-
nedor general (que tendrá el ancho y el alto de todo el control) conocido como track o
pista y el conocido por la librería como handler que es el objeto que se podrá arrastrar
por los límites de la pista hasta elegir un valor.
Ambos divs deben estar cargados en el DOM, ya sea estáticamente en el XHTML
o creados con JavaScript, como el siguiente ejemplo:

// Crea el slider

// Primero define propiedades CSS del contenedor


$(”nivelEducativo”).style.width = ”250px”;
$(”nivelEducativo”).style.height = ”17px”;
$(”nivelEducativo”).style.backgroundColor = ”white”;
$(”nivelEducativo”).style.border = ”1px solid gray”;

221
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 222

Maximiliano R. Firtman

// Crea dentro el objeto arrastrable o track del slider


$(”nivelEducativo”).appendChild(Builder.node(”div”,
{id: ”nivelEducativoTrack”,
style: ”width: 10px; height: 17px; cursor: move;
background-color: red”
}));
new Control.Slider(”nivelEducativoTrack”, ”nivelEducativo”);

Si se define que el handler y el tracker tendrán la misma altura se tendrá el efecto


que se ve en la figura 6-24. También es posible crear un handler más alto o que sea una
imagen que permita emular una perilla que sale de su contenedor. El handler, que es el
objeto que se va a arrastrar, debería tener un color de fondo distinto al del tracker para
que se diferencien visualmente.

Fig. 6-24. Con sólo crear el Slider sin opciones predefinidas se tendrá un objeto que puede ser arras-
trado por el control.

222
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 223

AJAX. Web 2.0 para profesionales

Atributos opcionales
A continuación se analizarán las propiedades que posee el control Slider.

Propiedad Por defecto Descripción

axis ‘horizontal’ Define si el slider será horizontal o vertical

increment 1 Indica la relación pixel-valor seleccionada. Por defecto


es un pixel movido, un valor aumentado

maximum (longitud del track) Define el valor máximo que puede obtener el control

minimum 0 Define el valor mínimo que puede obtener el control

alignX 0 Define el inicio del handler sobre el tracker en el eje X

alignY 0 Define el inicio del handler sobre el tracker en el eje Y

sliderValue 0 Define el valor inicial con el que arranca el control

disabled false Si se define en true, el control no se puede usar hasta


que vuelva a activarse

handle Image Si se desea utilizar una imagen como objeto que se


puede arrastrar por el slider, aquí se define.

handle Disabled Es la imagen que se coloca cuando el control está de-


sactivado

values Acepta un array de enteros. Si se define, el usuario sólo


podrá elegir esos valores dentro de los posibles

range Define el rango válido de opciones con $R (desde,


hasta)

Además, el control Slider tiene los métodos o las funciones siguientes, que se
pueden activar si se guarda una referencia cuando se lo instancia.

Método Descripción

setValue Permite cambiar el valor al slider desde JavaScript en forma manual.


El handler se moverá de manera automática al valor seleccionado

setDisabled Define disabled=true

setEnabled Define disabled=false

Por último, se cuenta con las alternativas siguientes que se pueden capturar para
obtener los valores que eligió el usuario.

223
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 224

Maximiliano R. Firtman

Método Descripción

onSlide Se ejecuta cuando el usuario comienza a mover el slider. Recibe por


parámetro el valor actual

onChange Se ejecuta cuando el usuario suelta el control y finalmente


selecciona un valor. Recibe por parámetro el valor seleccionado

Implementando Nivel Educativo


Ahora bien, el slider que se incluye en nuestro proyecto permite elegir cualquier valor
entre 0 y 250 (el ancho del control). Eso está bien para algunos casos en los que sirva
hacer que el usuario seleccione cualquier valor numérico. No obstante, en nuestro caso
nos interesa más poder seleccionar el nivel educativo de un rango de opciones más re-
ducido, por ejemplo, cinco valores posibles: Inicial-Secundario-Terciario-Universitario-
Posgrado.
Para ello, entonces, vamos a hacer más ancho nuestro handler, de 50 píxeles, así
tiene un quinto del ancho total. Sin embargo, todavía se puede elegir cualquier valor.
Es factible restringir los valores a 5 mediante la opción values que recibe un vector de
opciones válidas. Por ejemplo:

[0, 1, 2, 3, 4]

Asimismo, el range se define como válido entre 0 y 200 (deben contarse los 50 pí-
xeles de ancho de nuestro handler).
De esta manera, el usuario sólo puede elegir esas cinco opciones y el slider salta
de una a otra cuando el usuario arrastra el control.
Por último, se van a capturar las acciones onSlide y onChange para manipularlas.

new Control.Slider(”nivelEducativoTrack”, ”nivelEducativo”,


{values: [0, 50, 100, 150, 200], range:$R(0, 200),
onSlide: slideNivelEducativo, onChange: cambioNivelEdu-
cativo});

La función slideNivelEducativo se ejecutará cada vez que el usuario mueva el sli-


visual, der sobre la pista o track, donde se puede cambiar el texto que está dentro, o incluso
se podría alterar el color o algún otro elemento de la página web.
Por ejemplo, si al elegir nivel universitario se va a pedir al usuario que ingrese su
universidad, se podría activar ese control en esta acción (fig. 6-25A, B y C).

224
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 225

AJAX. Web 2.0 para profesionales

Fig. 6-25.A Ahora sólo es posible moverse entre las opciones predefinidas.

Fig. 6-25.B Dentro del control se verá que se arrastró el nivel educativo.

225
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 226

Maximiliano R. Firtman

Fig. 6-25.C Finalmente vemos que se eligió el nivel educativo más alto, postgrado.

function slideNivelEducativo(valor) {
// Cambiamos el texto y el color del handler
$(”nivelEducativoTrack”).style.fontSize = ”9px”;
$(”nivelEducativoTrack”).style.color = ”white”;
$(”nivelEducativoTrack”).style.textAlign = ”center”;
// Esto lo podemos hacer en el .CSS directamente

switch (valor) {
case 0: // Primario
$(”nivelEducativoTrack”).innerHTML = ”Inicial”;
break;
case 50:
ncia y
$(”nivelEducativoTrack”).innerHTML = ”Secundario”;
break;
case 100:
$(”nivelEducativoTrack”).innerHTML = ”Terciario”;
break;
case 150:
$(”nivelEducativoTrack”).innerHTML = ”Universitario”;
break;
case 200:
$(”nivelEducativoTrack”).innerHTML = ”Posgrado”;
break;
}
}

226
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 227

AJAX. Web 2.0 para profesionales

Por último, queda capturar la acción onChange que se ejecuta cuando el usuario
suelta el control. En esta acción se puede poner la opción elegida en algún lugar o, in-
cluso, definir algún valor en un campo oculto tipo <INPUT TYPE=”hidden” /> para luego
enviar en un formulario (figs. 6-26 y 6-27).

function cambioNivelEducativo(valor) {
// Activamos un efecto de highlight para confirmarle al usuario
// que acaba de elegir una opción
new Effect.Highlight(”nivelEducativo”);

// Creamos un nuevo input oculto si no existía y le ponemos el


valor
if ($(”hiddenNivelEducativo”)==undefined) {
var hidden = Builder.node(”input”,
{type: ’hidden’, id: ’hiddenNivelEducativo’});
$(”formRegistro”).appendChild(hidden);
}

// Guarda el valor seleccionado en un campo oculto para enviar


luego
$(”hiddenNivelEducativo”).value = valor;

Fig. 6-26 En www.aldenta.com/examples/script.aculo.us/slider-scrollbar.html hay un ejemplo en el


que se usan Sliders gráficos como barras de desplazamiento de un DIV.

227
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 228

Maximiliano R. Firtman

Fig. 6-27 Con la librería Yahoo UI! Library se pueden crear Sliders con mayor complejidad visual, pero
esto requiere mucho más código.

DatePicker

Este control tiene nombres distintos, entre ellos: Calendar, DatePicker, DateSelect y
otros similares. El objetivo es que el usuario pueda seleccionar una fecha pero en lugar
de ingresarla en un campo de texto común, la busque y la elija en un calendario.

Yahoo UI

Para implementar este control rico hay muchas librerías que ofrecen una versión de él; no
obstante, vamos a utilizar por primera vez en nuestros proyectos la librería Yahoo UI! Library.
La librería gratuita de Yahoo! tiene la ventaja de ser una de las más completas en
controles ricos y en la funcionalidad que pueden ofrecer estos controles. Sin embargo,
como contrapartida, es mucho más pesada que las que se venían utilizando; además,
el código a utilizar suele ser más largo (figs. 6-28 y 6-29).
Otra ventaja de esta librería respecto de las demás es que tiene una documenta-
ción muy extensa, muy bien explicada y con numerosos ejemplos. Incluso, es posible
descargar archivos en formato PDF, que se conocen como Cheat Sheet, que son hojas
para imprimir y tener resumida toda una librería y su funcionamiento básico.

228
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 229

AJAX. Web 2.0 para profesionales

Fig. 6-28. El sitio web de la librería es developer.yahoo.com/yui.

Fig. 6-29. En el sitio web se encontrará una hoja para imprimir, una Cheat Sheet, de cada funcionali-
dad con el resumen de las API.

229
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 230

Maximiliano R. Firtman

La última versión de YUI (como se la conoce abreviada) comprende las utilidades


siguientes:
• Utilidades
- Animación.
- Manejo del historial del navegador (experimental).
- Administrador de conexiones AJAX.
- Utilidad de orígenes de dato o DataSource para enlazar datos a controles
en la página.
- Utilidad de drag and drop.
- Utilidades de DOM.
- Utilidades para manejo de acciones.
- Un objeto global YAHOO.

• Librería de CSS
- CSS para grillas.
- CSS para tipografías.

• Librería de controles
- AutoComplete.
- Controles de botones más atractivos.
- Calendar.
- Contenedores (ventanas, paneles).
- DataTable.
- Logger.
- Menú.
- Slider.
- TabView.
- TreeView.

La librería se puede descargar a nuestro proyecto y es factible incluir los .js rela-
tivos a nuestra carpeta o directamente los .js siempre actualizados desde el servidor
de Yahoo! utilizando referencias absolutas.

230
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 231

AJAX. Web 2.0 para profesionales

Calendar
El control rico que se va a usar por el momento es el de Calendar. Este objeto per-
mite que el usuario elija una o más fechas de un calendario (o un calendario que mues-
tra dos meses en forma simultánea) (fig. 6-30).

Fig. 6-30. De cada control o utilidad de la librería se encontrarán ejemplos, documentación, licencia y
la descarga.

Se agregará un calendario en nuestro formulario en la Fecha de Inicio Deseada. El


primer paso para implementar un calendario en la página es incluir un CSS en el
XHTML:

<link rel=”stylesheet” type=”text/css”


href=”http://yui.yahooapis.com/2.2.2/build/calendar/assets/calendar.c
ss” />

Si se descarga la librería al proyecto se puede cambiar la referencia a la carpeta


donde se instalen los .js y .css de la librería.
También habrá que incluir estos dos JavaScript:

231
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 232

Maximiliano R. Firtman

<script type=”text/javascript”
src=”http://yui.yahooapis.com/2.2.2/build/yahoo-dom-event/yahoo-dom-
event.js”></script>
<script type=”text/javascript”
src=”http://yui.yahooapis.com/2.2.2/build/calendar/calendar-
min.js”></script>

Una vez hecho esto en el window.onload, se está en condiciones de crear el ca-


lendario (en el mismo lugar donde se había creado el slider).
La librería YUI trabaja con el concepto de namespaces o espacios de nombre que
equivalen a una agrupación de los objetos bajo algún nombre en particular. El calen-
dario está incluido en el namespace conocido como YAHOO.widget, donde están
todos los controles. Esto no nos debe preocupar mucho más que conocer cómo in-
vocar a los controles.
La sintaxis básica es la siguiente:

// instancia el control calendario


var calendario = new YAHOO.widget.Calendar(id_calendario, id_contene-
dor, opciones);
// dibuja el calendario
calendario.render();

Las opciones son numerosas y se pueden encontrar en la documentación de la li-


brería, ya sea online o en la versión descargable.
En nuestro ejemplo, se había colocado un campo de texto para ingresar la fecha,
en el siguiente código:

<div class=”filaCampo”>
<div class=”etiqueta”>Fecha de Inicio Deseada: </div>
<div class=”campo”><input type=”text” id=”txtFechaIni-
cio” /></div>
</div>

Si bien se puede integrar el campo de texto al control Calendario, por el momento


se lo va a reemplazar por un div contenedor:

<div class=”filaCampo”>
<div class=”etiqueta”>Fecha de Inicio Deseada: </div>
<div class=”campo”><div id=”calFechaInicio” /></div>
</div>

232
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 233

AJAX. Web 2.0 para profesionales

Asimismo, en el window.onload del formulario.js se incorporará el código siguiente


(fig. 6-31):

// Crea el calendario
var calendario = new YAHOO.widget.Calendar(”calendario”, ”cal-
FechaInicio”);
// dibuja el calendario
calendario.render();

Fig. 6-31. Lo primero que sucede al crear el objeto Calendar es que se rompe el diseño del formula-
rio. Con CSS se pueden acomodar las alturas.

Inmediatamente se tendrá un control calendario por completo funcional, y por


medio de la propiedad calendario.getSelectedDate se podrá obtener la fecha que el
usuario seleccionó. No obstante, se observa que el control está automáticamente
abierto, o sea, que está visible todo el tiempo. Si se lo desea, se lo puede mantener ce-
rrado e incluir una imagen o un botón que permita abrir el calendario y no ocupar la
pantalla de manera permanente.
Para ello, hay una opción close del calendario donde se puede indicar si se desea
que aparezca cerrado y, luego, con un método show() poder activarlo de nuevo. De

233
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 234

Maximiliano R. Firtman

paso, se utilizan algunas opciones extras que se pueden encontrar explicadas en las
API de la documentación (fig. 6-32). Por ejemplo:

// Crea el calendario en una variable global


calendario = new YAHOO.widget.Calendar(”calendario”, ”calFe-
chaInicio”, {title: ”¿Cuando quiere iniciar?”, close: true});
// dibuja el calendario
calendario.render();

var boton = Builder.node(”input”, {type:”button”, value:”Ver


Calendario”, id: ”btnCalFechaInicio”});
$(”calFechaInicio”).parentNode.appendChild(boton)
$(”btnCalFechaInicio”).onclick = function() {
calendario.show();
}
// Apagamos el calendario al inicio
$(”calFechaInicio”).style.display = ”none”;

Fig. 6-32. Ahora se ve un botón que invita a abrir el calendario. Al presionarlo, se abrirá en ese mo-
mento.

Sólo queda capturar la acción para cuando el usuario seleccione una fecha para
mostrarla en algún texto (podría haber sido el textbox que había originalmente). El ca-

234
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 235

AJAX. Web 2.0 para profesionales

lendario posee varias acciones, pero la que servirá en este caso es selectEvent, que se
ejecuta cuando el usuario selecciona una fecha.
En ese caso se puede recurrir al mismo modelo que se armó para el slider. Crear
un campo oculto para guardar su valor. Además, es factible cerrar el calendario cuando
el usuario selecciona una fecha.

window.onload = function() {
// …

// Crea el calendario
calendario = new YAHOO.widget.Calendar(”calendario”, ”calFe-
chaInicio”, {title: ”¿Cuando quiere iniciar?”, close: true});
// dibuja el calendario
calendario.render();
// definimos el handler
calendario.selectEvent.subscribe(cambioFechaInicio, calendario,
true);

function cambioFechaInicio(tipo, argumentos) {


// La fecha la obtenemos así:
var fecha = argumentos[0][0];
// nos deja un vector con año,mes,dia

// Creamos un nuevo input oculto si no existía y le ponemos el


valor
if ($(”hiddenFechaInicio”)==undefined) {
var hidden = Builder.node(”input”,
{type: ‘hidden’, id: ‘hiddenFechaInicio’});
$(”formRegistro”).appendChild(hidden);
}

// Guarda el valor seleccionado en un campo oculto para enviar


luego
$(”hiddenFechaInicio”).value = fecha;

// Cerramos el calendario
calendario.hide();
}

Funciones avanzadas
El calendario tiene muchas funciones avanzadas, cuyos ejemplos se pueden revisar
en la API de YUI. Entre ellas se observan:
• Selección de muchas fechas dentro del calendario.
• Abrir más de un calendario en forma simultánea.

235
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 236

Maximiliano R. Firtman

• Seleccionar un rango de fechas válidas.


• Calendarios duales.
• Personalización de idiomas para los nombres de los meses y los días.
• Manejo de acciones avanzadas.

NumericTextBox

En el campo de la edad se desea que sólo el usuario pueda ingresar números. ¿Cómo
se implementa? Se sabe que si se coloca un input type=”text” el usuario puede in-
corporar cualquier texto dentro. Veamos cómo restringir el ingreso del usuario, en este
caso, a sólo números.
El primer paso es capturar la acción onkeyup que se ejecuta cada vez que el
usuario presiona una tecla en el campo de texto. Esta acción recibe un parámetro
que es un objeto con la tecla que se acaba de presionar. Este parámetro tiene una pro-
piedad keyCode que identifica la tecla presionada, que en el caso de letras y símbo-
los es también el código ASCII del carácter. La tecla ENTER representa el 13 y el
Backspace, el 8.
Si se averiguan los códigos de cada tecla, se podría aceptar o no cada carácter
ingresado. De todas formas hay una manera más sencilla (a lo mejor menos óptima)
de implementar esto con el siguiente código:

$(”txtEdad”).onkeyup = function(evento) {
this.value = this.value.replace(/[^\/\d]/g, ‘’);
}

Este código utiliza expresiones regulares (esos caracteres extraños encerrados


entre / y /g. Una expresión regular es un lenguaje para aceptar un texto, o no, con cier-
tas condiciones complejas. Es recomendable investigar sobre el tema de expresiones
regulares.
En este caso lo que se hace es reemplazar todos los caracteres que no sean dí-
gitos 0-9 del valor del campo de texto por vacío, o sea, se los elimina.

NumericUpDown
Al campo numérico se le puede agregar una funcionalidad más, que es incluir a la de-
recha una imagen con una flecha para arriba y otra para abajo. El objetivo es que
cuando el usuario utilice estas flechas aumente o disminuya la edad.
Para ello, se utilizan dos archivos GIF, flechaup.gif y flechadown.gif, que se agre-
gan al lado del campo de texto. Se los puede crear en forma manual en el código
XHTML o de manera dinámica con JavaScript en el window.onload:

236
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 237

AJAX. Web 2.0 para profesionales

var flechaUp = Builder.node(”img”, {src: ”flechaup.gif”, on-


click: ”sumaEdad()”});
var flechaDown = Builder.node(”img”, {src: ”flechadown.gif”,
onclick: ”restaEdad()”});
// Agrego las imágenes como ”hermanos” del campo de texto en el
DOM
$(”txtEdad”).parentNode.appendChild(flechaDown);
$(”txtEdad”).parentNode.appendChild(flechaUp);

Y se crean las funciones:

function sumaEdad() {
if ($(”txtEdad”).value!= ””) {
$(”txtEdad”).value++;
}
}

function restaEdad() {
if ($(”txtEdad”).value!= ””) {
$(”txtEdad”).value—;
}
}

Ahora hay un campo de texto que sólo acepta números y, por medio de flechitas
a su derecha, es posible subir y bajar el número con más rapidez (fig. 6-33).

Fig. 6-33. El campo numérico en acción.

237
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 238

Maximiliano R. Firtman

SortableList

Una lista reordenable o Sortable List permite que el usuario tenga una cantidad de op-
ciones predefinidas y pueda cambiar el orden en que aparecen. En nuestro caso había
un listado de cursos a los que el alumno podía inscribirse y la idea sería entonces que,
por ejemplo, pueda elegir el orden en que quiere cursarlos.
La misma posibilidad se puede presentar en un administrador donde el dueño del
sitio web elija en qué orden de prioridad quiere mostrar las noticias en la Página Prin-
cipal o ejemplos similares.
Para llevar a cabo la Sortable List se va a utilizar la librería Script.aculo.us que im-
plementa un sistema sencillo y rápido para crear listas reordenables.
Para ello basta con crear un elemento que contenga otros elementos (p. ej., un div
con otros divs adentro), aunque por defecto la librería trabaja con listas desordenadas
(UL) y sus elementos (LI).
La idea sería entonces cargar de manera estática vía PHP todos los cursos dis-
ponibles por orden alfabético o cargarlos en forma dinámica cuando la página se carga
vía AJAX (como se hizo con los países).

Consultando los cursos


En este caso se va a utilizar esta última opción para seguir con el mismo proceso de
trabajo. Entonces, se cuenta con un PHP que traerá todos los cursos disponibles:

<?php
/***
* Devuelve una lista de Cursos en JSON
*/

header(”Content-Type: text/text; charset=ISO-8859-1”);

include(”BD.php”);

// Lleva el nombre de la tabla y el campo por el cual vamos a ordenar


// Equivale a un SELECT * FROM CURSOS ORDER BY NOMBRE
$aCursos = $bd->ExecuteTable(”CURSOS”, ”Nombre”);

// Abrimos un vector
$respuesta = ”[”;

foreach ($aCursos as $curso) {


// Le vamos concatenando a la respuesta cada opción
$respuesta .= ”{id: ” . $curso[”id”] . ”, nombre: ‘” .
$curso[”nombre”] . ”‘},”;
}

238
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 239

AJAX. Web 2.0 para profesionales

// Nos queda una última coma que debemos eliminar


$respuesta = substr($respuesta, 0, strlen($respuesta)-1);

// Cerramos el vector
$respuesta .= ”]”;

echo $respuesta;

?>

En el window.onload se agrega:

// Pide todos los países


$Ajax(”cursos.php”, {onfinish: cargarCursos, tipoRespuesta:
$tipo.JSON});

Y la función que muestra los cursos (fig. 6-34):

Fig. 6-34. Aquí se observa el listado de cursos que vino en forma asincrónica desde el servidor.

239
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 240

Maximiliano R. Firtman

function cargarCursos(listaCursos) {
// El parámetro es un vector de objetos JSON curso
// Creo una lista desordenada
var ul = Builder.node(”ul”);
ul.id = ”contenidoCursos”;
for (var i=0; i<listaCursos.length; i++){
var curso = listaCursos[i];
// Creo una LI
var opcion = Builder.node(”li”);
opcion.innerHTML = curso.nombre;
opcion.id = ”Curso” + curso.id;

// Agregamos cada elemento a la lista


ul.appendChild(opcion)
}
ul.style.padding = ”0px”;
ul.style.margin = ”0px”;
// Agregamos toda la lista a la zona designada
$(”cursos”).appendChild(ul);
}

Ahora queda crear el control que permita cambiar el orden de los cursos utilizando
arrastrar y soltar. Para ello, Script.aculo.us ofrece un objeto llamado Sortable con la
sintaxis siguiente:

Sortable.create(”id_contenedor”, opciones);

Entre las opciones posibles se encuentran:

Propiedad Por defecto Descripción

tag ‘li’ El tag que está dentro del contenedor y que se utilizará
para arrastrar

only Define una clase CSS que debe estar definida, para lo
cual sólo aceptará elementos de esa clase

overlap ‘vertical’ Define el tipo de lista a utilizar

containment Habilita la opción para arrastrar elementos entre dos


contenedores distintos

onChange Se ejecuta cuando el usuario cambia el orden de


alguna operación

onUpdate Se ejecuta ante cada cambio que se produzca,


aunque sea en el mismo lugar

240
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 241

AJAX. Web 2.0 para profesionales

Entonces, alcanza con incluir el código siguiente al final de la función cargarCur-


sos habilitando la opción de ordenable al id que contenía las opciones, en nuestro caso
el UL (fig. 6-35).

Sortable.create(”contenidoCursos”);

Fig. 6-35. Al habilitar la opción Sortable sobre la lista, ésta se puede reordenar como se desee.

Ahora bien, ¿cómo nos enteramos del nuevo orden elegido por el usuario? En
principio se podría capturar la acción onChange del control, pero esto no indica cómo
cambió.
Para averiguar el orden final simplemente se puede iterar entre los elementos hijos
del contenedor (contenidoCursos), y el DOM aportará el orden de cada curso, se podrá
obtener el id para saber qué curso es cada uno o el innerHTML para conocer el nom-
bre.

241
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 242

Maximiliano R. Firtman

Por ejemplo:

var cursos = $(”contenidoCursos”).childNodes;


cursos.each(function(curso) {
// en curso.id tenemos el id del curso, por ej: Curso22

});

Mediante CSS se puede definir el estilo real que se desea que tenga cada opción
y es recomendable cambiar el cursor para que el usuario entienda que puede comen-
zar a arrastrar los elementos de la lista.

RichTextBox

Si bien no es el caso en nuestro formulario, en muchos otros es posible que haya que
incluir un campo de texto rico o Rich TextBox. Este tipo de controles permite ingresar
texto pero dándole formato al mejor estilo procesador de texto. Se pueden definir ta-
maños, negritas y colores, y es una opción ideal para administradores o intranets donde
el usuario puede editar un texto que luego se verá online.
Hay muchos controles de este tipo, pero se recomendarán dos:
• Free Rich Text Editor (www.freerichtexteditor.com)
• FCK Editor (www.fckeditor.net) (fig. 6-36)

Fig. 6-36. FCKEditor es uno de los editores ricos más utilizados.

242
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 243

AJAX. Web 2.0 para profesionales

Ambos son gratuitos, aunque el segundo es el más utilizado y más completo. In-
cluye soporte para crear controles ricos desde JavaScript y desde varios lenguajes de
servidor, como PHP y ASP.NET.
Una de las maneras de trabajar con estos controles es reemplazar un TEXTAREA
(área de texto) que permite incluir texto en numerosas líneas.
Entonces, se cuenta con un textarea como el siguiente:

<textarea id=”observaciones”></textarea>

Se importa el script, por ejemplo, de FCK Editor que se descargó con anterioridad:

<script type=”text/javascript”
src=”/FCKeditor/fckeditor.js”></script>

Y luego (fig. 6-37):

Fig. 6-37. FCKEditor soporta distintos skins para darle formato visual a otras herramientas, como Office
2003.

243
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 244

Maximiliano R. Firtman

window.onload = function() {
var editorRico = new FCKeditor(’observaciones’);
// Definimos la carpeta desde donde obtiene las imágenes
// para crear la Toolbar con las opciones
editorRico.BasePath = ”/FCKeditor/”;
editorRico.ReplaceTextarea() ;
}

Validación activa
La validación activa o formulario activo es una técnica que permite ir validando los
datos del formulario mientras el usuario escribe y completa los campos sin necesidad
de esperar a finalizar todo el proceso.
En nuestro caso, se puede validar que el nombre de usuario no se haya utilizado
con anterioridad. Entonces, cuando el usuario elige un nombre de usuario y sale del
foco del campo de texto, se puede hacer una petición al servidor para verificar si está
disponible o no. Si no lo está, se le puede cambiar el estilo CSS al campo de texto y
mostrar un color o un mensaje de error que invite al usuario a cambiar el nombre de
usuario elegido.
Para ello, se crea un script PHP que verifica si el usuario que recibe por GET existe
o no, devolviendo un objeto JSON para que el JavaScript actúe.

existeusuario.php

<?php
/***
* Devuelve un JSON con true o false si existe el usuario o no
*/

header(”Content-Type: text/text; charset=ISO-8859-1”);

include(”BD.php”);

$cantidad = $bd->ExecuteScalar(”SELECT COUNT(*) FROM USUARIOS WHERE


nombre_usuario = ’” .
$_GET[“u”] . ”‘”);

if ($cantidad==0) {
echo ”{ existeUsuario: false }”;
} else {

244
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 245

AJAX. Web 2.0 para profesionales

echo ”{ existeUsuario: true }”;


}
?>

Al window.onload se le agrega:

$(”txtUsuario”).onchange = function() {
// Tomo el valor del Textbox
var usuario = this.value;
$Ajax(”existeusuario.php?u=” + usuario,
{onfinish: validaUsuario, tipoRespuesta:
$tipo.JSON});
}

Por último, se crea la función validaUsuario:

function validaUsuario(respuesta) {
// respuesta es un JSON que tiene una propiedad en true o false
if (respuesta.existeUsuario==true) {
// Existe usuario hay que pedirle al usuario que lo cam-
bie.
// Ponemos el fondo en rojo
$(”txtUsuario”).style.backgroundColor = ”#a00”;
} else {
// El usuario es correcto, ponemos el fondo en verde
$(”txtUsuario”).style.backgroundColor = ”#0a0”;
}
}

Es posible hacer una validación más compleja, por ejemplo, en la que se sugie-
ran opciones de nicks cuando el usuario ya está ocupado, se muestre un mensaje o
alerta que indique el error o se desactive el botón de Enviar mientras no se haya in-
gresado un nombre de usuario que esté libre (figs. 6-38 y 6-39).

Enviando el formulario
Ya tenemos nuestro gran formulario lleno de nuevos controles ricos. Y bien…, ¿cómo
se hace para enviarlo? En una aplicación Web 1.0 la solución era sencilla. Simplemente
el botón era de tipo Submit o cuando el usuario presionaba enter se generaba una pe-
tición al servidor vía POST. No obstante, en nuestro caso no queremos que la petición

245
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 246

Maximiliano R. Firtman

Fig. 6-38. Si el nombre de usuario ya existe el fondo del campo de texto aparece en color rojo; se de-
bería agregar un texto a su derecha que indique este error.

Fig. 6-39. Algunas librerías, en este caso Microsoft AJAX Control Toolkit, permiten crear validaciones
mucho más atractivas sin mucho código.

246
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 247

AJAX. Web 2.0 para profesionales

la haga el browser cerrando nuestra página, sino que se intenta hacer la petición por
medio de AJAX.
Para ello, nuestra librería ya estaba preparada. Lo único necesario era conver-
tir todos los valores a enviar en un formato de parámetros URL, como el siguiente
variable=valor&variable=valor. Felizmente, Prototype tiene una solución mucho más sen-
cilla: el método serialize().
De esta manera, si todas las variables que se quieren enviar al servidor se en-
cuentran en algún campo de formulario (recuérdese que en el caso de los controles
ricos sus valores se habían convertido a campos ocultos), el siguiente código enviará
el formulario:

function enviarFormulario() {
// Aquí habría que validar todo el formulario
// Que no haya campos vacíos, etc.

var valores = $(”formRegistro”).serialize();


$Ajax(”registro.php”,
{metodo: $metodo.POST,
parametros: valores,
onfinish: formularioEnviado});
}

Ahora sólo debería llamarse esta función cuando el usuario presione el botón Re-
gistrar:

window.onload = function() {
(…)
$(”btnRegistrar”).onclick = enviarFormulario;
}

Mostrando una alerta


Por último, si la respuesta del servidor fue correcta al recibir y guardar todos los datos,
se puede mostrar una ventana modal con un mensaje. Una ventana modal es la que
apaga toda la página web hasta tanto se presione aceptar a la ventana o ésta se cierre.
Ya que se venía utilizando la librería de Yahoo! UI, se puede hacer uso de los diá-
logos que ofrece, muy atractivos por cierto. Para conocer más sobre estos controles,
se puede revisar la documentación y API (fig. 6-40).

247
C06.qxd:Project Ajax4.1.qxd 10/18/07 8:10 PM Página 248

Maximiliano R. Firtman

Fig. 6-40. Ejemplo sobre cómo se ven los SimpleDialog de YUI.

En el capítulo siguiente se seguirá el camino por los patrones de diseño sobre


aplicaciones AJAX, con el objetivo de solucionar problemas comunes en el mundo de
las aplicaciones ricas de Internet y crear un vocabulario común entre los desarrollado-
res, aplicando lo expuesto y la librería de trabajo creada antes.

248
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 249

Patrones de diseño para RIA


7
Qué son
Un patrón de diseño no es más que una sencilla receta a un problema concreto, pro-
blema que en general es repetitivo y es factible encontrarlo varias veces dentro de un
desarrollo. Su origen se remonta a la arquitectura donde se definían patrones de diseño
a problemas comunes, por ejemplo, cómo organizar los espacios en un ambiente de 3
x 4 m, o cuánto espacio dedicar a la cocina en un departamento de 100 m2.
Con ulterioridad los patrones de diseño se llevaron al mundo del desarrollo de soft-
ware para resolver problemas de diseño y arquitectura de una aplicación. De esta ma-
nera, surgieron los primeros patrones de diseño aplicados más que nada a plataformas
orientadas a objetos, conocidos como los patrones GoF, o Gang of Four (la banda de
los cuatro), dado que fueron creados por cuatro gurúes del diseño de software.
Si se recuerda Model-View-Controller, se trata de un patrón de diseño de arqui-
tectura de aplicaciones.
De esta forma, se definió un patrón de diseño de software como un documento
escrito que especifica, entre otras cosas:
• Un nombre identificativo.
• Resumen del patrón.
• Detalle del problema.
• Solución propuesta.
• Decisiones para tomar.
• Diagrama de la solución (a veces en lenguaje UML).
• Código de ejemplo en algún lenguaje (no es obligatorio).
• Alternativas y patrones relacionados.

249
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 250

Maximiliano R. Firtman

En resumen, los patrones de diseño sirven para:


• No reinventar la rueda, aplicar soluciones ya probadas para problemas comunes.
• Mantener un vocabulario en común entre programadores, por ejemplo, todos
deberíamos entender la siguiente frase: Implementé un Singleton en todas las
clases.
• Tomar ideas de diseño para generar nuestras propias soluciones personalizadas.

Los patrones como ley

Un error común entre los desarrolladores que comienzan a implementar patrones de di-
seño es tomarlos como ley y usarlos en forma obligatoria. Esto es un error grave, dado
que los patrones de diseño son ideas y sugerencias y de ninguna manera debemos
estar obligados a utilizarlos.
En el caso de que implementemos un patrón de diseño, tampoco es obligatorio
hacerlo exactamente como lo indica el documento. Somos todos seres inteligentes
(¿no es así?) y deberíamos ser capaces de comprender la solución propuesta por el pa-
trón y adaptarla a nuestros intereses y necesidades.

Patrones GoF

En la tabla 7-1 se observan todos los patrones clásicos o GoF.

Patrones de creación Patrones de estructura Patrones de comportamiento


Singleton (Instancia Unica) Adapter (Adaptador) Chain of Responsability (Cadena
de Responsabilidades)
Prototype (Prototipo) Bridge (Puente) Command (Comando)
Factory (Fábrica) Composite (Composición Interpreter (Intérprete)
de Objetos)
Builder (Constructor) Decorator (Envoltorio) Iterator (Iterador)
Abstract Factory (Fábrica Facade (Fachada) Mediator (Mediador)
abstracta)
Flyweight (Peso liviano) Memento (Recuerdo)
Proxy (Intermediario) Observer (Observador)
State (Estado)
Strategy (Estrategia)
Template Method (Plantilla)
Visitor (Visitante)

250
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 251

AJAX. Web 2.0 para profesionales

Su uso en AJAX

¿Qué tienen que ver estos patrones de diseño con nuestros desarrollos AJAX? El con-
cepto se utiliza como cualquier desarrollo de software y, además, en el caso de apli-
caciones ricas de Internet, la industria ya definió decenas de patrones de diseño
creados para solucionar problemas concretos de aplicaciones AJAX.
Generan un idioma y un vocabulario específicos de aplicaciones ricas de Internet
(como puede ser el autocompletado, visto en el cap. 6) y ofrecen ideas y soluciones
concretas a problemas comunes.
Recuérdese que cuando se crean desarrollos web en AJAX se están creando apli-
caciones complejas y es necesario ser prolijos y ordenados dentro de la arquitectura
del código JavaScript generado. Los patrones de diseño nos ayudan en esta tarea.
En el sitio www.ajaxpatterns.org se ofrece un listado actualizado de más de 70
patrones de diseño para aplicaciones RIA y AJAX específicamente con el detalle de
cada patrón, ejemplos de código JavaScript, librerías y frameworks que lo aplican,
ejemplos de sitios que lo implementan y mucha más información actualizada (fig. 7-1).

Fig. 7-1. En el sitio web AjaxPatterns.org se ofrece un listado con más de 70 patrones aplicados a RIA.

251
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 252

Maximiliano R. Firtman

Si bien algunas de las tantas soluciones allí planteadas tal vez no merezcan la ca-
tegoría de patrón de diseño, desde ya es de suma utilidad analizarlas y tenerlas pre-
sentes.
En este libro se estudiarán las más útiles y aplicables, y las ejemplificaremos con
nuestra librería (fig. 7-2).

Fig. 7-2. Cada patrón de diseño tiene la definición del problema, la solución, los nombres alternativos,
los ejemplos de código y los sitios web que lo aplican.

Patrones generales
Dentro de los patrones de diseño pensados para todo tipo de aplicación, hay algunos
que merecen analizarse porque pueden ser de mucha utilidad en aplicaciones AJAX.
Si bien estos patrones están pensados para aplicarse en entornos orientados a
objetos estrictos, como Java o .NET, sus ideas pueden adaptarse con facilidad a so-
luciones más estructuradas, como puede ser el código JavaScript generado.

252
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 253

AJAX. Web 2.0 para profesionales

Factory

El objetivo del patrón de diseño Fábrica o Factory es abstraer la instanciación de los


objetos en una clase (o función en nuestro caso) encargada de instanciar ese objeto.
Esto permite, primero, modularizar nuestro código y, segundo, crear código que pueda
adaptarse con facilidad a futuras interfaces o plataformas (fig. 7-3).

Fig. 7-3. Esquema clásico del Patrón Factory.

Un ejemplo de este patrón, que ya se había aplicado, es la función que instanciaba


el objeto XMLHttpRequest de forma distinta según se tratara de Internet Explorer o
Firefox, por ejemplo. Si esta funcionalidad de condicionales se agrupa en una función
o clase encargada de entregar el objeto XMLHttpRequest correcto, se estaría aplicando
este patrón de diseño. De esta forma todo el código que requeriría el objeto llamaría a
la función en lugar de instanciar el objeto en forma directa.
Otra posible utilidad de este patrón es encapsular en una función o un objeto la
instanciación y la creación de elementos visuales en la página web. Imagínese el có-
digo JavaScript siguiente:

var boton = document.createElement(”input”);


boton.type = ”button”;
boton.id = ”boton1”;
boton.value = ”presioname”

Este código se podría encapsular en una clase o una función, a las que se llama-
rán cada vez que se necesite crear un botón:

253
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 254

Maximiliano R. Firtman

// Clase Elementos que se encarga de darnos objetos visuales


function Elementos() {
this.crearBoton = function(id, texto) {
var aux = document.createElement(”input”);
aux.type=”button”;
aux.id = id;
aux.value = texto;
return aux;
}
}

Entonces, para crear un botón se ejecuta:

var boton = Elementos.crearBoton(”boton1”, ”Presioname”);

En este código la clase conocida como Factory o fábrica, es Elementos.


¿Qué ventaja hay además de encapsular las líneas de código para reutilizarlas?
Que si en el futuro se desea crear botones de otra manera, por ejemplo, con la etiqueta
XHTML button, sólo se deberá cambiar la fábrica y no todos los códigos JavaScript
que creaban un botón. Por ejemplo:

// Clase Elementos que se encarga de dar objetos visuales


function Elementos() {
this.crearBoton = function(id, texto) {
var aux = document.createElement(”button”);
aux.id = id;
aux.innerHTML = texto;
return aux;
}
}

Abstract Factory
Hay una variante al patrón Factory, conocida como fábrica abstracta, cuyo objetivo es
crear distintas posibles fábricas de elementos, mientras todas ostenten la posibilidad
de crear los mismos objetos. Por ejemplo, se podría contar con dos fábricas, una para
crear objetos XHTML compatibles y otra para crear objetos en formato XAML para uti-
lizar dentro de la plataforma Silverlight (propietaria de Microsoft).

254
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 255

AJAX. Web 2.0 para profesionales

De esta forma, la aplicación tendría el mismo código controlador y de modelo de


datos, sólo que cambiaría el objeto que fabrica los elementos visuales y todo el código
funcionaría igual (fig. 7-4).

Fig. 7-4. Esquema clásico del Patrón Abstract Factory.

El Abstract Factory también es muy útil cuando se desea crear una aplicación que
pueda tener nuevas pieles o skins instalables a futuro y creadas por otros usuarios. Si
cada skin se considera una fábrica concreta que elabora objetos que la aplicación re-
quiere (botones, imágenes, textos, etc.), entonces nuestra aplicación sólo necesita ins-
tanciar la fábrica correcta (aunque haya sido generada por otro programador) y luego
usarla, sin importar de cuál se trate.
No se va a entrar en detalles de este patrón, pero se deja la idea para que quien
lo necesite investigue nuevos aspectos y ejemplos.

Observer

El patrón observador, también conocido como Publish-Subscribe (publicar-suscribir),


permite desacoplar dos objetos o clases, que tienen que interactuar entre sí. La idea
es que uno de ellos es el que publica acontecimientos que pueden ocurrir (publisher)
y muchos otros pueden suscribirse u observarlo.

255
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 256

Maximiliano R. Firtman

Se puede analizar mejor con un ejemplo: imagínese que se crea una aplicación
AJAX para un Webmail al estilo Windows Live Mail o Gmail. Un acontecimiento que
puede producirse de manera periódica cuando se tiene la aplicación abierta en el na-
vegador web es que llegue un nuevo e-mail.
Cuando esto sucede, supóngase que hay varios elementos que pueden presen-
tarse, por ejemplo:
• Mostrar un cartel o ícono.
• Reproducir un sonido.
• Cambiar el título de la página.
• Activar el antivirus.
• Activar filtros.

Incluso, el usuario podría activar o desactivar algunas de estas opciones. Un pri-


mer análisis del problema indicaría que en el código, cuando se sabe que llegó un e-
mail nuevo, se empieza a preguntar si hay que mostrar un ícono, si hay que reproducir
un sonido, etc. No obstante, de esta manera el código se estaría acoplando mucho.
¿Qué sucede si mañana se desea incorporar un sistema de plugins, donde otros de-
sarrolladores creen mejoras para el sistema? Por ejemplo, alguien podría crear un adi-
cional que, cuando llega un nuevo e-mail avisa si esa persona está online en algún
mensajero. No suena lógico que, ante cada nueva funcionalidad que se desee agregar
cuando llega un correo se modifique el código principal.
Entonces, aparece el patrón de diseño Observer para ofrecer una solución un
poco más prolija y escalable (fig. 7-5).
La solución propuesta es que la clase encargada de recibir nuevos e-mails im-
plemente este patrón, definiendose a sí mismo como el Publisher o el que es obser-
vado. Para ello incorpora una colección o un vector de suscriptores u observadores, y
una función o método para agregar uno nuevo o quitar uno. Cuando realmente llega un
nuevo e-mail, el Publisher sólo recorre la colección e invoca a cada uno de los sus-
criptores para avisarles que el acontecimiento acaba de producirse.
De esta forma, todo aquel que quiera suscribirse al acontecimiento Llegaron nue-
vos e-mails sólo debe pedir ser agregado a la lista de suscriptores y en forma auto-
mática recibirá el aviso cuando eso ocurra. Cada suscriptor hará lo que considere
necesario, sin que deba modificarse el código original.
Se podría suponer que el manejo de acontecimientos de JavaScript (onclick, onload,
onchange) se parece a este control. En realidad esto sucede a medias, dado que cada
vez que uno modifica el onclick de un elemento, se elimina el que estaba suscripto
antes. Es por eso que muchas librerías de AJAX, como Prototype o Yahoo! UI imple-
mentan este patrón en forma completa.

256
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 257

AJAX. Web 2.0 para profesionales

Fig. 7-5. Esquema clásico del Patrón Observer.

Command

El patrón de diseño Comando permite separar en capas nuestra aplicación y definir


una colección de comandos o acciones que se pueden realizar dentro de nuestra apli-
cación RIA, así como cuál es la función o el código por ejecutar cuando se produce
cada acción.
Entonces, cada vez que se desea ejecutar una acción (p. ej., entrar en la bandeja
de entrada, enviar un nuevo e-mail, etc.), en lugar de escribir el código o la llamada para
ejecutar la acción, se invoca la clase Comando enviándole por parámetro la acción
que se quiere ejecutar, por ejemplo:

comando.ejecutar(”EnviarMail”);

La clase Comando tendrá una lista de comandos posibles, buscará el apropiado


y lo ejecutará.

257
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 258

Maximiliano R. Firtman

El uso de esta idea tiene algunas ventajas:


• Simplifica la llamada a acciones desde cualquier lugar del código de la apli-
cación sin tener que recordar cómo se denominaba la función.
• Posibilita agregar o quitar funciones con facilidad antes o después de una ac-
ción sin tener que buscar en todo el código todas las veces en que se había
invocado la misma.
• Permite generar una bitácora o log de todas las acciones que se realizaron,
dado que todas las llamadas a acciones se centralizan en esta clase.
• Permite enlazarse con otro patrón de diseño, llamado Memento, que permite
guardar el estado de la aplicación ante cada llamada a una acción nueva e im-
plementar el famoso Deshacer o Undo.

Se puede implementar en JavaScript de muchas maneras, la idea es muy simple


para codificar. No es más que un vector que tenga nombre de la acción y una función
con el código por ejecutar en cada una.
Un ejemplo:

function Command() {
this.acciones = [];

this.agregar = function(nombre, funcion) {


this.acciones[nombre] = funcion;
}

this.ejecutar = function(nombre) {
// Busca la acción en la colección
if (this.acciones[nombre]!=undefined) {
// Ejecuta la acción considerando que es una función
this.acciones[nombre]();
// Aquí es posible generar un log de las acciones
// ejecutadas o guardar estados de la aplicación
}
}
}

var comando = new Command();


comando.agregar(”NuevoMail”, function() { GenerarNuevoEmail() });
comando.agregar(”Verificar”, function() { actual=0; Verificar() });

258
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 259

AJAX. Web 2.0 para profesionales

Asimismo, cuando se desea invocar una acción simplemente se usa la clase sin
preocupase por cómo se invoca la acción con exactitud.

$(”btnNuevoMail”).onclick = function() {
comando.ejecutar(”NuevoMail”);
}

// Ejecuta la verificación de nuevos mails cada 15 segundos


setInterval(”comando.ejecutar(’Verificar’)”, 15000);

Memento

Otro de los patrones clásicos que se pueden utilizar muy bien en las aplicaciones ricas
de Internet es el Memento. Si bien lo primero que se viene a la mente es una película
de los últimos años, el objetivo que cumple el patrón de diseño bien tiene que ver con
esa película.
Memento permite recordar el estado de la aplicación en el pasado para volver fá-
cilmente para atrás implementando una acción conocida en aplicaciones de escritorio
como Deshacer o Undo.
Lo primero que hay que hacer para implementar este patrón de diseño es decidir
qué variables, valores e información forman parte del estado de la aplicación en un
momento dado, como si se tomara una fotografía de la aplicación.
Esto depende mucho del tipo de aplicación que se tenga. Por ejemplo, en un web-
mail, el estado de la aplicación podría constar de:
• Lugar donde se encuentra el usuario: una carpeta, escribiendo un mail, en op-
ciones, etcétera.
• Si estaba escribiendo un e-mail, a quién y el texto que había escrito.
• Si estaba en una carpeta, en cuál y qué mensaje tenía seleccionado.

Si fuera un sistema en el que se administran tablas de una base de datos, el es-


tado de la aplicación en un momento dado puede ser:
• Lugar donde estaba el usuario (listando, editando, insertando).
• Si elimina un registro, qué registro eliminó y los datos que tenía.
• Si edita un registro, cuál y qué valores cambió.
• Si inserta un registro, qué valores había ingresado el usuario.

259
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 260

Maximiliano R. Firtman

Fig. 7-6. Google Docs ofrece la clásica opción de deshacer en los documentos y las hojas de cálculo.

Este estado de la aplicación podrá almacenarse en un objeto JSON, por ejemplo,


con todos estos valores que hacen a la fotografía de la aplicación en un momento dado
y, cada vez que el usuario genere una nueva acción, se guardará esa fotografía de la
aplicación en una pila de objetos.
De esta forma, cuando el usuario aplique la función Deshacer se podrá cambiar
el estado actual por el anterior. Más adelante se verá cómo capturar el botón Atrás del
navegador. En ese caso, esta implementación también podrá servir para que, cada vez
que el usuario presione atrás, vuelva al estado anterior.

Value Object

La idea del patrón Value Object es pensar en el transporte de objetos entre el servidor
y el cliente en una aplicación RIA. Ya se vio que una solución era transportarlo en un
XML o en un texto para luego parsearlo.

260
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 261

AJAX. Web 2.0 para profesionales

La idea detrás de Value Object es crear objetos con cierta estructura definida, ar-
marlos en el servidor y volver a rearmarlos en el cliente, sean cuales fueran los len-
guajes intervinientes.
De esta manera, los datos llegan estructurados y no se debe parsear o tener cui-
dado al convertir de un formato a otro. En principio, si se transportan objetos JSON
entre el servidor y el cliente se utiliza este patrón de diseño, dado que JavaScript lo re-
conoce en el cliente como un objeto estructurado.

Patrones exclusivos de RIA


Los patrones de diseño vistos antes se pueden utilizar en todo tipo de aplicaciones.
Esta parte del capítulo se centrará en los patrones de diseño exclusivos para Aplica-
ciones Ricas de Internet y, de manera específica, en su posible implementación en
AJAX. Muchos de estos patrones de diseño también se pueden encontrar en el sitio
ajaxpatterns.org o aplicarse a otras plataformas, como Adobe Flex.
Muchos de los patrones de diseño que se verán tienen alguno de los siguientes
objetivos:
• Optimizar al máximo las peticiones que se realizan al servidor.
• Ofrecer una solución a problemas comunes cuando se crean aplicaciones ricas.
• Solucionar problemas de uso en aplicaciones ricas.
• Simplificar la tarea de codificación.

Guesstimate

Para optimizar las peticiones al servidor, el patrón de diseño Guesstimate sugiere in-
tentar adivinar la información para mostrar al usuario según alguna metodología o es-
tadística cuando no se necesita que la información que se exhibe sea exacta.
Si bien no es un patrón de diseño muy utilizado, en algunos casos, la idea puede
ser de utilidad.
Google hace uso de este patrón en la página principal de Gmail, donde aparece
el famoso contador de espacio disponible en las cuentas que comenzó con 2 Gb y fue
subiendo a razón de bytes por segundo (fig. 7-7). Cuando se ingresa en la página prin-
cipal, se puede ver que la cantidad de bytes disponibles aumenta a medida que pasan
los segundos, no obstante…, ¿esta información es real? No porque sea mentira, pero,
¿se envían peticiones al servidor para saber cada 2 segundos en cuántos bytes está
cambiando la capacidad?
Imaginamos que no. Google hace una estimación de cuántos bytes tienen las casi-
llas en cada momento según una cuenta estadística que posee. Por supuesto, cuando se
carga la página por primera vez, sí viene el dato real y a partir de allí se lo estima.

261
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 262

Maximiliano R. Firtman

Otro ejemplo era uno de los primeros sitios de iTunes, el software de administra-
ción de contenido de Apple, famoso por ser la aplicación necesaria para los iPods. El
sitio mostraba cómo aumentaba la cantidad de descargas de la aplicación segundo a
segundo. Ya nos estaremos imaginando de dónde salía ese valor.
Un último ejemplo que se puede dar sobre el uso de este patrón es cuando se im-
plementa alguna aplicación o juego que requiere actualización constante de la posición
de un jugador o un elemento en pantalla. Imagínese que se muestra sobre un mapa
cómo se mueve un avión real que llega a una ciudad. Es posible actualizar la informa-
ción contra un servidor cada 10 segundos pero, ¿qué pasa entre esos 10 segundos o
si el servidor tarda en responder? Dejar el avión quieto por tanto tiempo en pantalla
puede ser contraproducente para el dinamismo de la aplicación. Entonces, se puede
hacer una estimación, según la velocidad y la dirección que ya tenía, sobre cómo se
mueve entre los lapsos en los que no hay información nueva.
Como toda estimación puede tener errores, se tendrá que ajustar la visualización
cuando llegan los datos reales, pero en la mayoría de los casos se podrá ofrecer una inter-
faz más dinámica sin que el usuario se dé cuenta cuándo hubo que recurrir a una estimación.

Fig. 7-7. Se observa la cantidad de bytes disponibles en Gmail, que aumenta segundo a segundo es-
timando la información real.

262
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 263

AJAX. Web 2.0 para profesionales

On-Demand JavaScript

Hasta ahora cada librería o código JavaScript que se necesitaba para la aplicación
AJAX se importaba en el HEAD del XHTML, con un tag SCRIPT, como el siguiente:

<script type=”text/javascript” src=”scripts/nombre.js”></script>

Ahora bien, si se hace una petición Full RIA, o sea, que toda la funcionalidad se
ofrece en una sola URL, ¿qué sucede con todos los JavaScript que se deben incluir?
¿No se sobrecarga mucho el navegador con tanto código que, a lo mejor, no se usa en
su totalidad?
Para resolver este tema, el patrón de diseño On-Demand JavaScript, o JavaScript
bajo demanda, permite que se puedan cargar al inicio de la aplicación sólo los scripts
JavaScript que se van a utilizar seguro y, luego, bajo necesidad o demanda, cargar los
módulos nuevos cuando el usuario activa otra acción no cargada.
Si se piensa unos segundos sobre cómo resolver este problema parece que no tu-
viera una solución directa. Sin embargo, hay dos soluciones posibles.

Código dinámico con JSON


La primera de las posibles soluciones es traer la nueva funcionalidad en un objeto
JSON. Recuérdese que los objetos JSON pueden transportar funciones dentro de su
estructura, por lo que si se hace una petición AJAX al servidor (p. ej., directamente con
XMLHttpRequest o usando nuestra librería) y se convierte la respuesta a JSON, se
podrá ejecutar el código que tenga ese objeto dentro.
Si se utiliza esta opción es conveniente que cada módulo de funcionalidad de la
aplicación sea una variable global que, si no está cargado, quede en valor undefined
o null. Por ejemplo:

// Definición de los módulos que se pueden cargar bajo demanda


var moduloCorrectorOrtografico = null;
var moduloAdjuntarVideos = null;

Entonces, los pasos serían los siguientes:


1. Cargar en el HEAD sólo los scripts principales de la aplicación.
2. Cuando el usuario quiere invocar una acción en particular (p. ej., mediante el
uso del patrón Command, visto antes) debe consultarse si el módulo que con-
tiene a la funcionalidad deseada está cargado. Si lo está se ejecuta, y si no es
así se hace una petición AJAX para recibir el módulo que, dentro, posee el có-
digo a ejecutar. Cuando el objeto llega, se guarda en el módulo global y se
ejecuta.

263
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 264

Maximiliano R. Firtman

function activarCorrectorOrtografico() {
if (moduloCorrectorOrtografico == null) {
// No está cargado el módulo
// Genero la petición para traerlo
$Ajax(”scripts/corrector.js”, {
tipoRespuesta: $tipo.JSON,
onfinish: function(modulo) {
// Recibe el objeto con el código a cargar
moduloCorrectorOrtografico = modulo;
// Invoca el módulo
moduloCorrectorOrtografico.activar();
}
} else {
moduloCorrectorOrtografico.activar();
}
}

Una buena práctica es activar un cartel o ícono de loading (o modificar el cursor


a uno de tipo espera) para indicar al usuario que debe esperar para que la funcionali-
dad que acaba de iniciar funcione.

Código dinámico con XHTML


La otra opción disponible para implementar este patrón de diseño es recurrir al DOM
del XHTML para incorporar al documento un nuevo script. De esta manera, cuando el
navegador web detecta que hay una nueva etiqueta SCRIPT que no ha cargado, inicia
una petición al servidor para traer el código necesario.
Para ello, sólo se crea un nuevo elemento HTML de tipo SCRIPT con los atribu-
tos correspondientes y se lo agrega al DOM. Por ejemplo:

function cargarScript(nombreJS) {
// Creamos un nuevo elemento DOM
var script = document.createElement(”script”);
// Definimos atributos
script.type = ”text/javascript”;
script.src = nombreJS;

// Agregamos el elemento al DOM, en el HEAD


document.getElementsByTagName(”head”)[0].appendChild(script);

// Inmediatamente el browser trae el archivo


}

¿Cuál es el único inconveniente de esta solución? ¿Cómo se hace para detectar


cuándo se cargó el script realmente? Aquí parece que se complica la situación, dado

264
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 265

AJAX. Web 2.0 para profesionales

que si se usa AJAX se tendrá un control completo de la petición cuando es devuelta


por el servidor.
Una solución es incluir como última instrucción del SCRIPT una llamada a una
función global del SCRIPT, que sí fue precargada por la aplicación, que avise que ya
se cargó. Por ejemplo:

home.js (controlador ya cargado)

function activarCorrectorOrtografico() {
if (corrector==undefined) {
// no existe la función corrector()
cargarScript(”scripts/corrector.js”);
}
}

function avisoCorrectorCargado() {
// Se acaba de cargar el módulo corrector, lo invocamos
corrector();
}

corrector.js (módulo cargado con ulterioridad)

function corrector() {

}

// Esta línea se va a ejecutar cuando se cargue este archivo


avisoCorrectorCargado();

Una gran ventaja que tiene esta metodología es que se pueden cargar scripts que
estén en servidores externos que no sean necesariamente el mismo donde está alojada
la página. Si son scripts a los que no se tiene acceso (p. ej., de Google o Yahoo!), no
se obtendrá la confirmación o el aviso de que se cargó el módulo.
Para asegurar que se cargó se puede consultar cada n cantidad de segundos si
un objeto o una función (que se sabe que el módulo posee) existen. Cuando sea así,
entonces el módulo se cargó. Por ejemplo:

cargarScript(”http://otrodominio.com/otroscript.js”);

// Cada dos segundos me fijo si cargó o no cargó con una tarea progra-
mada
var verificadorScript = setInterval(”verificaScript()“, 2000);

265
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 266

Maximiliano R. Firtman

function verificaScript() {
if (objeto_o_funcion != undefined) {
// Ya se cargó el módulo, lo puedo invocar
// Elimino la tarea programada para que no siga preguntando
crearInterval(verificadorScript);
}
}

Cargador de scripts
Si bien no es exactamente el patrón que se comentó, tiene relación con la solución ex-
puesta antes.
Nos vamos dando cuenta de que, a medida que se utilizan cada vez más librerías,
como Prototype o Script.aculo.us, la cantidad de scripts que se deben incluir en el
XHTML es mucha, puede ser incluso más de diez o quince. Para evitar escribir los tags
SCRIPT en el XHTML cada vez que se desea agregar un .js nuevo, se puede inventar
un sistema cargador de scripts iniciales.
Para ello, nuestro controlador o archivo JS principal se incluirá en el XHTML (el
único) y, dentro de este archivo se agregarán los módulos adicionales, al mejor estilo
include.

var scripts = [”prototype.js”, ”otro.js”];


window.onload = function() {
scripts.each(function(script) {
var script = document.createElement(”script”);
script.type = ”text/javascript”;
script.src = script;

document.getElementsByTagName(”head”)[0].appendChild(script);
});
}

var cantScripts = 0;
function cargado() {
cantScripts++;
if (cantScripts==scripts.length) {
// Están todos cargados
init();
}
}

Para esto hay que incorporar una nueva función que reemplace a window.onload.
Porque, ahora, la acción window.onload implica que se cargó el XHTML, pero no ne-
cesariamente todos los JS que se van a usar. Por lo tanto, ahora hay que inventar nues-
tro propio onload que se ejecute cuando realmente todos los JS queden cargados.

266
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 267

AJAX. Web 2.0 para profesionales

Para ello, se puede inventar una función global llamada init, onload, o main, donde
estaremos seguros de poder invocar al código de todas las librerías. Mientras tanto se
puede poner un cartel de loading para que la página no se pueda usar hasta tanto se
carguen todos los módulos.
El único requisito que tienen que cumplir todos los JS que queramos importar a
nuestro sistema cargador es que la última línea sea una llamada al JS global que indi-
que que el código se cargó.

cargado();

El sistema se puede mejorar para detectar errores creando un timeout para mos-
trarle un mensaje al usuario que indique que uno o más módulos no pudieron cargarse.

Cross Domain Proxy

Este patrón de diseño ya se había visto en su aplicación al lector RSS. La idea es poder
sortear los problemas de seguridad que se encuentran en los navegadores web cuando
se desea invocar una petición a un servidor externo.
La solución es hacer la petición a nuestro servidor local, que actuará de interme-
diario o proxy al realizar la petición al servidor externo, recibir la respuesta y retrans-
mitirla a nuestro script. De esta manera, para el navegador web, la petición se hace
desde y hacia el mismo servidor.
Según el lenguaje o la plataforma que tengamos en el servidor web encontraremos
distintos scripts más simples, más complejos y con mejor seguridad.
La solución se puede asemejar al siguiente script PHP:

PHP<?php
// Si fuera XML
header(”Content-Type: text/xml”);
$archivo = ”http://” . $_GET[”url”];
readfile($archivo);

?>

Heartbeat

Todos seguramente conocen el concepto de Sesión que se aplica en casi todas las
plataformas de desarrollo web desde el servidor (Java, PHP, ASP). Una sesión se man-
tiene abierta mientras el usuario esté navegando por el sitio web haciendo peticiones.
Cuando el usuario no hizo petición alguna por más de un tiempo predeterminado (en

267
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 268

Maximiliano R. Firtman

general 15 o 20 minutos), su sesión se considera cerrada y se borran de la memoria del


servidor todas las variables de sesión que el programador haya guardado.
Este efecto lo conocen todos los usuarios de Internet, ya que cuando el usuario
se retira del equipo y luego vuelve, el sistema lo obliga a identificarse otra vez en el sitio
con usuario y contraseña, o cuando se borra todo el contenido de su canasto de com-
pras, lo invita a volver a comprar.
Ahora bien, ¿qué sucede con una aplicación RIA? El usuario hace una primera
petición, y luego cada petición de envío o recepción de información la hace por AJAX,
por ejemplo. Cada una de estas peticiones hace que la sesión se mantenga viva en
el servidor, pero dado que ahora el usuario puede hacer muchas tareas casi de modo
offline es posible que recién haga una petición extra luego del timeout cierre en el
servidor.
Por ejemplo, en una aplicación de webmail se puede escribir un correo electrónico
durante media hora y, en principio, al presionar Enviar, cuando la aplicación AJAX hace
la petición al servidor, la sesión se cierra y el servidor ya no nos reconoce.
Una posible solución a este problema la aporta el patrón de diseño HeartBeat o
latido de corazón. La idea es hacer una petición al servidor cada cierta cantidad de
segundos o minutos solamente con el fin de que la sesión no se cierre, como una es-
pecie de aviso al servidor de que estamos vivos y con la aplicación abierta (fig. 7-8).

Fig. 7-8. Cada un segundo se hace una petición de tipo HeartBeat sin importar si, además, se están
haciendo otras peticiones.

Una primera posibilidad, y más sencilla, es generar una petición de la siguiente


manera:

setInterval(”$Ajax(’sigovivo.php’)”, 60000);

268
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 269

AJAX. Web 2.0 para profesionales

El código anterior hace una petición AJAX a un script llamado sigovivo.php cada
un minuto. Nótese que no se definió ningún parámetro opcional de nuestra librería.
Simplemente se desea hacer la petición y no interesa recibir o procesar la respuesta.
Una solución un poco más eficiente, pero más compleja de implementar, implica
aprovechar todas las peticiones Ajax que nuestra aplicación haga como último latido.
Por ejemplo, mientras el usuario haga peticiones pidiendo y enviando cosas al servi-
dor no se hace la petición de latido de corazón (dado que la sesión se mantiene igual
abierta). Cuando por un cierto lapso no se hizo petición alguna al servidor, entonces sí
se emite un latido.
Para esto es necesario integrarnos con nuestra librería de AJAX, para no tener
que encontrar en forma manual todas las peticiones que se hagan. La idea sería la si-
guiente: se cronometra una petición latido para dentro de un minuto. Cada vez que el
usuario hace una petición normal, se reinicia el contador para la próxima petición a un
minuto desde ese momento.

Unique URL

Cuando se comentaron las desventajas de las aplicaciones ricas de Internet, se anali-


zaron dos de ellas que van de la mano y eran que, al tratarse de una sola URL, ¿qué
sucede cuando un usuario agrega a Favoritos o envía a un amigo por mail o chat la di-
rección? El instinto hace que copiemos y peguemos la URL desde el navegador pero,
en una aplicación RIA normal donde se cuenta con una sola URL para todo, la direc-
ción que se envía o se agrega a favoritos no es más que la Página Principal inicial y no
exactamente la información que se tiene frente a la pantalla.
Para solucionar este inconveniente, aparece el patrón de diseño Unique URL o
direcciones únicas, y la idea es generar dinámicamente una URL cada vez que el usua-
rio cambia de visualización en la aplicación. Todo depende mucho del tipo de aplica-
ción RIA, pero algunos ejemplos son:
1. En un fotolog se puede guardar qué álbum se está viendo o qué foto.
2. En un sitio de e-commerce, qué artículo se está viendo, en qué color y otras
especificaciones.
3. En un sitio de mapas, la ubicación central, el nivel de zoom y otras informa-
ciones.

En lo primero que se piensa es en utilizar URL que reciban por parámetros de tipo
QueryString estos valores, por ejemplo:

http://www.dominio.com/misitioria.html?producto=22

269
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 270

Maximiliano R. Firtman

Un primer análisis indicaría que esto está bien, y hasta funcionaría. Es posible leer
desde JavaScript el contenido de la URL que está a la derecha del símbolo ?, por lo
que en el window.onload se lo podría leer con window.location.query.
Sin embargo, la idea es que cada vez que el usuario cambie el artículo que mira
desde la aplicación AJAX, esta URL se modifique. Lo primero en que se piensa es cam-
biar la propiedad window.location, por ejemplo a:

http://www.dominio.com/misitioria.html?producto=52

Y aquí viene el problema. Al cambiar la URL, el navegador lo que hace es invocar


la nueva URL al servidor y sacar de memoria nuestra actual RIA, como si fuera un vín-
culo o link normal, lo que hace que el usuario deba esperar a que la nueva página car-
gue, al viejo estilo 1.0.
Para esto hay dos soluciones, que comenzaremos a descubrir.

Generar URL bajo demanda


La primera solución que aparece es no generar la nueva URL cada vez que el usuario
cambia de visualización sino cuando lo pide en forma explícita. Esto implica incluir un
botón o link en la página web que diga enlazar con esta página o Generar URL, o algo
similar que el usuario comprenda. Cuando el usuario hace clic en esa dirección, en-
tonces se generará la petición normal que desembocará en la misma visualización que
tenía antes, pero con una URL completa de parámetros.
Google Maps hace uso de esta técnica, como se ve en las figuras 7-9 a 7-11.

Generar URL en forma automática


La otra opción sería generar el cambio de URL de manera automática cada vez que se
cambia de visualización en la pantalla. No obstante, ya se vio que se presenta el in-
conveniente de que ante cada cambio parece que siempre se actualiza toda la página,
y se desea evitar ese efecto.
Para eso se puede utilizar cierto truco que evoca a viejas épocas del HTML con
una funcionalidad que en el presente se usa poco y son las anclas o anchors. Básica-
mente es posible generar una URL distinta sin hacer que el browser refresque toda la
página indicando un ancla. Ésta es una identificación que aparece en la URL luego de
un símbolo numeral (#). Mientras toda la URL que está a la izquierda del numeral sea
la misma, el navegador nunca refrescará toda la página.
De esta manera es factible cambiar la URL agregando #nueva_vista a la URL me-
diante window.location. El navegador no refrescará la página y el usuario cuando copie
o pegue la URL llevará el identificador de la vista que se podrá capturar al cargar la pá-
gina al inicio.

270
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 271

AJAX. Web 2.0 para profesionales

Fig. 7-9. Cuando se observa un mapa de Google Maps siempre hay una opción que invita a Enlazar
con esta Página.

¿Por qué Google Maps no utiliza esta técnica si parece más útil? Pensemos por
un instante. Si cada vez que nos movemos en el mapa o hacemos zoom la URL se va
modificando, produciría un efecto un poco molesto en la vista del usuario. Es por eso
que hay que tener cuidado en cómo se utiliza.

Periodic Refresh

En ciertas ocasiones es preciso recibir actualizaciones desde el servidor de cierto con-


tenido, por ejemplo, si se reciben nuevos correos en la casilla, si aparecieron noticias
o entradas en un RSS, etcétera.

271
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 272

Maximiliano R. Firtman

Fig. 7-10. Al generar la URL se tendrá la misma vista, pero en la barra de dirección se verá una direc-
ción llena de parámetros, lista para copiar y pegar o agregar a Favoritos. Al abrir esa URL se tendrá
exactamente la misma vista.

Dado que una aplicación AJAX usa, de fondo, el protocolo HTTP no es posible que
el servidor emita por decisión propia información hacia el cliente (el browser). De esta
manera tiene que ser el navegador web, sí o sí, el que emita la petición. Esta técnica
se conoce como Polling o Periodic Refresh.
La idea es simple. Cada cierta cantidad de segundos a definir se realiza una pe-
tición al servidor (como el HeartBeat), pero esperando una respuesta. La respuesta
puede ser vacía, en ese caso no hay actualizaciones o una lista de actualizaciones a
la información (fig. 7-12).

272
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 273

AJAX. Web 2.0 para profesionales

Fig. 7-11. Los parámetros pueden llegar a ser tan complejos como indicar qué calle, altura y nivel de
zoom estamos viendo. Aquí se observa el servicio Street View de Google Maps.

Esta técnica implica simplemente realizar una tarea programada de JavaScript


que realice la petición pidiendo novedades al servidor. Si se utiliza este patrón de di-
seño, no se necesita hacer uso de un HeartBeat.
Por ejemplo:

// Pide novedades al servidor cada 10 segundos


setInterval(”$Ajax(’novedades.php’)”, 10000);

273
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 274

Maximiliano R. Firtman

Fig. 7-12. Si se deja la página de GMail abierta se recibirán anuncios de correos nuevos, noticias, pu-
blicidades nuevas y mensajes de chat.

En este caso el servidor deberá tener registrada la sesión del usuario para saber
quién es. Si no, se le puede enviar un parámetro que indique un identificador de sesión
o similar.
Aquí hay un dilema para resolver:
• El ideal de actualización sería cada 1 segundo o menos. Apenas haya una ac-
tualización lo ideal sería que el usuario lo vea.
• No obstante, cada pedido de actualización requiere una petición al servidor, trans-
ferencia y proceso, por lo que es una sobrecarga al navegador y al servidor.

Por ello, es importante encontrar el equilibrio para no sobrecargar demasiado el


servidor ni dejar al usuario sin información actualizada por mucho más tiempo que el

274
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 275

AJAX. Web 2.0 para profesionales

que pasó en realidad en el servidor. Se pueden usar estadísticas globales o persona-


les de cada usuario para optimizar al máximo este valor.
Muchos sistemas de ayuda en línea o chats online utilizan esta técnica para lograr
un sistema de conversación sin refrescos de página (fig. 7-13).

Fig. 7-13. Un chat o sistema de conversación en línea utiliza la técnica de Periodic Refresh para reci-
bir mensajes nuevos.

MultiStage Download
La técnica de la descarga en varias etapas o Multistage Download permite que el con-
tenido de una página web no se descargue todo en una primera petición, sino que pri-
mero se carga el contenido principal que se desea mostrar y, mientras el usuario lee y
mira las opciones, se carga información extra vía peticiones AJAX.
Decidir qué contenido descargar más tarde tiene que ver con distintas decisiones
a tomar, entre ellas comerciales (p. ej., mostrar primero los banners) y técnicas (p. ej.,
cuando un proceso va a tardar mucho porque requiere consulta a otros servidores, se
carga vía AJAX sin hacer esperar el resto del contenido).

275
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 276

Maximiliano R. Firtman

Mientras alguna zona de la página se carga vía AJAX hay varias técnicas para de-
cidir qué mostrar en ella:
• No mostrar nada: cuando llegue el contenido aparecerá de golpe y acomo-
dará el contenido restante en la página.
• Mostrar un cartel de loading o una barra de progreso.
• Mostrar una zona gris simple.

Otro problema que se debe resolver es, si se decide hacer que 10 zonas se des-
carguen más tarde, ¿se realizán las 10 peticiones simultáneas? Lo ideal sería enviar de
a poco para no saturar al servidor, ya sea con un setTimeout o haciendo peticiones a
medida que llegan las respuestas de las anteriores.
El objeto Ajax.Updater de Prototype implementa justamente este patrón de di-
seño, donde se puede actualizar cierta zona de contenido en algún momento dado.
Utilizando nuestra librería, se podría hacer algo como lo siguiente:

<div id=”contenido”>
<div id=”encabezado”>Bienvenidos a nuestro sitio web</div>
<div id=”cuerpo”>Cargando…</cuerpo>
</div>

Y en el window.onload de un .js que se importa a este HTML se hace (fig. 7-14):

window.onload = function() {
$Ajax(”cuerpo.html”, {
onfinish: function(html) { $(”cuerpo”).innerHTML = html; });
}

Predictive Fetch
Una de las mejores experiencias de una Rich Internet Application es cuando el usua-
rio siente que todo lo que hace aparece en forma instantánea evitando las molestas es-
peras de las clásicas páginas web.
Por ejemplo, en una hoja de cálculo se selecciona una zona que contiene texto en
una columna y números en la segunda. Segundos después (lo que la coordinación ce-
rebro-mouse permita) se activa la opción de realizar un gráfico estadístico e inmedia-
tamente aparece el gráfico. ¿Cómo lo hizo tan rápido teniendo en cuenta que el gráfico
lo genera el servidor y no el browser?
Hay otro caso más conocido para el que volvemos a recurrir a Google Maps. Si
arrastramos el mapa y nos movemos de un lado a otro, ¿no sentimos que todo el mapa

276
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 277

AJAX. Web 2.0 para profesionales

Fig. 7-14. Con el Multistage download se pueden descargar zonas de la página web en distintos mo-
mentos.

siempre está descargado en nuestro equipo? Como si tuviéramos todo el globo terrá-
queo allí.
Para todo esto existe el patrón Predictive Fetch o Recolección Predictiva. Este
patrón de diseño sugiere predecir lo que el usuario hará como próximo paso y ejecu-
tarlo ahora, sin esperar a que en realidad lo haga.
Por ejemplo:
• Si se lee un artículo de 5 páginas, y se mira la primera, es muy probable que
luego se desee ver la segunda página.
• Si se lista un top 100 de artistas, de a 10 por página, lo más probable es que
se desee ver a los próximos 10.
• Si se selecciona una tabla con una columna de texto y otra de números, lo
más probable es que se la quiera graficar.
• Si se observa un mapa de una zona, lo más probable es que la intención sea
moverse en alguna dirección alrededor.

277
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 278

Maximiliano R. Firtman

La solución está en anticiparse al usuario y ya hacer la petición cuando se crea que


hay grandes probabilidades de que algo se produzca. Por supuesto, como toda pre-
dicción, está sujeta a errores y a que se hayan hecho peticiones de más sin sentido.
El algoritmo de predicción se puede hacer muy simple, o complejizarlo un poco.
Por ejemplo, en el primer caso del artículo de 5 páginas: se podría decidir que hay
grandes probabilidades de que el usuario pida la segunda página recién a los 15 se-
gundos de haberse cargado. Eso indicaría que la persona está leyendo el texto y que
no entró y se fue inmediatamente.
Para decidir cómo predecir se puede utilizar:
• El perfil del usuario: sobre la base del historial de navegación del usuario (que
habría que almacenar) se puede decidir la predicción. Por ejemplo, si cuando
el usuario mira un artículo en venta, luego observa la descripción completa, es
factible predecir que siempre que entre a ver un producto en concreto se
puede ir descargando su descripción.
• La actividad reciente del usuario: según cuál fue la última acción del usua-
rio, se puede predecir cuál será la siguiente. Por ejemplo, si acaba de buscar
pizzerías en un mapa, lo más probable es que quiera ver el detalle de cada
una de ellas.
• La actividad de otros usuarios: es posible tomar estadísticas de qué accio-
nes realiza con el sitio web el promedio de los usuarios y así optimizar la res-
puesta del resto de ellos.

Prefetch cliente
El código JavaScript para implementarlo es sencillo. Lo complejo está en decidir cómo
predecir y decidir qué información ir trayendo del servidor aunque el usuario no la haya
pedido todavía en forma explícita.
Por ejemplo, si se desea ir cargando el contenido de la página 2 del artículo que
el usuario está leyendo, pero recién a los 15 segundos de que haya comenzado, el có-
digo sería algo similar al siguiente:

// Debe ser una variable global


prefetchNota = setTimeout(”$Ajax(’leerarticulo.php?pag=2’, {onfinish:
cacheNota})”, 15000);

La función cacheNota sólo debe encargarse de guardar en una variable global el


contenido de la nota (sea texto, JSON o XML), y si el usuario realmente pide la se-
gunda página, entonces se leería el contenido del caché.

278
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 279

AJAX. Web 2.0 para profesionales

Si el usuario cambia de nota, se limpia el prefetch para que no traiga la segunda


página:

clearTimeout(prefetchNota);

Por otro lado, si el usuario pide la página 2, preguntamos si la tenemos en el caché


ya cargada o, si no, hacemos la petición en el momento.

Prefetch servidor
Por otro lado, también es posible que el servidor decida qué información enviar de más
como predicción. De esta manera, cuando el browser le pide al servidor un artículo,
éste podrá decidir según ciertos parámetros enviarle ese artículo pedido y agregar al-
gunos más relacionados para que el cliente ya precargue.

Para esto es necesario implementar un mecanismo para que el cliente (el código
JavaScript) reconozca cuál es la información que realmente él pidió y cuál es la que le
envió el servidor prediciendo los próximos pasos del usuario, que el código cliente de-
berá almacenar en algún objeto local (fig. 7-15).

Fig. 7-15. También es posible que el servidor prediga las próximas acciones del usuario y envíe más
información que la que el cliente pidió.

279
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 280

Maximiliano R. Firtman

Local Cache

Con el objetivo de minimizar las peticiones que se hacen al servidor, el patrón Local
Cache, o memoria local, permite guardar todas las respuestas recibidas del servidor por
si en el futuro se solicita de nuevo la misma petición. En ese caso, en lugar de hacerla
otra vez, devolvemos la versión guardada con anterioridad.
Para esto hay que tener en cuenta que no todas las peticiones son susceptibles
de poder hacerles un caché. En el ejemplo del patrón Periodic Refresh siempre se
hacen peticiones a novedades.php y justamente se desea hacer la petición en forma
explícita cada vez, y no tomar una versión guardada con anterioridad. Por otro lado, en
el ejemplo de los países y las provincias en lista en cascada, las provincias de un país
específico nunca cambian, por lo que estaría bien hacer caché.
Por eso, nuestra librería $Ajax tenía una opción adicional para decidir si se dese-
aba caché o no, pero hasta ahora sólo se la usaba para generar una URL aleatoria por
si el programador no quería caché.
Ahora se la puede extender para incorporarle la funcionalidad de caché en caso
de que el usuario lo quiera. Para eso la complejidad del código de la librería aumenta
un poco porque tenemos distintas bifurcaciones:
1. El programador no solicitó caché en la petición, por lo tanto, se hace la peti-
ción al servidor.
2. El programador pidió caché, pero no estaba (es la primera vez que se hace).
Se realiza la petición real al servidor y, cuando llegan los datos, se guardan en
caché.
3. El programador pidió caché y está disponible. No se hace la petición real y se
invoca al onfinish directamente con el objeto previamente guardado en el
caché (sea texto, JSON o XML).

La ventaja de implementar este patrón de diseño en nuestra librería es que su im-


plementación es inmediata y no hay que modificar nada del código de los controladores.

Submission Throttling

Sin una traducción coherente al español, el patrón de diseño Submission Throttling in-
tenta hallar un objetivo previamente buscado, que es minimizar las peticiones al servi-
dor. La idea es mejorar el rendimiento de la aplicación reduciendo las peticiones al
máximo.
Para ello, se basa en la premisa siguiente:
• Muchas aplicaciones RIA efectúan numerosas peticiones simultáneas en un
lapso breve (p. ej., 2 segundos).

280
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 281

AJAX. Web 2.0 para profesionales

Imaginemos el caso de un Autocomplete, en el que se hace una petición por cada


carácter que el usuario escribe para ofrecerle sugerencias. Si el usuario escribe muy rá-
pido se harán muchas peticiones simultáneas.
El objetivo del patrón es juntar todas las peticiones que se hayan intentado hacer
en cierto período y hacerlas todas juntas en una sola reaprovechando los recursos.
Esto implica algunas cuestiones:
1. El tiempo bajo el cual juntamos las peticiones es crucial. Si es muy breve, no
tendrá efecto. Si es muy prolongado, el usuario esperará más de lo normal
las respuestas del servidor.

2. Requiere un trabajo adicional (y no siempre sencillo) en el servidor dado que,


¿cómo se hace para que una sola petición invoque lo que antes eran dos?
3. Si se realiza una sola petición para, por ejemplo, tres peticiones distintas, cada
una de ellas obtendrá una respuesta diferente que se recibirá como una sola.

Implementación
La implementación de este patrón implica los siguientes pasos (fig. 7-16):
1. Crear una colección global de peticiones pendientes.
2. Cada vez que el código JS quiere hacer una petición AJAX (p. ej., con $Ajax),
en lugar de hacerlo realmente, ésta se guarda en la colección de peticiones
pendientes.
3. Cada n cantidad de segundos ejecutar un código que revisa si hay alguna pe-
tición pendiente.
4. Si hay una la envía de modo normal.
5. Si hay más de una, crea una petición encapsulando las pendientes en algún
formato por convenir (p. ej., un XML o un JSON) que contenga los datos de
cada una (acción o URL, parámetros, etc.).
6. Enviar la única petición a un script en el servidor que hará las funciones de
portero, esto es, abrir el paquete, separar cada petición y hacer cada una de
ellas por separado.
7. El servidor esperará las respuestas de cada petición, las juntará en una sola
respuesta (en un XML o en un JSON) y responderá al cliente.
8. En el cliente se recibirá la múltiple respuesta y se invocarán las funciones de
cada petición original, cada una con su respuesta correspondiente.

Todo este framework que se cambia en el cliente y el servidor tiene que quedar
justificado con un aumento del rendimiento. Cada caso particular merece su propio
análisis.

281
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 282

Maximiliano R. Firtman

Fig. 7-16. Utilizar Submission Throttling complejiza el funcionamiento de nuestra aplicación, pero en
ciertos casos de aplicaciones complejas puede aumentar mucho el rendimiento.

Peticiones que se sobreescriben


En el caso anterior, cuando se juntaba más de una petición en un período, se suponía
que eran todas válidas y se enviaban todas al servidor. Sin embargo, ¿qué pasa en un
autocomplete? Si alguien escribió “a” y luego “ar”, y después “arg”, ¿es necesario
hacer las tres peticiones o la que vale es realmente la última?
Aquí se ve que en algunos casos, mientras se esté dentro del plazo en que las
peticiones quedan en un buffer o memoria intermedia, es posible que una nueva peti-
ción deje sin efecto la anterior porque ya no tiene sentido (fig. 7-17).
Otro ejemplo es un cliente de correo electrónico. Si se ingresa en la bandeja de en-
trada e inmediatamente en la de salida, ¿hace falta hacer la primera petición si el usua-
rio se retractó al instante y cambió de sección?

282
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 283

AJAX. Web 2.0 para profesionales

Fig. 7-17. Si se escribe rápido en Google Suggest se observará que en realidad no se están haciendo
todas las peticiones, sino que algunas se anulan implementando un Submission Throttling.

En el capítulo 8 se realizará un sitio completo de comercio electrónico utilizando


ASP.NET como desarrollo en el servidor. Allí se llevarán a cabo técnicas de arrastrar y
soltar, búsquedas de productos sin refrescar la página y servicios ricos en un sitio web.

283
C07.qxd:Project Ajax4.1.qxd 10/18/07 8:13 PM Página 284
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 285

Comercio electrónico
con AJAX 8
Introducción
A esta altura todos conocen qué es un sitio web de comercio electrónico. El asunto es,
¿qué puede aportar una aplicación rica de Internet en un desarrollo de este tipo? Apor-
tará muchas características interesantes, que harán aumentar la cantidad de compras
que se hagan en nuestro sitio web. Un sitio web rico tiene mayor tasa de conversión;
esto es, la gente compra más cuando se trata de una aplicación rica.
A continuación se detallan algunas características de un comercio electrónico con
AJAX:
• El proceso de compra es notoriamente más veloz.
• Es posible obtener estadísticas detalladas del comportamiento del usuario
para ofrecerle sugerencias, ofertas o paquetes de productos.
• El usuario puede interactuar mejor con el sistema, puede comparar productos,
arrastrar productos al canasto de compras o tener su lista de productos de-
seados (wish list).
• El usuario nunca sale de una sola interfaz donde navega por categorías, busca,
elije y compra.

Estructura

Lenguaje de servidor
En los ejemplos anteriores del libro se habían elegido PHP y MySQL como solución del
lado del servidor. Para demostrar que AJAX en realidad puede comunicarse con cual-
quier plataforma del servidor, se va a hacer uso de la tecnología ASP.NET con lenguaje

285
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 286

Maximiliano R. Firtman

Visual Basic y con SQL Server. Fácilmente se podría haber utilizado también C#,
IronPython u otro lenguaje .NET.
Para los que no conozcan la tecnología de ASP.NET, pueden descargarse en forma
gratuita el editor Visual Web Developer Express y el motor de base de datos SQL Ser-
ver Express. Asimismo, este proyecto será fácil de migrar a PHP u otra plataforma.

Base de datos
Se va a utilizar SQL Server como motor de base de datos con la estructura de un e-
commerce que se puede ver en la figura 8-1. La estructura es simple, y lo es a los efec-
tos de demostrar las capacidades de AJAX en un sitio de estas características.
Un sitio en producción debería tener mayores capacidades, cálculo de estadísti-
cas y probablemente mayor información y filtros acerca de los productos. También se
debería almacenar más información del usuario que hace la compra.
Nótese que en la tabla pedidos hay un campo finalizado. La idea es ofrecer un
servicio de autoguardado que guarde el pedido en el servidor por si se cierra el nave-
gador o el usuario tiene algún problema. Esto es un servicio muy útil en aplicaciones
ricas de Internet, que le ofrece al usuario una buena experiencia de navegación.

Fig. 8-1. Diagrama de la base de correo electrtónico.

286
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 287

AJAX. Web 2.0 para profesionales

Clases de conexión
Así como en PHP había una clase para conectarse a la base de datos y centralizar así
el acceso, se hará lo mismo en .NET. El string de conexión a la base de datos, que in-
cluye usuario y password, también podría incorporarse en el archivo de configuración
web.config.
Esta clase es BD.vb y sólo se la debe ubicar en la carpeta App_Code del proyecto
web.

Imports Microsoft.VisualBasic
Imports System.Data
Imports System.Data.SqlClient

Public Class BD

Public Shared _conexion As SqlConnection

Public Shared Property Conexion() As SqlConnection


Get
If _conexion Is Nothing Then
_conexion = New SqlConnection(”Data
Source=nombre_server;Initial Catalog=ecommerce;Persist Security
Info=True;User ID=usuario;Password=pwd”)
End If
Return _conexion
End Get
Set(ByVal value As SqlConnection)
_conexion = value
End Set
End Property

Public Sub New()


End Sub

Public Shared Sub Abrir()


If Conexion.State <> ConnectionState.Open Then
Conexion.Open()
End If
End Sub

Public Shared Sub Cerrar()


If Conexion.State <> ConnectionState.Closed Then
Conexion.Close()
End If
End Sub

Public Shared Sub ExecuteNonQuery(ByVal cmd As String)


Abrir()
Dim com As New SqlCommand(cmd, Conexion)

287
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 288

Maximiliano R. Firtman

com.ExecuteNonQuery()
Cerrar()
End Sub

Public Shared Sub ExecuteNonQuery(ByVal cmd As SqlCommand)


Abrir()
cmd.Connection = Conexion
cmd.ExecuteNonQuery()
Cerrar()
End Sub

Public Shared Function ExecuteScalar(ByVal cmd As String) As Object


Abrir()
Dim com As New SqlCommand(cmd, Conexion)
Return com.ExecuteScalar()
Cerrar()
End Function

Public Shared Function ExecuteScalar(ByVal cmd As SqlCommand) As


Object
Abrir()
cmd.Connection = Conexion
Return cmd.ExecuteScalar()
Cerrar()
End Function

Public Shared Function Execute(ByVal cmd As String) As DataTable


Dim comando As New SqlCommand(cmd, Conexion)
comando.Connection = Conexion
Dim adap As New SqlDataAdapter(comando)
Dim dt As New DataTable
adap.Fill(dt)
Return dt
End Function

Public Shared Function Execute(ByVal cmd As SqlCommand) As DataTa-


ble
cmd.Connection = Conexion
Dim adap As New SqlDataAdapter(cmd)
Dim dt As New DataTable
adap.Fill(dt)
Return dt
End Function

End Class

Con esta clase se tendrá centralizado el acceso para realizar consultas a la base
de datos en forma sencilla. Se ofrece una solución similar a la observada antes en PHP.

288
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 289

AJAX. Web 2.0 para profesionales

Diseño web

El diseño del sitio de comercio electrónico se basará en una Full Rich Internet Appli-
cation, o sea, una sola URL donde el usuario podrá realizar todas las acciones de la
aplicación web.
La página web tendrá las zonas siguientes (fig. 8-2):
• Zona de menú: permitirá acceder a distintas opciones de menú, como bus-
car por categorías, buscar por palabra o ver el canasto de compras.
• Zona de resultados: mostrará el resultado de una búsqueda con el nombre y
el precio del producto.
• Zona de detalle: mostrará el detalle de un producto seleccionado. Esta infor-
mación puede ubicarse debajo de cada resultado o en una zona predefinida.
• Zona de canasto: permitirá ver todos los productos que hay en el canasto; se
pueden modificar cantidades, eliminar productos y limpiar el canasto.
• Zona de finalización de compra: confirmará los datos de envío de los pro-
ductos y finalizará la compra.

Fig. 8-2. Esqueleto del diseño de comercio electrónico con XHTML y CSS. Está realizado con cajas
de colores para identificar mejor las zonas en los ejemplos.

289
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 290

Maximiliano R. Firtman

Se tendrá la estructura XHTML siguiente:

<!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>Comercio Electrónico con AJAX</title>
<link href=”estilos.css” type=”text/css” rel=”stylesheet” />
</head>

<body>

<div id=”menu”></div>

<div id=”contenedor”>
<div id=”canasto”></div>
<div id=”resultados”></div>
<div id=”detalle”></div>
</div>

<div id=”finalizacion”></div>

</body>
</html>

Y el CSS adjunto

* {
font-family:Verdana, Arial, Helvetica, sans-serif;
font-size: 11;
padding: 0px;
margin: 0px;
}

#menu {
width: 100%;
background-color:#CCFF99;
height: 70px;
}

#resultados {
width: 69%;
background-color: #FFCCCC;
height: 250px;
float: left;
}

290
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 291

AJAX. Web 2.0 para profesionales

#detalle {
width: 69%;
background-color: #EEEEEE;
height: 250px;
float: left;
}

#canasto {
float: right;
width: 30%;
background-color:#0033CC;
color: white;
height: 500px;
}

Se va a ir armando el menú de navegación (fig. 8-3):

Fig. 8-3. Se agregan opciones al menú de navegación.

291
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 292

Maximiliano R. Firtman

<div id=”menu”>
<div id=”menuOpciones”>
Navegar por Categorías:
<select id=”listaCategorias”>
</select>

Buscar:
<input type=”text” id=”textoBusqueda” />
<input type=”button” id=”btnBuscar” value=”Buscar” />
</div>
</div>

Y el siguiente CSS:

#menuOpciones {
height: 70px;
vertical-align: middle;
padding: 20px;
font-size: larger;
}

#listaCategorias {
margin-right: 20px;
}

Comportamiento inicial
Ahora también se le agrega algo de información a cada sección y se van incorporando
los archivos de inclusión de JavaScript. Los JavaScript que importaremos son:
• AjaxLib.js: nuestra librería de trabajo AJAX.
• index.js: el controlador de nuestra aplicación.
• Prototype.js: la librería Prototype vista con anterioridad en el libro.
• Scriptaculous.js: la librería Script.aculo.us. Recuérdese que este JS permi-
tirá cargar el resto de los .js necesarios.

También se agregará un DIV que permitirá mostrar un aviso de cargando. Con


todos estos cambios el código queda así (fig. 8-4):

292
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 293

AJAX. Web 2.0 para profesionales

Fig. 8-4. Visualmente vamos encontrando la ubicación de cada uno de los elementos.

<!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>Comercio Electrónico con AJAX</title>
<link href=”estilos.css” type=”text/css” rel=”stylesheet” />
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”scriptaculous.js”></script>
<script type=”text/javascript” src=”AjaxLib.js”></script>
<script type=”text/javascript” src=”index.js”></script>
</head>

<body>

<div id=”menu”>
<div id=”menuOpciones”>
Navegar por Categorías:
<select id=”listaCategorias”>
</select>

293
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 294

Maximiliano R. Firtman

Navegar por Categorías:


<select id=”listaCategorias”>
</select>

Buscar:
<input type=”text” id=”textoBusqueda” />
<input type=”button” id=”btnBuscar” value=”Buscar” />
</div>
</div>

<div id=”contenedor”>
<div id=”canasto”>
<h2>Canasto de Compras</h2>
<div id=”listaCanasto”>
</div>
</div>
<div id=”resultados”>
<h2>Resultados de Búsqueda</h2>
<div id=”listaResultados”>
</div>
</div>
<div id=”detalle”>
<h2>Detalle de Resultados</h2>
<div id=”listaDetalle”>
</div>
</div>
</div>

<div id=”cargando”>Por favor espere...</div>

<div id=”finalizacion”></div>

</body>
</html>

Y el archivo de estilos quedaría como el siguiente:


*
{
font-family:Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
padding: 0px;
margin: 0px;
}

#menu
{
width: 100%;
background-color:#CCFF99;
height: 70px;
}

#menuOpciones
{

294
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 295

AJAX. Web 2.0 para profesionales

height: 70px;
vertical-align: middle;
padding: 20px;
font-size: larger;
}

#listaCategorias
{
margin-right: 20px;
}

#contenedor h2
{
padding: 10px;
font-size: larger;
}

#resultados
{
width: 69%;
background-color: #FFCCCC;
height: 200px;
float: left;
}

#detalle
{
width: 69%;
background-color: #EEEEEE;
height: 200px;
float: left;
}

#canasto
{
float: right;
width: 30%;
background-color:#0033CC;
color: white;
height: 400px;
}

#cargando
{
position: absolute;
top: 10px;
right: 50px;
background-color: red;
color: white;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
}

295
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 296

Maximiliano R. Firtman

Ahora se verán los pasos a seguir en el controlador:


1. Traer vía AJAX todas las categorías para completar la lista.
2. Cargar los productos disponibles en la primera categoría.
3. Darle funcionalidad a la lista de categorías y al buscador.
4. Apagar el cartel de cargando.

Luego, se irá incorporando el resto de las funciones por medio de JavaScript y


CSS (fig. 8-5).

Fig. 8-5. Vía AJAX ya se cuenta con el listado de Categorías funcionando.

296
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 297

AJAX. Web 2.0 para profesionales

Index.js

window.onload = function() {
$Ajax(”categorias.aspx”, {
onfinish: cargarCategorias,
tipoRespuesta: $tipo.JSON,
onerror: function(e) { alert(e) }
});

$(”btnBuscar”).onclick = enviarBusqueda;
$(”listaCategorias”).onchange = buscarCategoria;
}

function cargarCategorias(lista) {
// Itero entre cada categoría recibida
for (var i=0; i<lista.length; i++) {
var cat = lista[i];
// Agrego la categoría a la lista de Opciones
var opc = new Option(cat.nombre, cat.id);
$(”listaCategorias”).options[$(”listaCategorias”).length] = opc;
};
// Apago el cartel de Loading
$(”cargando”).hide();
}

function enviarBusqueda() {
$Ajax(”buscar.aspx”, {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON
});
}

function buscarCategoria() {
$Ajax(”categoria.aspx?id=” + $F(”listaCategorias”), {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON
});
}

function cargarResultados() {
// TODO
}

Resta ver el código de categorías.aspx en Visual Basic. Recuérdese que se podría


haber utilizado cualquier otro lenguaje .NET, como C# o incluso compilar esta funcio-
nalidad en clases separadas.

297
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 298

Maximiliano R. Firtman

<%@ Page Language=”VB” %>


<%@ Import Namespace=”System.Data” %>
<script runat=”server”>

” ’ <summary>
” ’ Lee las categorías y las devuelve en formato JSON
” ’ </summary>
” ’ <remarks></remarks>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
‘Este evento se ejecuta cuando se carga la página en el
servidor
Dim Resultado As DataTable
Resultado = BD.Execute(”SELECT * FROM CATEGORIAS ORDER BY
NOMBRE”)

Dim Json As String = ”[”

For Each Registro As DataRow In Resultado.Rows


‘Voy armando el JSON de cada categoría
Json += ”{”
Json += ”id: ” + Registro(”id”).ToString + ”, ”
Json += ”nombre: ’” + Registro(“nombre”) + ” ’”
Json += ”}”

’Coma que separa cada objeto con el siguiente


Json += ”,”
Next

’Hay que eliminar la última coma


Json = Json.Remove(Json.Length - 1, 1)

Json += ”]”

Response.Write(Json)
End Sub
</script>

Resultados de búsqueda

Teniendo en cuenta que nuestro sistema puede tener muchos productos incorpora-
dos, desde el servidor se van a enviar el id, el nombre y el precio de los productos a
incorporar en el canasto en los resultados de búsqueda.
Recuérdese que se pueden recibir resultados de dos maneras:
• Por selección de categoría.
• Por búsqueda por palabra.

298
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 299

AJAX. Web 2.0 para profesionales

Los dos scripts de servidor que devolverán los resultados son los siguientes:

categoria.aspx

<%@ Page Language=”VB” %>


<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<script runat=”server”>

” ’ <summary>
” ’ Busca Productos y los devuelve en formato JSON
” ’ </summary>
” ’ <remarks></remarks>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As Sys-
tem.EventArgs)
‘Este evento se ejecuta cuando se carga la página en el
servidor
Dim Resultado As DataTable

‘Leo el ID desde un parámetro GET


‘Convierto a Entero el ID para evitar problemas de seguridad
Dim id As Integer
Try
id = Integer.Parse(Request.QueryString(“id”))
Catch ex As Exception
id = 0
End Try
If id > 0 Then
Dim sql As String
sql = “SELECT * FROM PRODUCTOS WHERE IdCategoria = “ +
id.ToString
Resultado = BD.Execute(sql)

Dim Json As String = “[“

For Each Registro As DataRow In Resultado.Rows


‘Voy armando el JSON de cada producto
Json += “{“
Json += “id: “ + Registro(“id”).ToString + “, “
Json += “nombre: ‘“ + Registro(“nombre”) + “‘, “
Json += “precio: “ + Registro(“precio”).ToString
Json += “}“

‘Coma que separa cada objeto con el siguiente


Json += “,”
Next

‘Hay que eliminar la última coma


Json = Json.Remove(Json.Length - 1, 1)

299
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 300

Maximiliano R. Firtman

Json += ”]”

Response.Write(Json)

End If
End Sub
</script>

buscar.aspx (fig. 8-6)

<%@ Page Language=”VB” %>


<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<script runat=”server”>

” ’ <summary>
” ’ Busca Productos y los devuelve en formato JSON
” ’ </summary>
” ’ <remarks></remarks>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs)
‘Este evento se ejecuta cuando se carga la página en el
servidor
Dim Resultado As DataTable

‘Lee las palabras a buscar desde un parámetro GET


Dim palabra As String = Request.QueryString(”buscar”)
If palabra IsNot Nothing Then
‘Eliminamos comillas para evitar problemas de seguridad
palabra = palabra.Replace(” ’”, ””)
Dim sql As String
sql = ”SELECT * FROM PRODUCTOS WHERE NOMBRE LIKE ’%” + _
palabra + ”% ’ OR DESCRIPCION LIKE ’%” + palabra
+ ”% ’”
Resultado = BD.Execute(sql)

Dim Json As String = ”[”

For Each Registro As DataRow In Resultado.Rows


‘Voy armando el JSON de cada producto
Json += ”{”
Json += ”id: ” + Registro(“id”).ToString + ”, ”
Json += ”nombre: ’” + Registro(“nombre”) + ” ’, ”
Json += ”precio: ” + Registro(“precio”).ToString
Json += ”}”

‘Coma que separa cada objeto con el siguiente

300
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 301

AJAX. Web 2.0 para profesionales

Json += ”,”
Next

‘Hay que eliminar la última coma


Json = Json.Remove(Json.Length - 1, 1)

Json += ”]”

Response.Write(Json)

End If
End Sub
</script>

Fig. 8-6. Se observa una respuesta del buscar.aspx en formato JSON.

301
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 302

Maximiliano R. Firtman

Ahora queda terminar el JavaScript para que muestre los resultados de búsqueda.

window.onload = function() {
$Ajax(”categorias.aspx”, {
onfinish: cargarCategorias,
tipoRespuesta: $tipo.JSON,
onerror: function(e) { alert(e) }
});

$(”btnBuscar”).onclick = enviarBusqueda;
$(”listaCategorias”).onchange = buscarCategoria;
}

function cargarCategorias(lista) {
// Itero entre cada categoría recibida
for (var i=0; i<lista.length; i++) {
var cat = lista[i];
// Agrego la categoría a la lista de Opciones
var opc = new Option(cat.nombre, cat.id);
$(”listaCategorias”).options[$(”listaCategorias”).length] = opc;
};

// Cargo los productos de la primera categoría


buscarCategoria();
}

function enviarBusqueda() {
$Ajax(”buscar.aspx?buscar=” + $F(”textoBusqueda”), {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON,
divCargando: ”cargando”
});
}

function buscarCategoria() {
$Ajax(”categoria.aspx?id=” + $F(”listaCategorias”), {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON,
divCargando: ”cargando”
});
}

var listaResultados;

function cargarResultados(lista) {
// Apago el cartel de Loading
$(”cargando”).hide();

// Guardo la lista en una variable global


// para posible uso futuro
listaResultados = lista;

// Limpio la lista de resultados vieja


$(”listaResultados”).innerHTML = ””;

302
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 303

AJAX. Web 2.0 para profesionales

// Itero entre los resultados


for (var i=0; i<lista.length; i++) {
agregarResultado(lista[i]);
}
}

function agregarResultado(producto) {
var div = ”<div class=’productoResultado’ ” +
”id=’producto” + producto.id + ” ’>”;
div += ”<div class=’nombreProducto’ onclick=’detalle(” + producto.id
+ ”)’ >” + producto.nombre + ”</div>”;
div += ”<div class=’precioProducto’>$ ” + producto.precio +
”</div>”;
div += ”<div class=’agregarProducto’ onclick=’agregar(” +
producto.id
+ ”)’>Agregar</div>”;
div += ”</div>”
$(”listaResultados”).innerHTML += div; }

Nótese que se agregan en forma dinámica unos DIV con cada fila de resultado de un pro-
ducto. Para ello se utilizan algunos estilos CSS nuevos como los siguientes (figs. 8-7 y 8-8):

#listaCanasto, #listaResultados, #listaDetalle


{
padding: 15px;
overflow: auto;
height: 60%;
}

.productoResultado
{
width: 470px;
padding: 4px;
margin: 2px;
background-color: White;
font-size: large;
height: 15px;
}

.productoResultado:hover
{
background-color: #EEEEEE;
}
.nombreProducto
{
width: 300px;
float: left;
cursor: pointer;
}

.precioProducto

303
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 304

Maximiliano R. Firtman

{
width: 70px;
font-weight: bold;
text-align: right;
float: left;
}

.agregarProducto
{
width: 70px;
font-weight: bold;
cursor: pointer;
color: Purple;
float: right;
text-align: right;
}

.agregarProducto:hover
{
width: 20%;
font-weight: bold;
color: Red;
}

Fig. 8-7. Al elegir una categoría, se ve el listado de productos como resultado.

304
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 305

AJAX. Web 2.0 para profesionales

Fig. 8-8. CSS permite ubicarle una barra de desplazamiento a la lista de resultados cuando no entran
en pantalla.

Se puede apreciar que cada resultado de la búsqueda está encapsulado en un DIV


de clase productoResultado.
Cada fila tiene el nombre del producto, que al pulsar invoca la función detalle, el
precio y un texto con apariencia de link que permite agregar el producto al canasto de
compras, llamando a la función agregar. Ambas funciones todavía no están imple-
mentadas.
Nótese que mediante CSS se le dio cursor:pointer tanto al nombre como al link de
agregar, para dar al usuario la idea de que puede utilizar esas opciones.

Detalle de producto

Cuando se selecciona un producto del resultado de la búsqueda, la idea es que debajo


aparezca el detalle de ella, que emule un sistema de ventanas estilo Outlook donde se
observa la vista previa de un producto.

305
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 306

Maximiliano R. Firtman

Fig. 8-9. Por medio del HTML Inspector de Firebug se puede ver cómo quedó la lista de resultados
dinámica.

Para ello se tenía preparada la zona de Detalle. Lo que se debe hacer es, cuando
se hace clic en un producto, ir a buscar sus datos completos y ubicarlos en esta zona.
Veamos el código que se agrega al index.js:

function detalle(id) {
// Tengo que ir a buscar al servidor los detalles del producto
$Ajax(”producto.aspx?id=” + id, {
onfinish: mostrarDetalle,
tipoRespuesta: $tipo.JSON,
avisoCargando: ”cargando”
});
}

function mostrarDetalle(producto) {
// Creo el contenido de la zona de Detalle
var html = ”<div class=’detalleNombre’>” + producto.nombre +
”</div>”;
if (producto.foto!= ””) {
// Si tiene foto, la incluimos

306
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 307

AJAX. Web 2.0 para profesionales

html += ”<img src=’fotos/” + producto.foto + ” ’


class=’detalleFoto’ />”;
}
html += ”<input type=’button’ class=’detalleAgregar’ value=’Agre
gar al Canasto’ ”
+ ”onclick=’agregar(” + producto.id + ”)’ />”;
html += ”<div class=’detalleCategoria’>Categoría: ” +
producto.categoria + ”</div>”;
html += ”<div class=’detallePrecio’>Precio: $” + producto.precio+
”</div>”;
html += ”<div class=’detalleDescripcion’>q” + producto.descrip
cion + ”</div>”;
$(”listaDetalle”).innerHTML = html;
}

En este archivo se llama a un nuevo script de servidor que traerá un JSON con el
detalle completo de un producto:

Producto.aspx

<%@ Page Language=”VB” %>


<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>
<script runat=”server”>

” ’ <summary>
” ’ Devuelve el detalle de un Producto
” ’ </summary>
” ’ <remarks></remarks>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As Sys-
tem.EventArgs)
‘Este evento se ejecuta cuando se carga la página en el
servidor
Dim Resultado As DataTable

‘Leo el ID desde un parámetro GET


‘Convierto a Entero el ID para evitar problemas de seguridad
Dim id As Integer
Try
id = Integer.Parse(Request.QueryString(“id”))
Catch ex As Exception
id = 0
End Try
If id > 0 Then
Dim sql As String
sql = “ SELECT PRODUCTOS.*, CATEGORIAS.NOMBRE AS CATEGO-
RIA “

307
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 308

Maximiliano R. Firtman

sql += ” FROM PRODUCTOS INNER JOIN CATEGORIAS ”


sql += ” ON IdCategoria = CATEGORIAS.Id WHERE ”
sql += ” PRODUCTOS.Id = ” + id.ToString
Resultado = BD.Execute(sql)
Dim Json As String = ””

‘Tomo la primera fila como resultado


‘dado que es el único registro
Dim Registro As DataRow = Resultado.Rows(0)
If Resultado.Rows.Count = 1 Then
‘Voy armando el JSON de cada producto
Json += ”{”
Json += ”id: ” + Registro(”id”).ToString + ”, ”
Json += ”nombre: ’” + Registro(”nombre”) + ” ’, ”
Json += ”precio: ” + Registro(”precio”).ToString + ”,

Json += ”descripcion: ’” +
Registro(”descripcion”).ToString + ” ’, ”
Json += ”foto: ’” + Registro(”foto”).ToString + ” ’, ”
Json += ”categoria: ’” + Registro(”categoria”).ToS-
tring + ” ’ ”
Json += ”}”

End If

Response.Write(Json)

End If
End Sub
</script>

Por último se agregaron algunos estilos CSS para el detalle del producto (fig. 8-10):

.detalleNombre
{
font-size: 19px;
font-weight: bold;
Canasto de compras
color: Blue;
}

.detalleAgregar
{
float: right;
}

.detalleDescripcion

308
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 309

AJAX. Web 2.0 para profesionales

{
font-style: italic;
color: Gray;
}

.detallePrecio
{
font-size: 15px;
padding: 15px;
}

.detalleCategoria
{
color: red
}

.detalleFoto
{
float: left;
padding: 5px;
top: 0px;
max-height: 110px;
}

Fig. 8-10. Se observa la zona de Detalle en funcionamiento utilizando AJAX y CSS.

309
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 310

Maximiliano R. Firtman

Sólo resta la funcionalidad del canasto de compras. Aquí se deben cumplir las funcio-
nes siguientes:
• Incorporar productos que el usuario agrega desde las zonas de Resultados y
de Detalle.
• Aumentar o reducir la cantidad de un producto ya agregado.
• Eliminar un producto del canasto.
• Vaciar el canasto.
• Mostrar el total por facturar.
• Permitirle al usuario finalizar la compra.

Todas estas funciones se van a resolver en la zona de Canasto. Además, hay que
decidir dónde almacenar el canasto como tal. Se va a crear un modelo de datos local
en el cliente que almacene el canasto de compras. La estructura será un vector que,
en cada posición, tenga un objeto con las propiedades: id, nombre, precio y cantidad.
Éste será un objeto global llamado canasto.
Ahora bien, si la función agregar sólo recibe el id del producto que se desea in-
corporar, ¿de dónde se obtiene su nombre y su precio? Parece poco lógico hacer una
nueva petición al servidor para ir a buscar esa información cuando en realidad ya es-
taba disponible con anterioridad cuando se trajo el resultado de la búsqueda.
Para resolver este problema hay varias soluciones posibles; una de ellas es guar-
dar en un vector tipo hash, también conocido como asociativo, todos los productos
que se van leyendo desde resultados de búsqueda. Esto sería algo similar a una me-
moria caché de los productos que alguna vez pasaron por el resultado de búsqueda.
Los vectores tipo hash mantienen como índice cualquier valor alfanumérico. En
este caso se puede utilizar el ID del producto como índice y guardar un objeto con las
propiedades nombre y precio adentro.

// Hash de productos previamente navegados


var cacheProductos = [];

function agregarResultado(producto) {
var div = ”<div class=’productoResultado’ ” +
”id=’producto” + producto.id + ” ’>”;
div += ”<div class=’nombreProducto’ onclick=’detalle(” +
producto.id + ”)’ >” + producto.nombre + ”</div>”;
div += ”<div class=’precioProducto’>$ ” + producto.precio +
”</div>”;
div += ”<div class=’agregarProducto’ onclick=’agregar(” +
producto.id + ”)’>Agregar</div>”;

310
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 311

AJAX. Web 2.0 para profesionales

div += ”</div>”
$(”listaResultados”).innerHTML += div;

// Agregamos el producto al hash


cacheProductos[producto.id] = {
nombre: producto.nombre,
precio: producto.precio
}

Agregando al canasto
Entonces, ahora se puede crear la función agregar:

// Agrega un producto al canasto de compras


function agregar(id) {
// Primero buscamos si el producto ya estaba en el canasto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
} else {
i++;
}
}

if (encontrado) {
// El producto ya estaba en el canasto, sólo aumentamos
// su cantidad. ”i” tiene la posición actual
canasto[i].cantidad++;
} else {
// El producto no estaba en el canasto, lo agregamos
// obtenemos los datos del producto desde el hash global
var producto = cacheProductos[id];
nuevoProducto = {
’id’: id,
’nombre’: producto.nombre,
’precio’: producto.precio,
’cantidad’: 1
};

canasto[canasto.length] = nuevoProducto;
}
// Llama a la función que dibuja el canasto
actualizarCanasto();
}

311
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 312

Maximiliano R. Firtman

La función realiza los siguientes pasos:


1. Busca primero si el producto agregado al canasto no se había agregado ya.
a. En caso positivo, lo que hace es utilizar la posición encontrada en el ca-
nasto para aumentar la cantidad.
b. En caso negativo, genera una entrada nueva en el canasto.
i. Trae del hash global el producto buscando por ID.
ii. Genera un objeto nuevo con los datos del producto y la cantidad en 1.
iii. Agrega el objeto al array global del canasto.
2. Llama la función que actualiza en pantalla el canasto.

Entonces lo único que resta es generar la función que muestre el resultado en el


canasto de compras. Se crea una función que recorre el vector del canasto y lo va di-
bujando sobre la pantalla, y otra que dibuja el total.

Mostrando el canasto

// Dibuja el canasto en la zona especificada


function actualizarCanasto() {
// Primero creamos la lista de productos
var contenido = ””;
if (canasto.length==0) {
contenido = ”El canasto está vacío. <br />”;
} else {
var filaCanasto;
var total = 0;
for (var i=0; i<canasto.length; i++) {
// Creo una fila por cada producto
filaCanasto = ”<div class=’filaCanasto’ ”;
filaCanasto += ” id=’canasto_” + canasto[i].id + ” ’>”;
// Armamos cada fila con una tabla
var tablaCanasto;
tablaCanasto = ”<table width=’100%’><tr>”;
tablaCanasto += ”<td class=’canastoNombre’>” +
canasto[i].nombre + ”</td>”;
tablaCanasto += ”<td class=’canastoCantidad’>Cant: ” +
canasto[i].cantidad + ”</td>”;
tablaCanasto += ”<td class=’canastoPrecio’>$” +
canasto[i].cantidad*canasto[i].precio +
”</td>”;
tablaCanasto += ”<td><a href=’javascript:quitar(” +
canasto[i].id
+ ”)’ class=’canastoQuitar’>Quitar</a></td>”;
tablaCanasto += ”</tr></table>”;
filaCanasto += tablaCanasto + ”</div>”;

312
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 313

AJAX. Web 2.0 para profesionales

contenido += filaCanasto;
total += canasto[i].precio * canasto[i].cantidad;
}
// Mostramos el TOTAL
contenido += generarFilaTotal(total);

// Agregamos el botón para Finalizar la Compra


contenido += ”<input type=’button’ id=’btnFinalizar’
value=’Finalizar Compra’ />”;
}
$(”listaCanasto”).innerHTML = contenido;
}

function generarFilaTotal(total) {
var filaCanasto = ”<div class=’totalCanasto’> ”;
var tablaCanasto;
tablaCanasto = ”<table width=’100%’><tr>”;
tablaCanasto += ”<td class=’canastoNombre’>TOTAL</td>”;
tablaCanasto += ”<td class=’canastoCantidad’></td>”;
tablaCanasto += ”<td class=’canastoPrecio’>$” + total+ ”</td>”;
tablaCanasto += ”<td><a href=’javascript:vaciar()’
class=’canastoQuitar’>Vaciar</a></td>”;
tablaCanasto += ”</tr></table>”;
filaCanasto += tablaCanasto + ”</div>”;
return filaCanasto;
}

Mediante CSS se le dan distintos estilos a cada elemento agregado:

.filaCanasto
{
background: #000099;
margin: 1px;
padding: 2px;
}

.totalCanasto
{
background: #990000;
font-weight: bold;
font-size: large;
}

.canastoNombre
{
width: 110px;
}

.canastoPrecio
{
width: 40px;
text-align: right

313
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 314

Maximiliano R. Firtman

.canastoCantidad
{
width: 70px;
text-align: right
}

.canastoQuitar
{
color: White;
font-size:smaller;
text-align: right;
padding-left: 2px;
}

#btnFinalizar
{
margin-top: 15px;
font-size: larger;
background-color: White;
}

Ya se puede ver cómo queda el canasto de compras. Nótese que si se agrega un


producto más de una vez, en lugar de sumarse una fila nueva se le cambia la cantidad
al producto agregado con anterioridad (figs. 8-11 y 8-12).

Fig. 8-11. El canasto de compras en funcionamiento.

314
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 315

AJAX. Web 2.0 para profesionales

Fig. 8-12. Cuando se agrega un producto más de una vez se puede apreciar que se cambia su canti-
dad.

Quitando del canasto


Ahora queda implementar las funciones de quitar y vaciar, que eliminan un producto en
particular o todos a la vez, respectivamente. La función de finalizar la compra se dejó
para más adelante, en este capítulo.
Para quitar un elemento de un vector se utiliza la función without que incorpora la
librería Prototype a todos los Arrays (fig. 8-13).

// Quita un producto del canasto


function quitar(id) {
// Primero buscamos si el producto ya estaba en el canasto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
// Lo eliminamos de la lista con Prototype
canasto = canasto.without(canasto[i]);
} else {

315
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 316

Maximiliano R. Firtman

i++;
}
}
actualizarCanasto();
}

// Vacía todo el canasto


function vaciar() {
canasto = [];
actualizarCanasto();
}

Fig. 8-13. Al quitar todos los productos o vaciar todo el canasto, se observa la leyenda que indica que
no hay productos en el canasto.

Modificando cantidades
Hasta ahora sólo se puede modificar la cantidad de un producto dado buscándolo por
categoría o nombre y agregando una cantidad de nuevo, y no es posible disminuir la
cantidad. Sólo quitar todo el producto en cuestión. Falta la posibilidad de modificar la
cantidad de un producto ya agregado en el canasto.

316
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 317

AJAX. Web 2.0 para profesionales

Para ello hay varias metodologías. Una sería implementar un editor en el mismo
lugar o In place editor. Para lograrlo, se debe ocultar el div que muestra el texto y crear
un campo de texto que, al salir de foco, se vuelve a convertir a un div.
Otra de las soluciones sería incluir dos imágenes (flecha arriba y flecha abajo) que
permitan aumentar o disminuir los valores junto a cada cantidad. Se implementará esta
opción utilizando dos archivos GIF para cada flecha: flechaup.gif y flechadown.gif.
Lo que se hace, entonces, es modificar el código para cuando se mostraba la
cantidad con el código siguiente:

tablaCanasto += ”<td class=’canastoCantidad’> ” +


canasto[i].cantidad
+ ”<img src=’flechadown.gif’ onclick=’bajar(” + canasto[i].id +
”)’ />”
+ ”<img src=’flechaup.gif’ onclick=’subir(” + canasto[i].id + ”)’
/></td>”;

Asimismo, se agregan las dos funciones para subir y bajar la cantidad (figs. 8-14
y 8-15).

Fig. 8-14. Ahora se pueden modificar las cantidades mediante las flechas que tiene cada producto.

317
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 318

Maximiliano R. Firtman

Fig. 8-15. Se observa el canasto de compras funcionando en un navegador Apple Safari, el clásico na-
vegador de Mac, pero instalado sobre Windows.

Arrastrar y soltar
Introducción

Todos conocen el concepto de arrastrar y soltar (drag and drop, en inglés). Es la posi-
bilidad de mover o copiar objetos en una interfaz gráfica arrastrándolos con el puntero
y soltándolos en el destino.
Por defecto XHTML no provee metodología interna alguna para crear este efecto,
aunque ofrece algunos eventos, como ondrop y ondrag desde JavaScript.
La librería Script.aculo.us, que ya conocemos, provee un entorno para trabajar
con la modalidad de arrastrar y soltar de manera muy simple, sencilla, pero a la vez muy
potente.
Para que esta funcionalidad esté disponible sólo se necesita contar con el archivo
dragdrop.js, además del scriptaculous.js, en la carpeta de nuestro proyecto.

318
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 319

AJAX. Web 2.0 para profesionales

Scriptaculous trabaja con dos tipos de objetos: Draggables (zonas que se pueden
arrastrar) y Droppables (zonas donde se pueden soltar elementos). Veamos cómo fun-
ciona el sistema. Una extensión a este framework es el objeto Sortables, ya utilizado
con anterioridad para crear listas que se pueden reordenar.

Draggables

La idea es poder convertir todos los objetos que se desee que se puedan arrastrar en
objetos Draggables. En principio cualquier elemento XHTML se puede convertir en un
objeto que se puede arrastrar, aunque lo más común, y lo que trae menores problemas,
es el conocido DIV (fig. 8-16).
La sintaxis es la siguiente:

new Draggable(’id_del_elemento’, opciones);

Fig. 8-16. En el sitio web de Script.aculo.us hay varios ejemplos de cómo implementar arrastrar y
soltar.

319
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 320

Maximiliano R. Firtman

Las opciones posibles son:

Propiedad Descripción

revert Si se define en true, cuando el usuario suelta el elemento, éste


vuelve a su posición original con una animación

snap Se define en false si se desea que el usuario pueda mover el objeto


con libertad, o un vector [x, y] si lo que se quiere es que el usuario
sólo pueda mover el elemento en una grilla de tamaño x,y

zindex Es el valor CSS del eje Z que se aplicará al elemento cuando se está
arrastrando
constraint Se puede definir en horizontal o vertical para que sólo se pueda
arrastrar en un eje, o vacío si se desea libertad

ghosting Si se define en true, al comenzar a arrastrar el elemento se crea un


clon del elemento y se lo arrastra, dejando el original en su lugar

starteffect Define el efecto que se aplicará al comenzar a arrastrar. Por defecto


es Opacity

reverteffect Define el efecto que se aplicará cuando se suelta un elemento y


éste vuelve a su posición original. Por defecto es Move

endeffect Define el efecto que se aplicará cuando se suelta el elemento.


Por defecto es Opacity

change Es una función que se ejecutará ante cada cambio en el uso de


arrastrar y soltar. Recibe el objeto Draggable donde se puede
consultar en qué lugar está el objeto en la actualidad

Por defecto, al activar un objeto Draggable se lo podrá mover por toda la panta-
lla, pero no hay zonas específicas para soltar los elementos. Por defecto el elemento
puede soltarse en cualquier lugar, por ejemplo:

new Draggable(’divContenido’);

Y si se desea que al soltarlo vuelva a su lugar original:

new Draggable(’divContenido’, {revert:true});

Por defecto el elemento, en este caso divContenido, siempre podrá arrastrarse.


Para eliminar esta función, es preciso guardar el objeto y luego destruirlo, por ejemplo:

320
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 321

AJAX. Web 2.0 para profesionales

var drag = new Draggable(’divContenido’, {revert:true});


(…)
drag.destroy();

Droppables

Los elementos Droppables son los que tienen un ancho y un alto definidos, donde se
podrán soltar objetos Draggables. Es factible crear y eliminar zonas de depósito de
elementos con el código siguiente:

Droppables.add(’id_elemento’, opciones);

Las opciones disponibles son:

Propiedad Descripción

accept Por defecto, las zonas Droppables aceptan cualquier Draggable. Si se


define esta propiedad con un string, o con un vector de strings, la zona
sólo aceptará Draggables que tengan como className de CSS alguno
de los strings ingresados

containment Si se define esta propiedad con un ID o un vector de ID, la zona sólo


aceptará elementos contenidos en esos ID (que sean descendientes)

hoverclass Si se especifica, la zona Droppable tomará esta clase CSS cuando un


elemento que se pueda aceptar se arrastre por encima de la zona

overlap Se puede definir en horizontal o vertical. En ese caso sólo acepta el


elemento cuando está más del 50% dentro de la zona en la dirección
indicada

Si hay muchos objetos que se arrastran, se puede definir una clase CSS (aunque
no tenga su definición de estilos) y agregársela a los elementos. Esto permitirá definir-
los en la propiedad accept. Por otro lado, es una buena práctica definir un hoverclass
que modifique levemente el color de fondo y aporte un borde resaltado a las zonas
Droppables. Esto ayudará al usuario a darse cuenta dónde puede soltar los objetos.

También hay dos eventos disponibles que se pueden capturar:

321
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 322

Maximiliano R. Firtman

Propiedad Descripción

onHover Se ejecuta cada vez que el usuario arrastra un elemento que se puede
aceptar en la zona Droppable. Esta función recibe el objeto Draggable,
el Droppable y el porcentaje de solapamiento actual

onDrop Se ejecuta cuando el usuario suelta un Draggable sobre la zona y es


un elemento que se puede aceptar. Recibe el objeto Draggable, el
Droppable y un objeto Event con algunas propiedades útiles

Por medio del evento onDrop se puede capturar el momento en que el usuario
“suelta” un elemento y actuar en consecuencia.
La gran pregunta que surge al comienzo del uso de Drag and Drop en Scriptacu-
lous es cómo se identifica el objeto que se soltó en la zona Droppable. Para eso se uti-
liza el primer parámetro del evento onDrop, que da el elemento Draggable y se puede
obtener cualquier propiedad de él, como ID o alt.
El tercer parámetro que se recibe en la función onDrop posee las propiedades si-
guientes:

Propiedad Descripción

type Evento desencadenado (por ejemplo: mouseup)

target Destino del drop

screenX, screenY Posición X e Y de la pantalla donde se soltó el elemento

ctrlKey Indica true si la tecla Control estaba presionada cuando soltó el


elemento

shiftKey Indica true si la tecla Shift estaba presionada cuando soltó el


elemento

altKey Indica true si la tecla Alt estaba presionada cuando soltó el elemento

Se puede eliminar una zona Droppable con:

Droppables.remove(’id_elemento’);

322
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 323

AJAX. Web 2.0 para profesionales

Uso avanzado

Es posible trabajar con arrastrar y soltar en un nivel más avanzado por medio del ob-
jeto Draggables disponible en JavaScript por la librería.
Este objeto tiene los siguientes métodos y propiedades:

Propiedad Descripción

drags Es un vector con todos los elementos Draggables actuales del


documento

observers Es un array con todos los observadores


register(función) Registra una función que recibe un Draggable. Se ejecutará cada vez
que se agregue un elemento que se puede arrastrar

unregister(función) Elimina la función de la lista

activate(draggable) Activa la opción de arrastrar sobre un elemento aunque el usuario no


lo haya iniciado

deactivate(draggable) Desactiva el arrastre de un elemento

addObserver(obs) Agrega un objeto observador

removeObserver(obs) Elimina un objeto observador

notify() Notifica a todos los observadores

Un observador es un objeto que tiene definido element, con el elemento que se


desea observar, y una o más de las siguientes funciones definidas: onStart, onDrag,
onEnd. Esto permite centralizar el control de los elementos que se arrastran por la pá-
gina web.

Aplicación

Ahora se van a aplicar todos los conceptos vistos antes al proyecto de comercio elec-
trónico.

Arrastrando al canasto
Lo primero en que se piensa es en implementar la función de arrastrar y soltar entre los
elementos del resultado de la búsqueda y el canasto de compras.

323
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 324

Maximiliano R. Firtman

Para ello, hay que elegir qué elementos van a ser Draggables y cuáles van a ser
Droppables. Para eso se puede analizar cómo estaba organizada la estructura de ele-
mentos en nuestro proyecto, como se puede ver en la figura 8-17.

Fig. 8-17. Es factible analizar qué elementos son Draggables y Droppables utilizando las herramientas
que se pueden anexar a los navegadores.

Al analizar allí, se puede decidir que el elemento con ID listaCanasto debería ser
nuestro elemento Droppable, y los elementos que se pueden arrastrar y soltar allí de-
berían ser los de clase CSS productoResultado (p. ej., los ID producto1 y producto3).
El elemento Droppable se puede definir directamente en el window.onload debido
a que, aunque todavía no haya elementos, debería ser posible arrastrar los resultados
de búsqueda. Ya es factible definir que sólo se aceptan elementos que sean de clase
productoResultado y así restringir el acceso a la zona del canasto.

window.onload = function() {
// …

324
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 325

AJAX. Web 2.0 para profesionales

// Define el Droppable
Droppables.add(”listaCanasto”, {
onDrop: sueltaProducto,
accept: ”productoResultado”
});
}

Queda por definir la función sueltaProducto. ¿Cómo se sabe qué producto se


acaba de soltar en el canasto? Para eso se pueden utilizar los ID de los elementos
Draggables que son del estilo: productoXX, donde XX es el ID del producto en la tabla.
Entonces, mediante los métodos de la clase String se puede obtener el ID que hay que
agregar.

// Se ejecuta cuando el usuario suelta un producto en el canasto


function sueltaProducto(drag, drop, evento) {
// Obtenemos el ID
var id = drag.id.subString(9, drag.id.length);
// Agregamos el producto al canasto
agregar(id);
}

Los elementos Draggables se deben definir cuando se crean, y esto se hacía


cuando se recibían los resultados de la búsqueda del servidor.
Si se presentan algunos problemas con el contenedor cuando se arrastra un ele-
mento (el elemento se queda en su contenedor), se debe eliminar la propiedad over-
flow del div contenedor.
Veamos el código:

function agregarResultado(producto) {
var div = document.createElement(”div”);
div.className = ’productoResultado’;
div.id = ’producto’ + producto.id;
div.innerHTML += ” <div class=’nombreProducto’ onclick=’detalle(”
+ producto.id + ”)’ >” + producto.nombre + ”</div>”;
div.innerHTML += ” <div class=’precioProducto’>$ ” +
producto.precio + ”</div>”;
div.innerHTML += ” <div class=’agregarProducto’ onclick=’agre-
gar(” + producto.id + ”)’>Agregar</div>”;
$(”listaResultados”).appendChild(div);
// Agregamos el producto al hash
cacheProductos[producto.id] = {
nombre: producto.nombre,

325
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 326

Maximiliano R. Firtman

precio: producto.precio,
// Definimos el producto como Draggable
drag: new Draggable(”producto” + producto.id, {revert:true})
}
}

Se agrega al cacheProductos para luego tener una referencia al objeto Draggable


(fig. 8-18).

Fig. 8-18. Cuando se utiliza revert:true, al soltar el elemento éste vuelve a su posición original, pero con
el evento onDrop se lo agrega al canasto.

También es factible hacer que se pueda arrastrar la foto del producto desde el de-
talle. Para ello se cambia la función siguiente:

326
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 327

AJAX. Web 2.0 para profesionales

function mostrarDetalle(producto) {
// Creo el contenido de la zona de Detalle
var html = ”<div class=’detalleNombre’>” + producto.nombre +
”</div>”;
if (producto.foto!= ””) {
// Si tiene foto, la incluimos
html += ”<img src=’fotos/” + producto.foto + ” ’ class=’deta-
lleFoto’ ”
+ ”id=’foto” + producto.id + ” ’ />”;
}
html += ”<input type=’button’ class=’detalleAgregar’ value=’Agre-
gar al Canasto’ ”
+ ”onclick=’agregar(” + producto.id + ”)’ />”;
html += ”<div class=’detalleCategoria’>Categoría: ” +
producto.categoria + ”</div>”;
html += ”<div class=’detallePrecio’>Precio: $” + producto.precio+
”</div>”;
html += ”<div class=’detalleDescripcion’>q” + producto.descrip-
cion + ”</div>”;
$(”listaDetalle”).innerHTML = html;

new Draggable(”foto” + producto.id, {revert:true});


}

Además, ahora también hay que aceptar en la zona de Drop la clase CSS deta-
lleFoto, por lo que se cambia por:

window.onload = function() {
// …

// Define el Droppable
Droppables.add(”listaCanasto”, {
onDrop: sueltaProducto,
accept: [”productoResultado”, ”detalleFoto”]
});
}

Asimismo, se debe cambiar la función sueltaProducto para tomar tanto fotos


como filas del resultado de búsqueda (fig. 8-19):

// Se ejecuta cuando el usuario suelta un producto en el canasto


function sueltaProducto(drag, drop, evento) {
var id;

327
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 328

Maximiliano R. Firtman

if (drag.id.substring(0, 8)==”producto”) {
// Obtenemos el ID, es productoXXX
id = drag.id.substring(8, drag.id.length);
} else {
// Obtenemos el ID, es fotoXXX
id = drag.id.substring(4, drag.id.length);
}
// Agregamos el producto al canasto
agregar(id);
// Hacemos un efecto sobre el canasto
// Para que el usuario vea la confirmación de su Drop
new Effect.Appear(’listaCanasto’, {duration: 0.2});
}

Fig. 8-19. Ahora también se pueden arrastrar las fotos del detalle hacia el canasto y se agrega el pro-
ducto.

328
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 329

AJAX. Web 2.0 para profesionales

Arrastrando a la basura
Otra de las grandes ideas que se pueden implementar con arrastrar y soltar es incor-
porar un “bote de basura” en la zona del canasto y que se puedan arrastrar los pro-
ductos que hay allí hacia el bote, lo que sería equivalente a utilizar la opción “Quitar”.
En este caso, la zona de Drop es la misma imagen que se incorporó y los ele-
mentos Draggables son todas las filas que se incluyeron en el canasto que son de clase
filaCanasto.

function actualizarCanasto() {
// …

// Agrego todas las filas del canasto como Draggables


for (var i=0; i<canasto.length; i++) {
new Draggable(”canasto_” + canasto[i].id, {revert:true});
}

// Creamos el bote de basura


var bote = document.createElement(”img”);
bote.src = ”basura.png”;
bote.width = ”100”;
bote.height = ”100”;
bote.id = ”basura”
$(”listaCanasto”).appendChild(bote);
// Creo la zona de Drop con el bote
Droppables.add(”basura”, {
accept: ’filaCanasto’,
onDrop: tiraProducto
});

Y la función tiraProducto hace lo siguiente (fig. 8-20):

function tiraProducto(drag, drop, evento) {


var id = drag.id.substring(8, drag.id.length);
quitar(id);
}

329
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 330

Maximiliano R. Firtman

Fig. 8-20. Ahora hay dos tipos de objetos Drop, el canasto y el bote de basura, donde se pueden sol-
tar los elementos del canasto.

Finalizando la compra
Ahora le toca el turno a la finalización de la compra. Se había colocado el botón de “Fi-
nalizar”, pero que por el momento no hacía nada. Lo primero que se debe hacer es
agregarle comportamiento:

$(”btnFinalizar”).onclick = finalizar;

El paso siguiente es armar el formulario con XHTML y CSS en el div que se había
creado originalmente vacío (fig. 8-21):

330
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 331

AJAX. Web 2.0 para profesionales

Fig. 8-21. El formulario en funcionamiento. Se podría aplicar un estilo para lograr que sea “modal” y,
de esa forma, que no se pueda utilizar el resto de la página mientras esta ventana se encuentra vigente.

<div id=”finalizacion”>
<table width=”100%”>
<tr>
<td>Nombre y Apellido</td>
<td><input type=”text” id=”txtNombre” /></td>
</tr>
<tr>
<td>Telefono</td>
<td><input type=”text” id=”txtTelefono” /></td>
</tr>
<tr>
<td>Direccion</td>
<td><input type=”text” id=”txtDireccion” /></td>
</tr>
<tr>
<td></td>

331
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 332

Maximiliano R. Firtman

<td>
<input type=”button” id=”btnCancelar” value=”Cance-
lar” onclick=”cancelar()” />
<input type=”button” id=”btnEnviar” value=”En-
viar” onclick=”enviar()” />
</td>
</tr>
</table>

</div>

#finalizacion
{
display: none;
width: 400px;
top: 100px;
left: 200px;
position: absolute;
background-color: White;
border: 2px gray solid;
padding: 15px;
}

Para crear un efecto de ventana modal, sólo se debe insertar el DIV dentro de otro
con algún identificador, por ejemplo, ventanaModal:

<div id=”ventanaModal”>
<div id=”finalizacion”>

</div>
</div>

Agregar el siguiente código al CSS

#ventanaModal
{
visibility: hidden;
position: absolute;
left: 0px;
top: 0px;
width:100%;

332
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 333

AJAX. Web 2.0 para profesionales

height:100%;
text-align:center;
z-index: 1000;
background-image:url(fondo_modal.gif);
}

#ventanaModal div
{
width:300px;
margin: 100px auto;
background-color: #fff;
border:1px solid #000;
padding:15px;
text-align:center;
}

Para que funcione bien en Internet Explorer, es necesario definirle a body la si-
guiente propiedad CSS:

height:100%;

Mediante un GIF o un PNG transparente (fondomodal.gif) aplicado como fondo


de la ventanaModal es posible dar un efecto de grisado sobre todo el fondo, para que
el usuario comprenda que primero debe cerrar la ventana modal. Este fondo tendrá un
tramado transparente. Ahora cuando se desee colocar la ventana sólo se deberá hacer
visible ventanaModal (figs. 8-22 y 8-23).
La función finalizar queda:

// Muestra el formulario de Finalización de Compra


function finalizar() {
$(”ventanaModal”).style.visibility=”visible”;
}

Luego queda la función de cancelar, que sólo quita el formulario:

// Cancela el envío de la compra


function cancelar() {
$(”ventanaModal”).style.visibility=”hidden”;
}

333
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 334

Maximiliano R. Firtman

Fig. 8-22. Con un tramado transparente se puede lograr el efecto de la ventana modal.

Por último se encuentra la función que recolecta toda la información y la envía al


servidor. Dejamos en el lector las validaciones pertinentes.

// Envía toda la información del pedido


function enviar() {
// TODO: Validaciones
// Armamos un string de tipo QueryString con los datos personales
var parametros = ””;
parametros += ”nomyape=” + $F(”txtNombre”);
parametros += ”&direccion=” + $F(”txtDireccion”);
parametros += ”&telefono=” + $F(”txtTelefono”);

// Recorremos todo el canasto y armamos un string con los ID y


las cantidades
var strCarrito = ””;

334
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 335

AJAX. Web 2.0 para profesionales

Fig. 8-23. Se observa la ventana modal. Nótese que todo el fondo está apagado y no puede utilizarse
hasta tanto se cierre la ventana.

for (var i=0; i<canasto.length; i++) {


strCarrito += canasto[i].id;
// Para separar ID de Cantidad usamos un guion
strCarrito += ”-”;
strCarrito += canasto[i].cantidad;
// Usamos punto para separar productos
strCarrito += ”.”;
}
// Eliminamos último pipe
strCarrito = strCarrito.substring(0, strCarrito.length-1);
parametros += ”&carrito=” + strCarrito;

$Ajax(”enviar.aspx”, {
metodo: $metodo.POST,
parametros: parametros,

335
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 336

Maximiliano R. Firtman

avisoCargando: ”cargando”,
onfinish: function() {
alert(“Su pedido ha sido guardado”);
cancelar();
vaciar();
}
});
}

Enviar.ASPX guarda el pedido en la base de datos. Éste tiene el código VisualBa-


sic.NET siguiente:

<%@ Page Language=”VB” %>


<%@ Import Namespace=”System.Data.SqlClient” %>
<script runat=”server”>

Protected Sub Page_Load(ByVal sender As Object, ByVal e As Sys-


tem.EventArgs)
‘Faltan las Validaciones
Dim nombre As String = Request.Form(”nomyape”)
Dim direccion As String = Request.Form(”direccion”)
Dim telefono As String = Request.Form(”telefono”)

Dim sql As New SqlCommand


‘SELECT @@IDENTITY nos devuelve el último ID autonumérico
insertado
sql.CommandText = ”INSERT INTO PEDIDOS (Fecha, Finalizado,
NombreApellido, Telefono, Direccion) VALUES (@Fecha, @Finalizado,
@NombreApellido, @Telefono, @Direccion); SELECT @@IDENTITY”
With sql.Parameters
.AddWithValue(”@Fecha”, Date.Today())
If Request.Form(”temporal”) Is Nothing Then
.AddWithValue(”@Finalizado”, True)
Else
.AddWithValue(”@Finalizado”, True)
End If
.AddWithValue(”@NombreApellido”, nombre)
.AddWithValue(”@Direccion”, direccion)
.AddWithValue(”@Telefono”, telefono)
End With
‘Ejecuto un escalar para retener el ID insertado
Dim id As Integer = BD.ExecuteScalar(sql)

‘Proceso el canasto de compras


Dim canasto As String = Request.Form(”carrito”)

336
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 337

AJAX. Web 2.0 para profesionales

‘Genero un vector de Productos desde el string


Dim vecProductos As String()
vecProductos = canasto.Split(”.”)
For Each producto As String In vecProductos
‘Separo cada producto de su cantidad
Dim vecAux As String()
vecAux = producto.Split(”-”)
Dim idProducto As Integer = Integer.Parse(vecAux(0))
Dim cantidad As Integer = Integer.Parse(vecAux(1))

‘Inserto el registro en la tabla detalle


sql = New SqlCommand
sql.CommandText = ”INSERT INTO PRODUCTOSxPEDIDO (IdPro-
ducto, IdPedido, Cantidad) VALUES (@IdProducto, @IdPedido, @Canti-
dad)“
With sql.Parameters
.AddWithValue(”@IdProducto”, idProducto)
.AddWithValue(”@IdPedido”, id)
.AddWithValue(”@Cantidad”, cantidad)
End With
BD.ExecuteNonQuery(sql)

Next

End Sub
</script>

Guardado automático

Un servicio interesante que se le puede brindar al usuario es guardarle automática-


mente el canasto de compras para futuros ingresos o ante el caso de que se le cierre
el navegador o se le cuelgue la aplicación AJAX. De esta forma, la próxima vez que ini-
cie el sistema se le podría avisar que tiene un canasto de compras guardado y ofrecer
si quiere recuperarlo.
Este proceso debería hacerse automáticamente desde el momento en que el
usuario agregue algo al canasto y, al cargar la página por primera vez, consultarle al ser-
vidor con otra petición si tiene un canasto guardado.
El canasto se puede guardar en:
• Una cookie, es un valor que queda almacenado en la computadora del usua-
rio. También es posible guardar el ID del pedido en una cookie. De esta ma-
nera el servidor buscaría un pedido no finalizado con ese ID.
• En sesión en el servidor. Se mantendría en memoria del servidor mientras dure
la sesión (por lo general hasta que pasen 20 minutos sin actividad).

337
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 338

Maximiliano R. Firtman

Para ello simplemente se genera una versión del finalizar que envíe también el pa-
rámetro POST temporal, y el ASPX ya tiene configurado que guarde que no está fina-
lizado cuando así sea. A esta función se la llama con un temporizador, por ejemplo,
cuando el canasto tiene algo (en el agregar):

// Variables globales
var autoguardado;

function agregar() {

if (autoguardado==undefined) {
autoguardado = setInterval(30000, ”autoguardado()”);
}
}

function quitar() {

if (canasto.length==0) {
// Me quedé sin productos
clearInterval(autoguardado);
}
}

function vaciar() {
clearInterval(autoguardado);
}

Código completo
Ya se analizaron todas las cuestiones relativas al sitio de comercio electrónico. Dado
que se fue modificando de a poco el proyecto con fines didácticos, véase cómo que-
daron el XHTML, el CSS y el JS en versión final.

index.html

<!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” />

338
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 339

AJAX. Web 2.0 para profesionales

<title>Comercio Electrónico con AJAX</title>


<link href=”estilos.css” type=”text/css” rel=”stylesheet” />
<script type=”text/javascript” src=”prototype.js”></script>
<script type=”text/javascript” src=”scriptaculous.js”></script>
<script type=”text/javascript” src=”AjaxLib.js”></script>
<script type=”text/javascript” src=”index.js”></script>
</head>

<body>

<div id=”menu”>
<div id=”menuOpciones”>
Navegar por Categorías:
<select id=”listaCategorias”>
</select>

Buscar:
<input type=”text” id=”textoBusqueda” />
<input type=”button” id=”btnBuscar” value=”Buscar” />
</div>
</div>

<div id=”contenedor”>
<div id=”canasto”>
<h2>Canasto de Compras</h2>
<div id=”listaCanasto”>
</div>
</div>
<div id=”resultados”>
<h2>Resultados de Búsqueda</h2>
<div id=”listaResultados”>
</div>
</div>
<div id=”detalle”>
<h2>Detalle de Resultados</h2>
<div id=”listaDetalle”>
</div>
</div>
</div>

<div id=”cargando”>Por favor espere...</div>


<div id=”ventanaModal”>
<div id=”finalizacion”>
<table width=”100%”>
<tr>
<td>Nombre y Apellido</td>
<td><input type=”text” id=”txtNombre” /></td>
</tr>
<tr>
<td>Telefono</td>
<td><input type=”text” id=”txtTelefono” /></td>

339
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 340

Maximiliano R. Firtman

</tr>
<tr>
<td>Direccion</td>
<td><input type=”text” id=”txtDireccion” /></td>
</tr>
<tr>
<td></td>
<td>
<input type=”button” id=”btnCancelar”
value=”Cancelar” onclick=”cancelar()” />
<input type=”button” id=”btnEnviar”
value=”Enviar” onclick=”enviar()” />
</td>
</tr>
</table>

</div>
</div>

</body>
</html>

estilos.css

* {
font-family:Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
padding: 0px;
margin: 0px;
}

#menu {
width: 100%;
background-color:#CCFF99;
height: 70px;
}

#menuOpciones {
height: 70px;
vertical-align: middle;
padding: 20px;
font-size: larger;
}

#listaCategorias {
margin-right: 20px;

340
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 341

AJAX. Web 2.0 para profesionales

#contenedor h2 {
padding: 10px;
font-size: larger;
}

#listaCanasto, #listaResultados, #listaDetalle {


padding: 15px;
/*overflow: auto;*/
height: 60%;
}

#resultados {
width: 69%;
background-color: #FFCCCC;
height: 200px;
float: left;
}

#detalle {
width: 69%;
background-color: #EEEEEE;
height: 200px;
float: left;
}

#canasto {
float: right;
width: 30%;
background-color:#0033CC;
color: white;
height: 400px;
}

#cargando {
position: absolute;
top: 10px;
right: 50px;
background-color: red;
color: white;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
}

.productoResultado {
width: 470px;
padding: 4px;
margin: 2px;

341
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 342

Maximiliano R. Firtman

background-color: White;
font-size: large;
height: 15px;
}

.productoResultado:hover
{
background-color: #EEEEEE;
}

.nombreProducto {
width: 300px;
float: left;
cursor: pointer;
}

.precioProducto {
width: 70px;
font-weight: bold;
text-align: right;
float: left;
}

.agregarProducto
{
width: 70px;
font-weight: bold;
cursor: pointer;
color: Purple;
float: right;
text-align: right;
}

.agregarProducto:hover
{
width: 20%;
font-weight: bold;
color: Red;
}

.detalleNombre
{
font-size: 19px;
font-weight: bold;
color: Blue;
}

.detalleAgregar
{
float: right;
}

342
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 343

AJAX. Web 2.0 para profesionales

.detalleDescripcion
{
font-style: italic;
color: Gray;
}

.detallePrecio
{
font-size: 15px;
padding: 15px;
}

.detalleCategoria
{
color: red
}

.detalleFoto
{
float: left;
padding: 5px;
top: 0px;
max-height: 110px;
}

.filaCanasto
{
background: #000099;
margin: 1px;
padding: 2px;
}

.totalCanasto
{
background: #990000;
font-weight: bold;
font-size: large;
}

.canastoNombre
{
width: 110px;
}

.canastoPrecio
{
width: 40px;
text-align: right
}

343
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 344

Maximiliano R. Firtman

.canastoCantidad
{
width: 70px;
text-align: right
}

.canastoQuitar
{
color: White;
font-size:smaller;
text-align: right;
padding-left: 2px;
}

#btnFinalizar
{
margin-top: 15px;
font-size: larger;
background-color: White;
}

#finalizacion
{
width: 400px;
background-color: White;
border: 2px gray solid;
padding: 15px;
}

#ventanaModal
{
visibility: hidden;
position: absolute;
left: 0px;
top: 0px;
width:100%;
height:100%;
text-align:center;
z-index: 1000;
background-image:url(fondo_modal.gif);
}

#ventanaModal div
{
margin: 100px auto;
}

body
{
height: 100%;
}

344
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 345

AJAX. Web 2.0 para profesionales

index.js

window.onload = function() {
$Ajax(”categorias.aspx”, {
onfinish: cargarCategorias,
tipoRespuesta: $tipo.JSON,
onerror: function(e) { alert(e) }
});

$(”btnBuscar”).onclick = enviarBusqueda;
$(”listaCategorias”).onchange = buscarCategoria;

// Define el Droppable
Droppables.add(”listaCanasto”, {
onDrop: sueltaProducto,
accept: [”productoResultado”, ”detalleFoto”]
});
}

function cargarCategorias(lista) {
// Itero entre cada categoría recibida
for (var i=0; i<lista.length; i++) {
var cat = lista[i];
// Agrego la categoría a la lista de Opciones
var opc = new Option(cat.nombre, cat.id);
$(”listaCategorias”).options[$(”listaCategorias”).length] = opc;
};

// Cargo los productos de la primera categoría


buscarCategoria();
}

function enviarBusqueda() {
$Ajax(”buscar.aspx?buscar=” + $F(”textoBusqueda”), {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON,
divCargando: ”cargando”
});
}

function buscarCategoria() {
$Ajax(”categoria.aspx?id=” + $F(”listaCategorias”), {
onfinish: cargarResultados,
tipoRespuesta: $tipo.JSON,
divCargando: ”cargando”
});
}

var listaResultados;

345
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 346

Maximiliano R. Firtman

function cargarResultados(lista) {
// Apago el cartel de Loading
$(”cargando”).hide();

// Guardo la lista en una variable global


// para posible uso futuro
listaResultados = lista;

// Limpio la lista de resultados vieja


$(”listaResultados”).innerHTML = ””;

// Itero entre los resultados


for (var i=0; i<lista.length; i++) {
agregarResultado(lista[i]);
}
}

var cacheProductos = [];

function agregarResultado(producto) {
var div = document.createElement(”div”);
div.className = ’productoResultado’;
div.id = ’producto’ + producto.id;
div.innerHTML += ” <div class=’nombreProducto’ onclick=’detalle(”
+ producto.id + ”)’ >” + producto.nombre + ”</div>”;
div.innerHTML += ” <div class=’precioProducto’>$ ” +
producto.precio + ”</div>”;
div.innerHTML += ” <div class=’agregarProducto’ onclick=’agre-
gar(” + producto.id + ”)’>Agregar</div>”;
$(”listaResultados”).appendChild(div);
// Agregamos el producto al hash
cacheProductos[producto.id] = {
nombre: producto.nombre,
precio: producto.precio,
// Definimos al producto como Draggable
drag: new Draggable(”producto” + producto.id, {revert:true})
}
}

function detalle(id) {
// Tengo que ir a buscar al servidor los detalles del producto
$Ajax(”producto.aspx?id=” + id, {
onfinish: mostrarDetalle,
tipoRespuesta: $tipo.JSON,
avisoCargando: ”cargando”,
cache: true
});
}

function mostrarDetalle(producto) {
// Creo el contenido de la zona de Detalle

346
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 347

AJAX. Web 2.0 para profesionales

var html = ”<div class=’detalleNombre’>” + producto.nombre +


”</div>”;
if (producto.foto!= ””) {
// Si tiene foto, la incluimos
html += ”<img src=’fotos/” + producto.foto + ” ’ class=’deta-
lleFoto’ ”
+ ”id=’foto” + producto.id + ” ’ />”;
}
html += ”<input type=’button’ class=’detalleAgregar’ value=’Agre-
gar al Canasto’ ”
+ ”onclick=’agregar(” + producto.id + ”)’ />”;
html += ”<div class=’detalleCategoria’>Categoría: ” +
producto.categoria + ”</div>”;
html += ”<div class=’detallePrecio’>Precio: $” + producto.precio+
”</div>”;
html += ”<div class=’detalleDescripcion’>q” + producto.descrip-
cion + ”</div>”;
$(”listaDetalle”).innerHTML = html;

new Draggable(”foto” + producto.id, {revert:true});


}

// Vector global del canasto de compras


var canasto = [];

// Agrega un producto al canasto de compras


function agregar(id) {
// Primero buscamos si el producto ya estaba en el canasto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
} else {
i++;
}
}

if (encontrado) {
// El producto ya estaba en el canasto, sólo aumentamos
// su cantidad. ”i” tiene la posición actual
canasto[i].cantidad++;
} else {
// El producto no estaba en el canasto, lo agregamos
// obtenemos los datos del producto desde el hash global
var producto = cacheProductos[id];
nuevoProducto = {
’id’: id,
’nombre’: producto.nombre,
’precio’: producto.precio,

347
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 348

Maximiliano R. Firtman

’cantidad’: 1
};

canasto[canasto.length] = nuevoProducto;
}
// Llama a la función que dibuja el canasto
actualizarCanasto();
}

// Dibuja el canasto en la zona especificada


function actualizarCanasto() {
// Primero creamos la lista de productos
var contenido = ””;
if (canasto.length==0) {
contenido = ”El canasto está vacío. <br />”;
} else {
var filaCanasto;
var total = 0;
for (var i=0; i<canasto.length; i++) {
// Creo una fila por cada producto
filaCanasto = ”<div class=’filaCanasto’ ”;
filaCanasto += ” id=’canasto_” + canasto[i].id + ” ’>”;
// Armamos cada fila con una tabla
var tablaCanasto;
tablaCanasto = ”<table width=’100%’><tr>”;
tablaCanasto += ”<td class=’canastoNombre’>” +
canasto[i].nombre + ”</td>”;
tablaCanasto += ”<td class=’canastoCantidad’> ” + ca-
nasto[i].cantidad
+ ”<img src=’flechadown.gif’ onclick=’bajar(” + ca-
nasto[i].id + ”)’ />”
+ ”<img src=’flechaup.gif’ onclick=’subir(” + ca-
nasto[i].id + ”)’ /></td>”;
tablaCanasto += ”<td class=’canastoPrecio’>$” +
canasto[i].cantidad*canasto[i].precio + ”</td>”;
tablaCanasto += ”<td><a href=’javascript:quitar(” + ca-
nasto[i].id
+ ”)’ class=’canastoQuitar’>Quitar</a></td>”;
tablaCanasto += ”</tr></table>”;
filaCanasto += tablaCanasto + ”</div>”;
contenido += filaCanasto;
total += canasto[i].precio * canasto[i].cantidad;
}
// Mostramos el TOTAL
contenido += generarFilaTotal(total);

// Agregamos el botón para Finalizar la Compra


contenido += ”<input type=’button’ id=’btnFinalizar’
value=’Finalizar Compra’ />”;
}
$(”listaCanasto”).innerHTML = contenido;

348
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 349

AJAX. Web 2.0 para profesionales

// Agrego todas las filas como Draggables


for (var i=0; i<canasto.length; i++) {
new Draggable(”canasto_” + canasto[i].id, {revert:true});
}

// Creamos el bote de basura


var bote = document.createElement(“img”);
bote.src = ”basura.png”;
bote.width = ”100”;
bote.height = ”100”;
bote.id = ”basura”
$(”listaCanasto”).appendChild(bote);
// Creo la zona de Drop con el bote
Droppables.add(”basura”, {
accept: ’filaCanasto’,
onDrop: tiraProducto
});

$(”btnFinalizar”).onclick = finalizar;
}

function generarFilaTotal(total) {
var filaCanasto = ”<div class=’totalCanasto’> ”;
var tablaCanasto;
tablaCanasto = ”<table width=’100%’><tr>”;
tablaCanasto += ”<td class=’canastoNombre’>TOTAL</td>”;
tablaCanasto += ”<td class=’canastoCantidad’></td>”;
tablaCanasto += ”<td class=’canastoPrecio’>$” + total+ ”</td>”;
tablaCanasto += ”<td><a href=’javascript:vaciar()’ class=’canas-
toQuitar’>Vaciar</a></td>”;
tablaCanasto += ”</tr></table>”;
filaCanasto += tablaCanasto + ”</div>”;
return filaCanasto;
}

// Quita un producto del canasto


function quitar(id) {
// Primero buscamos el producto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
// Lo eliminamos de la lista con Prototype
canasto = canasto.without(canasto[i]);
} else {
i++;
}
}

349
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 350

Maximiliano R. Firtman

actualizarCanasto();
}

// Vacía todo el canasto


function vaciar() {
canasto = [];
actualizarCanasto();
}

// Sube la cantidad de un producto del canasto


function subir(id) {
// Primero buscamos el producto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
// Lo eliminamos de la lista con Prototype
canasto[i].cantidad++;
} else {
i++;
}
}
actualizarCanasto();
}

// Baja la cantidad de un producto del canasto


function bajar(id) {
// Primero buscamos el producto
var i=0;
var encontrado = false;
while ((i<canasto.length) && (!encontrado)) {
if (canasto[i].id == id) {
encontrado = true;
// Lo eliminamos de la lista con Prototype
canasto[i].cantidad—;
// Si quedó en cero, quitamos el producto
if (canasto[i].cantidad==0) {
quitar(id);
}
} else {
i++;
}
}
actualizarCanasto();
}

// Se ejecuta cuando el usuario suelta un producto en el canasto


function sueltaProducto(drag, drop, evento) {
var id;
if (drag.id.substring(0, 8)==”producto”) {

350
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 351

AJAX. Web 2.0 para profesionales

// Obtenemos el ID, es productoXXX


id = drag.id.substring(8, drag.id.length);
} else {
// Obtenemos el ID, es fotoXXX
id = drag.id.substring(4, drag.id.length);
}
// Agregamos el producto al canasto
agregar(id);
}

function tiraProducto(drag, drop, evento) {


var id = drag.id.substring(8, drag.id.length);
quitar(id);
}

// Muestra el formulario de Finalización de Compra


function finalizar() {
$(”ventanaModal”).style.visibility=”visible”;
}

// Cancela el envío de la compra


function cancelar() {
$(”ventanaModal”).style.visibility=”hidden”;
}

// Envía toda la información del pedido


function enviar() {
// TODO: Validaciones
// Armamos un string de tipo QueryString con los datos personales
var parametros = ””;
parametros += ”nomyape=” + $F(”txtNombre”);
parametros += ”&direccion=” + $F(”txtDireccion”);
parametros += ”&telefono=” + $F(”txtTelefono”);

// Recorremos todo el canasto y armamos un string con los ID y


las cantidades
var strCarrito = ””;
for (var i=0; i<canasto.length; i++) {
strCarrito += canasto[i].id;
// Para separar ID de Cantidad usamos guion
strCarrito += ”-”;
strCarrito += canasto[i].cantidad;
// Usamos punto para separar productos
strCarrito += ”.”;
}
// Eliminamos último pipe
strCarrito = strCarrito.substring(0, strCarrito.length-1);
parametros += ”&carrito=” + strCarrito;

$Ajax(”enviar.aspx”, {
metodo: $metodo.POST,

351
C08.qxd:Project Ajax4.1.qxd 10/18/07 8:17 PM Página 352

Maximiliano R. Firtman

parametros: parametros,
avisoCargando: ”cargando”,
onfinish: function() {
alert(”Su pedido ha sido guardado”);
cancelar();
vaciar();
}
});
}

Entre las técnicas avanzadas que se verán en el capítulo 9 se podrá tener un manejo del histo-
rial del navegador web, la compresión y el ocultamiento del código JavaScript y la creación de apli-
caciones que puedan funcionar de manera desconectada de Internet.

352
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 353

AJAX avanzado
9
Técnicas
Historial

Uno de los grandes problemas que tenían las aplicaciones AJAX era el uso del botón
Atrás del navegador web. Como recordamos, una aplicación rica de Internet completa
mantiene una sola dirección web, o URL, y si se presiona el botón Atrás se estaría sa-
liendo de la aplicación web.
No hay un método oficial de los navegadores para capturar el botón de atrás de
los browsers, aunque es posible hacerlo mediante una técnica utilizando IFRAME. Sin
entrar en demasiados detalles técnicos sobre su funcionamiento, la idea es que al tener
un IFRAME oculto, cuando el IFRAME cambie su URL se generará una nueva posición
en el historial del navegador y entonces al presionar Atrás no se estaría escapando de
la aplicación Ajax.
Existen varias librerías que permiten aprovechar esta técnica, aunque la más co-
nocida y utilizada es Really Simple History (Historial realmente simple) o RSH. La do-
cumentación, los ejemplos y la librería entera están disponibles en forma gratuita en el
sitio web http://codinginparadise.org/projects/dhtml_history/README.html.
Es un proyecto de Brad Neuberg, conocido por su blog en temas de AJAX Co-
dingInParadise.
La librería permite que los desarrolladores AJAX incorporen con facilidad funcio-
nes de administración de historial de navegación por medio del botón Atrás, y, además,
facilita el uso de favoritos y el intercambio de links. Asimismo, provee un mecanismo
por el cual almacenar información sobre el estado de la aplicación en un momento
dado, muy útil para implementar el patrón de diseño Memento.

353
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 354

Maximiliano R. Firtman

RSH está probado y funcionando en Internet Explorer 6 o superior, así como en


los sistemas basados en el motor Gecko (como Firefox). La librería consta de un solo
archivo JavaScript dhtmlHistory.js que provee a JavaScript de dos objetos globales:
dhtmlHistory y historyStorage.

Pasos a seguir
Como enuncia el manual de la librería, los pasos a seguir para utilizarla son:
1. Inicializar el objeto dhtmlHistory mediante el método initialize(). Esto sólo se
puede hacer en el window.onload, cuando toda la página está cargada.
2. Registrar una función de JavaScript (handler) que será notificada cuando el
usuario presione los botones Atrás o Adelante, o utilice alguna combinación
de teclas que active cambios en el Historial.
3. Determinar, al iniciar la aplicación, en qué estado se inicia y registrar ese es-
tado.
4. Cuando se considera que es necesario crear una nueva entrada en el histo-
rial, se lo hace por medio del método add del dhtmlHistory.
5. Cuando el usuario active alguna opción de cambio en el historial, se ejecutará
la función handler mencionada antes.

La gran decisión es cuándo generar una nueva entrada en el historial en una apli-
cación AJAX, como si fuera un hito en la navegación y el uso del usuario. Algunos ejem-
plos:
• En un sitio web normal, pero AJAX, cada nueva sección o página que el usua-
rio ve debería ser una nueva entrada en el historial.
• En un comercio electrónico, cuando el usuario hace una búsqueda, elije una
categoría que debería ser una nueva entrada. También cuando agrega un
nuevo producto al canasto de compras. De esta forma, cuando presiona para
atrás equivaldría a un deshacer.
• En un administrador, cuando el usuario ingresa a editar cada uno de los regis-
tros debería generarse una nueva entrada.
• En un visor de fotos, cada foto es una nueva entrada.

De todas formas, no todo es mágico con la librería. Cuando el usuario vuelve hacia
atrás, la librería por sí sola no vuelve a la aplicación al estado anterior (y está muy bien
que no lo haga). Somos nosotros los que, según ciertos parámetros que podemos al-
macenar, debemos reestructurar todo el DOM para que la aplicación se vea como se
veía antes de generar la nueva entrada en el historial.
Cada entrada nueva en el historial debe llevar un nombre identificatorio, por ejem-
plo: lista, agrega, edit:123, quienes_somos, etc.

354
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 355

AJAX. Web 2.0 para profesionales

Métodos
El objeto dhtmlHistory posee los eventos siguientes:

Método Descripción

initialize() Debe ser invocado en el window.onload para comenzar a hacer uso


del objeto.

addListener(funcion) Incorpora una función handler que recibirá la ejecución cuando el


usuario cambie el estado de la aplicación (Atrás o Adelante).

getCurrentLocation() Devuelve la ubicación actual del usuario dentro de nuestro esquema


de navegación interno. Si no hay una ubicación definida, devuelve null.
add(nombre, metadatos) Agrega una entrada nueva en el historial con el nombre especificado.
Como opción, se puede enviar metadata (que puede ser un string o un
objeto) para recuperarla en caso que se vuelva a la entrada en el futuro.

La idea de los metadatos es poder almacenar información sobre el estado de la


aplicación para que luego sea recuperada por la función handler cuando el usuario
vuelva para atrás. En el caso de un comercio electrónico, se podría almacenar qué pro-
ducto estaba viendo el usuario y el estado del canasto completo en ese momento.
Cada vez que se agrega una entrada nueva al historial, automáticamente RSH
agrega a la URL el nombre de la nueva entrada luego de un símbolo numeral. Por ejem-
plo:
Misitio.html#nueva_entrada

esto permite que se pueda leer ese valor (con el método getCurrentLocation) y co-
menzar la aplicación en ese estado al iniciar. Si el usuario envía a un amigo la URL
completa o la incorpora a favoritos, entonces al volver se le puede mostrar la misma
sección que antes veía.

Ejemplo
Si se vuelve al ejemplo analizado en el capítulo 5, en el que había un clásico sitio web
con secciones estáticas que se leían en forma asincrónica con AJAX, se le puede agre-
gar el soporte del botón Atrás del navegador de forma sencilla.
Primero se descarga el dhtmlHistory.js del sitio web de la librería y se lo incluye en
el HTML:

<script type=”text/javascript” src=”dhtmlHistory.js”></script>

355
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 356

Maximiliano R. Firtman

Recuérdese el código con el que se contaba originalmente.

window.onload = function() {
crearLinks();
}

function crearLinks() {
// Recorro todos los H3 dentro de la Sidebar1
var opciones = $$(”#sidebar1 h3”);
opciones.each(function(opcion) {
// Genero la acción del clic por cada uno
opcion.onclick = function() {
// utilizo el id de cada h3 como nombre de sección
mostrarSeccion(opcion.id);
}
})
}

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
$(”mainContent”).innerHTML = html;
}
});
}

Sigamos los pasos vistos antes.


1. Inicializar el objeto.

window.onload = function() {
crearLinks();
dhtmlHistory.initialize();
}

2. Registrar una función handler para cuando el usuario vaya para Atrás o para
Adelante.

window.onload = function() {
crearLinks();
dhtmlHistory.initialize();
dhtmlHistory.addListener(cambioHistorial);
}

356
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 357

AJAX. Web 2.0 para profesionales

3. Determinar el estado inicial de la aplicación.

window.onload = function() {
crearLinks();
dhtmlHistory.initialize();
dhtmlHistory.addListener(cambioHistorial);
// Verifica si viene de un favorito o link pidiendo una sección
específica
var seccion = dhtmlHistory.getCurrentLocation();
if (seccion!=null) {
// Ya inicio en la sección deseada
mostrarSeccion(seccion);
}
}

4. Cuando se considere necesario crear una nueva entrada, hacerlo por medio
del objeto dhtmlHistory.

function mostrarSeccion(nombre) {
$Ajax(nombre + ”.html”, {
cache: true,
onfinish: function(html) {
$(”mainContent”).innerHTML = html;
}
});
// Agrego la nueva sección al historial
dhtmlHistory.add(nombre);
}

5. Definir la función handler que se ejecutará cuando el usuario utilice el botón


atrás.

function cambioHistorial(nuevaSeccion, metadatos) {


// En nuevaSeccion ya tenemos el nombre
// de la sección donde hay que ir
mostrarSeccion(nuevaSeccion);
}

En el método add se podría haber guardado algún valor (String, número, o un ob-
jeto JSON) que luego se recibiría al volver para atrás por la función cambioHistorial
como el segundo parámetro metadatos.
Ahora el usuario ya puede navegar por todo el sitio y utilizar el botón Atrás como
está acostumbrado a hacerlo en un sitio no AJAX.

357
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 358

Maximiliano R. Firtman

Almacenando en el cliente

Como se vio a lo largo del libro, una aplicación AJAX almacena mucha información en
el cliente, en general como variables u objetos globales. Se almacenan cachés, vecto-
res, objetos, canastos de compras y mucha información adicional. No obstante, hay un
gran problema…, ¿qué sucede con esa información cuando el usuario sale de la apli-
cación AJAX? Recuérdese que el usuario sale de la aplicación cuando cierra el nave-
gador o cambia de URL.

Cambio de URL
Imagínese que el usuario está en nuestra aplicación AJAX navegando hace rato y posee
mucha información almacenada. Sin darse cuenta cambia la URL del navegador web;
por lo tanto, la página deja de estar en escena y se pierden todos sus datos. Si bien el
usuario puede volver para Atrás hacia nuestra aplicación, las variables igual se per-
dieron y se inicia la aplicación como si se cargara de cero.
La librería RSH, vista antes para el manejo del historial, posee un objeto llamado
historyStorage. Este objeto es un almacén de tipo hash (con clave alfanumérica) que
permite guardar variables y objetos en memoria aunque el usuario cambie de URL y
vuelva después. Tómese en cuenta que si el usuario abre una nueva sesión del nave-
gador o la cierra, estos datos se perderán. Sólo sirven para la propia ventana del na-
vegador.
Para utilizarlo se debe inicializar el dhtmlHistory como se había hecho en el ejer-
cicio anterior.
El objeto tiene los métodos siguientes:

Método Descripción

hasKey(clave) Indica si el almacén posee valores para la clave indicada.

put(clave, valor) Agrega un valor (simple u objeto) al almacén para recuperarlo luego.

get(clave) Devuelve el valor almacenado con anterioridad para la clave indicada.

Datos a futuro
Si lo que se desea almacenar es información para lectura futura, ya sea luego que el
usuario cierre el navegador o incluso en días ulteriores, hay varias opciones:
• Almacenar en el servidor, en sesión o base de datos.
• Almacenar en una cookie.

358
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 359

AJAX. Web 2.0 para profesionales

El primero de los casos ya se analizó en ejercicios anteriores. Desde JavaScript es


posible almacenar en una cookie. Ésta es un valor que se almacena en el equipo del
usuario y sólo está disponible para scripts que sean del mismo dominio que el que los
genera.
Las cookies se almacenan por un tiempo que se puede prefijar, aunque es posi-
ble que el usuario borre estas cookies con frecuencia, por lo que nunca se tiene segu-
ridad de que el valor no se haya borrado.
Para guardar una cookie se puede utilizar la función JavaScript siguiente:

function setCookie(nombre, valor, diasQueExpira)


{
var fecha=new Date()
fecha.setDate(fecha.getDate()+diasQueExpira)
document.cookie=nombre + ”=” +escape(valor)+
((diasQueExpira==null) ? ”” : ”;expires=”+fecha.toGMTString())
}

Por ejemplo, se puede guardar un valor por un año:

setCookie(”usuario”, ”itmaster”, 365);

Y luego se lo lee con getCookie:

function getCookie(nombre) {
if (document.cookie.length>0) {
var comienzo=document.cookie.indexOf(nombre + ”=”)
if (comienzo != -1) {
comienzo += comienzo.length+1
var fin=document.cookie.indexOf(”;”,comienzo)
if (fin == -1) fin =document.cookie.length
return unescape( document.cookie.substring(comienzo, fin))
}
}
return undefined;
}

Recuérdese que las cookies pueden ser eliminadas por el usuario o el navegador,
y no hay garantías de que sigan existiendo.

359
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 360

Maximiliano R. Firtman

Datos masivos
Las cookies tienen una gran desventaja: siempre y cuando sigan existiendo cuando se
desea leerlas, no se pueden guardar más de 2 Kb en ellas para tener compatibilidad
con todos los navegadores.
Para resolver este inconveniente había surgido una librería llamada AMASS (Ajax
Massive Storage System), que ahora forma parte de la librería Dojo, conocida como
Dojo.Storage.
Esta librería utiliza internamente un archivo de Adobe Flash (extensión SWF) y, por
medio de ese archivo, utiliza el sistema de almacenamiento que tiene el Flash Player.
Este sistema permite almacenar en el cliente hasta 100 Kb sin que el usuario dé su
consentimiento. Tiene la ventaja de que si el usuario elimina las cookies, no desecha
esta información, que sólo se elimina si se desinstala o se configura el Adobe Flash Pla-
yer. Cuando el browser lo soporta (como Firefox 2) puede llegar a reemplazar el uso del
Flash invisible por alguna técnica propia del navegador.
Pasados los 100 Kb, el sistema le pide autorización al usuario para almacenar la
información. Los creadores de la librería afirman que almacenaron más de 10 Mb de
información sin inconvenientes bajo este esquema.
El uso es muy similar al del historyStorage del RSH, como un almacén de tipo
hash. Por ejemplo:

// Previamente debemos inicializar el objeto

// Almaceno un objeto
dojo.storage.put(”objeto”, objetoGrande);

// Leo el objeto
var objetoGrande = dojo.storage.get(”objeto”);

Para ver documentación, ejemplos y/o descargar la librería Dojo, se puede visitar
el sitio web dojotoolkit.org y el manual en http://manual.dojotoolkit.org/WikiHome/Do-
joDotBook/Book50.

No esperemos las imágenes

Hasta ahora siempre se había trabajado con el famoso evento window.onload para eje-
cutar acciones cuando la página se cargara. Ahora bien, ¿cuándo se ejecuta realmente
este evento? En principio, cuando toda la página se carga, incluidos todos los archi-
vos JavaScript, el CSS y las imágenes. No obstante, es posible que se desee ejecutar
código sin importar si ya se cargaron las imágenes o no. Si no es necesario que estén
las imágenes o los JavaScripts, entonces se puede aprovechar el tiempo en que se

360
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 361

AJAX. Web 2.0 para profesionales

están descargando para realizar alguna función y así la página tardará menos en di-
bujarse.
Para resolver este problema, se puede recurrir a crear un evento ondomload, que
se ejecutaría cuando toda la estructura del documento DOM ya está cargada y se
puede trabajar sobre ella, sin importar el estado de la descarga de imágenes. Por ejem-
plo, ya se pueden crear elementos en el DOM o cambiarle propiedades. Si se desea tra-
tar con algún elemento presente en el DOM es preciso verificar si ya existe.
Es factible implementarlo por nuestra cuenta o utilizar alguna librería que ya solu-
cione el inconveniente.
En el sitio web brothercake.com/site/resources/scripts/domready se puede des-
cargar la librería DomReady, que es compatible con la mayoría de los navegadores del
mercado.
Para utilizarla, sólo se incluye el JavaScript en el XHTML:

<script type=”text/javascript” src=”domFunction.js”></script>

Para utilizarlo, creamos nuestra función donde reside el código por ejecutar:

function ejecutaAlInicio() {

Y luego la agregamos con el siguiente código:

new domFunction(ejecutaAlInicio);

La librería también permite recibir un segundo parámetro estilo JSON con una de
las siguientes opciones o más:
1. Un ID de un elemento con el valor id.
2. El nombre de una etiqueta con el valor tag.

En este caso, la función ejecutaAlInicio se llevará a cabo cuando se tenga com-


pleta seguridad de que existen los elementos pedidos, por ejemplo:

new domFunction(ejecutaAlInicio, { btnEnviar: ’id’, h2: ’tag’ });

En este caso se ejecutaría cuando ya haya un elemento con identificador btnEn-


viar y al menos una etiqueta h2.

361
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 362

Maximiliano R. Firtman

Reproducir sonido

Si bien es factible reproducir sonido con XHTML, con el uso de librerías se puede re-
solver el problema de manera más sencilla. Script.aculo.us, desde la versión 1.7.1,
posee un objeto Sound que permite reproducir un sonido compatible con todos los
navegadores. Su sintaxis es la siguiente:

Sound.play(url_sonido, opciones);

Las opciones disponibles son: track, que especifica el contenedor bajo el cual se
agregará el elemento que reproduce el sonido, y replace, que si lo indicamos en true,
parará todos los otros sonidos que se están reproduciendo antes de comenzar con el
nuevo.

Comprimiendo y ocultando el código

Al comienzo del libro se comentó el uso de la documentación estándar y las ventajas


que aportaba realizar comentarios en el código fuente. El problema que se encontraba
era que si se dejaban comentarios en el código fuente se aumentaba el tamaño del ar-
chivo JavaScript por un lado y se entregaba información de más a usuarios que podrían
estar investigando cómo funciona nuestra aplicación AJAX.
Una primera solución que surge al problema es comprimir el código JavaScript.
Hay varias herramientas que permiten comprimir un código y así reducir la transferen-
cia y la carga del archivo.
Entre las técnicas simples que se utilizan para comprimir un código JavaScript se
incluyen:
• Eliminar todos los comentarios.
• Eliminar espacios innecesarios, por ejemplo:

if (posicion > 5)

se transforma en

if(posicion>5)

• Eliminar todos los saltos de línea. Para esto el punto y coma cumple las fun-
ciones de fin de línea (fig. 9-1).

362
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 363

AJAX. Web 2.0 para profesionales

Fig. 9-1. Código JavaScript comprimido. Se puede reducir hasta un 30% del tamaño final del código
con esta técnica simple.

La idea es que cuando se termina de codificar la aplicación y funciona de manera


correcta, se la puede comprimir con estas herramientas. Con cada cambio que se prac-
tique, habrá que volver a realizar el proceso.
Dado que JavaScript es un lenguaje interpretado y no se compila, uno de los gran-
des problemas de los desarrolladores de aplicaciones AJAX es que su código siempre
está disponible para todo el mundo que quiera verlo. No hay soluciones de fondo a este
problema, pero existen algunas técnicas para reducir el riesgo de robo de nuestro có-
digo.
La primera de ellas, y la más utilizada, es una técnica conocida como ofuscación
(obfuscation). Esta técnica implica complicar tanto el código que se vuelta práctica-
mente ilegible para cualquier usuario. Además de la compresión antes vista, la ofus-
cación implica:
• Cambiar el nombre de todas las variables (y el código que las utiliza) por nom-
bres al azar, por ejemplo A, GZ, _4, etcétera.
• Cambiar el nombre de todas las clases y las funciones (y el código que las in-
voca) por nombres al azar.

363
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 364

Maximiliano R. Firtman

Con estos dos pequeños cambios ya hay una gran reducción de tamaño, dado
que por reglas de la buena programación, los nombres de variables deben ser claros
y largos. Al cambiarlos por nombres de uno o dos caracteres, la reducción de tamaño
se aprecia con rapidez. Asimismo, se logra un ocultamiento de código, dado que se
torna muy difícil de entender qué hace el código cuando ninguna variable y ninguna
función dicen algo sobre lo que almacenan o hacen (fig. 9-2).

Fig. 9-2. Todas las soluciones AJAX de Google implementan algún tipo de ofuscación en sus códigos.

El código siguiente se extrajo de una aplicación AJAX de Google, ¿quién podría


indicar qué hace?

try{var y4=[],hk=B5||B6?”\u200b”:”<WBR>”,O4=B5||B6?new
RegExp(”\u200b”,”gi”):/<WBR>/gi;function bU(a){if(BR){return a.inner-
Text}else{var
b=a.firstChild;while(b){if(b.nodeType==3){break}b=b.nextSibling}re-
turn b==null?””:b.data}}function xV(a,b){function c(e){var
f=AS(e,b);if(f){Bd(f,false);Jd(e)}}c(a);if(vb&&a.name!=vb){var
d=N(vb);if(d){c(d)}}}function Hz(a,b,c){var d=AS(a,b);if(!d){var
e=G(a,a.document.body,”div”);e.innerHTML=”<iframe id=”+b+” name=”+b+”
src=”+c+”></iframe>”;d=Af(a,b)}return d}function fu(a,
22b){var c=a.document.createElement(”TR”);for(var
d=0;d<b.length;d++){c.appendChild(b[d])}return c}function Sn(a,b){var
c=a.document.createElement(”TD”);if(b){c.colSpan=b}return c}function
aU(a,b){var c=[];kv(a,b,c);return c}function kv(a,b,c){for(var
d=a.firstChild;d;d=d.nextSibling){if(b.select(d)){c.push(d)}kv(d,b,c)
}}function kA(){}kA.prototype.select=function(a){var
b=a.nodeName.toUpperCase();return b==”INPUT”||b==”TEXTAREA”||b==”SE-
LECT”};var OT=new kA;function Ul(a){return aU(a,OT)}function
NT(a){var b=
23[],c=Ul(a);for(var d=0;d<c.length;d++){var
e=c[d];if(e.type!=”radio”&&e.type!=”checkbox”||e.checked){b[b.length]
=Bz(e.name)+”=”+Bz(e.value)}}return b.join(”&”)}function
ad(a,b,c,d){return xE(a,Ec(b),c,d)}function jh(a,b,c,d){var
e=xE(a,b,c,d);if(e){e.opener=null}return e}function xE(a,b,c,d){var
e=wE(top,b,c,d);

364
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 365

AJAX. Web 2.0 para profesionales

Dojo ShrinkSafe
Si bien hay decenas de herramientas que comprimen código JavaScript, a veces se
torna complicado encontrar una gratuita y de buena calidad.
Dojo ShrinkSafe es una herramienta gratuita, parte del framework Dojo, que per-
mite comprimir un código JavaScript como último paso del proceso de desarrollo. Esta
herramienta está desarrollada en Java y requiere contar con el Java Runtime (JRE) ins-
talado en nuestro equipo para ejecutarlo.
Dojo ShrinkSafe no sólo comprime, sino que también realiza algunas técnicas co-
nocidas como ofuscación. Las técnicas que utiliza la herramienta, además de lo que
ya se describió, permiten cambiar el nombre de variables locales por nombres cortos
al azar para reducir su tamaño.
Con estas técnicas, la herramienta puede llegar a reducir un 55% del tamaño del
código, y lograr un equilibrio entre compresión y legibilidad del código. Por este mo-
tivo no elimina todos los espacios ni los saltos de línea, ni cambia los nombres de fun-
ciones o clases.
Por ejemplo, el siguiente código JavaScript:

function MyClass(){
this.foo = function(argument1, argument2){
var addedArgs = parseInt(argument1)+parseInt(argument2);
return addedArgs;
}

var anonymousInnerFunction = function(){


// algo de código aquí
}
}

function MyFunc(){
// función global
}

queda reducido al archivo que sigue:

function MyClass(){
this.foo=function(_1,_2){
var _3=parseInt(_1)+parseInt(_2);
return _3;
};
var _4=function(){
};
}
function MyFunc(){
}

365
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 366

Maximiliano R. Firtman

Para utilizar la herramienta, los pasos son los siguientes:


• Descargar el paquete de http://dojotoolkit.org/docs/shrinksafe
• Del paquete, descomprimir el archivo con extensión .jar
• Abrir el archivo .jar con el Java Runtime, descargable desde java.sun.com si no
está instalada la Java Virtual Machine en nuestro equipo Windows, Mac o
Linux
• Seleccionar el archivo JavaScript por comprimir.

También hay una versión web del compresor (fig. 9-3), que permite seleccionar el ar-
chivo JavaScript desde nuestro equipo y recibir la versión comprimida sin instalar aplica-
ción alguna en nuestro equipo. Esta versión se encuentra en alex.dojotoolkit.org/shrinksafe.

Fig. 9-3. Dojo ShrinkSafe también se puede utilizar en versión sobre la web.

Javascript Chaos Engine


La empresa Syntropy (www.syntropy.de) tiene una de las herramientas más potentes del
mercado, conocida como JavaScript Chaos Engine Obfuscator (JCE). La herramienta
tiene una versión gratuita con la funcionalidad básica, y distintas versiones comerciales
con agregados de optimización y herramientas de integración con entornos de trabajo.

366
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 367

AJAX. Web 2.0 para profesionales

La versión gratuita (Free edition) tiene las siguientes características:


• Ofuscación que elimina nombres de variables y funciones.
• Eliminación de saltos de línea.
• Eliminación de comentarios.
• Multiplataforma (funciona en cualquier sistema operativo que tenga una Java
Virtual Machine).
• Se puede usar en productos comerciales.
• Puede ser utilizado por múltiples usuarios.

Las versiones comerciales, de las que se puede descargar una versión de prueba
por 30 días (fig. 9-4), agregan las opciones siguientes:
• Ejecución por línea de comandos e integración con entornos de trabajo.
• Ofuscación de múltiples archivos a la vez.
• Generación de informes estadísticos.
• Codificación de los strings con caracteres de escape.
• Ofuscación de nombres CSS y de identificadores del HTML.
• Reconocimiento de código de servidor (ASP/PHP) embebido dentro del Ja-
vaScript sin interpretarlo.

Las características más sobresalientes de las versiones comerciales son el cam-


bio que hace en todos los ID de los elementos HTML y de los CSS para volverlos in-
comprensibles, y la codificación de strings. Esta última idea cambiaría el código
siguiente:

var t = ”Esto es un string que cualquiera lee, aun ofuscado en forma


normal”;

por el que sigue:

var t = ”
%45%73%74%6F%20%65%73%20%75%6E%20%73%74%72%69%6E%67%20%71%75%65%20%63
%75%61%6C%71%75%69%65%72%61%20%6C%65%65%2C%20%61%FA%6E%20%6F%66%75%73
%63%61%64%6F%20%65%6E%20%66%6F%72%6D%61%20%6E%6F%72%6D%61%6C ”

Desde el punto de vista funcional es exactamente lo mismo. Claro que un usuario sin
conocimientos del tema no sabrá en primera instancia qué indica el string.

367
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 368

Maximiliano R. Firtman

Fig. 9-4. Las diferentes versiones del JavaScript Chaos Engine.

Para utilizar la versión gratuita, los pasos son los siguientes:


• Descargar la versión desde http://www.syntropy.se/index.php?ct=downloads
• Descomprimir el archivo .zip y ubicar el archivo jce.jar que queda en nuestro
equipo.
• Abrir el jce.jar con el Java Runtime. Si ya se encuentra instalada la Java Virtual
Machine en nuestro equipo sólo bastará con abrir el archivo, si no desde la
consola se puede ejecutar javaw jce.jar.
• Cuando se abre la interfaz de la aplicación (fig. 9-5), elegir Open y seleccionar
el archivo JavaScript a ofuscar.
• Pulsar Next para acceder a la sección de Control de la Ofuscación.
• En el control de ofuscación habrá un listado con todas las variables y las funcio-
nes que detectó el sistema. Se podrá eliminar alguna variable o una función de
la lista para no ofuscarla. Esto es necesario cuando esa función es invocada por
otra librería o se trata de un objeto (fig. 9-6) de sistema (como XMLHttpRequest)
cuyo nombre no debe cambiar.

368
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 369

AJAX. Web 2.0 para profesionales

Fig. 9-5. La pantalla inicial del Syntropy JCE Free Edition.

Fig. 9-6. En el control de ofuscación se podrá elegir a qué funciones no cambiarle el nombre, junto a
otras preferencias.

369
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 370

Maximiliano R. Firtman

• Se puede seleccionar si se desean eliminar todos los saltos de líneas y los co-
mentarios. En el primer caso se verifica que todas las sentencias estén termi-
nadas de manera correcta con punto y coma, y, si no, se los incorpora.
• Si no se selecciona la opción Use Short Identifiers, por defecto utiliza nom-
bres de funciones y variables un poco más largos para complicar más la lec-
tura. Al seleccionar la opción, emplea los más cortos posibles.
• Al pulsar Next se obtendrá el código ofuscado para copiar y pegar, o guardar
(Save) en un archivo .js

Si recordamos nuestra librería AjaxLib.js original, a continuación se observa la


misma librería, pero luego de pasar por el JCE Free Edition:

var $ED = {XML: 0,;TEXTO: 1,;JSON: 2 ;}var $KH = {GET: ”GET”,;POST:


”POST”;}function $Ajax(XD, XE) {if (Hh(XE, ”cache”, true)==false){var
WY = ”?”;if (XD.indexOf(”?”)>0) WY = ”&”;XD += WY +
Math.random();}var KH = Hh(XE, ”metodo”, $KH.GET);var vS = Hh(XE,
”parametros”);var lB = {method: KH,;onSuccess: EV.bind(this,
XE),;onException: Au.bind(this, XE),;onFailure: Au.bind(this, XE);}if
(vS!=undefined) {lB.DG = vS;}var kK = new Ajax.Request(XD, lB);if
(Hh(XE, ”avisoCargando”)!=undefined) {KS(XE.avisoCargando,
true);}}function EV(XE, KE) {if (Hh(XE, ”avisoCargando”)!=undefined)
{KS(XE.avisoCargando, false);}var jI = Hh(XE, ”onfinish”);var id =
Hh(XE, ”id”);if (jI!= undefined) {var Ad = Hh(XE, ”tipoRespuesta”,
$ED.TEXTO);switch(Ad) {case $ED.TEXTO:;jI(KE.responseText,
id);break;case $ED.XML:;jI(KE.responseXML, id);break;case
$ED.JSON:;var ab;try {ab = KE.responseText.evalJSON();} catch (e)
{Au(XE, KE, {code: -1, message: ”JSON No válido” });return;}jI(ab,
id);}}}function KS(kO, Ot) {if (Ot) {$(kO).show();} else
{$(kO).hide();}}function Au(XE, KE, Ut) {if (Hh(XE, ”avisoCar-
gando”)!=undefined) {KS(XE.avisoCargando, false);}if (Ut==undefined)
{Ut = {code: KE.status, message: ”Error del servidor”}}var Xv =
Hh(XE, ”onerror”);if (Xv!=undefined) {Xv(Ut, Hh(XE, ”id”));}}function
Hh(Co, Vg, PC) {if (Co==undefined) {return PC;} else {if (Co[Vg]==un-
defined) {return PC;} else {return Co[Vg];}}}

El archivo original ocupa 5,20 Kb; la versión ofuscada, apenas 1,55 Kb, con una
compresión de más del 70%. Lo más importante es que el código sigue funcionando
sin problemas ni cambios.
Si se emplea la versión gratuita hay que acordarse de eliminar del proceso de
ofuscación todas las funciones y las variables globales que sean utilizadas también
por otras librerías que formen parte del mismo HTML. Si se usa la versión comercial,
la librería se encarga de ofuscar tanto el HTML, el CSS como todos los JavaScript en
forma completa e integrada.

370
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 371

AJAX. Web 2.0 para profesionales

Compilar la lógica de negocios


Otra solución para ocultar el código que implica la lógica de negocios de nuestra apli-
cación, que no se desea que un usuario vea (p. ej., funciones de validación, funciones
que invocan y envían datos al servidor, etc.), es compilar el código.
Sin embargo, se había comentado que no es posible compilar código JavaScript,
entonces, ¿cómo lo logramos? La solución es compilar el código que contiene la ló-
gica que se desea ocultar en alguna otra plataforma que no sea propiamente XHTML.
En esta categoría entran Adobe Flash Player y Java. Dado que Flash está más difun-
dido, se utilizará esta técnica.
Adobe Flash Player permite ejecutar aplicaciones ricas embebidas en una página
XHTML. Si se oculta la aplicación, por ejemplo, al ubicarla con un ancho y un alto de
0 píxeles, el usuario no verá aplicación Flash alguna, pero se podrá hacer uso del có-
digo que la aplicación tenga.
Para programadores AJAX lo ideal será usar uno de los siguientes frameworks en
lugar del propio Adobe Flash:

OpenLaszlo: es el más sencillo de aplicar, dado que implementa directamente un motor


ECMAScript compatible con el JavaScript que ya conocemos. Sólo es preciso copiar
nuestro código JavaScript a un proyecto OpenLaszlo y compilarlo, y éste aportará un
archivo SWF compilado que se puede integrar a nuestro XHTML en forma oculta. Para
trabajar de manera correcta OpenLaszlo requiere Flash Player 7 o superior.

Una vez embebido el SWF se podrá ejecutar desde JavaScript cualquier función
del SWF y viceversa. Para ello es necesario utilizar un objeto especial de OpenLaszlo
(LzBrowser) que hace de interface entre el motor JavaScript del browser y el motor del
Flash Player.

Adobe Flex: también se puede utilizar el framework Adobe Flex para compilar el có-
digo JavaScript, pero aquí se debe hacer una pequeña conversión. Flex utiliza el len-
guaje ActionScript 3 que, si bien es primo de JavaScript, tiene algunas diferencias y es
totalmente tipado (typed), por lo que todas las funciones deben migrarse. En este caso
sería ideal pensar toda la lógica de la aplicación directamente en ActionScript 3 y lla-
marla luego desde JavaScript. Una desventaja de Flex frente a OpenLaszlo es que el
primero requiere Flash Player 9 instalado en el equipo del usuario, que si bien la ma-
yoría lo tiene, su porcentaje de distribución es menor que el de la versión 7 requerida
por Laszlo.
Para intercomunicar JavaScript con Flex se puede hacer uso de una clase interna
de Adobe Flex, llamada ExternalInterface, o de una librería gratuita, también de
Adobe, llamada Ajax-Flex Bridge, que permite comunicarse de manera bidireccional
como si ambos códigos formaran parte del mismo espacio (fig. 9-7).

371
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 372

Maximiliano R. Firtman

Fig. 9-7. Con la librería Ajax-Flex Bridge se podrá comunicar cualquier aplicación Flex (visible o no) con
código JavaScript en un XHTML.

Compilar parte del código que se comunica al servidor en un SWF implica que todas
las peticiones que se hagan al servidor no serán vistas, por ejemplo, por Firebug, y sólo
pueden ser analizadas por herramientas tipo proxy, como Charles JS Debugging o Mi-
crosoft Fiddler. Además, se puede acceder a muchas funciones que JavaScript no posee,
como abrir puertos TCP o interactuar a bajo nivel con la impresora. Esto hace que el uso
de un Flash Player invisible sea de gran utilidad para las aplicaciones AJAX.
Por supuesto, también es factible interactuar con una aplicación Flash visible
(compilada con Adobe Flash, Adobe Flex u OpenLaszlo) y así utilizar componentes
ricos que estas plataformas posean sorteando las limitaciones del HTML.

Comprimiendo el XHTML

Otra idea interesante es pensar en la posibilidad de comprimir el código XHTML de


nuestra página web para reducir la transferencia entre el servidor y el cliente, y así tam-

372
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 373

AJAX. Web 2.0 para profesionales

bién la espera del usuario. Esta técnica se utiliza un poco menos que la de ofuscación
del JavaScript, pero no es menos útil.
Recuérdese por un momento que en una aplicación AJAX se puede hacer que
todo el documento sea generado en forma dinámica por JavaScript. Con esta idea de
base se puede implementar un sistema que consista en:
• Un HTML vacío que sólo contenga la llamada a un JavaScript.
• Un código JavaScript que al iniciarse realice una petición AJAX al servidor en
la que solicite un XML o un JSON comprimidos u ofuscados con anterioridad.
• Un archivo con esas características que cuando se reciba, JavaScript lo reco-
rra y por cada nodo cree un elemento HTML correspondiente y lo agregue al
DOM.

¿Dónde se gana compresión? El formato XML o JSON recibido no tiene por qué
ser exactamente XHTML, sino una versión comprimida de él. Por ejemplo, piénsese
en el código HTML siguiente:

<div class=”contenidoPrincipal”>
<img src=”/imagenes/logo.gif” width=”300” height=”400” id=”ima-
gen” />
<table width=”100%” cellspacing=”2” cellpadding=”3” id=”tabl1”>
<tr class=”fila”>
<td class=”celda”>Nombre</td>
<td class=”celda”>Apellido</td>
<td class=”celda”>Telefono</td>
</tr>
<tr class=”fila”>
<td class=”celda”>Juana</td>
<td class=”celda”>De Arco</td>
<td class=”celda”>344 9888</td>
</tr>
<tr class=”fila”>
<td class=”celda”>Alejandro</td>
<td class=”celda”>Magno</td>
<td class=”celda”>981 7711</td>
</tr>
</table>
</div>

Se puede inventar un formato XHTML comprimido que luego se transforme de


nuevo:

373
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 374

Maximiliano R. Firtman

<d c=”contenidoPrincipal”>
<i s=”logo.gif” w=”300” h=”400” i=”imagen” />
<t w=”%” cs=”2” cp=”3” id=”tabl1” trc=”fila” tdc=”celda”>
<tr><td>Nombre</td><td>Apellido</td><td>Telefono</td></tr>
<tr><td>Juana</td><td>De Arco</td><td>344 9888</td></tr>
<tr><td>Alejandro</td><td>Magno</td><td>981 7711</td></tr>
</t>
</d>

Lo que se hizo fue reemplazar algunas etiquetas por otras (como table por t), cier-
tos atributos por otros (como width por w) y algunas convenciones nuevas:
• Cuando se utiliza %, equivale a 100%.
• Cuando se utiliza trc y tdc, indica la clase que llevan todos los tr y los td de una
tabla.

Éste es simplemente un formato de compresión que se puede inventar. Ahora lo


que se debe hacer es un código JavaScript que recorra este XML y vaya creando ele-
mentos en el DOM según el formato indicado antes. Por supuesto, el objetivo final es
que el JavaScript que descomprime no termine siendo más pesado o más lento de
procesar que lo que estamos reduciendo de código XHTML. Por eso, estas técnicas
son más útiles cuando el DOM es grande y tiene mucho contenido.
Incluso, todavía se podrían eliminar todos los espacios y los saltos de línea del
XML o reemplazarlos por un JSON como el siguiente:

{
css: [”contenidoPrincipal”, ”fila”, ”celda”],
d: {
css:1,
i: {
$s:”logo.gif”,$w:300,$h:400,$i:”imagen”
},
t: {
$w:”%”,$cs:2,$cp:3,$i:tabl1,
tr: {
css: 2,
td: {css: 3, $: ’Nombre’},
td: {css: 3, $: ’Apellido’},
td: {css: 3, $: ’Telefono’},
},
tr: {
css: 2,
td: {css: 3, $: ’Juana’},

374
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 375

AJAX. Web 2.0 para profesionales

td: {css: 3, $: ’De Arco’},


td: {css: 3, $: ’344 9888’},
},
tr: {
css: 2,
td: {css: 3, $: ’Alejandro’},
td: {css: 3, $: ’Magno’},
td: {css: 3, $: ’981 7711’},
}
}
}
}

La primera ventaja de este otro formato de compresión es que se pueden armar


vectores con las propiedades más usadas, como las clases CSS, y luego invocar el ín-
dice de ese vector en lugar de repetir los nombres de las clases CSS, por ejemplo.
También se eliminan todas las comillas cuando se trata de valores numéricos, como
width o cellspacing.
Cuando es JSON hay que diferenciar los atributos de un elemento (p. ej., usando
$w para width) de elementos hijos (usando t para table), así como del texto que va den-
tro de una etiqueta (inventando la propiedad $ para esa funcionalidad).
Por supuesto, se puede seguir reduciendo el tamaño de este JSON simplemente
eliminando espacios y saltos de línea:

{css:[”contenidoPrincipal”,”fila”,”celda”],d:{css:1,i:{$s:”logo.gif”,
$w:300,$h:400,$i:”imagen”},t:{$w:”%”,$cs:2,$cp:3,$i:tabl1,tr:{css:2,t
d:{css:3,$:’Nombre’},td:{css:3,$:’Apellido’},td:{css:3,$:’Tele-
fono’},},tr:{css:2,td:{css:3,$:’Juana’},td:{css:3,$:’De
Arco’},td:{css:3,$:’344
9888’},},tr:{css:2,td:{css:3,$:’Alejandro’},td: {css: 3, $:
‘Magno’},td:{css:3,$:’981 7711’},}}}}

Mientras que la versión de XHTML original ocupa 557 bytes, la versión XML re-
ducida ocupa 317 y el JSON reducido 377. Así se logra casi un 45% de compresión.
Este porcentaje va a depender mucho del largo de la página web y de cuánto conte-
nido textual haya.

Pruebas unitarias

Aunque no todo el mundo comprenda por completo el concepto, todos escucharon ha-
blar alguna vez de Calidad de Software. Sin entrar en demasiados detalles teóricos

375
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 376

Maximiliano R. Firtman

sobre la idea, el objetivo de la calidad de software es lograr generar aplicaciones con una
mejor certeza de que funcionan de manera correcta según los objetivos planteados por
ellas. Empíricamente lo que se hacía era probar la aplicación como si uno fuera un usua-
rio para comprobar si se lograba colgarla en algún momento y así arreglar los errores.
No obstante, la verdad es que esta técnica no alcanza. Siempre hay una variante
que no se tuvo en cuenta y siempre el usuario hace una combinación de acciones que
a nosotros nunca se nos hubiera ocurrido, que logra que la aplicación deje de funcio-
nar, o, peor, funcione con errores sin que el usuario se dé cuenta.
Otro problema cuando se modifica algo en el futuro o se agrega alguna funciona-
lidad nueva es que hay una alta probabilidad de que al modificar algo, una porción del
código que antes funcionaba de manera correcta, ahora no haga lo deseado porque
estaba acoplada al código que se modificó recientemente.
Entonces se precisa una forma, una metodología que permita detectar estos pro-
blemas antes de que le lleguen al usuario final. Una de ellas es el uso de pruebas unita-
rias (Unit Testing). Las pruebas unitarias se encargan de probar y verificar el
funcionamiento correcto de cada unidad de la aplicación, entendiendo por unidad cada
uno de los módulos, las funciones o las clases de la aplicación. Si cada unidad responde
de manera correcta ante cada posible estado de la aplicación se puede suponer que la
aplicación en su totalidad funcionará sin mayores problemas. Dentro de la Calidad de
Software también hay otro tipo de pruebas más integradoras, que escapan a este libro.
Entonces la idea es poder diseñar pruebas para cada componente de la aplicación
y ejecutarlas ante cada cambio que se haga en el código. Si las pruebas están diseñadas
en forma correcta, y ninguna falla, se puede garantizar cierta calidad en el producto final.

xUnit
Una especie de estándar que se empezó a utilizar para resolver estas pruebas es el co-
nocido como xUnit, donde la x es reemplazada por cada lenguaje a participar, por
ejemplo, JUnit para Java, NUnit para .NET o PHPUnit para PHP. Estos frameworks tra-
bajan de manera similar, por lo que una vez que se conoce su funcionamiento, se podrá
migrar de uno a otro sin mayores inconvenientes.
JavaScript no podría quedar afuera y hay varias implementaciones de JSUnit para
crear y procesar pruebas sobre nuestro código JavaScript. Algunos frameworks de
testing para JavaScript son:

Script.aculo.us Unit Testing Framework


JsUnit (www.jsunit.net)

Ambos trabajan en forma similar. El objetivo es crear un archivo .js que contenga
todas las pruebas que se quieren ejecutar. Se precisaría contar con una prueba por
cada función o método de cada clase o módulo de nuestra aplicación.

376
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 377

AJAX. Web 2.0 para profesionales

Una prueba no es más que un código que ejecuta la función que está probando
con distintas combinaciones de parámetros y verifica que el resultado concuerde con
lo que se sabe que debería dar. Estas pruebas se conocen como Asserts y las hay de
varios tipos, según la librería que se utilice, por ejemplo:

assertEqual: verifica que el resultado de una función sea igual a una constante que no-
sotros definimos.
assertNull: verifica que el resultado sea nulo.
assertInstanceOf: verifica que el resultado sea instancia de una clase en particular.
assertTypeOf: verifica el tipo de datos devuelto.
assertTrue o assertReturnsTrue: verifica que la función devuelva verdadero.
assertNaN: verifica que el resultado no sea un número (Not a Number).

También existen las negativas de las anteriores, por ejemplo, assertNotEqual o


assertNotNull.
Todas estas funciones también permiten enviarle por parámetro un comentario
para que en la ejecución de la prueba se pueda entender mejor dónde se produjo la
falla, así como armar grupos de pruebas para una mejor organización.
Un ejemplo sencillo de prueba sería:

function suma(a, b) {
return a+b;
}

// Prueba sobre la función suma


function testSuma() {
// Hacemos varias pruebas sobre valores normales y límites
assertEquals(suma(2, 2), 4);
assertEquals(suma(2, 4), 6);
assertEquals(suma(0, 10), 10);
assertEquals(suma(-4, 3), -1);
assertEquals(suma(-5, -9), -14);
assertNull(suma(null, null));
assertNull(suma(null, 2));
assertNull(suma(5, null));
assertNull(suma(”a”, ”a”));
}

Una vez que se diseñaron todos los casos de prueba, se los puede ejecutar. La
ejecución de la prueba implica crear un HTML que comprenda todos los JavaScripts,
incluidas las pruebas, y ejecutar todas las pruebas.

377
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 378

Maximiliano R. Firtman

El framework de pruebas que se use buscará todas las funciones que sean de
pruebas (p. ej., que empiecen con test) y ejecutará todos los asserts. Si alguno falla,
hará un informe que indique dónde y cómo falló.
En nuestro caso anterior fallaría, en el último assert, dado que nuestra función suma
no verifica que los datos sean numéricos nada más. Entonces, si le invocamos dos strings
como parámetros, los concatenará y por validación nosotros queríamos retornar nulo.
Por lo tanto, ahora habrá que modificar nuestra función suma para que todos los
tests pasen la prueba:

function suma(a, b) {
if (isNaN(a) || isNaN(b))
return null;
else
return a+b;
}

Fig. 9-8. Se observa un ejemplo de una prueba en la que se utiliza JSUnit luego que todas las prue-
bas se pasen de manera satisfactoria.

378
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 379

AJAX. Web 2.0 para profesionales

Fig. 9-9. Se puede detectar una incompatibilidad con algún navegador al ejecutar la prueba y que
ésta falle, como en este caso en Opera.

Conexión con Google


Google Code

El famoso buscador, actual portal, Google tiene una gran política abierta en cuanto a
API y la posibilidad de que nuestras aplicaciones se puedan conectar con sus servicios
y bases de datos. Desde el sitio web code.google.com se tendrá acceso directo a
todas las librerías, API, ejemplos y documentación para conectarnos a cada servicio
(fig. 9-10).

379
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 380

Maximiliano R. Firtman

Fig. 9-10. El sitio web Google Code es el punto inicial para trabajar con los servicios de Google.

Servicios disponibles
Dentro de los servicios de Google a los que es posible conectarse se encuentran:

Nombre del servicio Descripción

Google Maps API La primera API pública y conocida. Permite incluir en la página web
mapas de Google Maps e interactuar con ellos.
Blogger API Permite ver y actualizar el contenido de cualquier blog de Blogger,
adquirido por Google.
Gmail Atom Feeds Permite que cualquier aplicación pueda leer los correos de GMail,
mediante un feed Atom.
Google Authentication Permite simplificar la identificación de los usuarios utilizando la cuenta
de Google.
Google AdSense API Permite integrar una aplicación con el servicio de AdSense con el cual
los usuarios reciben ingresos por insertar publicidad de Google. Por ejem-
plo, es posible hacer que un sitio web le muestre a su dueño cuánto va
ganando en el sistema sin necesidad de que ingrese en AdSense.

380
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 381

AJAX. Web 2.0 para profesionales

Google AdWords API Permite integrarse con el servicio de publicidad de AdWords. De esta
forma se pueden generar informes de nuestras publicidades desde
nuestra aplicación AJAX, o generar campañas nuevas en forma
dinámica.
Google AJAX Feed API Permite leer feeds en distintos formatos desde nuestra aplicación
AJAX.
Google AJAX Search API Permite integrar un buscador de Google en nuestro sitio web y
organizar la información y los resultados de búsqueda como nos
parezca más cómodo en nuestro sitio.
Google Apps API Permite integrarse con el servicio Apps for your Domain que facilita
contar con los servicios de Google con nuestro dominio.
Google Base Data API Permite consultar e incorporar información a la base de datos
Google Base.
Google Calendar Data API Permite leer datos de un calendario y agregar citas nuevas al
calendario de los usuarios desde nuestra aplicación.
Google Code Search API Permite que nuestra aplicación vea resultados obtenidos desde el
buscador de código fuente de Google.
Google Data API (GData) Provee un protocolo estándar de comunicación en la web basado en
feeds.
Google Gadgets API Permite crear miniaplicaciones web que se pueden insertar en Google
Desktop (la barra del escritorio) o en iGoogle (la página personalizada
de Google).
Google Mapplets Permite crear miniaplicaciones web que se pueden insertar en Google
Maps.
Google Notebook API Permite que nuestra aplicación AJAX consulte y agregue información
en el bloc de notas del usuario (servicio Notebook).
Google Safe Browsing API Permite consultar una lista de sitios web sospechosos de ser falsos,
de engaño al usuario o que ofrecen virus y troyanos.
Google Sitemaps Permite definir en un formato XML un archivo que será de utilidad
para que Google indexe nuestro sitio web.
Google SOAP Search API Permite consultar un web service sobre la base de datos de miles de
millones de sitios web de Google.
Google Spreadsheets Data API Permite ver y actualizar cualquier planilla de cálculo que posea un
usuario de Google.
Google Talk XMPP Permite conectarnos a cualquier mensajero instantáneo, incluido
Google Chat.
Google Toolbar API Permite crear botones personalizados para la barra del navegador de
Google.
Picasa Web Albums Data API Permite que mostremos, consultemos y actualicemos los álbumes de
un usuario de Picasa desde nuestra aplicación.
YouTube API Permite integrar nuestra aplicación fácilmente con videos de YouTube.

381
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 382

Maximiliano R. Firtman

Frameworks y formatos
Vimos que Google tiene decenas de servicios disponibles, todos en forma gratuita.
Muchos servicios se pueden utilizar directamente desde JavaScript, otros vía JSON o
XML y otros utilizando alguno de los siguientes formatos:

Google KLM
Permite almacenar información geográfica para utilizar en Google Maps, Google Earth
o Maps for Mobile.

Google Data
Permite intercambiar datos en un formato estándar y simple.

Google también ofrece los siguientes frameworks para los desarrolladores AJAX:

Google Web Toolkit


Es un completo entorno de trabajo para crear aplicaciones AJAX sin escribir una sola
línea de JavaScript. El framework trabaja sobre plataforma Java y compila el código en
XHTML y JavaScript.

Google Gears
Es un framework para JavaScript que incluye un plugin para Internet Explorer y Fire-
fox, así como una API para trabajar desde JavaScript que permite ejecutar aplicacio-
nes AJAX fuera de línea, sin conexión a Internet, soportando un servidor web local y
una base de datos SQL que se ejecuta en el cliente y se puede consultar directamente
desde JavaScript.

Google Open Source


También Google aloja varios proyectos Open Source, de los cuales hay varios para in-
tegrar a AJAX en el sitio web http://code.google.com/projects.html

API Key

Para la mayoría de los servicios de Google es necesario obtener una clave única (API
Key), que entrega Google en forma gratuita al utilizar la cuenta de Google. Esa clave
funciona en un solo dominio web, por lo que debemos obtener una distinta por cada
servicio y dominio por utilizar. La clave es un string largo que se debe incluir como pa-
rámetro en la API, según la documentación de cada una.

382
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 383

AJAX. Web 2.0 para profesionales

Algunas claves tienen limitaciones. Por ejemplo, la Google Maps API Key permite
hacer hasta 50.000 peticiones por día al servidor. En el sitio web de cada API se pue-
den consultar las limitaciones y se obtendrá la información de cómo contactarse si se
necesitan más (fig. 9-11).
Una vez que se obtiene la clave, en el caso de la Google Maps API, simplemente
se la utiliza como parámetro en el include del script de Google, por ejemplo:

<script src=”http://maps.google.com/maps?file=api&amp;v=2&amp;key=AB-
QIAAAAxQfxnHXO3Zef6S9gO1cMnBQqypn89n46cd85HEhSisKGjCfDGamLbf8PtgLD-
VoIbqYQ”
type=”text/javascript”></script>

Fig. 9-11. Se observa una clave obtenida para utilizar el servicio de Google Maps.

383
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 384

Maximiliano R. Firtman

Google Maps API

A modo de ejemplo, se analizará cómo funciona básicamente la Google Maps API para
incorporar un mapa en el sitio web e integrarlo a él.

Objetos de la API
Una vez que se incorpore el script externo del servidor de Google, se dispondrá de va-
rios objetos para utilizar, entre ellos algunos de los más importantes son los siguientes:

Objeto Descripción

GMap2 Crea un nuevo mapa en un elemento DIV.

GMarker Representa un ícono (el famoso pinche) apuntando en el mapa.

GPolyline Representa una figura o una zona geométrica dentro del mapa.

GPoint Representa una coordenada.

GXmlHttp Un objeto que encapsula a XMLHttpRequest.

GMapOptions Permite definir propiedades del mapa.

GInfoWindow Representa a un globo de información que aparece al abrir un


GMarker.

GIcon Permite insertar íconos en el mapa.

GDraggableObject Permite arrastrar elementos en el mapa y capturar las coordenadas


de drop.

GRoute Representa una ruta sobre el mapa.

GBrowserIsCompatible Indica si el navegador soporta Google Maps.

La API permite no sólo mostrar un mapa en una ubicación, sino integrarla con
nuestra base de datos, consultar las coordenadas a partir de una dirección postal o que
el usuario indique en el mapa un punto o una zona que quiere utilizar.
El Hola Mundo de Google Maps (nunca más acertado el uso de mundo), sería el
siguiente:

<!DOCTYPE html PUBLIC ”-//W3C//DTD XHTML 1.0 Strict//EN”


”http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

384
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 385

AJAX. Web 2.0 para profesionales

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”content-type” content=”text/html; charset=utf-8”/>
<title>Google Maps Hola Mundo</title>
<script
src=”http://maps.google.com/maps?file=api&amp;v=2&amp;key=CLAVE!!”
type=”text/javascript”></script>
<script src=”mapa.js” type=”text/javascript”></script>
</head>
<body
<div id=”mapa” style=”width: 500px; height: 400px”></div>
</body>
</html>

mapa.js

function load() {
if (GBrowserIsCompatible()) {
var mapa = new GMap2(document.getElementById(”mapa”));
// Define latitud y longitud inicial y nivel de zoom
mapa.setCenter(new GLatLng(23.986253,-102.150879), 11);
}
}

En la documentación de la API encontraremos decenas de ejemplos de cómo in-


corporar mayor funcionalidad en nuestro sitio web.

Conexión con Microsoft Live


Windows Live Dev

Microsoft no se quedó atrás en el uso de API públicas para que podamos conectarnos
con su servicio Windows Live y desarrolló el sitio web Windows Live Dev en
code.live.com (fig. 9-12).
Los servicios que ofrece Windows Live para los desarrolladores son:

385
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 386

Maximiliano R. Firtman

Servicios Descripción

Silverlight Streaming Permite alojar videos para realizar transmisiones streaming desde
Silverlight.

Live Space Photo Permite conectarse con el servicio Space para ver y publicar nuevas
fotos en los fotologs de los usuarios.

Windows Live Contacts Facilita la conexión con la agenda de contactos de un usuario para ver
y/o agregar datos nuevos. Se conecta con las agendas de Messenger,
Live Mail y Mobile.

Virtual Earth Permite la conexión con el servicio de mapas en 2D y 3D de Microsoft.


Live Search SDK Integra con el motor de búsqueda de Live.

Live ID Facilita que nuestras aplicaciones identifiquen a los usuarios con


Live ID (antes conocido como Passport).

Windows Alerts Permite la integración con el sistema de notificación de alertas de los


servicios Live y MSN.

Live Spaces Blog Integra con los blogs de Space.

Fig. 9-12. Windows Live Dev es el punto de inicio para conectarse con el servicio de Microsoft.

386
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 387

AJAX. Web 2.0 para profesionales

Conexión con Yahoo!


Yahoo! Developer Network

El portal Yahoo! también ofrece distintas API abiertas para conectarse con sus servi-
cios online en developer.yahoo.com. En general en la mayoría de ellos podemos elegir
conectarnos y recibir información en XML o también en JSON.
Entre los servicios disponibles para desarrolladores, se pueden mencionar:

Servicios Descripción

Yahoo! Maps Permite la integración con los mapas de Yahoo! vía AJAX o Flash.

Yahoo! Music Engine Agrega funcionalidad al servicio musical del portal.

Yahoo! Widgets Permite desarrollar widgets (miniaplicaciones) que se ejecutan bajo los
servicios de Google.

Yahoo! Search Integra nuestras aplicaciones con el servicio de búsqueda del famoso
portal.

Yahoo! Travel Facilita la conexión con el organizador de viajes (Travel Trip Planner).

Yahoo! Browser-based Permite que nuestras aplicaciones identifiquen al usuario utilizando


authentication el Yahoo! ID.

Yahoo! Search Marketing API Permite la conexión al sistema de administración de campañas de


marketing online.

Conexión con Amazon


AWS

Amazon Web Services (AWS) es un conjunto de servicios web abiertos que permiten
consultar la base de datos de libros de la popular librería Amazon e integrar nuestro
contenido con información de ese comercio. El sitio web está disponible en aws.ama-
zon.com y desde allí podremos registrarnos para hacer uso de él (fig. 9-13).
Entre los servicios web disponibles se encuentran:

387
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 388

Maximiliano R. Firtman

Servicios Descripción

Amazon E-commerce Service Permite consultar la base de datos de productos (libros, CD, etc.),
recibir detalles de un producto dado y recibir comisión por ventas
enviadas.
Amazon Elastic
Computer Cloud (EC2) Distribuye capacidad de procesamiento en una nube de equipos.

Amazon Historial Pricing Permite consultar el historial de precios de productos de los últimos
3 años.

Amazon Simple Storage Facilita el almacenamiento de información hasta 5 Gb y su obtención


Service (S3) en cualquier momento vía Internet.
Amazon Simple Queue Service Almacena mensajes entre aplicaciones en un servidor centralizado.

Alexa Web Services Permite acceder a varios servicios del sitio Alexa, entre ellos, búsqueda,
información de un sitio web dado, el top ten de sitios web de una
categoría y la foto de un sitio.

Fig. 9-13. Amazon no se queda atrás y permite la conexión con su base de datos de productos.

388
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 389

AJAX. Web 2.0 para profesionales

Muchos sitios web utilizan la API de Ecommerce de Amazon para ofrecer publici-
dad de libros del tema del que trata el sitio, para luego recibir comisión de las posibles
ventas que se produjeran por ese link. Además, si se consulta a la base de datos desde
un script de servidor, la información de los libros es indexada por los buscadores como
contenido de nuestro sitio web.

Aplicaciones desconectadas
Hasta ahora, siempre que se pensó en una aplicación AJAX se la consideró conectada
a Internet. Sin embargo, al principio del libro se había comentado un nuevo concepto
que apareció en los últimos tiempos: las aplicaciones ricas de escritorio.
Bajo ese concepto el objetivo es que una aplicación desarrollada con técnicas de
tipo Web conectada, como AJAX, pueda funcionar de manera desconectada (offline).
Al momento de escribir este libro, hay dos soluciones en estado beta para utilizar
una aplicación AJAX de forma desconectada.

Adobe AIR

Adobe lanzó un nuevo framework llamado AIR (Adobe Integrated Runtime) que per-
mite crear aplicaciones de escritorio a partir de una aplicación AJAX, con XHTML y Ja-
vaScript, o una aplicación Flash/Flex. Hasta hace poco se lo conoció por su nombre
de proyecto, Adobe Apollo. Las aplicaciones AIR/AJAX se empaquetan en un archivo
.air que se compila con el AIR SDK (herramienta gratuita). Este archivo contiene los
HTML, JavaScript, CSS, imágenes y otros archivos que forman parte de nuestra apli-
cación, junto a un archivo XML que describe algunas características, como nombre,
ícono, tamaño de ventana, etc. (fig. 9-14).
Estas aplicaciones se instalan como cualquier ejecutable y al momento funcionan
sin recompilar en Windows XP, Windows Vista y Mac OS X luego de que el usuario ins-
tale el Adobe AIR Runtime, la herramienta gratuita que permite ejecutar aplicaciones
AIR. Se espera la salida de un runtime para equipos móviles (teléfonos y PDA) y otros
sistemas operativos (fig. 9-15).
Además de todo lo conocido para JavaScript, una aplicación AJAX montada sobre
AIR permite:
• Ejecutar cualquier librería AJAX, como Prototype o Script.aculo.us
• Acceder al sistema de archivos del usuario para escribir y leer archivos en el
disco.
• Detectar cuándo el usuario pierde conexión a Internet y cuándo la recupera.
• Almacenar una base de datos en el cliente compatible con SQL.

389
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 390

Maximiliano R. Firtman

Fig. 9-14. Adobe AIR permite portar una aplicación web AJAX, Flex o Flash al escritorio sin demasiado
esfuerzo.

Fig. 9-15. Con Adobe AIR es posible crear aplicaciones AJAX que corran en ventanas transparentes,
tanto en Windows como en Mac.

390
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 391

AJAX. Web 2.0 para profesionales

• Recibir objetos arrastrados desde el sistema operativo, una aplicación nativa


(como Word) u otra aplicación AIR. Entonces se podrán arrastrar y soltar como
si fueran una aplicación nativa del usuario.
• Abrir sockets TCP/IP para comunicaciones de bajo nivel, por ejemplo, para
enviar o recibir desde un servidor FTP.

Adobe AIR incluye como motor de XHTML y JavaScript a WebKit, un motor open
source que se utiliza también en Safari y Nokia Web Browser. Por lo tanto, las aplica-
ciones AJAX deberían responder de manera muy similar a como lo hacen en Safari.
Para utilizar AIR con aplicaciones AJAX, sólo se necesita descargar lo siguiente
desde www.adobe.com/go/air:
1. Adobe AIR SDK. Incluye el compilador y ejemplos.
2. Adobe AIR Runtime. Se necesitará para probar las aplicaciones.
3. Hay un plugin para Dreamweaver CS3 que permite compilar y verificar las
aplicaciones AIR desde el entorno. Se lo debe buscar bajo el nombre Adobe
AIR Extension for Dreamweaver CS3. Se espera que futuras versiones lo ten-
gan incorporado.
4. También se podrán crear aplicaciones AIR con Adobe Flex 3 o Flash Professional.

Google Gears

Google Gears es un plugin para el navegador (por el momento, Internet Explorer y Fi-
refox) que permite que una aplicación AJAX funcione desconectada. A diferencia de
AIR, las aplicaciones Gears funcionan en el navegador, por lo que se ejecutan en ese
ámbito y no incorporan un nuevo motor.
El plugin puede descargarse de gears.google.com, aunque es factible insertar un
script para que la propia página web que quiere hacer uso de la API envíe al usuario a
instalarse el plugin. Éste funciona en Windows, Mac y Linux, y le pide autorización al
usuario antes de aprobar su uso en un sitio web (figs. 9-16 y 9-17).
Esta librería permite que una aplicación AJAX:
• Guarde y recupere archivos de recursos (imágenes, películas, etc.) localmente
sin necesidad de conexión (LocalServer).
• Guarde y recupere datos en una base de datos relacional que se almacena en
el disco del cliente y permite ejecutar sentencias SQL. Este motor está basado
en SQLite, al igual que el de AIR (Database).
• Ejecute cierto código JavaScript en un hilo de ejecución separado para evitar
que la aplicación parezca congelada cuando realiza operaciones pesadas de
entrada y salida a disco (WorkerPool).

391
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 392

Maximiliano R. Firtman

Fig. 9-16. Google Gears permite que cualquier aplicación AJAX funcione aun desconectada de Internet.

Fig. 9-17. Cuando un sitio quiere hacer uso de Gears, debe pedirle autorización al usuario, dado que
estará escribiendo información en su disco. De todas maneras, por seguridad, la aplicación Gears no
puede leer ni escribir cualquier archivo.

392
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 393

AJAX. Web 2.0 para profesionales

Ejemplo

Al observar los ejemplos y la documentación del sitio web oficial para desarrolladores,
se puede analizar cómo hacer uso de esta solución. Para mostrar la manera de utili-
zarla, se expondrá un ejemplo sencillo basado en otro de los que se exhiben en el sitio
web.
En el XHTML se incluye el código de la librería y el controlador:

<script type=”text/javascript” src=”gears_init.js”></script>


<script type=”text/javascript” src=”ejemplo.js”></script>

Y en ejemplo .js se incorpora:

// Se ejecuta globalmente
var db;
init();
window.onload = init;

// Intenta abrir una base de datos local


function init() {
if (!window.google || !google.gears) {
// Plugin no disponible
return;
}

try {
db = google.gears.factory.create(’itmaster’, ’1.0’);
} catch (ex) {
setError(’No se pudo crear la base de datos local: ’ + ex.message);
}

if (db) {
db.open(’itmaster’);
// Creamos la tabla si no existe
db.execute(”create table if not exists Cursos” +
” (nombre varchar(255))”);
// Insertamos un nuevo curso desde JavaScript
db.execute(”insert into Cursos (nombre) values (’AJAX’)”);
muestraCursos();
}

function muestraCursos() {

try {
// Leemos todos los cursos con un cursor (rs)

393
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 394

Maximiliano R. Firtman

var rs = db.execute(’select * from Cursos order by nombre’);


var index = 0;
while (rs.isValidRow()) {
// Agregamos el curso leído a un DIV
$(”divCursos”).innerHTML += rs.field(0);
rs.next();
}
rs.close();

} catch (e) {
throw new Error(e.message);
}

El ejemplo sólo se expone a los fines de muestra, y siempre agrega el mismo curso.
No obstante, si se lo modifica un poco se lo podrá adaptar a una aplicación más grande.
Incluso ya surgieron algunas librerías que funcionan sobre Gears para ofrecer una
abstracción mayor y escribir menos código. Una de ellas es Dojo Offline.

AJAX en el móvil
Ya se había comentado que varios navegadores incluidos en los teléfonos y dispositi-
vos móviles soportan AJAX, entre ellos:
• Nokia Web Browser, basado en WebKit (al igual que Safari).
• Opera Mobile.
• Internet Explorer Mobile.
• Mozilla Minimo, basado en Firefox.
• Safari para iPhone.

Incluso, en el conocido equipo de Apple, iPhone, la única forma de desarrollar


aplicaciones y juegos es mediante aplicaciones AJAX.
Las consideraciones para tener en cuenta son:
• Considerar el tamaño de la pantalla.
• Considerar que no se contará con algunos eventos, como onmouseover.
• No utilizar librerías JavaScript pesadas porque cada Kb en general es un costo
adicional para el usuario.

394
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 395

AJAX. Web 2.0 para profesionales

• No hacer operaciones grandes de DOM que requieran muchas instrucciones


de procesador.
• Reducir al máximo las peticiones al servidor.

Aplicaciones para iPhone y Ipod Touch

Se comentó que todas las aplicaciones y los juegos para Apple iPhone se deben de-
sarrollar en AJAX. Dado que el motor que utiliza es Safari, se puede suponer que se eje-
cutarán igual que en ese navegador. Como el iPhone es totalmente sensible al tacto en
toda su pantalla, no hay un mouse o cursor, sino clics realizados con el dedo del usua-
rio, por eso se deben realizar interfaces gráficas acordes con ello.
Hay una librería gratuita llamada iUI (www.joehewitt.com/iui/) que simplifica el de-
sarrollo de aplicaciones AJAX para Apple iPhone brindando las siguientes funciones a
JavaScript (fig. 9-18):
• Diseño gráfico de controles ricos similares a los encontrados en la interfaz de
usuario del sistema operativo del iPhone.
• Transiciones y efectos iguales a los provistos por el sistema operativo.
• Detección de cambio de orientación (vertical/horizontal) por medio del acele-
rómetro que incluye el equipo.
• Soporte de historial y botón de Atrás.
• Desplazamiento de listas largas utilizando gestos con el dedo.

Fig. 9-18. La única herramienta para crear aplicaciones para Apple iPhone es AJAX. La librería iUI sim-
plifica la tarea visual para crear este tipo de aplicaciones.

395
C09.qxd:Project Ajax4.1.qxd 10/18/07 8:21 PM Página 396
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 397

Librerías y frameworks
10
Librerías de cliente
Ya en capítulos pasados se trabajó con las librerías de cliente más utilizadas en el mer-
cado, entre ellas el conjunto Prototype+Script.aculo.us y Yahoo! UI Library. En este ca-
pítulo se va a hacer un repaso por otras librerías alternativas que van ganando mercado
de a poco.
La mayoría tiene la funcionalidad básica similar e incorpora algunas funciones pro-
pias o controles ricos con distinto grado de uso y metodología de implementación.
Recuérdese que todas estas librerías se ejecutan directamente en el cliente, o sea,
en el navegador web.

Adobe Spry

Spry es una librería JavaScript de Adobe pensada para la creación de aplicaciones ricas
de Internet con AJAX. Su sitio web se puede encontrar en www.adobe.com/go/spry,
donde hay documentación, descarga y ejemplos.
El objetivo de la librería es utilizar AJAX pero abstrayendo al programador o el di-
señador de cómo se realiza la comunicación con el servidor o cómo se realizan los
controles ricos. La librería utiliza una metodología de trabajo que requiere poco código
JavaScript y agrega atributos nuevos a los elementos XHTML que todos conocen.
Adobe Dreamweaver CS3 incorpora la librería Spry en forma transparente para
crear controles ricos y enlazar controles a fuentes de datos asincrónicas en XML. Tam-
bién incorpora comportamientos y efectos nuevos que hacen uso de la librería Spry que
ya viene incorporada con el entorno (fig. 10-1).

397
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 398

Maximiliano R. Firtman

Fig. 10-1. Spry está incorporada en Dreamweaver CS3, donde se podrán crear controles ricos y en-
lazarlos a XML en vista Diseño.

Spry Widgets
En la librería de Adobe se incluyen varios widgets o controles ricos listos para utilizar
con una sola línea de JavaScript. Un widget se compone de:
1. Estructura del Widget. Es un código HTML que define la composición y el
contenido del control.
2. Comportamiento del Widget. Es un código JavaScript que instancia el widget,
define su comportamiento y captura eventos.
3. Estilos del Widget. Son clases CSS que definen la visualización del control
rico.

El objetivo de la librería es que la comunidad de desarrolladores cree widgets y


controles nuevos bajo el mismo esquema utilizando la base de Spry.
Los controles disponibles hasta la versión 1.5 son:
• Accordion: permite agrupar distintos contenidos con un título y abrir y colap-
sar uno por uno exclusivamente con un efecto de acordeón.

398
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 399

AJAX. Web 2.0 para profesionales

• Collapsible Panel: permite incluir un contenido con un título, y que al presio-


nar sobre el título se pueda ver y colapsar el contenido.
• Tabbed Panels: permite agrupar varias ventanas de información bajo las fa-
mosas pestañas o tabs.
• Menu Bar: permite crear un menú desplegable, similar a los disponibles en
aplicaciones de escritorio.
• Validation Text Field: unido a un campo de texto, se encarga de validar el
contenido y mostrar un mensaje de error cuando la validación falla.
• Validation Text Area: similar al anterior, pero con un campo de texto multilínea
(etiqueta TextArea).
• Validation Select: similar a los anteriores, pero valida una lista de selección.
• Validation CheckBox: valida que un campo de selección simple esté acti-
vado.

Todos estos controles pueden ser configurados y previsualizados desde Adobe


Dreamweaver CS3, incluso por cualquier diseñador sin conocimientos de JavaScript
(figs. 10-2 y 10-3).

Fig. 10-2. Se observan las clásicas pestañas implementadas desde Dreamweaver CS3. También se
las puede hacer totalmente con JavaScript y DIV.

399
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 400

Maximiliano R. Firtman

Fig. 10-3. Los validadores permiten mostrar mensajes de error y estilos CSS distintos cuando falla
algún requisito mínimo, como ser obligatorio o tratarse de un e-mail válido. Se puede validar al hacer
el envío o cuando el usuario sale de foco del control.

XML DataSets
Adobe Spry soporta un subset del lenguaje de consultas XPath que permite navegar
por un XML de manera más sencilla que con la especificación DOM. De esta manera,
un XML con información se transforma en un objeto conocido como DataSet para la
librería que puede enlazarse a cualquier elemento HTML.
Aquí se ve un ejemplo de cómo se crea un DataSet:

<script type=”text/javascript” src=”includes/xpath.js”></script>


<script type=”text/javascript” src=”includes/SpryData.js”></script>

<script type=”text/javascript”>

400
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 401

AJAX. Web 2.0 para profesionales

var dsClientes = new Spry.Data.XMLDataSet(”clientes.xml”,


”clientes/cliente”);
</script>

El segundo parámetro es una consulta XPath que indica qué leerá del XML, de la
etiqueta clientes, todas aquellas etiquetas cliente que existan y esa colección de nodos
cliente será considerada como el registro a iterar.
Una vez que el DataSet está cargado (lo trae vía XMLHttpRequest) se lo puede en-
lazar en forma automática con casi cualquier etiqueta XHTML (hay algunas restriccio-
nes) por medio de un atributo propio de Spry. Por ejemplo:

<div id=”divClientes” spry:region=”dsClientes”>


<table>
<tr>
<th>Código</th>
<th>Nombre</th>
<th>Teléfono</th>
</tr>
<tr spry:repeat=”dsClientes”>
<td>{codigo}</td>
<td>{nombre}</td>
<td>{telefono}</td>
</tr>
</table>
</div>

En el vocabulario de Spry el divClientes se conoce como una región dinámica.


Cuando se crea el DataSet la fila TR que contiene la instrucción spry:repeat se repe-
tirá por cada nodo definido. Asimismo, {codigo} se reemplazará por una subetiqueta (o
atributo, si se lo especifica al estilo {@codigo}) llamada código, que exista dentro de
cada cliente.
Estos atributos con prefijo spry: son XHTML válidos y no tienen problemas con los
navegadores. Recuérdese que la repetición de los TR y el reemplazo por los datos del
XML se realizan en el cliente, vía JavaScript. La librería no funciona sobre el servidor
que es lo que uno supone cuando ve por primera vez una página que utiliza Spry (fig.
10-4).
Con muy poco código también se puede crear una página que utilice el modelo
Maestro-Detalle, por ejemplo, para mostrar el detalle de un cliente y los productos dis-
ponibles cuando el usuario selecciona un cliente de una lista.
Entre los atributos disponibles que permiten trabajar con datos se encuentran:

401
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 402

Maximiliano R. Firtman

Atributo Descripción

spry:repeat Repite la etiqueta actual por cada nodo del XMLDataSet.

spry:repeatchildren Igual al anterior, sólo que repite el nodo XHTML hijo del actual.

spry:if Permite mostrar la etiqueta actual sólo si se cumple la condición


indicada en este atributo.

spry:choose Equivale a un switch o case que permite mostrar sólo un hijo de la


etiqueta. Cada hijo tendrá que incluir la condición para ser mostrado,
en un atributo spry:when o spry:default.
spry:state Define que el contenido de la etiqueta actual aparezca sólo cuando la
aplicación esté en un cierto estado que nosotros definimos, por
ejemplo: esperando, cargando, finalizado.

spry:hover Especifica el nombre de una clase CSS para cuando el usuario posa el
cursor sobre el elemento.

spry:select Especifica el nombre de una clase CSS para cuando el usuario


selecciona un elemento.

Fig. 10-4. En el sitio web de Spry se encontrarán varios ejemplos simples y muy vistosos sobre cómo
enlazar XHTML a datos XML.

402
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 403

AJAX. Web 2.0 para profesionales

Cuando estamos en un repeat u otra instrucción que itera entre varios registros,
podemos utilizar algunas de las opciones siguientes en cualquier nodo XHTML:

Expresión Descripción

{etiqueta} Muestra el valor de una etiqueta del nodo en el cual se itera.

{@etiqueta} Muestra el valor que tiene un atributo del nodo en el que se itera.

{ds_RowID} El ID del registro actual.

{ds_RowNumber} El índice del registro actual empezando en 0.

{ds_RowNumberPlus1} El índice del registro actual empezando en 1.


{ds_RowCount} La cantidad total de filas.

{ds_SortColumn} El nombre de la columna por la cual se está ordenando.

{ds_EvenOddRow} Devuelve ‘even’ (par) u ‘odd’ (impar), según el índice del registro actual.

Efectos Spry
Adobe Spry también presenta una galería de efectos que se pueden aplicar en casi
cualquier elemento XHTML. Los efectos que incluye la librería son: Fade, Highlight,
Blind Up, Blind Down, Grow, Shake y Squish. Según la misma documentación de Spry,
para los efectos se utilizó la misma nomenclatura y algo de las técnicas de los efectos
de Script.aculo.us trabajando en conjunto con el creador de esta última librería (fig.
10-5).

Fig. 10-5. Se pueden aplicar efectos Spry desde código JavaScript o en Dreamweaver CS3 seleccio-
nando en vista diseño.

403
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 404

Maximiliano R. Firtman

Microsoft AJAX Library

Microsoft no se quiso quedar atrás en el mundo de AJAX y lanzó una serie de herra-
mientas para trabajar con esta plataforma. Entre ellas se encuentran los siguientes fra-
meworks:
• Microsoft ASP.NET AJAX Extensions: es una librería de servidor que permite
ejecutar aplicaciones ASP.NET utilizando tecnología AJAX.
• ASP.NET AJAX Control Toolkit: es una colección de código abierto de con-
troles ricos que se pueden incorporar a ASP.NET AJAX.
• Microsoft AJAX Library: es una librería de cliente (la misma que utiliza la li-
brería de servidor) que permite integrarse a PHP o cualquier otra plataforma.

La librería de cliente, entonces, se puede descargar como archivos JavaScript y


no requiere que se utilice la plataforma de Microsoft en el servidor. La librería de cliente
se puede descargar desde ajax.asp.net/downloads.
Hay un proyecto open source, auspiciado por el mismo Microsoft, para enlazar
esta librería con PHP de manera sencilla. Se llama PHP Library for the Microsoft Ajax
y se puede descargar de codeplex.com/phpmsajax.
La librería de cliente es compatible con todos los navegadores conocidos del mer-
cado e incorpora a JavaScript algunos conceptos que son propios del framework .NET,
en lenguajes como C# o Visual Basic, incluidos soporte de JSON y WebServices. Entre
las características que incorpora se encuentran (fig. 10-6):
• Soporte de creación de clases y herencia.
• Soporte de espacio de nombres o namespaces bajo los cuales existen y se
agrupan las clases.
• Modificadores de acceso. Si bien en JavaScript no se puede definir como pri-
vado un atributo, se toma la convención de que si el atributo comienza con
guión bajo (_) éste es privado y no se permite su acceso.
• Soporte de creación de interfaces.
• Soporte de enumeraciones.
• API de Reflection para analizar el contenido de una clase.
• Agrega métodos conocidos en .NET a clases de JavaScript, por ejemplo:
– El método parse a los Boolean y Number.
– Los métodos startsWith, endsWith, lTrim, rTrim, format, localeFormat a
los Strings.
– add, clone, contains, indexOf, foreach, insert, remote, get_length a los Arrays

404
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 405

AJAX. Web 2.0 para profesionales

– createError que equivale a throw new Exception en .net.


– El método toFormattedString a las fechas.

Fig. 10-6. Microsoft ofrece un video donde explica cómo integrar fácilmente su librería de cliente con
código PHP.

jQuery

jQuery es una librería bastante nueva en el mercado de AJAX, pero que promete cum-
plir con la misma funcionalidad de Prototype+Script.aculo.us, aunque de manera más
liviana, rápida y sencilla de codificar.
Su sitio web oficial es jquery.com y ofrece en 20 Kb toda su funcionalidad com-
patible con todos los navegadores conocidos del mercado.
Entre las funciones que incluye se pueden mencionar:
• Soporte del evento ready que se ejecuta cuando el DOM se encuentra com-
pletamente cargando sin las imágenes.
• Manejo de eventos sencillo mediante funciones.

405
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 406

Maximiliano R. Firtman

• Efectos visuales con poco código.


• Soporte de cadena de ejecución con la posibilidad de ejecutar múltiples ins-
trucciones en una sola línea.
• Manipulación de documentos con CSS 1, 2 y 3.
• Soporte de algunos estándares de Prototype como $ y $$ incorporando ex-
presiones XPath.
• Soporte de nuevos plugins.

Algunos ejemplos con jQuery (fig. 10-7):

Fig. 10-7. jQuery quiere convertirse en el reemplazante del binomio Prototype y Scriptaculous.

// Trae todos los radiobuttons seleccion


var radio = $(”input[@type=radio][@checked]”);

// Le agrega la clase CSS texto a todos los párrafos


$(”p”).addClass(”texto”);

406
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 407

AJAX. Web 2.0 para profesionales

// Pone a todos los links para que se abran en ventana nueva


$(”a”).attr({ target: ”_blank”, title: ”Se abrirá en ventana nueva”
});

// Agrega una imagen luego de cada fin de párrafo


$(”p”).after(”<img src=’fin.jpg’ /> ”);

// Define la función a ejecutarse en el clic del botón


$(”btnEnviar”).click(function() { alert(”Gracias por enviar los
datos”) });

// Anima un div
$(”divContenido”).fadeIn(”slow”);

// Hace una petición AJAX


$.ajax({
type: ”POST”,
url: ”guardar.php”,
data: ”nombre=Juan&apellido=Gomez”,
success: function(mensaje){
alert(mensaje);
}
});

// Hace algo si es Internet Explorer


if ($.browser.msie) {

// Itera entre una colección


$.each( [2, 4, 6], function(i, total) { alert(i) });

// Busca todos los párrafos que sean de clase ”copete”,


// les agrega la clase ”deportes” y los muestra con un efecto lento
$(”p.copete”).addClass(”deportes”).show(”slow”);

Es una librería interesante con bastante futuro, que intenta que los desarrollado-
res AJAX puedan hacer más cosas con menos código.

Dojo Toolkit

Dojo es un framework muy completo para realizar aplicaciones ricas de Internet con
JavaScript. Una de sus desventajas es que es uno de los más pesados a la hora de car-
gar código JavaScript, pero a su favor tiene su gran funcionalidad, que incorpora como
un nuevo modelo de eventos y facilidades de escritura y utilitarios para las tareas más

407
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 408

Maximiliano R. Firtman

comunes en un desarrollo de este tipo. Su sitio oficial es dojotoolkit.org, donde se en-


contrarán ejemplos y la documentación oficial, además de la librería (fig. 10-8).
En realidad, Dojo Toolkit surgió como la unión de varios frameworks y librerías
que se unieron bajo un mismo paraguas de trabajo.

Fig. 10-8. Dojo es una librería muy completa que incorpora la funcionalidad de muchas otras en una sola.

Dijit
Sobre Dojo hay una librería de widgets o controles ricos conocida como Dijit. Esta li-
brería incluye controles agrupados en categorías:
• Controles de formulario.
• Auto Completer.
• Inline Edit Box.
• TextBox (con validación y formato).
• Buttons (de varios tipos).
• Dropdown Calendar.

408
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 409

AJAX. Web 2.0 para profesionales

• Number Spinner.
• Resizeable Text Area.
• Select.
• Slider.

Controles de disposición
• Content Pane.
• Title Pane.
• Layout Container.
• Tab Container.
• Page Container.
• Split Container.
• Accordion Container.
• Dialog.

Controles de comando
• ToolBar.
• Menúes Popup.

Controles de asistencia al usuario


• Progress Bar.
• Tooltip.

Controles avanzados
• Color Palette.
• Tree.
• Rich Text Editor.
• Grid.
• Toggler.

Todos los widgets soportan temas para combinar estilos y colores, y contienen
una lista de atributos que todos comparten en común y hacen más sencilla la tarea de
programarlos.

409
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 410

Maximiliano R. Firtman

Módulos
Entre los módulos de funcionamiento que incorpora, se pueden mencionar (fig. 10-9):
• Charts: permite crear gráficos estadísticos.
• Offline: permite crear aplicaciones desconectadas junto a Google Gears.
• Storage: permite almacenar información en el cliente.
• Drag and Drop.
• Animación.
• Botón de Atrás.
• Internacionalización y múltiples idiomas.

Fig. 10-9. Dojo Toolkit es la librería que agrupa más controles ricos compatibles con AJAX.

Otras librerías

Un repaso final a otras librerías JavaScript (figs. 10-10 y 10-11).

410
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 411

AJAX. Web 2.0 para profesionales

Fig. 10-10. moo.FX es una librería ultraliviana que permite hacer efectos visuales con sólo 3 Kbytes
de JavaScript.

Fig. 10-11. Algunas librerías, como OAT Framework, permiten crear charts o gráficos estadísticos
desde JavaScript.

411
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 412

Maximiliano R. Firtman

Moo.fx – moofx.mad4milk.net
Librería ultraliviana que permite hacer efectos y acordeones con sólo 3 Kb.

OAT Framework – oat.openlinksw.com


Completa librería que contiene controles ricos y creación de gráficos estadísticos con
SVG y otras tecnologías.

Aflax – aflax.org
Librería que permite crear aplicaciones Flash en SWF desarrollando toda la interfaz
desde JavaScript.

Rico – openrico.org
Antigua librería para AJAX que permite crear controles ricos con facilidad.

Number Formatting Library - xaprb.com


Permite darle formato a un número según un patrón dado.

Mochikit – mochikit.com
Librería general que agrega mucha funcionalidad a JavaScript y AJAX.

Librerías para PHP


Las librerías de servidor para AJAX tienen la ventaja de que, en general, nos abstraen
del JavaScript que se conecta al servidor. Para ello, desde código de servidor se con-
figura cierta información y luego se puede hacer uso de ella desde JavaScript, como
si fueran objetos locales de JavaScript.
Muchas de estas librerías tienen la desventaja de que se pierde el control de bajo
nivel de la petición y de lo que sucede en la comunicación cliente-servidor.
Se empezará por analizar las más utilizadas en PHP.

SAJAX

Simple AJAX Toolkit for PHP (SAJAX) fue una de las primeras librerías para PHP que
incorporaron funcionalidades de AJAX a este lenguaje. Se puede descargar gratis de
ww.modernmethod.com/sajax y la idea es muy sencilla.

412
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 413

AJAX. Web 2.0 para profesionales

Desde PHP se hacen algunos includes obligatorios y luego se definen funciones


que se exportan a AJAX. Estas funciones, entonces, estarán disponibles para su eje-
cución directamente desde JavaScript. La librería se encargará de hacer la petición
XMLHttpRequest, pasar los parámetros y ejecutar la función finalmente en PHP.
Por ejemplo:

<?
require(”Sajax.php”);

function sumar($a, $b) {


return $a * $b;
}

sajax_init();
// Exportamos la función a JavaScript
sajax_export(”sumar”);
sajax_handle_client_request();

?>
<html>
<head>
<title>Suma AJAX</title>
<script>
<?
sajax_show_javascript();
?>

function recibirResultado(z) {
document.getElementById(”z”).value = z;
}

function hacerSuma() {
var a, b;

a = document.getElementById(”a”).value;
b = document.getElementById(”b”).value;
// Llamamos a la función de PHP con un prefijo _x
// Y le agregamos un último llamado que es la función
callback
x_sumar(a, b, recibirResultado);
}
</script>

</head>
<body>
<input type=”text” name=”a” id=”a” value=”2” size=”3”>
*
<input type=”text” name=”b” id=”b” value=”3” size=”3”>
=

413
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 414

Maximiliano R. Firtman

<input type=”text” name=”z” id=”z” value=”” size=”3”>


<input type=”button” name=”check” value=”Hacer Suma”
onclick=” hacerSuma (); return false;”>
</body>
</html>

XAJAX

XAJAX es similar a SAJAX con la diferencia de que implementa la funcionalidad en cla-


ses PHP compatible con PHP 4 y 5. Se puede descargar desde www.xajaxproject.org.
XAJAX incorpora un objeto llamado xajaxReponse, que permite que desde PHP
se le den instrucciones a JavaScript para que modifique algo del HTML, por ejemplo:

require_once(”xajax.inc.php”);
$xajax = new xajax();
$xajax->registerFunction(”myFunction”);

function suma($a, $b) {


$respuesta = new xajaxResponse();
$z = $a + $b;
// Le damos instrucciones al JavaScript desde PHP
$respuesta->addAssign(”divContenido”,”innerHTML”, ”La suma es
$z”);
$respuesta->addAssign(”z”,”value”, $z);
return $respuesta;
}

PAJAX

PAJAX es otra librería para PHP que va un poco más allá que las anteriores.
Este framework permite crear clases en PHP con la lógica de negocios que se
desea aplicar, y luego, desde JavaScript simplemente instanciar esas clases y ejecu-
tar sus métodos sin preocuparse por la comunicación con el servidor.

Por ejemplo:

<?
class Calculadora extends PajaxRemote {
function suma($x, $y) {

414
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 415

AJAX. Web 2.0 para profesionales

return $x + $y;
}

function multiplicacion($x, $y) {


return $x * $y;
}

...
}
?>

desde el XHTML se agrega un include:

<script type=”text/javascript”
src=”pajax_import.php?Calculadora”>
</script>

y luego simplemente se instancia el objeto y se lo usa como si fuera local de Java


Script.

window.onload = {
var calculadora = new Calculadora();
alert(calculadora.suma(2, 3));
}

La librería está para su descarga en www.auberger.com/pajax

Librerías para ASP.NET


Ahora se analizarán las librerías disponibles para la tecnología ASP.NET de Microsoft.

Ajax.NET Professional

Ésta fue la primera librería que surgió para conectar ASP.NET con tecnología AJAX de
manera fácil desde el servidor. Funciona en las versiones del .NET Framework 1.1 y 2.0
o superior.
Su sitio web es www.ajaxpro.info y sus funcionalidades permiten ejecutar desde
JavaScript métodos de una página ASPX sin ocuparse de las peticiones al servidor.

415
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 416

Maximiliano R. Firtman

Se debe descargar el paquete e instalar en la carpeta bin del proyecto el archivo


AjaxPro.dll, si se usa .NET 1.1, o AjaxPro.2.dll, si se utiliza .NET 2.0 o superior.
En el archivo de configuración web.config se debe incluir lo siguiente:

<?xml version=”1.0” encoding=”utf-8” ?>


<configuration>
<system.web>
<httpHandlers>
<add verb=”POST,GET” path=”ajaxpro/*.ashx” type=”AjaxPro.Ajax-
HandlerFactory, AjaxPro.2”/>
</httpHandlers>
</system.web>
</configuration>

Luego, se debe definir un atributo ante cada método que se desea llamar desde
JavaScript, por ejemplo, en C#:

[AjaxPro.AjaxMethod]
public int Suma(int a, int b)
{
return a+b;
}

o desde Visual Basic:

<AjaxPro.AjaxMethod> _
Public Function Suma(ByVal a as Integer, ByVal b as Integer) as
Integer
Return a+b
End Function

por último se agrega una línea en el evento Page_Load

AjaxPro.Utility.RegisterTypeForAjax(typeof(_Default));

el paso siguiente es conocer el espacio de nombres o nombre del proyecto donde se


está trabajando, y el nombre de la clase de la página, por ejemplo, _Default. Ahora,
desde JavaScript sólo se debe utilizar:

MiProyecto._Default.Suma(a, b, mostrarResultado);

416
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 417

AJAX. Web 2.0 para profesionales

Microsoft ASP.NET AJAX Extensions

Microsoft lanzó su paquete de agregado a la tecnología ASP.NET para la creación de


aplicaciones AJAX y realmente permite que se desarrolle una aplicación RIA con
ningún esfuerzo. Primero se lo conoció como Microsoft Atlas y por último se lo llamó
Microsoft ASP.NET AJAX Extensions. Su sitio oficial es ajax.asp.net.
Con soporte para Visual Studio y Visual Web Developer Express (la versión gra-
tuita) es posible crear aplicaciones AJAX en vista diseño sin tratar con JavaScript.
Para ello, la librería incorpora unos controles de servidor no visuales que se inte-
gran con el framework de ASP.NET para que cualquier página ASP.NET 2.0 o superior
se pueda convertir en AJAX insertando sólo un nuevo control en el formulario web.
Esto permite migrar sitios no AJAX en pocos minutos y garantizar toda la misma
funcionalidad que tenían antes (figs. 10-12 y 10-13).

Fig. 10-12. Microsoft ASP.NET AJAX da un paso adelante en la creación de sitios ricos sin necesidad
de programar nada de JavaScript utilizando controles de servidor.

417
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 418

Maximiliano R. Firtman

Fig. 10-13. Microsoft ofrece decenas de videos de cómo utilizar su librería de AJAX para ASP.NET.

Controles
Al paquete de controles básicos de ASP.NET se incorporan luego de instalar las ex-
tensiones:

Control Descripción

ScriptManager Es un control obligatorio que se debe insertar en el ASPX que generará


todos los JavaScripts necesarios.

UpdatePanel Permite insertar contenido y controles, y todos ellos harán postbacks


asincrónicos vía AJAX sin ningún otro cambio. También es posible
definir que otros eventos fuera del panel invoquen peticiones AJAX en
forma automática.

UpdateProgress Al asignar un UpdateProgress a un UpdatePanel se verá un cartel de


Cargando cuando el panel se actualice vía AJAX.

TimerControl Permite realizar una petición al servidor cada x segundos y ejecutar un


evento en el servidor.

ScriptManagerProxy Permite ejecutar AJAX en aplicaciones que usen páginas maestras


(MasterPages).

418
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 419

AJAX. Web 2.0 para profesionales

La versión más simple de este framework es incluir un ScriptManager al inicio de


un ASPX y luego un UpdatePanel encerrando todo el contenido. De manera automá-
tica toda la página pasará a actualizarse vía AJAX en lugar de hacer postbacks sin-
crónicos al servidor. Los eventos en el servidor se seguirán ejecutando de igual forma
y no se debe cambiar nada más. Para optimizar la transferencia, en UpdatePanel sólo
debería encerrarse el contenido que se actualiza en las peticiones.

Por ejemplo:

<asp:Form runat=”server”>
<ajax:ScriptManager id=”script1” runat=”server” />
<ajax:UpdatePanel runat=”server” id=”update1”>
<asp:Button runat=”server” onclick=”PulsaBoton” text=”Re-
cibir AJAX” />
<asp:Label runat=”server” id=”etiqueta” />
</ajax:UpdatePanel>
</asp:Form>

Por ejemplo, la función PulsaBoton, podría hacer:

etiqueta.Text = ”Hola AJAX”

Y cuando el usuario pulse el botón, se realizará una petición AJAX automática,


que dará como resultado que en la etiqueta se vea el texto Hola AJAX.

Control Toolkit
Además del paquete inicial, hay un paquete de controles visuales que agregan carac-
terísticas de sitios ricos de Internet a una aplicación web ASP.NET. Son todos contro-
les de servidor que se pueden arrastrar y soltar en Visual Studio o Visual Web Developer
y automáticamente estarán funcionando con XHTML, CSS y JavaScript. Algunos de
ellos son adaptadores que modifican el comportamiento de otros controles básicos,
como un TextBox con un AutoComplete.
Los controles son de código abierto y se actualizan en forma constante. Se puede
ver un ejemplo de cada control en ajax.asp.net/ajaxtoolkit (fig. 10-14).
Al momento de escribir este libro la lista es:

Accordion MutuallyExclusiveCheckBox
AlwaysVisibleControl NoBot
Animation NumericUpDown
AutoComplete PagingBulletedList
Calendar PasswordStrength

419
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 420

Maximiliano R. Firtman

CascadingDropDown NumericUpDown
CollapsiblePanel PagingBulletedList
ConfirmButton PasswordStrength
DragPanel PopupControl
DropDown Rating
DropShadow ReorderList
DynamicPopulate ResizableControl
FilteredTextBox RoundedCorners
HoverMenu Slider
ListSearch SlideShow
MaskedEdit TextBoxWatermark
ModalPopup ToggleButton
MutuallyExclusiveCheckBox UpdatePanelAnimation
NoBot ValidatorCallout

Fig. 10-14. Con AJAX Control Toolkit se podrán tener controles visuales ricos con sólo arrastrarlos y
configurarlos en el IDE.

420
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 421

AJAX. Web 2.0 para profesionales

Otros lenguajes
Se puede consultar una lista de frameworks y librerías actualizadas para cada lenguaje
en:

Java
ajaxpatterns.org/Java_Ajax_Frameworks

ColdFusion
ajaxpatterns.org/Coldfusion_Ajax_Frameworks

.NET
ajaxpatterns.org/DotNet_Ajax_Frameworks

Python
ajaxpatterns.org/Python_Ajax_Frameworks

PHP
ajaxpatterns.org/PHP_Ajax_Frameworks

Ruby
ajaxpatterns.org/Ruby_Ajax_Frameworks

421
C10.qxd:Project Ajax4.1.qxd 10/18/07 8:23 PM Página 422

Das könnte Ihnen auch gefallen