You are on page 1of 216

Aprende jQuery

PROGRAMACIN
TTULO DE LA OBRA ORIGINAL:

.3

Learning jQuery 1.3


RESPONSABLE EDITORIAL:

Vctor Manuel Ruiz Caldern


Alicia Czar Concejil
TRADUCTOR:

Beatriz Parra Prez


DISEO DE CUBIERTA:

Cecilia Poza Melero

.'
:".-

Ionathan Chaffer
Karl Swedberg

.s

,"-

..:~~

h\Nh\Yh\
.-MULTIMEDIA_

_~,
_._c. _ ~

\,.

Todos los nombres propios de programas, sistemas operativos, equipos


hardware, etc. que aparecen en este libro son marcas registradas de
sus respectivas compaas u organizaciones.

Reservados todos los derechos. El contenido de


esta obra est protegido por la Ley, que establece
penas de prisin y/o multas, adems de las
correspondientes indemnizaciones por daos y
perjuicios, para quienes reprodujeren, plagiaren,
distribuyeren o comunicaren pblicamente, en
todo o en parte, una obra literaria, artstica o
cientfica, o su transformacin, interpretacin
o ejecucin artstica fijada en cualquier tipo
de soporte o comunicada a travs de cualquier
medio, sin la preceptiva autorizacin.

Authorized translation from English language edition published


by Packt Publishing Ltd.
Copyright 2009 by Packt Publishing

Edicin espaola:
EDICIONES ANAYA MULTIMEDIA (GRUPO ANAYA, S.A.), 2010

Juan Ignacio Luca de Tena, 15. 28027 Madrid


Depsito legal: M-47.674-2009
ISBN: 978-84-415-2665-5
Printed in Spain
Impreso en: Grficas Hermanos Gmez, S. L. L.

Quiero dar las gracias a Jenny por su incansable entusiasmo y apoyo,


a Karl por su motivacin por continuar escribiendo cuando el espritu era dbil,
ya la comunidad Ars Technica por su constante inspiracin hacia la excelencia tcnica.
Jonathan Chaffer

"

;:;"';,
~,':.

Quiero dar las gracias a mi mujer Sara, por su constante amor y apoyo.
Gracias tambin a mis dos encantadores hijos, Benjamin y Lucia. Jonathan Chaffer
cuenta con mi ms profundo respeto por su experiencia en programacin y mi gratitud por su
deseo de escribir este libro conmigo.
Muchas gracias a [ohn Resig por crear la librera JavaScript ms grande del mundo y por
fomentar una sorprendente comunidad a su alrededor.
Gracias tambin a las personas de Packt Publishing, los revisores tcnicos de este libro, y a
todos aquellos que han proporcionado ayuda e inspiracin en el camino.
Karl Swedberg

Agradecimientos

Aprende jQuery 1.3

Sobre los autores

En estos momentos, Akash proporciona redaccin tcnica independiente y desarrollo


Web por medio de su sitio Web, http://bitmeta
. org.

]onathan Chaffer es el Director Tecnolgico de Structure Interactive, una agencia


interactiva con sede en Grand Rapids, Michigan. All supervisa los proyectos de desarrollo Web utilizando una amplia variedad de tecnologas, y colabora en tareas de
programacin del da a da, tambin.
En la comunidad de cdigo abierto, [onathan ha estado muy activo en el proyecto CMS
Drupal, que ha adoptado jQuery como el marco de trabajo JavaScript de su eleccin. Es
el creador del Content Construction Kit, un mdulo popular para gestionar contenido
estructurado en sitios Drupal. Es responsable de reparaciones importantes del sistema
de men de Drupal y desarrollador de referencia de API.
Jonathan vive en Grand Rapids con su mujer, Jennifer.
Karl Swedberg es desarrollador Web en Fusionary Media en Grand Rapids, Michigan,
donde pasa la mayor parte de su tiempo implementando diseo con el foco en "estndares Web", HTML semntico, CSS bien formado, y JavaScript sencillo, Miembro del
Equipo de proyecto jQuery y colaborador activo de la lista de distribucin jQuery, Kart .. _
es conferenciante habitual y ha impartido formacin corporativa en Europa y Amrica
del Norte.
Antes de su relacin actual con el desarrollo Web, Karl trabaj como editor de estiJQ,' ..profesor de ingls en un instituto y propietario de una cafetera. Su fascinacin con la"
tecnologa empez a principios de los aos 90 cuando trabaj en Microsoft en Redmond,
Washington, y ha continuado sin cesar desde entonces.
Karl preferira pasar el tiempo con su mujer, Sara, y sus dos hijos, Benjamin y
Lucia.

Sobre los revisores


Akash Mehta es des arrollador de aplicaciones Web, escritor tcnico y consultor con
sede en Brisbane, Australia. Sus proyectos anteriores incluyen sitios Web, soluciones
de e-learning y sistemas de informacin. Ha escrito artculos sobre desarrollo Web para
varios editores en medio impreso y online, es conferenciante habitual en conferencias
locales, y contribuye en blogs PHP.
Como estudiante, Akash mantena aplicaciones Web PHP y cre interfaces de usuario
utilizando el conjunto de herramientas jQuery. Mientras se dedicaba a obtener su titulacin en comercio y TI,Akash desarroll aplicaciones Web en plataformas PHP y Python.
Despus de horas, organiz su grupo de usuarios PHP local.
Akash desarrolla aplicaciones sobre una amplia variedad de libreras de cdigo
abierto. Su conjunto de herramientas incluyen una serie de marcos de trabajo de aplicaciones, incluido Zend, CakePHP y Django; marcos de trabajo Javascript como jQuery,
Prototype y Mootools, plataformas como Adobe Flash/Flex, y los motores de base de
datos MySQL y SQLite.

"

Dave Methvin cuenta con ms de'<25aos de experiencia en desarrollo de software


tanto en entornos Windows como Unix, Su carrera se ha centrado en software incorporado
en los campos de la robtica, telecomunicaciones, y medicina. Posteriormente, pas a
proyectos de software basados en PC utilizando C/C++ y tecnologas Web.
Dave cuenta tambin con ms de 20 aos de experiencia en periodismo informtico.
Fue Editor Ejecutivo en pe Tech Journal y Windows Magazine, tratando temas de PC e
/ Internet; sus columnas prcticas sobre JavaScript ofrecan algunas de las primeras solucienes de cortar y pegar a problemas comunes de pginas Web. Tambin fue co-autor
del libro Networking Windows NT (john Wiley & Sons, 1997).
Actualmente, Dave es Director Tecnolgico en PC Pitstop, un sitio Web que ayuda
a los usuarios a solucionar y optimizar el rendimiento de sus ordenadores. Tambin es
un colaborador activo en la comunidad jQuery.
Mike Alsup ha participado en el proyecto jQuery casi desde su creacin y ha contribuido con muchos plug-ins populares en la comunidad. Es un participante activo en el
jQuery Google Group donde frecuentemente proporciona soporte a los nuevos usuarios
jQuery.
Mike vive en el norte del estado de Nueva York con su mujer, Diane, y sus tres hijos
adolescentes. Es desarrollador de software en Click Commerce, Inc. donde se centra en
[ava, Swing, y desarrollo de aplicaciones Web.
Sus plug-ins jQuery se pueden encontrar en http : / / j query . mal sup . com/.

.,

Indice
d c nt id

i:':.,,~

Prlogo

18

Introduccin

22

Qu trata este libro


Qu necesita para este libro
Para quin es este libro
Convenciones
Cdigo fuente

24
25
25
25
26

1. Empezar a trabajar

28

Qu hace jQuery
Por qu jQuery funciona bien
Historia del proyecto jQuery
Nuestra primera pgina Web con jQuery
Descargar jQuery
Configurar el documento HTML
Aadir jQuery
Encontrar el texto del poema
Aplicar la nueva clase
Ejecutar el cdigo
El producto terminado
Resumen

29
31
32
33
33
33
36
36
37
37
38
39

2. Selectores

40

UUM

41

$0

42

ndice de contenidos

ndice de contenidos

Selectores CSS
Aplicar estilo a niveles de elementos de lista
Selectores de atributo
Aplicar estilo a vnculos
Selectores personalizados
Aplicar estilo a filas alternas
Selectores de formulario
Mtodos transversales DOM
Aplicar estilo a celdas especficas
Encadenar
Acceder a elementos DOM
Resumen

43
44
46
46

3. Eventos

56

Llevar a cabo tareas al cargar la pgina


Planificacin de la ejecucin de cdigo
Mltiples scripts en una pgina
,:
Mtodos abreviados para cdigo
Coexistir con otras libreras
Eventos sencillos
Un sencillo conmutador de estilo
Habilitar los otros botones
Contexto de manejador de evento
Mayor consolidacin
Eventos abreviados
Eventos compuestos
Mostrar y ocultar caractersticas avanzadas
Destacar elementos sobre los que se hace clic
El viaje de un evento
Efectos secundarios del burbujeo de eventos
Alterar el viaje: el objeto event ..................................................................w
Destinos de los eventos
Detener la propagacin de evento
Acciones predetermnadas
Delegacin de evento
Eliminar un manejador de evento
Espacio de nombres de evento
Volver a vincular eventos
Simular interaccin de usuario
Eventos de teclado
Resumen

57
57
58
60 ' . 60
61

48
48
51
51
52

53
54

55

"61
63'"
65
67
68
70
70
71
72
74
75
76
76
77
78
80
80
81
83

84
86

4. Efectos

88

Modificaciones CSS en lnea


Mtodos bsicos ocultar y mostrar

93

89

Efectos y velocidad
Aplicar velocidad
Aparecer y desaparecer de forma paulatina
Efectos compuestos
>.................................................................................
Crear animaciones personalizadas
Alternar el aparecer y desaparecer paulatino
Animar mltiples propiedades
Posicionar con CSS
Efectos simultneos frente a "en cola"
Trabajar con un solo conjunto de elementos
Trabajar con mltiples conjuntos de elementos
Rellamadas
,
En pocas palabras
Resumen

99 .
100
101
102
102
105
107
109
109

5. Manipulacin

110

DOM

95
96
96
97

98

Manipular atributos
Atributos que no son clase
La funcin factory $0 revisada
Insertar nuevos elementos
Mover elementos
Marcar, numerar y vincular el contexto
Anexar pies de pgina
Situar elementos alrededor de otros
Copiar elementos
Clonar con eventos
Clonar citas
Una desviacin CSS
De vuelta al cdigo
Embellecer las citas
Mtodos de manipulacin DOM
Resumen

111
112
114
115
118
121
122
124
125
126
126
127
127
129
131
132

6. AJAX

134

i~~

Ca~:~~t~::1~
~~.~~.~~:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Trabajar con objetos JavaScript
140
Recuperar un objeto JavaScript.
140
Funciones jQuery globales
141
Ejecutar un script
144
Cargar un documento XML
146
Elegir un formato de datos
150
Pasar datos al servidor
151
Llevar a cabo una peticin GET
151

lIfJI

Llevar a cabo una peticin POST


Serializar un formulario
Estar pendiente de la peticin
AJAX Yeventos
,.., ,
,..' ,
, ,
Limitaciones de seguridad , ,
Utilizar JSONP para datos remotos
Opciones adicionales , ,
"
, , "
El mtodo AJAX de bajo nivel...
Modificar opciones predeterminadas
, ,
Cargar partes de una pgina HTML..
Resumen
,
7.

ndice de contenidos

ndice de contenidos

Manipulacin

de tabla

154

,' , ,
,

' "

, , 156

,
,

,, ,
,.".,

158
160
, 161
162
163
164
, 164
165
, 167
17O

Ordenar y paginar
172
Ordenacin del lado del servidor
172
Impedir que la pgina se refresque
173
Ordenacin JavaScript
:
173 .
Etiquetas de agrupacin de filas
175
Ordenacin alfabtica bsica
175
El poder de los plug-ins
1z,'
Problemas de rendimiento
180.,
Manipular las teclas de ordenar
182
Ordenar otros tipos de datos
183
Resaltar columna
186
Alternar la direccin de la ordenacin
186
Paginacin del lado del servidor
188
Ordenar y paginar van juntos
189
Paginacin JavaScript
190
Mostrar el paginador
191
Habilitar los botones del paginador
192
Marcar la pgina actual..
: ~' ,
',
, 193
Paginacin con ordenacin
,
,
,.194
El cdigo terminado,
", ,
,.., ,
195
Modificar la apariencia de la tabla
197
Resaltar filas
,
,
,
197
Alternar color de filas
,..,
,..,
198
Alternar colores de fila avanzado
200
Resaltar filas basado en interaccin del usuario
202
Descripciones emergentes
,
,..,,
,
, ,.204
Contraer y expandir secciones
,
,
,
.,
209
Filtrado
,
,.., , ,
,
" , , ,
, ,..,.., ,..,
211
Opciones de filtro.,
,.".,
,
,
,
, ,
, 212
Invertir los filtros
,..,
,
,
,..,
,
, ,
, , , 213
Interactuar con otro cdigo
214

El cdigo terminado
Resumen
, : ,

, ,
,..,

,
,.,

8. Formularios con funciones

,
,

, , ;.. 216
, 219

220

~~

Mejorar un formulario bsico ..,


,.., , ,.."..,
Estilo de formulario mejorado de forma progresiva
La leyenda
,
,
,.., ,..,..".."
,
,,
Mensajes de campo obligatorio
Campos mostrados condicionalmente ., , , ,
Validacin de formulario ,
, , , , ,.., "
Campos obligatorios .."
, , ,
'
Formatos obligatorios ."
,
Una ltima comprobacin
, , ,.., ,..,
,
Manipulacin de casilla de verificacin
El cdigo terminado
,
,
,
, ,..,
Formularios compactos
,
,
Texto como marcador de posicin para campos
Autocompletar AJAX
,..,..,.,
, ,..,.., ,
En el servidor
,
, , ,
,..,
En el navegador
,
Completar el campo de bsqueda
Navegacin por medio de teclado
Gestionar las teclas del cursor.. ,
, ,..,
Insertar sugerencias en el campo
Eliminar la lista de sugerencias
Autocompletar frente a live search
El cdigo terminado
,
Trabajar con datos de formulario numricos
Estructura de tabla de carro de la compra
Rechazar entrada no numrica
,
"
,
Clculos numricos
,
,
,
, ,..,
Analizar y aplicar formato a moneda
Tratar con decimales .,
, ,
,..,
, ,
Otros clculos ,
,
,.., , " '.',.,
,
Redondear valores
,
,
".." , ,..,.,." ,.,
Toques finales."
, ,.., ,.., , ,..,.,
Eliminar elementos
,
Editar informacin de envo
, ,.., ,.., ,
' ,
El cdigo terminado
, "..,
, ,
Resumen
,.,.., "
, '..,..,

'
,
,
'
,

,
,
' ,

,
,
, ,
,
, ,
,

, ,
,
,
,.,

9. Rotativos
Titular rotativo
Configurar la pgina

221
222 '
,
, 224
225
228
,..,., ,
" 231
'
,
231
, ,..".., 234
,.. 236
238
241
243
243
, 246
"
247
'..,..,
, ,.., 247
249
249
, , ,
"".251
252
253
253
254
256
256
" 259
,
260
261
,
262
264
,
, 265
,
265
",
266
'
, , 270
,
, 273
,..,..,
,.. 275

276
,
,

,
,..,

, '

, ,

"
,

277
278

fndice de contenidos

ndice de contenidos

Recuperar el feed
Configurar el rotativo
La funcin rotar titular
Detenerse al pasar por encima
Recuperar un feed de un dominio diferente
Aadir un indicador de carga
Efecto degradado
El cdigo terminado
Un carrusel de imgenes
Configurar la pgina
Revisar los estilos con JavaScript..
Mover las imgenes cuando se hace clic
Aadir animacin deslizable
Mostrar iconos de accin
Ampliar imagen
Ocultar la portada ampliada
Mostrar un botn cerrar .........................................................................:
Ms diversin con el etiquetado
Animar la ampliacin de la portada
Aplazar las animaciones hasta que la imagen se carga
Aadir un indicador de carga
El cdigo terminado
Resumen

279
282
283
286
288
289
290
292
294
294
296
297
299
301
304
305
307
308
309
313

10. Utilizar plug-ins

320

Encontrar plug-ins y ayuda


Cmo utilizar un plug-in
El plug-in Form
Consejos y trucos
La librera de plug-ins jQuery UI...
Efectos
Animaciones de color
Animaciones de clase
Aceleracin y desaceleracin avanzada
Efectos adicionales
Componentes de interaccin
Widgets
ThemeRoller
Otros plug-ins recomendados
Formularios
Autocomplete
Validation
Jeditable
Masked input.

321
322
323
324
325
325
325
326
326
327
327
330
332
332
333
333
334
334
335

:'

3r4, '
316
318

Tablas
;.. 335
Tablesorter
336
jqGrid
......................................................................................................................... 336
Flexigrid
,,~
337
Imgenes
337
Jcrop
337
Magnify
337
jQuery Lightbox y cuadros de dilogo modales
338
FancyBox
338
r
Thickbox
339
BlockUI
340
jqModal
340
Grficas
:
340
Flot
341
Sparklines
341
Eventos
341
hoverIntent
342
Live query
342
Resumen
343
11. Desarrollar plug-ins

344

Aadir nuevas funciones globales


Aadir mltiples funciones
Qu sentido tiene?
Crear un mtodo de utilidad
Aadir mtodos de objeto jQuery
Contexto del mtodo de objeto
Encadenar mtodos
Mtodos transversales DOM
Aadir nuevos mtodos abreviados
Parmetros de mtodo
Parmetros sencillos
Mapas de parmetro
Valores de parmetro predeterminados
Funciones de rellamada
Predeterminados personalizables
Aadir una expresin de selector
Compartir un plug-in con el mundo
Convenciones de nombrado
Uso del alias $
Interfaces de mtodo
Estilo de la documentacin
Resumen

345
346
347
347
349
349
352
353
356
359
360
361
362
363
364
366
368
369
369
369
370
370

ndice de contenidos

ndice de contenidos

Apndice A. Recursos online

372

Documentacin jQuery
Wiki jQuery
API jQuery
Navegador de la API jQuery
jQuery visual
Visor jQueryAPI Adobe AIR
Referencia JavaScript
Centro de desarrollo Mozilla
Dev.opera
Referencia JScript MSDN
Quirksmode
JavaScript Toolbox
Compresores de cdigo JavaScript
Compresor YUI

373
373
373
374
374
374
374
374
374
375
375
375
375
375

~~~

~~~~~~:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::~::::::::::::::::::::::
~;~

Referencia (X)HTML.
,
Pgina principal de W3c..
Referencia CSS
Pgina principal CSS de W3C.
La chuleta CSS de Mezzoblue
Position is everything
Blogs de utilidad
El blog jQuery
Learning jQuery
Ajaxian
[ohn Resig
JavaScript ant
Roberts talk
Estndares Web con imaginacin
Snook
Recurso JavaScript de Matt Snider
I cant
DOM scripting
As days pass by
A list apart
Marcos de trabajo de desarrollo Web utilizando jQuery
Apndice B. Herramientas

de desarrollo

Herramientas para Firefox


Firebug
.Barra de herramientas de desarrollador Web

::

376
376
376, '
376
377
377
377
377
377
377
378
378
378
378
378
378
378
379
379
379
379
382
383
383
384

Venkman
Comprobador' de expresiones regulares
Herramientas para Internet Explorer
Microsoft Intlrnet Explorer Developej Toolbar
Microsoft Visual Web Developer
DebugBar
Drip
Herramientas para Safari
Men Develop
Inspector Web
Herramientas para Opera
Dragonfly
Otras herramientas
,
- Firebug Lite
NitobiBug
Paquete TextMate jQuery
Charles
Fiddler
:
Aptana

384
:.. 384
384
384
385
385 .
385
385
385
386
386
386
386
386
386
387
387
387
387

Apndice C. ]avaScript Closures

388

Funciones internas
,
El gran escape
mbito de aplicacin de variables
Interacciones entre closures
Closures en jQuery
Argumentos para $(document).readyO
Manejadores de evento
Peligros de prdidas de memoria
Bucles de referencia accidentales
El problema de prdidas de memoria de Internet Explorer
La buena noticia
Resumen

389
390
392
394
395
395
396
397
398
399
400
400

Apndice D. Referencia rpida

402

Expresiones de selector
Mtodos transversales DOM
Mtodos de evento
Mtodos de efecto
Mtodos de manipulacin DOM
Mtodos AJAX
Mtodos variados

403
405
407
409
410
413
414

ndice alfabtico

415

,
(

'..

.
'

.-.~

Prlogo

Me siento honrado de saber que Karl Swedberg y [onathan Chaffer han emprendido
la tarea de escribir este libro. Como el primer libro sobre jQuery, establece el estndar
que otros libros jQuery, y realmente, otros libros JavaScript en general, han intentado
igualar. Constantemente ha sido uno de los libros JavaScript ms vendidos desde su
aparicin, debido a su calidad y atencin al detalle.
Estoy especialmente contento de que Karl y Jonathan hayan escrito el libro ya que
los conoca muy bien y saba que seran perfectos para el trabajo. Al ser parte del equipo jQuery, he tenido la oportunidad de llegar a conocer a Karl bastante bien en los ltimos dos aos, y especialmente dentro del contexto de su esfuerzo por escribir este
libro. Viendo el resultado final, queda claro que sus conocimientos como desarrollador
y profesor de ingls estaban perfectamente diseados para esta tarea.
Tambin he tenido la oportunidad de conocer a ambos en persona, una ocurrencia
extraa en el mundo de los proyectos de cdigo abierto distribuidos, y continan siendo
miembros ntegros de la comunidad jQuery.
La librera jQuery se utiliza por muchas personas diferentes en la comunidad jQuery.
La comunidad est llena de diseadores, desarrolladores, personas que tienen experiencia programando y otros que no la tienen. Incluso dentro del equipo jQuery, tenemos personas de todos los perfiles que proporcionan su conocimiento en la direccin
del proyecto. Hay una cosa que es comn a todos los usuarios de jQuery, sin embargo:
somos una comunidad de desarrolladores y diseadores que quieren que el desarrollo
JavaScript sea sencillo.
Es casi un clich, en este punto, decir que un proyecto de cdigo abierto est orientado
a la comunidad, o que un proyecto quiere centrarse en ayudar a los nuevos usuarios a
empezar. Pero no slo es un gesto vaco para jQuery; es el combustible para el proyecto.

E!II

Prlogo

En estos momentos tenemos ms personas en el equipo jQuery dedicadas a gestionar la


comunidad jQuery, escribir documentacin o escribir plug-ins que a mantener la base
de cdigo principal. Aunque la salud de la librera es increblemente importante, la comunidad que rodea ese cdigo es la diferencia entre un proyecto mediocre, y uno que
cumplir y superar con creces sus necesidades.
Cmo gestionamos el proyecto, y cmo utilizamos el cdigo, es fundamentalmente
muy diferente de la mayora de proyectos de cdigo abierto, y de la mayora de libreras
JavaScript. El proyecto jQuery y la comunidad son increblemente expertos; sabemos lo
que hace que jQuery sea una experiencia de programacin diferente y hacemos todo lo
posible para pasar ese conocimiento a los compaeros usuarios.
La comunicad jQuery no es algo sobre lo que pueda leer para aprender; es algo en lo
que realmente tiene que participar plenamente para conocerlo. Espero que tenga la oportunidad de participar en ello. Anmese a participar en los foros, listas de distribucin y
blogs y permtanos guiarle por la experiencia de conocer jQuery mejor.
Para m, jQuery es mucho ms que un bloque de cdig. Es la suma total de experiencias que han sucedido a lo largo de los aos para que la librera pudiera ocurrir: los
considerables altibajos, enfrentarse al desarrollo junto con la emocin de verlo crecer y
tener xito, estando cerca de sus usuarios y miembros del equipo, entendindoles y tra- . tando de crecer y adaptarse.
Cuando vi que este libro hablada de jQuery y lo trataba como una herramienta unificada, me sent sorprendido y emocionado. Ver cmo otros aprenden, entienden y rribl- '
dean jQuery para que se ajuste a ellos es mucho de lo que hace que el proyecto sea tan'
estimulante.
No soy el nico que disfruta de jQuery en un nivel que es muy diferente de una relacin normal herramienta-usuario. No s si puedo resumir a qu se debe, pero lo he visto
una y otra vez, el momento en el que la cara de un usuario se ilumina al darse cuenta de
lo mucho que le puede ayudar jQuery.
Existe un momento especfico para un usuario jQuery, cuando se da cuenta que esta
herramienta que haba estado utilizando era de hecho mucho ms que una sencilla herramienta, y de repente su entendimiento de cmo escribir aplicaciones Web dinmicas
cambia completamente. Es una cosa increble, y absolutamente p: parte favorita del
proyecto jQuery.
Espero que tenga tambin la oportunidad de experimentar esta sensacin.
john Resig
Creador de jQuery

""

.",

.::~

lntrodu cion

Todo empez como un mero trabajo desinteresado, por amor al arte, all por el ao
2005, por [ohn Resig, un nio prodigio en JavaScript que ahora trabaja para Mozilla.
Inspirado por los pioneros en este terreno como Dean Edwards y Simon Willison, Resig
reuni una serie de funciones para que por medio de programacin fuera sencillo encontrar elementos en una pgina Web y asignarles comportamientos. Cuando hizo pblico su proyecto por primera vez en enero de 2006, haba aadido modificacin DOM
y animaciones bsicas. Le asign el nombre jQuery para enfatizar el papel decisivo de
encontrar o "consultar" partes de una pgina Web y actuar sobre ellas con JavaScript.
Pasados pocos aos desde entonces, jQuery ha crecido en su conjunto de caractersticas,
mejorado en su rendimiento, y adquirido una amplia aprobacin por algunos de los sitios ms populares en Internet. Aunque Resig sigue siendo el desarrollador principal del
proyecto, jQuery ha prosperado, al estilo de cdigo abierto, hasta el punto donde ahora
cuenta con un equipo de excelentes desarrolladores JavaScript, as como una comunidad
dinmica de miles de desarrolladores. La biblioteca JavaScript jQuery puede mejorar sus
sitios Web con independencia de su formacin previa. Proporciona una amplia variedad de caractersticas, una sintaxis fcil de aprender, y compatibilidad multiplataforma
robusta en un solo archivo compacto. Adems, se han desarrollado cientos de plug-ins
para ampliar la funcionalidad de jQuery, convirtindolo en una herramienta esencial
para casi cualquier ocasin de programacin del lado del cliente.
Este libro proporciona una introduccin a los conceptos jQuery, permitindole aadir interacciones y animaciones a sus pginas, incluso si los intentos previos de escribir
JavaScript le han dejado frustrado. Este libro le ayudar a superar los escollos asociados
con AJAX,eventos, efectos y caractersticas avanzadas del lenguaje JavaScript, y le proporciona una breve referencia a la librera jQuery para regresar una y otra vez.

Aprende jQuery 1.3

Introduccin

Qu trata este libro


En el captulo 1 conocer qu es la librera JavaScript jQuery. El captulo empieza con
una descripcin de jQuery y lo que puede hacer por usted. Le muestra cmo descargar
y establecer la librera, as corno escribir su primer script.
En el captulo 2 aprender cmo utilizar las expresiones selector de jQuery y los mtodos transversales DOM para encontrar elementos en la pgina, all donde se encuentren. Utilizar jQuery para aplicar estilo a un conjunto diverso de elementos de pgina,
algunas veces en una forma que CSS puro no puede.
En el captulo 3 utilizar el mecanismo de gestin de evento de jQuery para activar
comportamientos cuando ocurren eventos de navegador. Ver cmo jQuery facilita
anexar eventos a elementos discretamente, incluso antes de que la pgina termine de
cargarse. Y, se le presentarn ms temas avanzados, tales corno burbujeo de eventos,
delegacin y espacio de nombres.
En el captulo 4 se le presentarn las tcnicas de animacin de jQuery y ver cmo
ocultar, mostrar y mover elementos de pgina con efectos que son-tanto de utilidad
corno agradables a la vista.
En el captulo 5, aprender cmo cambiar su pgina. Este captulo le ensear cmo
alternar la estructura de un documento HTML, as corno su contenido, en el momento.
En el captulo 6 descubrir las muchas formas en las que jQuery facilita acceder-a .
funcionalidad del lado del servidor sin recurrir a refrescar pgina.
En los siguientes tres captulos (7, 8, Y9) trabajar en varios ejemplos del mundo real,
reuniendo lo que ha aprendido en varios captulos y creando soluciones jQuery robustas a problemas comunes.
En el captulo 7 ordenar, clasificar y aplicar estilo a informacin para crear diseos de datos bonitos y funcionales.
En el captulo 8 dominar los puntos de la validacin del lado del cliente, disear un
diseo de formulario adaptable, e implementar caractersticas de formulario interactivas
cliente-servidor corno autocompletar.
En el captulo 9 mejorar la belleza y utilidad de elementos, de pgina al mostrarlos
en bloques ms manejables. Har que la informacin se muestre a la vista y fuera de ella
tanto por su cuenta corno bajo el control del usuario.
Los captulos 10 y 11 le llevan ms all de los mtodos jQuery fundamentales para
explorar extensiones de terceros a la biblioteca, y le muestran varias formas en las que
puede ampliar la biblioteca usted mismo.
En el captulo 10 examinar el plug-in Form y la coleccin oficial de plug-ins de interfaz de usuario conocida corno jQuery UI. Tambin aprender dnde encontrar muchos
otros plug-ins jQuery populares y ver qu pueden hacer por usted.
En el captulo 11 aprender cmo aprovechar las impresionantes posibilidades de
uso de ampliacin de jQuery para desarrollar sus propios plug-ins desde el principio.
Crear sus propias funciones de utilidad, aadir mtodos de objeto jQuery, escribir
expresiones personalizadas de selector y mucho ms.
En el apndice A encontrar una gran cantidad de sitios Web informativos sobre
temas relacionados con jQuery, JavaScript, y el desarrollo Web en general.

lEa

En el apndice B descubrir un nmero de programas de terceros de utilidad y utilidades para editat y depurar cdigo jQuery dentro de su entorno de desarrollo personal.
En el apndice C adquirir un conocimiento profundo de los closures, qu son y cmo
los puede utilizar en su propio beneficio.
En el apndice D tendr una visin de conjunto de toda la librera jQuery, incluido
cada uno de sus mtodos y expresiones de selector. Su formato es perfecto para esos
momentos cuando sabe qu quiere hacer, pero no est seguro del nombre de mtodo o
selector correcto.

Qu necesita para este libro


Para poder escribir y ejecutar el cdigo que se demuestra en este libro, necesitar lo
siguiente:

Un editor de texto bsico.

Un navegador Web moderno corno Mozilla Firefox, Apple Safari, y Microsoft


Internet Explorer.

El archivo fuente jQuery, versin 1.3.1 o posterior, que se puede descargar de


http://jquery.com/.

Adems, para ejecutar los ejemplos AJAX del captulo 6, necesitar un servidor compatible con PHP.

Para quin es este libro


Este libro es para diseadores Web que desean crear elementos interactivos para
sus diseos, y para desarrolladores que desean crear la mejor interfaz de usuario para
sus aplicaciones Web. Conocimiento bsico de programacin JavaScript es necesario.
Necesitar saber los fundamentos bsicos de HTML y CSS, y debera estar cmodo con
la sintaxis de JavaScript. No se asume ningn conocimiento de jQuery, ni experiencia
con ninguna librera JavaScript.

Convenciones
Para ayudarle a sacar el mayor partido al texto y saber dnde se encuentra en cada
momento, a lo largo del libro utilizamos distintas convenciones:

Las combinaciones de teclas se muestran en negrita, corno por ejemplo Control-A.


Los botones de las distintas aplicaciones tambin se muestran en negrita.

ElJI

Introduccin

Los nombres de archivo, URL y cdigo incluido en texto se muestran en un tipo


de letra monoespacial.

Los mens, submens, opciones, cuadros de dilogo y dems elementos de la


interfaz de las aplicaciones se muestran en un tipo de letra Arial.

Un bloque de cdigo se establecer de la siguiente forma:


<html>
<head>
<title>el
</head>

ttulo</title>

<body>

<div>
<p>Esto
<p>Esto
<p>Esto
</div>
</body>
</html>

es un prrafo.</p>
es otro prrafo.</p>
es otro prrafo.</p>

Cuando deseamos llamar la atencin hacia una parte determinada de un bloque ..


de cdigo, las lneas relevantes o elementos aparecern en negrita:
$ (document)

.ready(function()

$ (/a [href'=mailto,
1/) .addClass (fmailto/)
$(/a[href$=.pdfl/)
.addClass(/pdflink/);
$ (fa [hrefA=http] [href*=henry] /)
.addClass(/henrylink/),

})

':;'"'-,

En estos cuadros se incluye informacin importante directamente relacionada con el


texto adjunto. Los trucos, sugerencias y comentarios afines relacionados con el tema
analizado se reproducen en este formato.

Cdigo fuente
Para desarrollar los ejemplos, puede optar por introducir manualmente el cdigo o
utilizar los archivos de cdigo fuente que acompaan al libro. Tambin puede descargar
el cdigo fuente utilizado en el sitio Web de Anaya (http://www .AnayaMultimedia .
es, seccin Soporte tcnico, opcin Complementos).

,
1[

"t;

r
r

...

1
m ez

a trabajar

Hoy en da World Wide Web es un entorno dinmico, y sus usuarios establecen un


nivel alto tanto para el estilo como para la funcin de los sitios. Para crear sitios interesantes e interactivos, los desarrolladores estn recurriendo a libreras JavaScript como
jQuery para automatizar tareas comunes y simplificar las complicadas. Una razn por
la que la librera jQuery es una eleccin popular es su capacidad de ayudar en una amplia variedad de tareas.
Puede parecer difcil saber por dnde empezar porque jQuery lleva a cabo muchas
funciones diferentes. Sin embargo, existe una coherencia y simetra en el diseo de la librera; la mayora de sus conceptos se toman de la estructura de HTML y CSS (Cascading
Style Sheets u Hojas de estilo en cascada). El diseo de la librera lleva a un comienzo
rpido para diseadores con poca experiencia de programacin ya que muchos desarrolladores Web tienen ms experiencia con estas tecnologas que con JavaScript. De hecho,
en este captulo escribimos un programa jQuery en slo tres lneas de cdigo. Por otro
lado, esta consistencia conceptual tambin ayudar a los programadores experimentados, como veremos en los captulos siguientes, ms avanzados.
Por lo tanto, veamos lo que jQuery puede hacer por nosotros.

Qu hace jQuery
La librera jQuery proporciona una capa de abstraccin de aplicacin general para
programacin Web comn, y por lo tanto es de utilidad en casi cualquier situacin de
programacin. Su naturaleza extensible significa que casi nunca podemos tratar todos

ElII

1. Empezar a trabajar

los posibles usos y funciones en un nico libro, ya que constantemente se estn desarrollando plug-ins para aadir nuevas posibilidades de uso. Las caractersticas principales,
sin embargo, abordan las siguientes necesidades:

Acceder a elementos en un documento: Sin una librera JavaScript, se tienen que


escribir muchas lneas de cdigo para recorrer el rbol DOM (Document Object
Model), y localizar partes especiales de la estructura de un documento HTML.
Un mecanismo selector robusto y eficiente se ofrece en jQuery para recuperar la
parte exacta del documento que se tiene que inspeccionar o manipular.

Modificar la apariencia de una pgina Web: CSS ofrece un mtodo potente de


influir en la forma en que se muestra un documento, pero se queda corto cuando
los navegadores Web no soportan todos los mismos estndares. Con jQuery, los
desarrolladores pueden llenar este vaco, basndose en el soporte de los mismos
estndares entre todos los navegadores. Adems, jQuery puede cambiar las clases
o propiedades de estilo individual aplicadas a una parte del documento incluso
despus de que se haya mostrado la pgina.

Alterar el contenido de un documento: No limitado a meros cambios estticos,


jQuery puede modificar el contenido de un documento con algunas teclas. El
texto se puede cambiar, las imgenes se pueden insertar o cambiar, las listas se
pueden reordenar, o toda la estructura del HTML se puede volver a escribir y
ampliar, todo ello con una sola API (Application Programming Interface o Interfaz
de programacin de aplicaciones) fcil de utilizar.

Responder a la interaccin de un usuario: Incluso los comportamientos ms


elaborados y potentes no son de utilidad si no podemos controlar cundo tienen
lugar. La librera jQuery ofrece una forma elegante de interceptar una amplia
variedad de eventos, como que el usuario haga clicen un vnculo, sin la necesidad
de saturar el propio cdigo HTML con manejadores de evento. Al mismo tiempo,
su API de gestin de eventos elimina las inconsistencias del navegador que a
menudo molestan a los desarrolladores Web.

Animar cambios realizados a un documento: Para implementar de forma eficiente


tales comportamientos interactivos, un diseador debe tambin proporcionar
feedback visual al usuario. La biblioteca jQuery facilita esto al proporcionar una
tabla de efectos, como desvanecerse, as como un conjunto de herramientas para
disear nuevas.

Recuperar informacin de un servidor sin refrescar una pgina: Este patrn de


cdigo se ha conocido como AJAX(Asynchronous JavaScript And XMLo JavaScript
asncrono y XML),Yayuda a los diseadores Web a disear un sitio rico en caractersticas. La librera jQuery elimina la complejidad especfica de navegador
de este proceso, permitiendo a los desarrolladores centrarse en la funcionalidad
del servidor.
Simplificar tareas JavaScript comunes: Adems de todas las caractersticas especficas de documento de jQuery, la librera proporciona mejoras a construcciones
JavaScript bsicas como iteracin y manipulacin de tabla.

Aprende jQuery 1.3

EII

Por qu.jQuery funciona bien


Con el reciente resurgimiento de iqters en HTML dinmico viene una proliferacin
de marcos de trabajo JavaScript. Algunos son especializados, centrndose en una o dos
de las tareas anteriores. Otros intentan catalogar cualquier comportamiento y animacin
posible, y las presentan pre-empaquetadas. Para mantener la amplia gama de caractersticas vistas anteriormente y seguir siendo compacto, jQuery emplea varias estrategias:

Aprovechar el conocimiento de CSS: Al basar el mecanismo para localizar elementos de pgina en selectores CSS,jQuery hereda una forma concisa y legible
de expresar la estructura de un documento. La librera jQuery se convierte en un
punto de entrada para diseadores que desean aadir comportamientos a sus
pginas porque
requisito previo para realizar desarrollo Web profesional es
conocimiento de sintaxis CSS.

un

Soportar extensiones: Para evitar el aumento de caractersticas, jQuery relega


usos especiales a plug-ins. El mtodo para crear nuevos plug-ins es sencillo y
bien documentado, que ha estimulado el desarrollo de una amplia variedad
de mdulos de utilidad. Incluso la mayora de las caractersticas en la descarga
jQuery bsica se realizan internamente por medio de la arquitectura plug-in, y
se pueden eliminar si se desea, resultando en una biblioteca incluso menor.

Abstraer los fallos de navegador: Una triste realidad del desarrollo Web es
que cada navegador tiene su propio conjunto de desviaciones de los estndares
publicados. Una parte significativa de cualquier aplicacin Web se puede relegar
a gestionar caractersticas de forma diferente en cada plataforma. Aunque el escenario de los navegadores en continuo cambio hace que un cdigo base neutro
para el navegador sea imposible para otras caractersticas avanzadas, jQuery
aade una capa de abstraccin que normaliza las tareas comunes, reduciendo el
tamao del cdigo, y simplificndolo tremendamente.

Siempre trabajar con conjuntos: Cuando le decimos a jQuery, Encontrar todos los
elementos con la clase collapsible y ocultarlos, no hay necesidad de pasar en bucle
por cada elemento devuelto. En su lugar, mtodos como. hide () se disean para
trabajar automticamente sobre conjuntos de objetos en lugar de individuales.
Esta tcnica, denominada iteracin implcita, significa que muchas construcciones
de bucle dejar).de ser necesarias, acortando el cdigo considerablemente.

Permitir mltiples acciones en una lnea: Para evitar uso excesivo de variables
temporales o repeticin malgastada, jQuery emplea un patrn de programacin
denominado encadenamiento para la mayora de sus mtodos. Esto significa que
el resultado de la mayora de operaciones en un objeto es el objeto en s mismo,
listo para la siguiente accin que se le va a aplicar.
Estas estrategias han mantenido el paquete jQuery reducido, por debajo de 20 KB
comprimido, mientras que al mismo tiempo proporciona tcnicas para mantener nuestro cdigo personalizado que utiliza la librera compacta, tambin.

1. Empezar a trabajar

La elegancia de la librera viene en parte por diseo, y en parte debido al proceso


evolutivo impulsado por la comunidad vibrante que ha surgido alrededor del proyecto.
Los usuarios de jQuery se renen para tratar no slo el desarrollo de plug-ins, sino tambin las mejores a la librera principal. El Apndice A detalla muchos de los recursos de
comunidad disponibles para los desarrolladores
jQuery. A pesar de los esfuerzos necesarios para crear un sistema as de robusto y flexible, el producto final es gratuito para
todos. Este proyecto de cdigo abierto tiene doble licencia bajo la Licencia Pblica de
GNU (apropiada para incluir en muchos otros proyectos de cdigo abierto) y la Licencia
MIT (para facilitar el uso de jQuery dentro de software propietario).

Aprende jQuery 1.3

jQuery 1.2.6 (mayo 2008): La funcionalidad


del popular
Brandon- Aaron se incluy en la librera principal.

jQuery}.3
(enero 2009): Una importante revisin del motor selector (Sizzle) proporcion un gran impulso al rerimiento de la librera. La delegacin de evento
pas a soportarse formalmente.

plug-in

Las notas para versiones jQuery ms antiguas se pueden encontrar


proyecto en http://docs
. j query. corn/His.tory
_of_jQuery.

Dimensions

de

en el sitio Web del

Historia del proyecto jQuerv


Este libro trata la funcionalidad
y sintaxis de jQuery 1.3.x, la versin ms actualizada
en el momento de escribir estas lneas. La premisa detrs de la biblioteca, proporcionar
una forma sencilla de encontrar elementos en una pgina Web y manipularlos,
no ha
cambiado en el transcurso de su desarrollo, pero s lo han hecho ciertos detalles de sintaxis y caractersticas. Esta breve visin de conjunto de la historia del proyecto describe
los cambios ms significativos de una versin a otra.

Fase de desarrollo pblico: [ohn Resig mencion por primera vez una mejora en
la biblioteca "Behaviour" del prototipo en agosto de 2005. Este nuevo marco de
trabajo se lanz formalmente
como jQuery el 14 de enero, 2006.

jQuery 1.0 (agosto 2006): sta, la primera versin estable de la biblioteca, ya dispona de soporte robusto para selectores CSS, manejadores de evento e interaccin
AJAX.

jQuery 1.1 (enero 2007): Esta versin simplificaba la API considerablemente.


Muchos mtodos rara vez utilizados se combinaron,
reduciendo
el nmero de
mtodos a aprender y documentar.

jQuery 1.1.3 (julio 2007): Esta versin menor contena importantes


mejoras de
velocidad para el motor selector de jQuery. A partir de esta versin, el rendimiento
de jQuery se comparara favorablemente
con las libreras JavaScript semejantes
como Prototype, Mootools, y Dojo.

jQuery 1.2 (septiembre


2007): La sintaxis XPath para seleccionar elementos se
elimin en esta versin, ya que pasaba a ser redundante
con la sintaxis CSS. La
personalizacin
de efectos pas a ser mucho ms flexible en esta versin, y el
desarrollo de plug-ins pas a ser ms sencillo con la incorporacin
de eventos de
espacio de nombre.

jQuery UI (septiembre 2007): Esta nueva suite de plug-in se anunci para sustituir
el plug-in popular, aunque antiguo, Interface. Se incluy una rica coleccin de
widgets prefabricados, as como un conjunto de herramientas para crear elementos
sofisticados como interfaces de arrastrar y soltar.

Nuestra primera pgina Web con jQuery


Ahora que hemos tratado el conjunto de caractersticas
jQuery, podemos examinar cmo utilizar la biblioteca.

que tenemos

disponibles

con

Descargar jQuery
El sitio Web jQuery oficial (http://j
query. corn/) es siempre el recurso ms ac ..
tualizado para cdigo y noticias relacionadas con la librera. Para empezar, necesitamos
una copia de jQuery, que se puede descargar desde la pgina principal del sitio. Varias
versiones de jQuery pueden estar disponibles
en cualquier momento dado; lo ms
apropiado para nosotros como desarrolladores
de sitios ser la versin no comprimida
ms actualizada de la librera. sta se puede reemplazar con una versin comprimida
en entornos de produccin. No necesita instalacin. Para utilizar jQuery, simplemente
necesitamos situarlo en nuestro sitio en una ubicacin pblica. Puesto que JavaScript es
un lenguaje interpretado,
no hay fase de compilacin o creacin por la que preocuparse.
Siempre que necesitemos una pgina para tener jQuery disponible, simplemente
haremos referencia a la ubicacin del archivo desde el documento HTML.

Configurar el documento HTMl


Existen tres partes en la mayora de ejemplos de uso jQuery: el propio documento
HTML, archivos CSS para aplicar estilo, y archivos JavaScript para actuar sobre l. Para
nuestro primer ejemplo, utilizaremos una pgina con un extracto de libro que tiene aplicadas un nmero de clases a partes de l.
<!DOCTYPE html PUELlC "-jjW3CjjDTD XHTML 1.0 TransitionaljjEN"
"http,jjwww.w3.orgjTRjxhtmlljDTDjxhtmll-transitional.dtd">
<html xmlns="http,jjwww.w3.orgj1999jxhtml"

lmI

1. Empezar a trabajar
xml:lang:=lIenll

Aprende jQuery 1.3

lang=lIen">

chead>
<meta
http-equiv="Content-Typell
content:="textjhtml; charset=utf-8 '/>
1

ctitle>Through

the Looking-Glassc/title>

<link rel="stylesheet"
href="alice.css"
type=lItext/cssll media=l!screenll />
cscript
cscript

src=lIjquery.jsll
sre= alice. j s
11

11

type=lItext/javascriptH></script>
type= text/j avascript ></ s c r pt s
I!

11

El diseo real de los archivos en el servidor no importa. Las referencias de un archivo a


otro se tienen que ajustar para coincidir con la organizacin que elegimos. En la mayora
de ejemplos de este libro, utilizaremos rutas de acceso relativas para hacer referencia
a archivos ( .. / images/foo. png) en lugar de rutas de acceso absolutas CI images/
f oo. png). Esto permitir que el cdigo se ejecute localmente sin la necesidad de un
servidor Web.

</head>
ebody>
<hl>Through the Looking-Glass</hl>
cdiv class="author">by
Lewis Carrollc/div>
cdiv class="chapter
id="chapter-l">
ch2 class=/(chapter-title">l.
Looking-Glass House</h2>
<p>There was a book lying near Alice on the table,
and while she sat watching the White King (for she
was still a little anxious about him, and had the
ink a11 ready te threw over him, in case he fainted
again), she turned over the leaves, to find some
part that she could read, <span c1ass="spoken">
"&mdashfor it1s all in some language I don't know,lI
</span> she said to herself.</p>
<p>It was like this.</p>
cdiv class="poem'1>
ch3 class=lpoem-title">YKCOWREBBAJc/h3>
cdiv class="poem-stanza">
cdiv>sevot yhtils eht dna ,gillirb sawT'c/div>
cdiv>;ebaw eht ni elbrnig dna eryg diDc/div>
cdiv>,sevogorob
eht erew ysmim l1Ac/div>
cdiv>.ebargtuo
shtar ernom eht dnAc/div>
c/div>
c/div>
<p>She puzzled over this for sorne time, but at last
a bright thought struck her. cspan class=l1spoken">
"Why, it's a Looking-glass
book, of course! And if
1 hold it up to a glass, the words will all go the
right way again."</span>c/p>
cp>This was the poem that Alice read.</p>
cdiv class="poem">
ch3 class="poem-title >JAEBERWOCKYc/h3>
cdiv class=l'poem-stanza11>
cdiv>'Twas brillig, and the slithy tovesc/div>
cdiv>Did gyre and gimble in the wabec/div>
cdiv>All mimsy were the borogoves,c/div>
cdiv>And the mame raths outgrabe.c/div>
11

tl

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

Inmediatamente a continuacin del prembulo HTML normal, se carga la hoja de


estilo. Para este ejemplo, utilizaremos una espartana.
body {
font: 62.5% Arial, Verdana,
)
hl
font-size: 2.5em
margin-bottom:
O
)
h2
font-size: 1.3em
margin-bottom:
.Semi
)
h3
font-size: l.lem;
margin-bottom:
O;
)
.poem (
margin: O 2em;
)
.highlight {
font-style, italic;
border, lpx solid #888;
padding, O.5em;
margin: O. Sem O,'
background-color:
#ffc;

sans-serif

Despus de hacer referencia a la hoja de estilo, se incluyen los archivos JavaScript. Es


importante que la etiqueta de script para la librera jQuery se site antes de la etiqueta
para nuestros scripts personalizados; de lo contrario, el marco de trabajo jQuery no se
encontrar disponible cuando nuestro cdigo intente hacerle referencia.

En el resto de este libro, solamente se imprimirn las partes relevantes de los archivos
HTMLy CSS. Los archivos completos se encuentran disponibles en la pgina Web de
Anaya Multimedia (http://www.AnayaMultimedia.es.
seccin Soporte tcnico,
opcin Complementos).

AprendejQuery

1. Empezar a trabajar

Ahora tenemos una pgina que se parece a la figura 1.1:

Through the Looking-Glass


by Lewi. Carroll

1. Looking.Glass House
There ...
as a book Iyill( ne.at AliOR on 11'1. tabla, anel whlle
throw ovar htm. in case he 'ante<!
aoaln),
she tumed OVIK

in. ,at w1Itcl11ng


Ihe

teeves.

lo find

the White King


~me part thal

wa~ stil! a Httle anxioltl


ccutd resd. "-f~ rts 811

(for $he
she

in

about him, anel hild the ink all ready lo


sorne lal'l9ullge
I clon't\I:.now,'"
she said lo

1.3

del libro. Pasaremos por las diferentes formas de localizar partes de un documento en
el captulo siguiente.
La funcin, $ () es en realidad una funcin factory para el objeto jQuery, que es el
componente bsico con el que trabaj~emos a partir de ahora. El objeto jQuery encapsula cero o ms elementos DOM, y nos permite interactuar con ellos de formas muy diferentes. En este caso, deseamos modificar la apariencia de estas partes de la pgina, y
realizaremos esto al cambiar las clases aplicadas al poema.

heuelf.
ltwldlike-lhls.

.Aplicar la nueva clase


r~--------------------

YKCOWRE8BAJ
sevot yhtils en! dn. ,glllirb S8Wr
:eb8w ent ni e\bmlg eoe etyV diO
,sevogOfob ~I erew ysmim tiA
.et>argtuo
shtar Rmom ehl dnA
She punled 0W!f Ihi, fOf soma time, bul al 1m. btighl lhought tUud: heJ. ~/hy. it's a loolting-gl8$ book. 01 coursel And i11 "old

it

up lo a glass, the words will all go

the rightW8y ageln."


T"is wu the

poem

thal Allc. ntad.

JA88ERWOCKY
'Twas bfillig, and the sllthy laves
Oid gyre and gimble in tne webe:
AII minuy
wete the borogoves.
And the mame raths outgrabe.

Figura 1.1. Aplicarestilosal poema.

Utilizaremos jQuery para aplicar un nuevo estilo al texto del poema.

El mtodo. addClass (), como la mayora de mtodos jQuery, tiene un nombre


auto descriptivo; aplica una clase CSS a la parte de la pgina que hemos seleccionado.
Su nico parmetro es el.nombre de la clase a aadir. Este mtodo, y su equivalente,
- . removeClass (), nos permitir fcilmente observar jQuery en accin a medida que
exploramos las diferentes expresiones de selector que tenemos disponibles. Por ahora,
nuestro ejemplo simplemente aade la clase highlight,
que nuestra hoja de estilo ha
definido como texto en cursiva con un borde.
Observe que no es necesaria iteracin para aadir la clase a todas las estrofas del
poema. Como hemos comentado, jQuery utiliza iteracin implcita dentro de mtodos
como. addClass (), por lo que una sola llamada de funcin es todo lo que necesita
para alterar todas las partes seleccionadas del documento.

Ejecutar el cdigo
Este ejemplo es para demostrar el uso sencillo de jQuery. En situaciones del mundo
real, este tipo de estilo se puede llevar a cabo slo con CSS.

$ (document) .ready(function() {
$ (' .poem-stanza') .addClass ('highlight');
}) ;

Juntos, $ () y . addClass () son suficientes para conseguir nuestro objetivo de cambiar la apariencia del texto del poema. Sin embargo, si esta lnea de cdigo se inserta
sola en el encabezado del documento, no tendr efecto. El cdigo JavaScript se ejecuta
generalmente tan pronto como se encuentra en el navegador, y en el momento en que se
procesa el encabezado, todava no hay HTML presente al que aplicar estilo. Necesitamos
retrasar la ejecucin del cdigo hasta despus de que el DOM est disponible para nuestro uso. El mecanismo tradicional para controlar cundo se ejecuta cdigo JavaScript es
llamar al cdigo desde los manejadores de evento. Muchos manejadores se encuentran
disponibles para eventos iniciados por el usuario, como c1icsdel ratn o pulsar teclas.
Si no tenemos jQuery disponible para nuestro uso, tendremos que basarnos en el manejador onload, que se activa despus de que la pgina (junto con todas sus imgenes) se
ha mostrado. Para activar nuestro cdigo desde el evento onload, situaremos el cdigo
dentro de una funcin:

Encontrar el texto del poema

function highlightPoemStanzas()
{
$(' .poem-stanza' I .addClass('highlight');

Aadir jQuery
Nuestro cdigo personalizado ir en el segundo archivo JavaScript, actualmente vaco, que hemos incluido desde HTML utilizando <script
S'rc="alice.js"
type=" text/j avascript"
></ s c r i.pt.>. Para este ejemplo, solamente necesitamos
tres lneas de cdigo:

La operacin fundamental en jQuery es seleccionar una parte del documento. Esto


se realiza con la construccin $ ( ) . Tpicamente, toma una cadena como parmetro, que
puede contener cualquier expresin de selector CSS.En este caso, deseamos encontrar
todas las partes del documento que tienen aplicada la clase poem-stanza, por lo que
el selector es muy sencillo. Sin embargo, trataremos opciones ms sofisticadas a lo largo

Luego anexaremos la funcin al evento al modificar la etiqueta HTML -cbody para


hacerle referencia:
<hody onload="highlightPoemStanzas()

">

ElII

1.

Aprende jQuery 1.3

Empezar a trabajar

Esto hace que nuestro cdigo se ejecute despus de que la pgina est completamente cargada.
Existen desventajas a este enfoque. Hemos alterado el propio HTML para efectuar
este cambio de comportamiento. Este estrecho acoplamiento de estructura y funcin satura el cdigo, posiblemente requiriendo que se repitan las mismas llamadas de funcin
durante muchas pginas diferentes, o en el caso de otros eventos como clics del ratn,
durante cada instancia de un elemento en una pgina. Aadir nuevos comportamientos
requerira entonces alteraciones en mltiples lugares, aumentando la oportunidad para
error y complicando flujos de trabajo paralelos para diseado res y programadores.
Para evitar este peligro, jQuery nos permite programar llamadas de funcin a activarse
una vez que se ha cargado el DOM, sin esperar a las imgenes, con la construccin $ (document) . ready () . Con nuestra funcin definida como antes, podemos escribir:

Through
by lewi,

the Looking-Glass

CanDil

1. Looking-Glass

H.ouse

Therewas a boot Iying rlCaf Auceen the tabla, 800 while she sal W8tchl~ theWhite King (fOfshe W8S51illa little anxiousabout hlm, 3M had the Ink all feady lo
IhJOWovar hlm. in case:he f.lnlQd ag.ain), ,he turrMld 0Vt!f tne leaves. lo fin<!som. p8Ji thal she aHJld ,ead, ~-fOf ir, all In tome language
I don', know,"S'ne said lo
1MfM:1t.
It WIU lb hls.
YKCOWREBBAJ
aelo'Oi yhtHa eht dna ,gillirb _wr
;ebaw ehl ni eJbei'J dna et)'9 diD
,H~ehtw.wj4llJti/Jl'
l/A
.abIugtuo mhu MKlIm ffht dnA
She puzzled 0W!f this for some time, but al last. bflgtrt lhoughl strud: h.. "Why, Ir. a L<x*ing-glau boOl. of cecrse!And If I hold 1I up lo a glaa. the words wlll all go
th4! tight.way 8gain,"
Thls was the poem lhal Allc. reed,
JAB8fRWOCKY

$Idocument)

.readylhighlightPoemStanzas);

Esta tcnica no requiere ninguna modificacin HTML. En su lugar, el comportamiento se anexa completamente desde el archivo JavaScript. Aprenderemos ms adelante
cmo responder a otros tipos de eventos, separando sus efectos desde la estructura
HTML tambin.
Esta encarnacin es todava un despilfarro porque la funcin highlightPoemStanzas () se define solamente para utilizarse inmediatamente, y exactamente una vez.
Esto significa que hemos utilizado un identificador en el espacio de nombres global de
funciones que tenemos que recordar no utilizar de nuevo. JavaScript, como otros lenguajes de programacin, tiene una forma de evitar esta ineficiencia denominada funciones
annimas (algunas veces tambin denominada funciones lambda). Al utilizar funciones
annimas, podemos escribir el cdigo como se present originalmente:
$Idocument)
.readylfunction()
{
$1' .poem-stanza')
.addClassl'highlight');
})

Al utilizar la palabra clave funct ion sin un nombre de funcin, definimos una funcin exactamente donde se necesita, y no antes. Esto elimina saturacin y nos lleva a tres
lneas de JavaScript. Este estilo es extremadamente adecuado en cdigo jQuery, ya que
muchos mtodos toman una funcin como un argumento y dichas funciones raramente
son reutilizables.
Cuando se utiliza esta sintaxis para definir una funcin annima dentro del cuerpo
de otra funcin, se puede crear un cierre. ste es un concepto avanzado y potente, pero
se debera entender cuando se haga amplio uso de definiciones anidadas de funcin ya
que puede tener consecuencias inesperadas y ramificaciones en el uso de memoria. Este
tema se trata en el Apndice C.

El producto terminado
Ahora que nuestro JavaScript est en su lugar, la pgina se parece a la que se muestra en la figura 1.2:

7wa. txil/ig, snd /he .Uthy lo","


Did g)n! and gmbl. in lita
AlI.IIIlmsy WBrIi! the borogo\OWII,
Artd the lIIfome ralha outgmbe.

w.~

Figura 1.2. Resultado final.

Las estrofas del poema ahora estn en cursiva y encerradas en cajas, como se ha especificado por la hoja de estilo alice. c s s, debido a la insercin de la clase highlight
por el cdigo JavaScript.

Resumen
Ahora ya tenemos una idea de por qu un desarrollador elegira utilizar un marco
de trabajo JavaScript en lugar de escribir todo el cdigo desde el principio, incluso para
las tareas ms bsicas. Tambin hemos visto algunas formas en las que jQuery sobresale como marco de trabajo, y por qu podramos elegirlo sobre otras opciones. Tambin
sabemos en general qu tareas hace ms sencillas jQuery.
En este captulo, hemos aprendido cmo poner jQuery disponible para el cdigo
JavaScript en nuestra pgina Web, utilizar la funcin $ () para localizar una parte de la
pgina que tiene una clase dada, llamar a . addClass () para aplicar estilo adicional a
esta parte de la pgina, e invocar $ (documen t ) . ready () para hacer que este cdigo
se ejecute al cargarse la pgina.
El ejemplo sencillo que hemos utilizado demuestra cmo funciona jQuery, pero no
es de mucha utilidad en situaciones del mundo real. En el siguiente captulo, ampliaremos este cdigo al explorar el sofisticado lenguaje selector de jQuery, encontrando usos
prcticos para esta tcnica.

,,

""

.'

2
electores,

La librera jQuery aprovecha el potencial de los selectores CSS (Cascading Style Sheets
u Hojas de estilo en cascada) para permitimos acceder rpida y fcilmente a elementos o grupos de elementos en el DQM (Document Object Modelo Modelo de Objetos de
Documento). En este captulo, exploraremos algunos de estos selectores, as como los
selectores personalizados de jQuery. Tambin examinaremos los mtodos transversales DOM de jQuery que proporcionan incluso mayor flexibilidad para obtener lo que
queremos.

El DOM
Uno de los aspectos ms potentes de jQuery es su capacidad para que la seleccin de
elementos en el DOM sea sencilla. El DOM es una estructura en rbol de tipos. HTML,
como otros lenguajes de marcacin, utiliza este modelo para describir las relaciones de
cosas en una pgina. Cuando hacemos referencia a estas relaciones, utilizamos la misma
terminologa que utilizamos cuando hacemos referencia a relaciones familiares, padres,
hijos, etc.
Un sencillo ejemplo puede ayudamos a entender cmo la metfora del rbol familiar
se aplica a un documento:
e ht.ml
<:head>

<title>the
</head>

title</title>

IIPJI

,,

2. Selectores
<body>
<div>
ep>This
ep>This
ep>This
e/div>
e/body>
e/htrnl>

Aprende jQuery 1.3

11m

Tabla 2.1. Ejemplo de selectores.


is a paragraph.</p>
is another paragraph.e/p>
is yet another paragraph.e/p>

Aqu, <h t ml > es el ancestro de todos los otros elementos; en otras palabras, todos
los otros elementos son descendientes de c ht.m Lc-. Los elementos -che ad y -ebody
no son slo descendientes, sino hijos de -cht.rnl., tambin. De igual forma, adems de
ser el ancestro de ehe ad y body, ht ml es tambin su padre. Los elementos <p>
son hijos (y descendientes) de <di V>, descendientes de body y <html , y hermanos
entre s. Para informacin sobre cmo visualizar la estructura de rbol familiar del DOM
utilizando software de terceros, consulte el Apndice B.
Un punto importante a destacar antes de empezar es que el conjunto de elementos
resultante desde selectores y mtodos siempre se encuentra situado en un objeto jQuery.
Es muy sencillo trabajar con objetos jQuery cuando queremos realmente hacer algo con
las cosas que encontramos en una pgina. Podemos fcilmente vincular eventos a estos
objetos y aadir les efectos, as como encadenar mltiples modificaciones o efectos juntos.
No obstante, los objetos jQuery son diferentes de los elementos DOM normales o listas de
nodo, y como tales no necesariamente proporcionan los mismos mtodos y propiedades
para algunas tares. En la ltima parte del captulo, por lo tanto, examinaremos formas
de acceder a los elementos DOM que se encuentran en un objeto jQuery.

La funcin factory

$0

Nombre etiqueta

$(/p/)

Selecciona
mento.

ID

#un-id

$(/#un-idl)

Selecciona el nico elemento en el documento


que tiene un ID de un-id.

Clase

.una-clase

$(/.una-clase/)

Selecciona todos los elementos en el documento que tienen una clase de una-clase.

Selecto res CSS


La librera CSS soporta casi todos los selectores incluidos en las especificaciones CSS
1 a 3, como se detalla en el sitio Web del World Wide Web Consortium: http://www
.
w3. org/Style/CSS/#specs.
Este soporte permite a los desarrolladores mejorar sus
sitios Web sin preocuparse por qu navegador (particularmente Internet Explorer 6)
podra no entender selectores avanzados, siempre y cuando los navegadores tengan
habilitado JavaScript.

Desarrolladores jQuery responsables deberan siempre aplicar los conceptos de mejora


progresiva y degradacin elegante a su cdigo, asegurando que una pgina se mostrar
igual de precisa con JavaScript desactivado como lo hace con JavaScript activado.
Continuaremos explorando estos conceptos a lo largo del libro.
Para empezar a aprender cmo funciona jQuery con selectores CSS, utilizaremos
una estructura que aparece en muchos sitios Web, a menudo para navegacin: la lista
anidada, sin ordenar.
<ul

Tres bloques principales de estos selectores son nombre etiqueta, ID, y clase. Se pueden utilizar de forma independiente o en combinacin con otros selectores. La tabla 2.1
muestra un ejemplo del aspecto que tiene cada uno de estos tres selectores.

en el docu-

Como se ha mencionado en el captulo anterior, cuando anexamos mtodos a la funcin factory $ ( ) , se pasa en bucle automticamente e implcitamente por los elementos
situados en el objeto jQuery. Por lo tanto, podemos evitar normalmente la iteracin explcita, como un bucle for, que a menudo es necesario en programacin DOM.
Ahora que hemos tratado los aspectos bsicos, estamos listos para empezar a explorar algunos usos de selectores ms potentes.

Con independencia del tipo de selector que queremos utilizar en jQuery, siempre
empezamos con el signo de dlar y parntesis: $ () . Cualquier cosa que podemos utilizar en una hoja de estilo tambin se puede situar entre comillas y dentro de parntesis,
permitindonos aplicar mtodos jQuery al conjunto coincidente de elementos.

En jQuery, el signo de dlar $ es simplemente un "alias" para jQuery. Pueden surgir


conflictos si ms de una de estas libreras se utilizan en una pgina dada porque una
funcin $ () es muy comn en libreras JavaScript. Podemos evitar tales conflictos al
reemplazar cada instancia de $ con j Query en nuestro cdigo jQuery personalizado.

todos los prrafos

id=llselected-plays >
<li>Comedies
<ul>
I

<li><a href="/asyoulikeit/n>As
You
eli>All/s
Well That Ends Well</li>
eli>A Midsurnrner Night/s
Drearne/li>

Like

It</a></li>

11m

Aprende jQuery 1.3

2.Selectores

<li>Twelfth

.horizontal
{
float, left;
list-style: none;
margin: l?;pX

Night</li>

</ul>
</li>
<li>Tragedies
<ul>
<li><a href="hamlet.pdf">Harnlet</a></li>
<li>Macbeth</li>
<li:>Romeo and Juliet</li>
</ul>
</lb
<li:>Histories
<ul>
<li>Henry

IV

}
.sub-level
(
background:

ll

V</a></li>

Observe que la primera -cu L tiene un ID de selected-plays,


pero ninguna de
las etiquetas < 1 i > tiene una clase asociada. Sin ningn estilo aplicado, la lista se parece
a la figura 2.1:
Comedies
o As You Like It
o All's Well That Ends Well
o A Midsummer Night's Dream
o 1We1fth Night
Tragedies
o Hamlet
o Macbeth
o Romeo and Juliet

Como se ha tratado en el captulo anterior, empezamos el cdigo jQuery con el


envoltorio $ (document)
. ready () r que se ejecuta tan pronto como se ha cargado el
DOM.
La segunda lnea utiliza el combinador hijo ( para aadir la clase horizontal
a todos los elementos de nivel superior nicamente. En efecto, el selector dentro de la
funcin $ () dice, encontrar todo elemento de lista (li) que es un hijo ( del elemento con un
ID de selected-plays
(#selected-plays).
Con la clase ahora aplicada, nuestra lista anidada se parece a la figura 2.2:

Comedes
o As You Uke lt
o AIt's Well That Ends Well
o A Midsummer NIght's Dream
o lWelfth Night

Histories
o Henry IV (email)

Pan!
PanlJ
o

2.1. Lista sin estilo.

La lista anidada aparece como esperaramos que lo hiciera, un conjunto de elementos


con boliches organizados verticalmente y sangrados de acuerdo a su nivel.

Aplicar estilo a niveles de elementos de lista


Supongamos que deseamos que los elementos de nivel superior, y solamente los elementos de nivel superior, se organicen horizontalmente. Podemos empezar por definir
una clase horizontal
en la hoja de estilo:

Tragedles
o Hamlet
o Macbeth
o Romeo and Juliet

Histories
o Henry N (emall)
Part

Part

o HenrvV
o Richard II

Figura 2.2. Aplicar la clase horizontal a la lista.

HenryV
Richard lJ

Figura

#CCC

$ (document) .ready(function()
{
$(f#selected-plays
> li/) .addClass(/horizontal/);

})

II</li>

</ul>
</li>
</ul>

'"

La clase horizontal
flota el elemento a la izquierda del que le sigue, elimina el
boliche de l si es un elemento de lista, y aade un margen de 10 pxeles en todos los
lados.
En lugar de anexar la clase horizontal
directamente en nuestro HTML, lo aadiremos.dinmicamente
a los elementos de lista de nivel superior nicamente, Comedies,
Tragedies,
Histories,
para demostrar el uso de selectores de jQuery:

href=lImailto:henryiv@king.co.uk >email</a

<ul>
<li>Part
I</li>
<li>Part II</li>
</ul>
<li><a href="http://www.shakespeare.co.uk/henryv.htm">Henry
<li>Richard

Aplicar estilo a los otros elementos, los que no se encuentran en el nivel superior, se
puede realizar de varias formas.
Puesto que ya hemos aplicado la clase horizontal
a los elementos de nivel superior, una forma de seleccionar todos los elementos por debajo del nivel es utilizar una
pseudo-clase de negacin para identificar todos los elementos de lista que no tienen una
clase horizontal.
Observe la incorporacin de la tercera lnea de cdigo:
(document) .ready(function()
{
$(/#selected-plays
> li/) .addClass(/horizontal/);
$(/#selected-plays
li:not(.horizontal)/)
.addClass(/sub-level/);

})

I!'

lIIlII

Aprende jQuery 1.3

2. Se/ectores

Digamos que queremos tener diferentes estilos para diferentes tipos de vnc;ulos.
Primero definimos los estilos en nuestra hoja de estilo:

Esta vez estamos seleccionando todo elemento de lista (1 i) que:


1. Es un descendiente del elemento con un ID de selected-plays
plays).
2. No tiene una clase hori zontal

(: not ( . hori zontal)

(#selected-

Histories

o
o
o
o

o
o
o
o

Figura

a
color,

'"

#OOc;

).

Cuando aadimos la clase sub-level


a estos elementos, reciben el fondo sombreado definido en la hoja de estilo. Ahora la lista anidada se parece a lo que se muestra en
la figura 2.3:
Comedias

lIiII

a.mailto
(
background,
url(images/mail.png)
padding-right,
18px;

no-repeat

right

top;

}
a .pdflink
(
background,
url(images/pdf.png)
padding-right,
18px;

no-repeat

right

top;

}
a.henrylink
{
background-color,
padding,
2px;
border,
lpx solid

#ff~;
#000;

2.3. Listaconfondosombreado.

Selectores de atributo
Los selectores de atributo son un subconjunto particularmente de utilidad de los selectores CSS.Nos permiten especificar un elemento por una de sus propiedades HTML,
como el atributo title
de un vnculo o el atributo alt de una imagen.
Por ejemplo, para seleccionar todas las imgenes que tiene un atributo al t , escribimos lo siguiente:
$ (limg [alt1 j)

En versiones anteriores a 1.2, jQuery utilizabala sintaxis XMLPath Language(XPath)


para sus selectoresde atributo e inclua un conjunto de otros selectoresXPath.Aunque
estos selectores XPath bsicos se han eliminado desde entonces de la librera jQuery
principal, siguen estando disponibles comoun plug-in: http://plugins
. j query.
com/project/xpath/

Aplicar estilo a vnculos


Los selectores de atributo aceptan una sintaxis de comodines inspirada por las expresiones regulares para identificar el valor al principio () o final (s) de una cadena.
Tambin pueden tomar un asterisco (*) para indicar el 'Valoren una posicin arbitraria
dentro de una cadena o un signo de exclamacin para indicar un valor negado.

Luego, aadimos las tres clases, mail t o, pdfl ink, y henryl Lrik, a los vnculos
apropiados utilizando jQuery.
Para aadir una clase para todos los vnculos de correo electrnico, construimos un
selector que busca todos los elementos ancla (a) con un atributo href ( [href) que empieza con mail to: (=mail to: 1 ), de la siguiente forma:
$( document) .ready(function()
(
$(/a[hrefA=mailto:l/)
.addClass(/mailto/);
}) ;

Para aadir una clase para todos los vnculos a archivos PDF, utilizamos el signo
de dlar en lugar del smbolo />. Esto es porque estamos seleccionando vnculos con un
atributo href que termina con. pdf:
$ (document) .ready(function()
{
$ (la [hrefA=mailto, 1/) .addClass (lmail to/) ;
$(/a[href$=.pdfl/)
.addClass(/pdflink/);
}) ;

Los selectores de atributo tambin se pueden combinar. Podemos, por ejemplo, aadir una clase henrylink para todos los vnculos con un valor href que empieza con
ht tp Ycontiene henry en cualquier lugar:
$Idocument) .readylfunctionl)
(
$(/a[hrefA=mailto:1/)
.addClassl/mailto/);
$1/a[href$=.pdf1/)
.addClassl/pdflink/);
$ (/a[hrefA=http1
[href*=henryl/l
.addClassl/henrylink/l;

}l ;

Con las tres clases aplicadas a los tres tipos de vnculos, deberamos ver la figura 2.4.
Observe el icono PDF a la derecha del vnculo Harnlet, el icono de sobre junto al vnculo
emal, y el fondo blanco y borde negro alrededor del vnculo Henry V.

KIlII

Aprende jQuery 1.3

2. Selectores

<td>Macbeth</td>
<td>Tr~gedy</td>
<td>1606</td>
</tr>
o

...

<tr>

o
o

<td>Romeo and Juliet</td>


<td>Tragedy</td>
<td>1595</td>
</tr>

Figura 2.4. Lista mejorada con clases.

<tr>

<td>Henry IV, Part I</td>


<td>History</td>
<td>1596</td>
</tr>
<.tr>

Selectores personalizados
Para la amplia variedad de selectores CSS,jQuery aade sus propios selectores personalizados. La mayora de los selectores personalizados nos permiten elegir ciertos
elementos de una lnea, por as decirlo. La sintaxis es la misma que la sintaxis de pseudo-clase CSS, donde el selector empieza con dos puntos (:). Por ejemplo, para seleccionar el segundo elemento de un conjunto coincidente de selectores di v con una clase de
horizontal,
escribimos esto:
$(1 div.horizontal,eq(l)1)

Observe que: eq ( 1) selecciona el segundo elemento en el conjunto porque la numeracin de tabla JavaScript es de base cero, lo que significa que empieza con O. Por el contrario, CSSes de base uno, parla que un selector CSScomo $ (/di v: nth-child
(1) /)
seleccionara todos los selectores di v que son el primer hijo de su padre (en este caso,
sin embargo, utilizaramos probablemente $ (/di v: first -childj)
en su lugar).

Aplicar estilo a filas alternas


Dos selectores personalizados de mucha utilidad en la librera jQuery son : odd y
: even. Echemos un vistazo a cmo podemos utilizar uno de ellos para las bandas bsicas de tablas, dada la siguiente tabla:
<.table>
<.tr>
<td>As

You Like It</td>

<td>comedy</td>
<td></td>
</tr>
<.tr>
<td>All/s

Well

<td>Henry V</td>
<td>History</td>
<td>1599</td>
</tr>
</table>

Ahora podemos aadir un estilo a la hoja de estilo para todas las filas de tabla, y utilizar una clase alt para las filas pares:
tr
background-color,

#fff;

.alt (
background-color,

#ccc;

Por ltimo, escribimos nuestro cdigo jQuery, anexando la clase a las filas de tabla
pares (etiquetas e t r s ):
$ (document) .ready(function()
(
$(/tr,odd/) .addClass(/alt/);

})

Pero, iespere! Por qu utilizar el selector :odd para las filas pares? Bueno, como
con el selector : eq ( ) , los selectores : odd y : even utilizan la numeracin en base cero
nativa de JavaScript. Por lo tanto, la primera fila cuenta como O (par) y la segunda fila
cuenta como 1 (impar), etc. Con esto en mente, podemos esperar que nuestro sencillo
cdigo produzca una tabla que se parece a la figura 2.5:

that Ends Well</td>

<td>comedy</td>
<td>1601</td>
</tr>
<.tr>

<td>Hamlet</td>
<td>Tragedy</td>
<td>1604</td>
</tr>
<.tr>

Figura 2.5. Aplicar estilo en filas alternas.

Aprende jQuery 1.3

2. Selectores

Observe que podemos ver resultados no deseados si existe ms de una tabla en una
pgina. Por ejemplo, puesto que la ltima fila en esta tabla tiene un fondo blanco, la primera fila en la siguiente tabla tendr el fondo gris "alterno". Una forma de evitar este
tipo de problema es utilizar el selector :nth - child () en su lugar. Este selector puede
tomar un nmero, odd, o even como su argumento. Sin embargo, : nth-child
() es
el nico selector jQuery que es en base uno. Para conseguir las mismas bandas de filas
que hemos realizado antes, y para que sea consistente entre mltiples tablas en un documento, el cdigo se parecera a esto:
$ (document) .ready(function()
(
$(/tr,nth-child(even)/)
.addClass(/alt/);
))

Para un ltimo toque de selector personalizado, supongamos por alguna razn que
queremos resaltar cualquier celda de tabla que haga referencia a una de las obras que
contienen Henry.
Todo lo que tenemos que hacer, despus de aadir una clase a la hoja de estilo para
que aparezca el texto en negrita y cursiva ( .highlight
{font-'(i'eight
:bold;
font-style:
i talics;
}), es aadir una lnea a nuestro cdigo jQuery, utilizando el
selector : contains
() .
$ (document) .ready(function()
(
$ (/tr,nth-child(even)/)
.addClass(/alt/);
$ (/td:contains(Henry)/)
.addClass(/highlight/);

})

Por lo tanto, ahora podemos ver nuestra hermosa tabla a rayas con las obras de Henry
destacadas de forma notable (vase la figura 2.6):

Selector.es de formulario
Cuando.se trabaja con formularios, los selectores personalizados de jQuery pueden
facilitar seleccionar simplemente 10'8 elementos que necesitamos. La tabla 2.2 describe
un conjunto de estos selectores.
Tabla

2.2. Selectores personalizados.

: text, :checkbox,
: radio, : image, :submit,
:reset, :password, :,file

Incorporaelementos con un atributotype igual al nombre del


selector (excluidoslos dos puntos).Por ejemplo, :text selecciona <input t.ype t.ext .

: input

Elementos input, textarea,

:button

Elementos button y elementos input con un atributotype


igual a button.

:enabled

Elementos de formularioque estn habilitados.

:disabled

Elementos de formularioque estn deshabilitados.

:checked

Botonesde opciny casillasde verificacinque estn seleccionadas.

:selected

Elementos de opcin que estn seleccionados.

e v

select,

y but ton.

Como con otros selectores, los selectores de formulario se pueden combinar para
mayor especificidad. Podemos, por ejemplo, seleccionar todos los botones de opcin
seleccionados (pero no las casillas de verificacin) con $ (/ : radio: checked/)
o
seleccionar todas las entradas de contrasea y entradas de texto deshabilitadas con
$ (/ : pas sword, : text : di sabled/ ) .Incluso con selectores personalizados, utilizamos
los mismos principios bsicos de CSS para crear la lista de elementos coincidentes.

Mtodos transversales DOM


Figura

2.6. Aplicarselector al cdigo.

Es importante destacar que el selector : contains


() es sensible a mayscula y minscula. Utilizar $ (/td: contains
(henry) /) en su lugar, sin la "H" mayscula, no
seleccionar ninguna celda.
Sin duda alguna, existen formas de conseguir las rayas de fila y resaltar texto sin
[Query, o cualquier programacin del lado del cliente, para el caso. No obstante, jQuery,
junto con CSS, es una estupenda alternativa para este tipo de estilo en casos donde el
contenido se genera dinmicamente y no tenemos acceso al HTML o al cdigo del lado
del servidor.

Los selectores jQuery que hemos explorado hasta el momento nos permiten seleccionar un conjunto de elementos a medida que navegamos por el rbol DOM y filtrar los
resultados. Si sta fuera la nica forma de seleccionar elementos, nuestras opciones estaran bastante limitadas (aunque, francamente, las expresiones de selector son robustas
por derecho propio, especialmente cuando se compara con las opciones de programacin
DOM normal). Existen muchas ocasiones cuando seleccionar un elemento padre o ancestro es esencial; aqu es donde los mtodos transversales DOM de jQuery entran en juego.
Con estos mtodos a nuestra disposicin, podemos recorrer el DOM con facilidad.
Algunos de los mtodos tienen un equivalente casi idntico entre las expresiones
de selector. Por ejemplo, la lnea que primero hemos utilizado para aadir la clase al t,

EJI

,,

2. Selectores

$ (/tr: odd/) . addClass


de la siguiente forma:
$ (/trj) .filter(/:oddj)

(/ alt/)

t,

se podra rescribir con el mtodo.

filter

()

{
&& this.hostname

IE~

!=

mil

As You Llke It
Comed y
IAU's Well t/lllt Ends weU C./ledY ,lE,]
Tragedy 1604
Hamlet

.addClass(/altj);

Sin embargo, en su mayor parte, las dos formas de seleccionar elementos se complementan entre s. Igualmente, el mtodo. f i 1ter () en particular tiene un enorme poder
porque puede tomar una funcin como su argumento.
La funcin nos permite crear pruebas complejas para determinar si los elementos se
deberan mantener en el conjunto que coincide. Supongamos, por ejemplo, que queremos
aadir una clase a todos los vnculos externos. jQuery no tiene selector para este tipo de
caso. Sin una funcin de filtro, estaramos forzados a pasar en bucle explcitamente por
cada elemento, comprobando cada uno por separado. Con la siguiente funcin de filtro,
sin embargo, podemos seguir basndonos en la iteracin implcita de jQuery y mantener
nuestro cdigo compacto:
$(/a/) .filter(function()
return this.hostname
)) .addClass(/external/);

Aprende jQuery 1.3

"Ii!!

I&e~ii IV:el!r.I: h
Henry V

~g!!I'~4J
'Ti'agedy 1595

Romeo and Jullet

'~'i.:jIt!sto!i:';1596]
Hlstory

1599

Figura 2.7. Celda especfico con estilo.

El mtodo . next () selecciona solamente el siguiente elemento hermano. Para resaltar todas las celdas que siguen a la que contiene Henry, podramos utilizar el mtodo
. nextAll () en su lugar.
$ (document) .ready(function()
{
$ (/td:contains
(Henry)/) .nextAll()
}) ;

.addClass(/highlight/);

location.hostname

La segunda lnea filtra el conjunto de elementos <a> por dos criterios:


1. Deben tener un atributo href con un nombre de dominio (this. hostname).
Utilizamos esta prueba para excluir vnculos mai 1to y otros de su tipo.

Como podramos esperar, los mtodos next () y . nextAll () tienen equivalentes:


.prev () y . prevAll () .Adems, . siblings () seleccionatodos los otros elementos
al mismo nivel DOM, con independencia de si vienen antes o detrs del elemento
seleccionadopreviamente.

2. El nombre de dominio con el que vinculan (de nuevo, this. hostname) no


debe coincidir (! =) con el nombre de dominio de la pgina actual (location.
hostname).

Para incluir la celda original (la que contiene Henry) junto con las celdas que siguen,
podemos aadir el mtodo. andSelf () :

Ms precisamente, el mtodo . f i 1ter () itera por el conjunto coincidente de elementos, comprobando el valor de retorno de la funcin. Si la funcin devuelve f alse, el
elemento se elimina del conjunto coincidente. Si devuelve true, el elemento se mantiene.
Ahora, echemos un vistazo a nuestra tabla a rayas de nuevo para ver qu ms es posible con los mtodos transversales.

Aplicar estilo a celdas especficas

$ (document) .ready(function()
{
$ (/td:contains(Henry)/)
.nextAll()

})

.andSelf()

.addClass(/highlight/);

Para estar seguro, existen una multitud de combinaciones de selectores y mtodos


transversales por lo que podemos seleccionar el mismo conjunto de elementos. Aqu,
por ejemplo, tiene otra forma de seleccionar cada celda en cada fila donde al menos una
de las celdas contiene Henry:
$ (document) .ready(function()
{
$ (/td:contains(Henry)/)
.parent()

.children()

.addClass(/highlight/);

});

Anteriormente hemos aadido una clase resaltada a todas las celdas que contenan
el texto Henry. Por el contrario, para aplicar estilo a la celda junto a cada celda que contiene Henry, podemos empezar con el selector que ya hemos escrito, y simplemente encadenar a ste el mtodo next ( ) :
$ (document) .ready(function()
{
$(/td:contains(Henry)/).next()
}) ;

En lugar de atravesar por los elementos hermanos, subimos un nivel en el DOM al


<t r con. parent () y luego seleccionamos todas las celdas de la fila con. children ( ) .

Encadenar
.addClass(/highlight/);

La tabla ahora debera parecerse a la figura 2.7.

Las combinaciones de mtodos transversales que acabamos de explorar ilustran la


posibilidad de encadenamiento de jQuery. Es posible con jQuery seleccionar mltiples
conjuntos de elementos y realizar mltiples cosas con ellos, todo dentro de una sola lnea

EII

Aprende jQuery 1.3

2. Selectores

de cdigo. Este encadenamiento no solamente ayuda a mantener el cdigo jQuery conciso, sino que tambin puede mejorar el rendimiento de un script cuando la alternativa
es volver a especificar un selector.
Tambin es posible dividir una sola lnea de cdigo en mltiples lneas para mayor
legibilidad. Por ejemplo, una sola secuencia de mtodos encadenada se podra escribir
como una lnea ...
$ (/td:contains(Henry)/)
.parent() .find(/td:eq(l)/)
.addClass(/highlight/)
.end() .find(/td:eq(2)/)
.addClass(/highlight/)
;

... o como siete lneas ...


$ (/td:contains(Henry)/)
// Encontrar
todas las celdas que contienen
.parent()
// Seleccionar
su padre
.find(/td:eq(l)/)
// Encontrar
la segunda celda descendiente
.addClass(/highlight/)
// Aadir la clase "highlight"
.end() // Devolver al padre de la celda que contiene "Henryll
.find(/td:eq(2)/)
// Encontrar
la tercera
celda descendiente
.addClass (/highlight/);
/ / Aadir la clase "highlight"

"Henry"

Ciertamente, el DOM transversal en este ejemplo es sinuoso hasta el punto del absurdo. En realidad no recomendaremos su uso, ya que existen mtodos claramente ms
sencillos y ms directos a nuestra disposicin. El objetivo del ejemplo es simplemente
demostrar la tremenda flexibilidad que nos permite el encadenamiento.
Encadenar puede ser como decir todas las palabras de un prrafo en un solo respiro, acabas rpidamente, pero puede ser difcil para cualquier otra persona entenderlo. Dividirlo en mltiples lneas y aadir comentarios puede ahorrar ms tiempo a la
larga.

Acceder a elementos DOM


Toda expresin de selector y la mayora de los mtodos jQuery devuelven un objeto
jQuery. Esto casi siempre es lo que queremos, debido a la iteracin implcita y posibilidades de encadenamiento que permite.
Sin embargo, existen muchos puntos en nuestro cdigo cuando necesitamos acceder
a un elemento DOM directamente. Por ejemplo, podemos necesitar poner disponible un
conjunto de elementos resultante a otra librera JavaScript. O bien podramos necesitar
acceder al nombre de etiqueta de un elemento, que se encuentra disponible como una
propiedad del elemento DOM. Para estas situaciones poco comunes, jQuery proporciona
el mtodo. get ( ) . Para acceder al primer elemento DOM referido por un objeto jQuery,
utilizaramos . ge t ( O) . Siel elemento DOM se necesita dentro de un bucle, utilizaremos
. get (index) . Por lo tanto, si queremos saber el nombre de etiqueta de un elemento
con id= "my- element", escribiramos:
var

myTag

$ (/#my-element/)

.get(O) .tagName;

.mil

Para mayqr conveniencia, jQuery proporciona un mtodo abreviado para. get () .


En lugar de escribir la lnea anterior, podemos utilizar corchetes cuadrados a continuacin del selector:
var

myTag

$ (/#my-element/)

'"

[OJ .tagName;

No en vano esta sintaxis se parece a una tabla de elementos DOM; utilizar los corchetes es como retirar el envoltorio jQuery para llegar a la lista de nodo s, mientras que
al incluir el ndice (en este caso, O), es como arrancar un elemento DOM .

Resumen
Con las tcnicas que hemos tratado en este captulo, ahora deberamos poder aplicar
estilo a los elementos de nivel superior y subnivel en una lista anidada al utilizar selectores CSS bsicos, aplicar diferentes estilos a diferentes estilos de vnculos al utilizar
selectores de atributo, aadir bandas a una tabla al utilizar los selectores personalizados jQuery : odd y : even o el selector CSS avanzado: nth- child () , y resaltar texto
dentro de ciertas celdas de tabla al encadenar mtodos jQuery.
Hasta el momento, hemos utilizado el evento $ (document) . ready () para aadir
una clase a un conjunto coincidente de elementos. En el siguiente captulo, exploraremos formas en las que aadir una clase en respuesta a una variedad de eventos iniciados por el usuario.

.'

3
Eventos

JavaScript tiene varias formas incorporadas de reaccionar a la interaccin del usuario


y otros eventos. Para conseguir que una pgina sea dinmica y responda, necesitamos
aprovechar esta posibilidad de uso de modo que podamos, en los momentos apropiados,
utilizar las tcnicas jQuery que hemos aprendido hasta el momento y otros trucos que
aprenderemos ms adelante. Aunque podemos hacer esto con JavaScript, jQuery mejora
y ampla los mecanismos bsicos de gestin de eventos para asignar les una sintaxis ms
elegante mientras que al mismo tiempo los hacemos ms potentes.

llevar a cabo tareas al cargar la pgina


Ya hemos visto cmo hacer que jQuery reaccione cuando se carga una pgina Web.
El manejador de evento $ (document) . ready () se puede utilizar para activar el cdigo de una funcin, pero se puede decir mucho ms sobre ello.

Planificacin de la ejecucin de cdigo


En el primer captulo hemos indicado que $ (document) . ready () era la forma de
jQuery de llevar a cabo tareas que se activaban tpicamente por el evento onload incorporado de JavaScript. Sin embargo, aunque los dos tienen un efecto similar, activan
acciones en momentos ligeramente diferentes. El evento window . onload se lanza cuando un documento se ha descargado completamente en el navegador. Esto significa que

ElII

Aprende jQuery 1.3

3. Eventos

todo elemento en la pgina se puede manipular por JavaScript, lo que es de gran ayuda
para escribir cdigo sin tener que preocuparse por el orden en que se carga.
Por otro lado, un manejador registrado utilizando $ (document) . ready () se invoca cuando el DOM est complemente listo para su uso. Esto tambin significa que todos
los elementos son accesibles por nuestros scripts, pero no significa que se ha descargado
todo archivo asociado. Tan pronto como se ha descargado y analizado el HTML en un
rbol DOM, el cdigo puede ejecutarse.

Para asegurarse de que la pgina tiene aplicado estilo antes de que se ejecute el cdigo
JavaScript, es una buena prctica situar etiquetas <link z e L " stylesheet"
> antes
de las etiquetas scr-.pt dentro del elemento head del documento.
Considere, por ejemplo, una pgina que presenta una galera de imgenes; dicha
pgina puede tener muchas imgenes grandes, que podemos ocultar, mostrar. mover y
manipular con jQuery. Si configuramos nuestra interfaz utilizando el evento onload, los
usuarios tendrn que esperar hasta que cada una de las imgenes se ha descargado por
completo antes de que puedan utilizar la pgina. Incluso peor, si los comportamientos
todava no se han anexado a elementos que tienen comportamientos predeterminados
(como los vnculos), las interacciones de usuario podran producir resultados no deseados. Sin embargo, cuando utilizamos $ (document) . ready () para la configuracin,
la interfaz se prepara mucho antes con el comportamiento correcto.

Luego podramos asignarla dentro de nuestro cdigo HTML:


<body on Loa.de vdo St u f f ();

Mltiples scripts en una pgina


El mecanismo tradicional para registrar manejadores de eventos por medio de
JavaScript (en lugar de aadir atributos de manejador en el HTML), es asignar una funcin al atributo correspondiente del elemento DOM. Por ejemplo, suponga que hubiramos definido la funcin:
function
doStuff()
11 Realizar una

{
tarea ...

11>

O bien, podramos
window.onload

asignar lo desde el propio cdigo JavaScript:

doStuff

Ambos enfoques harn que la funcin se ejecute cuando se carga la pgina. La ventaja
de la segunda es que el comportamiento est ms separado del cdigo.

Observe que cuando asignamos una funcin como un manejador, utilizamos el nombre
de la funcin pero omitimos los parntesis finales. Con los parntesis, la funcin se
invoca inmediatamente; sin ellos, el nombre simplemente identifica la funcin, y se
puede utilizar para invocarla ms tarde.
Con una funcin, esta estrategia funciona bastante bien. Sin embargo, suponga que
tenemos una segunda funcin:
function
doOtherStuff()
(
11 Realizar otra tarea.

Luego podramos tratar de asignar esta funcin para que se ejecute cuando se carga
la pgina:
window.onload

Utilizar $ (documen t) . ready () es casi siempre preferible a utilizar un manejador


onload, pero necesitamos recordar que puesto que es posible que no se hayan cargado los archivos que se soportan, atributos como altura y anchura de imagen no se
encuentran necesariamente disponibles en este momento. Si se necesitan, podemos
tambin elegir implementar un manejador onload (o ms probable, utilizarjQuery para
establecer un manejador para el evento Load); los dos mecanismos pueden coexistir
pacficamente.

EJI

doOtherStuff;

Sin embargo, esta asignacin supera a la primera. El atributo. onload puede almacenar solamente una referencia de funcin de cada vez, por lo que no podemos aadir
al comportamiento existente. El mecanismo $ (document) . ready () gestiona esta situacin. Toda llamada al mtodo aade la nueva funcin a una cola interna de comportamientos; cuando se carga la pgina, se ejecutarn todas las funciones. Las funciones
se ejecutarn en el orden en que se han registrado.

Para ser justos, jQuery no tiene el monopolio de la solucin a esta cuestin. Podemos
escribir una funcin JavaScript que forma una nueva funcin que invoca el manejador
onload existente, luego llama a un manejador pasado. Este enfoque, utilizado por
ejemplo por el addLoadEvent () de Siman Willison, evita conflictos entre manejadores rivales como hace $ (document) . ready ( ) , pero carece de algunos de los otros
beneficios que hemos tratado. Los mtodos especficos de navegador como documen t .
addEventListener
() ydocument. attachEvent
() ofrecenfuncionalidadsimiJar,
pero jQuery nos permite conseguir esta tarea sin preocupamos por inconsistencias de
navegador.

ElII

Aprende jQuery 1.3

3. Eventos

incluida (Prototype). Ahora, en nuestro script personalizado, podemos utilizar ambas


libreras, pero siempre que necesitamos utilizar un mtodo jQuery, necesitamos utilizar
j Query en lugar de $ como identificador.
El mtodo' '.ready () guarda un tr,coen la manga para ayudamos en esta situacin.
La funcin de retrollamada que le pasamos puede tomar un solo parmetro: el propio
objeto jQuery. Esto nos permite renombrarlo de forma efectiva sin miedo a conflictos:

Mtodos abreviados para cdigo


La construccin $ (document) . ready () en realidad llama al mtodo. ready () en
un objeto jQuery que hemos construido desde el elemento DOM documen t. La funcin
factory $ () nos proporciona un mtodo abreviado ya que se trata de una tarea comn.
Cuando se invoca sin argumentos, la funcin se comporta como si se pasara documento
Esto significa que en lugar de:
$ (document) .ready(function()
// Nuestro cdigo aqu ...
})

jQuery(document) .ready (function ($) {


1/ Aqu, podemos utilizar $ normal
}) ;
f

podemos escribir:

})

o bien, utilizar la sintaxis ms corta que hemos aprendido

$() .ready(function()
// Nuestro cdigo

jQuery(function($)
(
/
/ Cdigo que utiliza
(
aqu ..

lIlIII

anteriormente:

$.

});

Adems, la funcin factory puede tomar otra funcin como argumento. Cuando hacemos esto, jQuery lleva a cabo una llamada implcita a . ready () , por lo que para el
mismo resultado podemos escribir:
$(function()
{
// Nuestro cdigo

Aunque estas otras sintaxis son ms breves, los autores recomiendan la versin ms
larga para que quede claro lo que est haciendo el cdigo.

Coexistir con otras libreras


En algunos casos, puede resultar de utilidad utilizar ms de una librera JavaScript
en la misma pgina. Puesto que muchas libreras hacen uso del identificador $ (puesto que es corto y adecuado), necesitamos una forma de impedir colisiones entre estos
nombres.
Afortunadamente, jQuery proporciona un mtodo denominado . noConf 1i e t ()
para devolver control del identificador $ a otras libreras. El uso tpico de . no Conflict () sigue el siguiente patrn:
src:::"prototype.js"
type=l1textjjavascripttr></script>
src=Ujquery.jsll
type""lItext/javascriptll></script>
type=tttext/javascriptll>

<script
jQuery .noConflict ();
</script>
<script src="rnyscript.jsll

Existen muchos otros momentos aparte de cargar la pgina en los que podramos
querer llevar a cabo una tarea. Igual que JavaScript nos permite interceptar el evento
de carga de pgina con -c bo'd'y onload=
> o window. onload, proporciona enlaces
similares para eventos iniciados por el usuario como clics del ratn (onc 1i ck), campos
de formulario que se modifican (onchange), y ventanas que cambian de tamao (onresize). Cuando se asignan directamente a elementos en el DOM, estos enlaces tienen
desventajas similares a las que hemos detallado para onload. Por lo tanto, jQuery ofrece
una forma mejorada de gestionar estos eventos tambin.
11 11

aqu.

j);

<script
<script

Eventos sencillos

type="text/javascript"></script>

En primer lugar, se incluye la otra librera (Prototype en este ejemplo). Luego,


se incluye jQuery, asumiendo $ para su propio uso. A continuacin, una llamada a
. noConf 1i e t () libera s, de modo que el control de l regresa a la primera librera

Un sencillo conmutador de estilo


Para ilustrar algunas tcnicas de gestin de eventos, suponga que deseamos que una
pgina se muestre en varios estilos diferentes basndose en la entrada de datos de usuario. Permitiremos que el usuario haga clicen los botones para alternar entre vista normal,
una vista en la que el texto est limitado a una columna estrecha, y una vista con una
impresin mayor para el rea de contenido. En un ejemplo del mundo real, un buen ciudadano Web emplear el principio de mejora progresiva aqu. El conmutador de estilo
debera estar oculto cuando JavaScript no est disponible o, mejor an, debera seguir
funcionando por medio de vnculos a versiones alternativas de la pgina. Para los objetivos de este tutorial, asumiremos que todos los usuarios tienen activado JavaScript.
El cdigo HTML para el conmutador de estilo es de la siguiente forma:
<div id="switcher">
<h3>Style Switcher</h3>
<div class="button
selected
Default
</div>

ll

id=1!switcher-defaultll>

3,Eventos

Aprende jQuery

<:div class="buttonn
Narrow Colunm
</div>
cdiv

class=l'buttonrr
Large Print

id=lIswitcher-narrowlI>

1,3

lID

el mtodo. bind () . Este mtodo nos permite especificar cualquier evento JavaScr,ipt, y
anexarle un comportamiento. En este caso, el evento se denomina click, y el comportamiento es una funcin que consta de nuestra lnea anterior:

id=,rswitcher-large">

'\...

</div>
</div>

$ (docurnent).ready(function()

Combinados con el resto del cdigo HTML de la pgina y algo de CSS bsico, obtenemos una pgina que se parece a la figura 3.1.

{
$ (/#switcher-large/) .bind(/click/,
$ {/body/l .addClass (/large/l ;
}) ;

})

function()

Ahora cuando se pulsa el botn, se ejecuta nuestro cdigo y el texto se agranda como
se muestra en la figura 3.2.
Style Switcher

I
A Chrlstmas

Dofault

~~

II
!I!

'Narrow

Column

,.:,' ~1~~~;,,~~i:.~
~~::

1.1

largo Prtnt
>;; , '

'J

10:"

Carol

In Prose, Belng a Ghost Story of Chrlstmas

by Charles Olckens

Carol

In Prose, Being a Ghost Story of Christmas

Preface
t HAVE endeevoured In this GhosUy te book, to ralse the GhoSI ot an Idea, whlchshall not put my raaders out or humour wlth
themselVes, wlth each other, wlth Ole season, or wlth me, May lt haunt lhelr houses pleasantly, and no ona wtsh to lay It.

C.D.

I HAVE endeavoured in this Ghostly little book, to raise the Ghost of an Idea, which
shall no! put my readers out of humour wi!h themselves, with each other, with !he
season, or wi!h me. May it haunt their houses pleasantly,and no one wish to lay it.

December, 1843.
1: Marley's

Ghost

MARlEY was dead: to begin with, There Is no doubt whatever about tha!. The reglster ot hls buriel was slgned by lhe clergyman, the
clerk, Ihe undertaker, and the chlef moumer. Scrooge slgned It: and Scrooge's name was 9000 upon 'Changa, ror anythlng he chose
lo put hls hand to. Old Martey was as dead as a doornall.
Mlndll donl mean lo say mar 1I<now, 01 my own knowledge, whal tIlere Is panlcularty dead about a door-nall. I mlghl haye besn
Inclinad, myselt, to regard a comn-ne as me deadest plece of lronmongery In the ttade. But the wfsdom 01 our ancestors Is In the
slmile; and my unhaUowed hands shall not distorb 11.cr the Country's done foro You witl therefore permlt me lo rapeat, emphatlcally,

Figura 3_1. Combinar el conmutador

de estilo con cdigo,

Para empezar, pondremos operativo el botn Large Print. Necesitamos un poco de


CSS para implementar nuestra vista alternativa de la pgina:
body.large

.chapter (

font-size:

by Charles..Dlckens

Preface

Thelr lailhful Friend and Servant,

Stave

A Chrlstmas

1.Semi

Nuestro objetivo, entonces, es aplicar la clase large a la etiqueta -cbody. Esto permitir que la hoja de estilo vuelva a aplicar formato a la pgina de forma apropiada.
Utilizando lo que hemos aprendido en el captulo anterior, ya conocemos la sentencia
necesaria para conseguir esto:
$ Ubody/) .addClass (/large/);

Sin embargo, queremos que esto ocurra cuando se hace clic en el botn, no cuando
se carga la pgina como hemos visto hasta el momento. Para hacer esto, presentaremos

Their fai!hful Friend and Servan!,

e.o.
December, 1843.

Stave 1: Marley's Ghost


Figura

3.2. Vincular un evento.

Esto es lo que se necesita para vincular un evento. Las ventajas que hemos tratado
con el mtodo. ready () se aplican aqu, tambin. Mltiples llamadas a . bind () coexisten sin problema, aadiendo comportamiento adicional al mismo evento segn sea
necesario. Esta no es necesariamente la forma ms elegante o eficiente de realizar esta
tarea. A medida que avanzamos por este captulo, ampliaremos y mejoraremos este cdigo en algo de lo que estemos orgullosos.

Habilitar los otros botones


Ahora tenemos un botn Large Print que funciona segn lo esperado, pero necesitamos aplicar gestin similar a los otros botones (Default y Narrow Column) para
que realicen sus tareas. Esto es sencillo; utilizamos. bind () para aadir un manejador

"

3. Eventos

el i ck a cada uno de ellos, eliminando y aadiendo clases segn sea necesario. El nuevo
cdigo se muestra as:
$ (document) .ready(function() {
$ (/#switcher-default/) .bind(/click/, function() {
$ (/body/) .removeClass(/narrow/);
$ (/body/) .removeClass(/large/);
}) ;
$ (/#switcher-narrow/) .bind(/click/, function() {
$ (/body/) .addClass(/narrow/);
$ (/body/) .removeClass(/large/);

Hacer clic en Default elimina los nombres de clase de la etiqueta


do la pgina a -su forma inicial.

Contexto

de manejador

<body>,

1.3

devolvien.

de-evento

Nuestro conmutador se est comportando correctamente, pero no estamos proporcionando al usuario ninguna informacin sobre qu botn est actualmente activo. Nuestro
enfoque para gestionar esto ser aplicar la clase selected al botn cuando se hace clic,
y eliminar esta clase de los otros botones. La clase selected simplemente pone el texto
del botn en negrita:

j);

$ (/#switcher-large/) .bind(/click/, function()


$ (/body/) .removeClass(/narrow/);
$ (/body/) .addClass(/large/);
}) ;
})

Aprende jQuery

.selepted {
font-weight:

bold;

Esto se combina con una regla CSS para la clase narrow:


body.narrow .chapter
width: 400px;

.'

Ahora, despus de hacer clc en el botn Narrow Column, se aplica su CSS


correspondiente y el texto se muestra de forma diferente, como se puede apreciar en la
figura 3.3.

Podramos realizar esta modificacin de clase como hemos hecho anteriormente, al


hacer referencia a cada botn por ID y aplicar o eliminar clases segn sea necesario, pero
en su lugar, exploraremos una solucin ms elegante y escalable que explota el contexto
en el que se ejecutan los manejadores de evento.
Cuando se activa cualquier manejador de evento, la palabra clave thi s hace referencia al elemento DOM al que estaba anexado el comportamiento. Anteriormente hemos
indicado que la funcin factory $ () podra tomar un elemento DOM como su argumento;
sta es una de las razones clave por la que se encuentra disponible. Al escribir $ (this)
dentro del manejador de evento, creamos un objeto jQuery correspondiente al elemento,
y puede actuar sobre l como si lo hubiramos localizado con un selector CSS.
Con esto en mente, podemos escribir:
$(this) .addClass(/selected/);

A Christmas

Situar esta lnea en cada uno de los tres manejadores aadir la clase cuando se hace
clic en un botn. Para eliminar la clase de los otros botones, podemos aprovechamos de
la caracterstica de iteracin implcita de jQuery, y escribir:

Carol

In Prosa, Being a Ghost Story of Chl'istmas

$(/#switcher

by Charles Dlekens
Pmface
I HAVE endeavoured In thls GhosUy IIWe book, lo ralse Ihe Ghost 01 an
Idea, WhICh shall Mal put rny readers out of humour wlth themselves, wlth
eaeh other, wlth the season, or wlth me. May it haunt thelr houses
pleasantly, and no ane wlsh lo ley It.
Thelr faithful Friend and Servant,
C. D.
December, 1843.

5tave 1: Marley',

Ghost

MARLEY was oeac: to begln wlth. Therels no doubl whatever about that
The reglster of hls bunal was slgned by Ille clergyman. Ille elell<. Ille
undartaxer, and the chlef mourner. Scrooge slgned it: and Scrooge's name
was good upon 'Changa, tor anythlng he chose lo put hls hand to. Old
Mariey W8S as dead as B door-nau.

Figura 3.3. Vincularcomportamientoa los otros botones.

.button/) .removeClass(/selected/);

Esta lnea elimina la clase de cada botn dentro del conmutador de estilo. Por lo tanto,
al situados en el orden correcto, tenemos el cdigo como:
$ (document) .ready(function() {
$ (/#switcher-default/) .bind(/click/. function() {
$ (/body/) .removeClass(/narrow/);
$ (/body/) .removeClass(/large/);
$(/#switcher .button/) .removeClass(/selected/);
$(this) .addClass(/selected/);
}) ;
$ (/#switcher-narrow/) .bind(/click/, function() {
$ (/body/) .addClass(/narrow/);
$ (/body/) .removeClass(/large/);
$(/#switcher .button/) .removeClass(/selected/);
$(this) .addClass(/selected/);

ElII

3. Eventos

Aprende jQuery 1.3

}l;
$ (/#switcher-large/)
.bind(/click/,
function()
$ (/body/) .removeClass(/narrow/)
;
$ (/body/) .addClass(/large/);
$(/#switcher
.button/) .removeClass(/selected/);
$(this) .addClass(/selected/);
}l;

$(/#switcher
.button/) .removeClass(/selected/);
$ (thistaddClass(/selected/)
;
}l;

})

}l;

Ahora el conmutador
en la figura 3.4.

de estilo proporciona

informacin

apropiada

como se muestra

'"
Esta optimizacin aprovecha las tres caractersticas jQuery que hemos tratado. En
primer lugar, iteracin implcita es de nuevo de utilidad cuando vinculamos el mismo
manejador el iek a cada botn con una sola llamada a . bind () . En segundo lugar,
poner en cola comportamientos
nos permite vincular dos funciones al mismo evento
eliek, sin que el segundo sobrescriba el primero. Por ltimo, estamos utilizando las
posibilidades de uso de encadenamiento de jQuery para reducir la adicin y eliminacin
de clases a una lnea de cdigo cada vez.

S(ylo SWitcher

I
A Christmas

Oefawl

I LNa:~ I I
Colurnn

La~.

Prtnl

Carot

In Prose, Being a Ghost Story of Christmas


by Charles Olckens

Preface
I HAVE endeavoured in lhis Ghostly little book, lo raise the Ghost of an Idea, whih
shall not put my readers out of humour with themselves, wilh each other, with lhe
sea son, or with me. May it haunt their houses pleasanlly, and no one wish lo lay it,

Mayor consolidacin
La optimizacin de cdigo que acabamos de completar es un ejemplo de refactorizacin, es decir, modificar cdigo existente para llevar a cabo la misma tarea en una
forma ms eficiente o elegante. Para explorar ms oportunidades
de refactorizacin,
echemos un vistazo a los comportamientos
que hemos vinculado a cada botn. El parmetro del mtodo. removeClass () es opcional; cuando se omite, elimina todas las
clases del elemento. Podemos mejorar nuestro cdigo un poco al hacer uso de esto de
la siguiente forma:
$ (document)

.ready(function()

$ (/#switcher-default/)
.bind(/click/,
$ (/body/) .removeClass();

Their faithful Friend and Servant,

function()

}) ;
$ (/#switcher-narrow/)

.bind(/click/,
function()
$ (/body/) .removeClass()
.addClass(/narrow/);

C.D.

})
December, 1843.

Stave 1: Marley's Ghost


Figura 3.4. Proporcionar

$ (/#switcher-large/)
.bind(/click/,
function()
$ (/body/) .removeClass()
.addClass(/large/);

})
informacin

al usuario del botqn a~tivo.

Generalizar las sentencias al utilizar el contexto de manejador nos permite ser an


ms eficientes. Podemos tener en cuenta la rutina destacada en un manejador aparte,
como se muestra en el siguiente cdigo, porque es el mismo para los tres botones:
$ (document) .ready(function()
{
$ (/#switcher-default/)
.bind(/click/,
function()
{
$ (/body/) .removeClass(/narrow/)
.removeClass(/large/);
}) ;

$U#switcher
.button/) .bind(/cliCk/,
function()
$(/#switcher
.button/) .removeClass(/selected/);
$(this) .addClass(/selected/);

})
})

Observe que el orden de las operaciones ha cambiado un poco para acomodar la eliminacin general de nuestra clase; necesitamos ejecutar. removeClass () primero de
modo que no deshaga el . addClass () que realizamos al mismo tiempo.

$ (/#switcher-narrow/)
.bind(/click/,
function()
{
$ (/body/) .addClass(/narrow/)
.removeClass(/large/);

})

$ (/#switcher-large/)
.bind(/click/,
$ (/body/) .removeClass(/narrow/)

})

function()
{
.addClass(/large/);

$(/#switcher

.button/)

.bind(/click/,

function()

Solamente podemos eliminar de forma segura todas las clases porque estamos a cargo
del HTML en este caso. Cuando escribimos cdigo para reutilizar (como para un plug-in),
necesitamos respetar cualquier clase que pudiera estar presente y dejarla intacta.

3. Eventos

Aprende jQuery 1.3

Ahora estamos ejecutando parte del mismo cdigo en cada uno de los manejadores
de los botones. Esto se puede separar fcilmente en nuestro manejador general click
de botn:
$ (document) .ready(function()
{
$(/#switcher
.button/) .bind(/click/.
function()
$ (/body/) .removeClass();
$(/#switcher
.button/) .removeClass(/selected/);
$ (this) .addClass (/selected/);

})

})
})

$ (document) .ready(function
11 {
$(/#switcqer
.button/) .click(function()
$ (/body/) .removeClass();
if (th~s.id == /switcher-narrow/)
(
$I!body /) .addClass I/narrow.':) ;
}
.

else if (this.id == /switcher-large/)


$ (/body/) .addClass(/large/)
;

$ (/#switcher-narrow/)
.bind(/click/.
$ (/body/) .addClass(/narrow/);
}I;
$ (/#switcher-large/l
.bind (/click/.
$ (/body/) .addClass(/large/);

function()

$(/#switcher
.button/) .removeClass(/selected/);
$(this) .addClass(/selected/);

})
})
function

() (

Los mtodos de evento abreviados como ste existen para todos los eventos DOM
estndar:
.

Observe que necesitamos mover el manejador general por encima del especfico
ahora .. removeClass () necesita ocurrir antes de . addClass (), y.podemos contar
con esto porque jQuery siempre activa manejadores de evento en el orden en que se registraron.
Por ltimo, podemos libramos de los manejadores especficos por completo al hacer
uso una vez nuevamente del contexto de evento. Puesto que la palabra clave de contexto this nos proporciona un elemento DOM en lugar de un objeto jQuery, podemos
utilizar las propiedades DOM nativas para determinar el ID del elemento sobre el que
se hico clic. Podemos as vincular el mismo manejador a todos los botones, y dentro del
manejador llevar a cabo diferentes acciones para cada botn:
$ (document) .ready(function()
{
$(/#switcher
.button/) .bind(/click/.
$ (/body/) .removeClass();
if (this.id == /switcher-narrow/)
$ (/body/) .addClass(/narrow/);

function()

}
else if (this.id == /switcher-large/)
$ (/body/) .addClass(/large/);

}
$(/#switcher
.button/) .removeClass(/selected/);
$(this) .addClassl/selected/);

})

Eventos abreviados
Vincular unmanejador para un evento (como un sencillo evento c l .ck) es una tarea
tan sencilla que jQuery proporciona una forma ms concisa de logrario; los mtodos de
evento abreviados funcionan de la misma forma que sus equivalentes. bind () con
algunas menos teclas del teclado. Por ejemplo, nuestro conmutador de estilo se podra
escribir utilizando. click () en lugar de . bind () de la siguiente forma:

blur
change
click
dblclick
error
focus
keydown
keypress
keyup
load
mousedown
mousemove
mouseout
mouseover
mouseup
resize
scroll
select
submit
unload

Todo mtodo abreviado vincula un manejador al evento con el nombre correspondiente.

lIl.!II

3. Eventos

Aprende jQuery 1.3

Eventos compuestos

Despus del primer clie, los botones se ocultan todos, como se muestra en la figura
siguiente.

La mayora de los mtodos de gestin de eventos de jQuery corresponden directamente a eventos JavaScript nativos. Sin embargo, unos cuantos son manejadores personalizados aadidos por conveniencia y optimizacin entre navegadores. Uno de estos, el
mtodo. ready ( ), ya lo hemos tratado en detalle. Los mtodos. toggle () y . hover ()
son dos manejadores de evento personalizados; ambos se conocen como manejadores
de evento compuestos porque interceptan combinaciones de acciones de usuario, y responden a ellas utilizando ms de una funcin.

Mostrar y

ocultar

'-.
Figura

3.5. Ocultartodos los botones.

Un segundo clic los hace de nuevo visibles, como se ve en la figura 3.6.

caractersticas avanzadas

Suponga que quisiramos poder ocultar nuestro conmutador de estilo cuando no se


necesita. Una forma conveniente de ocultar caractersticas avanzadas es hacer que se
plieguen. Permitiremos que un clie en la etiqueta oculte los botones, dejando la etiqueta
sola. Otro clic en la etiqueta restaurar los botones. Necesitamos otra clase para gestionar los botones ocultos:
.hidden
{
display,

none;

Podramos implementar esta caracterstica al almacenar el estado actual de los botones en una variable, y comprobar su valor cada vez que se hace clie en la etiqueta para
saber si aadir o eliminar la clase hidden en los botones. Tambin podramos comprobar directamente la presencia de la clase en un botn, y utilizar esta informacin para
decidir qu hacer. En su lugar, jQuery proporciona el mtodo. toggle (), que lleva a
cabo esta tarea por nosotros.

Figura

3.6. Mostrartodos los botones.

Una vez ms nos basamos en.iteracin implcita; esta vez, para ocultar todos los botones de una sola vez sin necesidad de un elemento que lo englobe.
Para este caso especfico,jQuery proporciona otro mecanismo para la accin que estamos llevando a cabo. Podemos utilizar el mtodo. toggleClass
() para comprobar
automticamente la presencia de la clase antes de aplicarla o eliminarla:
$ (document) .ready(function()
{
$ (j#switcher
h3!) .click (function
$(!#switcher

})
})

.button!)

() {

.toggleClass(!hidden!);

En este caso, . toggleClass


() es probablemente la solucin ms elegante, pero
. toggle () es una forma ms verstil de llevar a cabo dos o ms acciones diferentes
en alternancia.
Existen en realidad dos mtodos. toggle () definidospor jQuery!Para informacin
sobre los efectos, consulte: http://docs.jquery.com/Effects/toggle.
El mtodo de evento. toggle () toma dos o ms argumentos, cada uno de los cules
es una funcin. El primer clie en el elemento hace que se ejecute la primera funcin, el
segundo clic activa la segunda funcin, y as sucesivamente. Una vez que se ha invocado
cada funcin, el ciclo empieza de nuevo desde la primera funcin. Con. toggle (), podemos implementar nuestro conmutador de estilo que se pliega bastante fcilmente:
$ (document) .ready(function()
{
$ (!#switcher
h3!) .toggle (function () {
$(!#switcher
.button!) .addClass(!hidden!);
l. function () {
$(!#switcher

})
})

.button!)

.removeClass(!hidden!);

Destacar elementos sobre

los

que se hace die

Al ilustrar la posibilidad del evento el i ck de operar sobre elementos de pgina sobre


los que normalmente no se hace clic, hemos diseado una interfaz que nos proporciona
algunas pistas de que los botones, en realidad slo los elementos <di V>, son en realidad partes vivas de la pgina, en espera de la interaccin del usuario. Para remediar
esto, podemos asignar a los botones un estado rollover, dejando claro que interactan
de alguna forma con el ratn:
#switcher
.hover {
cursar: pointer
background-color,

#afa;

fiII

3,

Aprende jQuery 1.3

Eventos

La especificacin CSS incluye una pseudo-clase denominada: hover, que permite


que una hoja de estilo afecte la apariencia de un elemento cuando el cursor del ratn del
usuario pasa por encima de l. En Internet Explorer 6, esta posibilidad de uso est restringida a los elementos de vnculo, por lo que no podemos utilizarla para otros elementos en cdigo multinavegador. En su lugar, jQuery nos permite utilizar JavaScript para
cambiar el estilo de un elemento, y por lo tanto, llevar a cabo cualquier accin arbitraria,
tanto cuando el cursor del ratn entra en el elemento y cuando deja el elemento,
El mtodo . hover () toma dos argumentos de funcin, como en nuestro ejemplo
. toggle () antes. En este caso, la primera funcin se ejecutar cuando el cursor del
ratn entra en el elemento seleccionado, y la segunda se activa cuando el cursor se aleja,
Podemos modificar las clases aplicadas a los botones en estos momentos para conseguir
un efecto rollover:

}I ;

})

ll

dog,

'"

<r
How razorback-jumping
<!p>
<!div>

trags can level six piqued

gymnasts!

Luego visualizamos el cdigo como un conjunto de elementos anidados como se


muestra en la figura 3.8.

<div>

$ (document) ,ready(function()
{
$(!#switcher
,button!) ,hover(function()
$(this) .addClass(!hover!);
}, function () (
$(this) ,removeClass(!hover!);

cdiv class=f'foo">
cspan class,.=l1bar >
<a href=lIhttp://www.example.comjll>
The Ruick brown fox jumps ayer the lazy
<la>
</span>

m-.

.'

De nuevo utilizamos iteracin implcita y contexto de evento para cdigo breve y


sencillo. Ahora cuando pasamos por encima de cualquier botn, vemos nuestra clase
aplicada como se muestra en la figura 3.7.

A Christmas Carol
In Prose, Being a Ghost Story o, Christmas
by Charles Dlckens
Pteface

Figura 3.8. Modelo de pgina,

Para cualquier evento, existen mltiples elementos que podran ser responsables lgicamente de reaccionar.
Cuando se hace clic en el vnculo en esta pgina, por ejemplo, el <di v , <span>, y
<a> todos deberan tener la oportunidad de responder al clic, Despus de todo, los tres
estn bajo el cursor del ratn del usuario al mismo tiempo. El elemento <P>. por otro
lado, no es parte de esta interaccin en absoluto.
Una estrategia para permitir que mltiples elementos respondan a un clic se denomina
captura de eventos. Con captura de eventos, el evento se pasa primero al elemento ms
global, y luego sucesivamente a los ms especficos. En nuestro ejemplo, esto significa
que primero el evento se pasa a d .v, luego a c span, y por ltimo a <a>, como se
muestra en la figura 3.9.

Figura 3.7. Utilizar efectos rollover.

El uso de . hover () tambin significa que evitamos dolores de cabeza causados por
propagacin de evento en JavaScript. Para entender esto, necesitamos echar un vistazo
a cmo JavaScript decide qu elemento gestiona un evento dado.

<div>

El viaje de un evento
Cuando ocurre un evento en una pgina, toda una jerarqua de elementos DOM tiene
la oportunidad de gestionar el evento. Considere un modelo de pgina como ste:

Figura 3.9. Captura de eventos.

Aprende jQuery 1.3

3. Eventos

Tcnicamente, en implementaciones de navegador de captura de evento, elementos


especficos se registran para escuchar eventos que ocurren entre sus descendientes. La
aproximacin proporcionada aqu est lo bastante cerca de nuestras necesidades.

manejador de evento. Esta secuencia de burbujeo es probable que no se desee; para los
botones en nuestro conmutador de estilo de ejemplo, podra significar que el que aparezca resaltado se desactive prematuramente.
El mtodo . hover () es consciente de estos problemas de burbujeo, y cuando utilizamos ese mtodo para anexar eventos, podemos ignorar los problemas causados por
el elemento errneo con un evento mouseover o mouseout. Esto hace que. hover ()
sea una alternativa muy atractiva para vincular los eventos individuales de ratn.

La estrategia contraria se denomina burbujeo de eventos (event bubbling). El evento se


enva al elemento ms especfico, y despus de que este elemento tiene una oportunidad
de reaccionar, el evento burbujea a los elementos ms generales. En nuestro ejemplo,
se pasa primero el evento a <a>, y luego a -c apa n y <di v en ese orden, como ilustra
la figura 3.10.

Si solamente se tiene que realizar una accin cuando el ratn entra o abandona un
elemento, pero no ambos, podemos vincular los eventos mouseenter y mouseleave
de jQuery, que tambin eluden los problemas de burbujeo. Sin embargo, estos eventos
se emparejan tan a menudo, que. hover () es por lo general la opcin correcta.

<div>
r-~--="""'"

Figura 3.10. Burbujeo de eventos.

Como cabe esperar, diferentes desarrolladores de navegador originalmente decidieron


diferentes modelos para programacin de evento. El estndar DOM que se desarroll especificaba que se deberan utilizar ambas estrategias: primero el evento se captura desde
elementos generales a especficos, y luego el evento burbujea hasta arriba del rbol DOM.
Los manejadores de eventos se pueden registrar para cualquier parte del proceso.
No todos los navegadores se han actualizado para coincidir con este nuevo estndar, y
en aquellos que lo soportan la captura debe estar habilitada especficaroente. Para proporcionar consistencia entre navegadores, por lo tanto, jQuery siempre registra manejadores
de evento para la fase de burbujeo del modelo. Siempre podemos asumir que el elemento
ms especfico tendr la primera oportunidad de responder a cualquier evento.

El escenario mouseout que se acaba de describir ilustra la necesidad de limitar el


mbito de aplicacin de un evento. Aunque. hover () gestiona este caso especfico, encontraremos otras situaciones en las que necesitamos limitar un evento espacialmente
(impidiendo que el evento se enve a ciertos elementos) o temporalmente (impidiendo
que el evento se enve en ciertos momentos).

Alterar el viaje: el objeto event


Ya hemos visto una situacin en la que el burbujeo de eventos puede provocar problemas. Para mostrar un caso en el que. hover () no ayuda a nuestra causa, alteraremos
el comportamiento colapsado que hemos implementado anteriormente.
Suponga que deseamos ampliar el rea sobre la que se puede hacer clic que activa el
contraer o expandir del conmutador de estilo. Una forma de hacer esto es mover el manejador de evento desde la etiqueta, <h3 , a su elemento <di v contenedor:
$ (document) .ready(function()
{
$ (/#switcher/)
.click(function()
{
$(/#switcher
.button/) .toggleClass(/hidden/);

})

}J;

Efectos secundarios del burbujeo de eventos


El burbujeo de eventos puede causar comportamiento no esperado, especialmente
cuando el elemento errneo responde a un mouseover o mouseout. Considere un manejador de evento mouseou t anexado al <di v en nuestro ejemplo. Cuando el cursor del
ratn del usuario sale del <di V>, el manejador mouseout se ejecuta segn lo previsto.
Puesto que se encuentra arriba de la jerarqua, ningn otro elemento recibe el evento.
Por otro lado, cuando el cursor sale del elemento <a>, se le enva un evento mouseout.
Este evento luego burbujear hasta el <spari y luego al <di v, activando el mismo

Esta alteracin hace que se pueda hacer clic sobre todo el rea del conmutador de
estilo para alternar su visibilidad. La desventaja es que hacer clic en un botn tambin
contrae el conmutador de estilo despus de que el estilo en el contenido se ha alterado.
Esto se debe al burbujeo de evento; el evento se gestiona primero por los botones, luego
Se pasa al rbol DOM hasta que llega a <di v id= swi tcher
, donde nuestro nuevo
manejador se activa y oculta los botones.
Para solucionar este problema, necesitamos acceder al objeto event. sta es una
construccin JavaScript que se pasa al manejador de evento de cada elemento cuando
11

11

m.

3. Eventos

.:

se invoca. Proporciona informacin sobre el evento, como dnde se encontraba el cursor del ratn en el momento del evento. Tambin proporciona algunos mtodos que se
pueden utilizar para afectar el progreso del evento por el DOM.
Para utilizar el objeto event en nuestros manejadores, solamente necesitamos aadir
un parmetro a la funcin:

}
el se if (this.id == /switcher-large/)
$ (/body/) .addClass(/large/);

$(/#switcher
.button/) .removeClass(/selected/};
$(this) .addClass(/selected/);
event.stopPropagation{)

II ;

Destinos de los eventos


Ahora tenemos el objeto event disponible como la variable event dentro de nuestro
manejador. La propiedad event . target puede ser de utilidad al controlar dnde ocurre
un evento. Esta propiedad es una parte de la API DOM, pero no se implementa en todos
los navegadores; jQuery ampla el objeto event segn sea necesario para' proporcionar
la propiedad en cada navegador. Con. target, podemos determinar qu elemento en
el DOM era el primero en recibir el evento, es decir, en el caso de un evento click, el
elemento sobre el que se hace dic. Recordando que this nos da el elemento DOM que
gestiona el evento, podemos escribir el siguiente cdigo:
$ (document) .ready(function()
{
$ (/#switcher/) .click(function(event}
{
if (event.target == this) {
$(/#switcher
.button/) .toggleClass(/hidden/);
}
}}

})

Este cdigo se asegura de que el elemento sobre el que se hace clic sea <di v
id=" swi tcher
, no uno de sus subelementos. Ahora hacer clic en los botones no plegar el conmutador de estilo, y hacer clic en el fondo del conmutados-s, Sin embargo,
hacer clic en la etiqueta, <h3 , ahora no hace nada, porque tambin es un subelemento.
En lugar de situar esta comprobacin aqu, podemos modificar el comportamiento de
los botones para conseguir nuestros objetivos.
11

Detener la propagacin de evento


El objeto event proporciona el mtodo. stopPropagation
(), que puede detener
el proceso de burbujeo completamente para el evento. Como . target, este mtodo es
una caracterstica JavaScript sencilla, pero no se puede utilizar de forma segura entre
todos los navegadores. Sin embargo, siempre y cuando registramos todos nuestros manejadores de evento utilizando jQuery, podemos utilizarlo con impunidad.
Eliminaremos la comprobacin event. target == this que hemos aadido, y en
su lugar aadiremos algo de cdigo en los manejadores el i ck de nuestros botones:

$ (document) .ready(function(}
{
$(/#switcher
.button/) .click(function(event)
$ (/body/) .removeClass();
if (ths.id == /switcher-narrow/)
$ (body/)
. addClass (/narro~i) ;

$ (document) .ready(function()
$ (/#switcher/) .click(function(event}
{
$(/#switcher
.button/) .toggleClass(/hidden/};
}} ;

)}

Aprende jQuery 1.3

})

Como antes, necesitamos aadir un parmetro a la funcin que estamos utilizando


como el manejador click, de modo que tenemos acceso al objeto event. Luego simplemente invocamos event. stopPropagation
() para impedir que cualquier otro
elemento DOM responda al evento. Ahora nuestro clic se gestiona por los botones, y
solamente los botones; clics en cualquier otro lado en el conmutador de estilo lo colapsar o expandir.

Acciones predeterminadas
Si nuestro manejador de evento click se registrara sobre un elemento de vnculo
a en lugar de un d .v genrico, tendramos otro problema. Cuando un usuario
hace die sobre un vnculo, el navegador carga una nueva pgina. Este comportamiento
no es un manejador de evento en el mismo sentido que hemos venido discutiendo; en su
lugar, se trata de la accin predeterminada para un die sobre un elemento de vnculo. De
forma similar, cuando se pulsa la tecla Intro mientras el usuario edita un formulario, se
activa el evento submi t en el formulario, pero entonces el envo del formulario ocurre en
realidad despus de esto. Sino se desean estas acciones predeterminadas, invocar. stopPropaga ti on () sobre el evento no ayudar. Estas acciones no ocurren en ningn sitio
en el flujo normal de la propagacin de evento. En su lugar, el mtodo. preventDefaul t () servir para detener el evento antes de que se active la accin predeterminada.

Invocar. preventDefaul t () es a menudo de utilidad despus de haber realizado


algunas pruebas sobre el entorno del evento. Por ejemplo, durante el envo de un
formulario, podramos desear comprobar que los campos obligatorios estn rellenos,
e impedir la accin predeterminada slo si no lo estn.
La propagacin de evento y acciones predeterminadas son mecanismos independientes; se puede detener cualquiera mientras ocurre la otra. Si deseamos detener ambas, podemos devolver fal se desde nuestro manejador de evento, que es un mtodo abreviado
para invocar. stopPropagat
ion () y . preventDefaul
t () sobre el evento.

ElII

Aprende jQuery 1.3

3. Eventos

Delegacin de evento
El burbujeo de eventos no siempre es un obstculo; a menudo lo podemos utilizar
para obtener beneficio. Una tcnica estupenda que hace uso del burbujeo se denomina
delegacin de evento. Con ello, podemos utilizar un manejador de evento sobre un solo
elemento para realizar el trabajo de muchos.

Hemos utilizado un nuevo mtodo aqu, denominado. is () . Este mtodo acepta


las expresiones de selector que hemos investigado en el captulo anterior, y comprueba el objeto [Query actual contra el selector. Si al menos un elemento en el conjunto se
corresponde con el selector, . i s () dfvuelve true. En este caso, $ (event . target)
.
i s (/ . but ton/) pregunta si el elemento sobre el que se ha hecho clic tiene asignada
una clase but ton. Si es as, continuamos con el cdigo desde antes, con un cambio significativo: la palabra clave this ahora se refiere a <di v id=" switeher" , de modo
que cada vez que estamos interesados en el botn que se puede hacer clic tenemos que
referirnos a l con event . target.

EnjQuery 1.3, sehan incorporado un nuevo par de mtodos, . li ve () y . die ( ) . Estos


mtodos llevan a cabo las mismas tareas que. bind () y .unbind () , pero por detrs
utilizan delegacin de evento para obtener los beneficios que describiremos en este
apartado. La documentacin sobre estos mtodos se puede encontrar en: http: / /
docs.jquery.com/Events/live.

.'

En nuestro ejemplo, existen tres elementos ed i v elass="button"


> que tienen
anexados manejadores el iek. Pero qu pasara si hubiera muchos? Esto es ms comn
que lo que uno pudiera pensar. Considere, por ejemplo, una tabla extensa de informacin
en la que cada fila tiene un elemento interactivo que requiere un manejador eliek. La
iteracin implcita facilita asignar todos estos manejadores eliek, pero el rendimiento
puede sufrir debido a la iteracin en bucle que se realiza internamente en jQuery, y debido a la huella de memoria de mantener todos los manejadores.
En su lugar, podemos asignar un solo manejador el iek a un elemento ancestro en
el DOM. Un evento eliek ininterrumpido llegar con el tiempo al ancestro debido al
burbujeo de evento, y nosotros podemos realizar nuestro trabajo ah.
A modo de ejemplo, apliquemos esta tcnica a nuestro conmutador de estilo (aunque
el nmero de elementos no requiere el enfoque). Como hemos visto antes, podemos utilizar la propiedad event. target para comprobar qu elemento estaba bajo el cursor
del ratn cuando ocurri el clic.
$ (document) .ready (function () (
$ (/#switcher/)
.click(function(event)
(
if ($ (event.target)
.is(/.button/))
{
$ (/body/) .removeClass()
;
if (event.target.id
== /switcher-narrow/)
$ (/body/) .addClass(/narrow/);

Tambin podemos comprobar la presencia de una clase en un elemento con un mtodo


abreviado, .hasClass () . El mtodo . is () es ms flexible, sin embargo, y puede
comprobar cualquier expresin de selector.
Sin embargo, tenemos un efecto secundario no intencionado en este cdigo. Cuando
se hace clic en un botn ahora, el conmutador se contrae, como hizo antes de que aadiramos la llamada a . stopPropagation
() . El manejador para alternar la visibilidad del conmutador est ahora vinculado al mismo elemento que el manejador para los
botones, por lo que detener el burbujeo de evento no impide que se active el alternar la
visibilidad. Para evitar este problema, podemos eliminar la llamada. stopPropagation () y en su lugar aadir otra comprobacin. is () :
$ (document) .ready(function()
(
$ (/#switcher/)
.click(function(event)
(
if (!$(event.target)
.is(/.button/))
{
$(/#switcher
.button/) .toggleClass(/hidden/);

}
})
})

$ (document) .ready(function()
(
$ (/#switcher/)
.click(function(event)
(
if ($ (event.target)
.is(/.button/))
(
$ (/body/) .removeClass();
if (event.target.id
== /switcher-narrow/)
$ (/body/) .addClass(/narrow/);

}
if (event.target.id
== /switcher-large/)
$ (/body/) .addClass(/large/);

else

$(/#switcher
.button/) .removeClass(/selected/);
$(event.target)
.addClass(/selected/);

el se if (event.target.id
== /switcher-large/)
$ (/body/) .addClass(/large/);

}
$(/#switcher

.button/)

.removeClass(/selected/);

$ (event.target)
.addClass(/selected/);
event.stopPropagation()
;

}
})
})

})
})

Este ejemplo es demasiado complicado para su tamao, pero como el nmero de


elementos con manejadores de evento aumenta, la delegacin de evento es la tcnica
correcta a utilizar.

.mil

Aprende jQuery 1.3

3. Eventos

La delegacin de evento es tambin de utilidad en otras situaciones que veremos ms


adelante, como cuando se aaden nuevos elementos por mtodos de manipulacin
DOM o rutinas AJAX.

Eliminar un manejador de evento

adelante. Para utilizar espacio de nombres, necesitamos regresar al mtodo no abreviado


de vincular ntanejadores de evento, el propio mtodo . bind ( ) .
El primer parmetro que pasamos a . bind () es el nombre del evento JavaScript del
que queremos estar pendiente. Podemos utilizar una sintaxis especial aqu, sin embargo,
que nos permite subcategorizar el evento.
$Idocument)
.readylfunctionl)
(
$I/#switcher/J
.bindl/click.collapse/,
functionlevent)
if 1!$levent.target)
.isl/.button/))
(
$I/#switcher
.button/) .toggleClassl/hidden/);

}
})

Existen momentos en los que habremos terminado con un manejador de evento que
hemos registrado previamente. Quiz el estado de la pgina ha cambiado tanto que la
accin ya no tiene sentido. Normalmente es posible gestionar esta situacin con sentencias condicionales dentro de nuestros manejadores de evento, pero puede ser ms elegante quitar la vinculacin del manejador por completo.
Suponga que queremos que nuestro conmutador de estilo que se puede contraer permanezca expandido siempre que la pgina no utiliza el estilo normal. Aunque el botn
Narrow Column O Large Print est seleccionado, hacer clc en el fondo del conmutador
de estilo no debera hacer nada. Podemos realizar esto al invocar el mtodo. unbind ( )
para eliminar el manejador para contraer cuando se hace clic en uno de los botones no
predeterminados del conmutador de estilo.

$.I/#swi tcher-narrow,
#switcher-large/l.
click Ifunction
$I/#switcher/)
.unbindl/click.collapse/);
}J;

1)

}J;

El sufijo. eollapse
es invisible para el sistema de gestin de evento; los eventos
el iek se gestionan por esta funcin, igual que si escribiramos. bind (1 eliek/)
. Sin
embargo, la incorporacin del espacio de nombres significa que podemos desvincular slo
este manejador, sin afectar al otro manejador eliek que escribimos para los botones.

Existen otras formas de hacer que nuestra llamada . unbind () sea ms especfica,
como veremos en un momento. Sin embargo, el espacio de nombres de evento es una
herramienta de utilidad en nuestro arsenal. Es especialmente de utilidad en la creacin
de plug-ins, como veremos ms adelante en el libro.

$Idocument) .readylfunctionl)
(
$I/#switcher/)
.clicklfunctionlevent)
(
if 1!$levent.target)
.isl/.button/))
(
$I/#switcher
.button/) .toggleClassl/hidden/);

}
})

$I/#switcher-narrow,
#switcher-large/)
$I/#switcher/)
.unbindl/click/);
}) ;

.clicklfunctionl)

}) ;

Ahora cuando se hace clic en un botn como Narrow Column, el ranejador eliek
en el conmutador de estilo <di v se elimina, y hacer clic en el fondo de la caja ya no
lo contrae. Sin embargo, el botn ya no funciona. Est anexado al evento eliek del
conmutador de estilo <di v tambin porque volvimos a escribir el cdigo de gestin
de botn para utilizar delegacin de evento. Esto significa que cuando invocamos
$ (/#switeher
1) . unbind (/ cliek/),
se eliminan ambos comportamientos.

Espacio de nombres de evento


Necesitamos que nuestra llamada. unbind () sea ms especfica, de modo que no
elimine los dos manejadores elick que hemos registrado. Una forma de hacer esto es
utilizar espacio de nombres de evento. Podemos incorporar informacin adicional cuando se vincula un evento que nos permita identificar ese determinado manejador ms

Volver a vincular eventos


Ahora hacer clic en el botn N arrow Column o Large Print hace que la funcionalidad
de contraer el conmutador de estilo se desactive. Sin embargo, queremos que regrese el
comportamiento cuando se pulsa el botn Default. Para hacer esto, necesitaremos volver a vincular el manejador siempre que se hace clic en Default.
En primer lugar, deberamos dar a nuestra funcin de manejador un nombre de modo
que podamos utilizado ms de una vez sin repetimos:
$Idocument)
.readylfunction()
(
var toggleStyleSwitcher
= function(event)
if (!$(event.target)
.is(/.button/))
(
$I/#switcher
.button/) .toggleClass(/hidden/);

};

$I/#switcher/)

.bind I/click. collapse/,

toggleStyleSwitcher);

1"

Aprende jQuery 1.3

3. Eventos

Observe que aqu estamos utilizando una nueva sintaxis para definir una funcin. En
lugar de definir la funcin al empezar con la palabra clave function,
asignamos una
funcin annima a una variable local. Se trata de una eleccin de estilo para hacer que
nuestros manejadores de evento y otras definiciones de funcin se parezcan ms entre
s; las dos sintaxis son funcionalmente equivalentes.
Tambin, recuerde que. bind () toma una referencia de funcin como su segundo
argumento. Es importante recordar, cuando se utiliza una funcin con nombre aqu, omitir los parntesis despus del nombre de funcin; los parntesis harn que se invoque
la funcin en lugar de que se le haga referencia. Ahora que la funcin tiene un nombre,
podemos vincularla nuevamente ms adelante sin repetir la definicin de funcin:

$ (/#switcher/)
.click(toggleStyleSwitcher);
$ (/#switcher-narrow,
#switcher-large/)
.click(function()
$ (/#switcher/) .unbind(/click/,
toggleStyleSwitcher);
}) ;
$ (/#switcher-default/)
.click(funebion()
(
$ (/#switcher/) .click(toggleStyleSwitcher);

})
})

Un mtodo abreviado se encuentra tambin disponible para la situacin en la que queremos desvincular un manejador de evento inmediatamente despus de la primera vez
, que se activa. Este mtodo abreviado, denominado. one ( ) r se utiliza de esta forma:
$ (doument) .ready(function()
(
$ (/#switcher/) .one(/click/,
toggleStyleSwitcher);

$ (document) .ready(function()
(
var toggleStyleSwitcher
= function(event)
if (!$(event.target)
.is(/.button/)
{
$(/#switcher
.button/) .toggleClass(/hidden/);

})

Esto har que la accin de alternar ocurra solamente una vez.


};
$ (/#switcher/)

.bind(/click.collapse/,

toggleStyleSwitcher);

.'

Simular inleraccin de usuario

$ (/#switcher-narrow,
#switcher-large/)
.click(function()
$ (/#switcher/) .unbind(/click.collapse/);

})

$ (/#switcher-default/)

.click (function

$ (/#switcher/)
.bind(/click.collapse/,

})
})

() (

toggleStyleSwitcher);

Ahora el comportamiento de alternar est vinculado cuando se carga el documento,


desvinculado cuando se hace clic en Narrow Column o Large Print, y vuelto a vincular
cuando se hace clic en Normal despus de esto.
Hemos evitado un peligro potencial aqu. Recuerde que cuando se vincula un manejador a un evento en jQuery, los manejadores anteriores siguen en vigor. Esto podra parecer significar que si se hace clic en Normal mltiples veces en sucesin, se vincularan
muchas copias del manejador togg 1eS t y 1e Swi t che r, provocando un comportamiento extrao cuando se hizo clic en <di v , De hecho, si hubiramos utilizado funciones
annimas en nuestro ejemplo, ste sera el caso. Pero puesto que asignamos a la funcin
un nombre y utilizamos la misma funcin en todo el cdigo, el comportamiento slo se
vincula una vez. El mtodo. bind () no anexar un manejador de evento a un elemento si ya se ha anexado. Como otro beneficio a nombrar esta funcin, ya no necesitamos
utilizar espacios de nombres. El mtodo . unbind () puede tomar una funcin como
segundo argumento; en este caso, desvincula solamente ese manejador especfico.
$ (document) .ready(function()
(
var toggleStyleSwitcher
= function(event)
(
if (!$(event.target)
.is(/.button/
{
$(/#switcher
.button/) .toggleClass(/hidden/);

};

A veces es conveniente ejecutar el cdigo que hemos vinculado a un evento, incluso si


no se dan las circunstancias normales del evento. Por ejemplo, suponga que quisiramos
que nuestro conmutador de estilo empiece en su estado contrado. Podramos realizar
esto al ocultar botones desde la hoja de estilo, o al invocar el mtodo. hide () desde un
manejador $ (document) . ready ( ) . Otra forma sera simular un clic en el conmutador
de estilo de modo que se active el mecanismo para alternar que ya hemos establecido.
El mtodo. trigger
() nos permite realizar precisamente esto:
$ (document) .ready(function()
(
$ (/#switcher/)
.trigger(/click/)
}) ;

Ahora justo cuando se carga la pgina se contrae el conmutador, como si se hubiera


hecho clic en l, como se muestra en la figura 3.11. Si estuviramos ocultando contenido que quisiramos que personas sin JavaScript pudieran ver, sta sera una forma de
implementar degradacin.

A Chrlstmas

Carol

In Prosa, Belng a Ghost Story 01 Chrlstmas


by Charles Dlckens

Preface

Figura 3.11. Simular la interaccindel usuario.

3. Eventos

Aprende jQuery 1.3

El mtodo. trigger
() proporciona el mismo conjunto de mtodos abreviados que
.bind () . Cuando se utilizan estos mtodos abreviados sin argumentos, el comportamiento es activar la accin en lugar de vincularla:

$ (/#switcher-default/)
break;
case /N/:
.~(/#switcher-narrow/)
break;

$ (document) .ready(function()
$ (/#switcher/) .click();

})

case

Eventos de teclado
Como otro ejemplo, podemos aadir mtodos abreviados de teclado a nuestro conmutador de estilo. Cuando el usuario escribe la primera letra de uno de los estilos, hacemos que la pgina se comporte como si se hiciera clic sobre el botn correspondiente.
Para implementar esta caracterstica, necesitaremos explorar eventos de teclado, que se
comportan algo diferente de los eventos de ratn. Existen dos tipos de eventos de teclado: aquellos que reaccionan al teclado directamente (keyup y keydown) y aquellos que
reaccionan a entrada de texto (keypress). Un solo evento de entrada de ,carcter podra
corresponder a varias teclas, por ejemplo cuando la tecla Mays en combinacin con
la tecla X crea la letra mayscula X. Aunque los detalles especficos de implementacin
difieren de un navega dar a otro (no es de sorprender), una regla general es la siguiente:
si desea saber qu tecla ha pulsado el usuario, debera observar el evento keyup o keydown; si desea saber qu carcter termin en pantalla como resultado, debera observar
el evento keypress.
Para esta caracterstica, simplemente queremos saber cuando el
usuario pulsa la tecla D, N, o L, por lo que utilizaremos keyup.
A continuacin, necesitamos determinar qu elemento debera estar pendiente del
evento. Esto es un poco menos obvio que con los eventos de ratn, donde tenemos un
cursar de ratn obvio que nos habla del destino del evento. En su lugar, el destino de un
evento de teclado es el elemento que actualmente tiene el foco del teclado. El elemento
con foco se puede cambiar de varias formas, incluidos clics del ratn y pulsaciones de la
tecla Tab. No todos los elementos pueden tener el foco, tampoco; solamente los elementos que tienen comportamientos predeterminados dirigidos por teclado como campos
de formulario, vnculos y elementos con una propiedad. t ab tndex-son candidatos.
En este caso, realmente no nos importa qu elemento tiene el foco; queremos que
nuestro conmutador funcione siempre que el usuario pulsa una de las teclas. El burbujeo
de eventos ser de nuevo de utilidad, ya que podemos vincular nuestro evento keyup
al elemento doeument y tener la seguridad que con el tiempo cualquier evento de tecla
burbujear hasta nosotros.
Por ltimo, necesitaremos saber qu tecla se puls cuando nuestro manejador keyup
se activa. Podemos inspeccionar el objeto event para esto. La propiedad . keyCode del
evento contiene un identifica dar para la tecla que se ha pulsado, y para teclas alfabticas,
este identificador es el valor ASCII de la letra mayscula. Por lo tanto podemos habilitar
el valor y activar el clic de botn apropiado:
$ (document) .ready(function()
(
$ (document) .keyup(function(event)
{
switch
(String.fromCharCode(event.keyCode))
case /D/:

.click();

.click();
~'"'tt

/L/:

$ (/#switcher-Iarge/)
break;

.click () ;

}
j);

})

Pulsar estas tres teclas ahora simula clics del ratn sobre los botones, siempre y cuando
ese evento de tecla no se interrumpa por caractersticas como la de "buscar texto cuando
empiezo a escribir" de Firefox.
Corno alternativa a utilizar . trigger
() para simular este clic, exploremos cmo
separar cdigo en una funcin de modo que ms de un manejador pueda invocarlo, en
este caso, el iek y keyup. Aunque no necesario en este caso, esta tcnica puede ser de
utilidad al eliminar redundancia de cdigo.
$ (document)

.ready(function()

/1

Permitir efecto de pasar por encima


$(/#switcher
.button/) .hover(function()
$(this) .addClass(/hover/);
}, function () (
$(this)

})

sobre

los botones

del conmutador

.removeClass(/hover/);

// Permitir
que el conmutador
de estilo se amplie
var toggleStyleSwitcher
= function(event)
{
if (! $ (event. target) .is (/ .button/))
{
$(/#switcher

.button/)

o colapse

.toggleclass(/hidden/);

};
$ (/#switcher/)
.click(toggleStyleSwitcher);
// Simular un clic de modo que empezamos
$ (/#switcher/) .click();

en un estado

// La funcin setBodyClass()
cambia el estilo
// El estado del conmutador
de estilo tambin
var setBodyClass
= function(className)
(
$ (/body/) .removeClass()
;
$ (/body/) .addClass(clasSName);
$(/#switcher
$(/#switcher-/
if (className

de pgina.
se actualiza.

.button/) .removeClass(/selected/);
+ className) .addClass(/selected/);
== /default/) (

$ (/#switcher/)

.click(toggleStyleSwitcher);

}
else

$ (/#switcher/) .unbind(/click/,
toggleStyleSwitcher);
$(/#switcher
.button/) .removeClass(/hidden/);

};
// Invocar setBodyClass()
cuando se hace
$ (/#switcher/)
.click(function(event)
{

clic

colapsado

en un botn

de estilo

,
Aprende jQuery 1.3

3. Eventos

if

($(event.target) .is(/.button/))
{
if (event.target.id
== /switcher-default/)
setBodyClass(/default/)
;

}
if

(event.target.id

==

setBodyClass(/narrow/)
else

if

(event.target.id

setBodyClass(/large/)

Invocar .unbind () para eliminar un manejador de evento con el que hemos


terminado.
~

Segregar manejadores de evento relacionados con espacios de nombre de evento

==

/switcher-large/)

de modo que se pueda actuar sobre ellos como un grupo.

// Invocar

setBodyClass()

cuando

case /D/,
setBodyClass(/default/)
break;
case /N/,
setBodyClass

(/narrow/) ;

break;
case /L/,
setBodyClass(/large/)

Hacer que los manejadores de evento vinculados se ejecuten con . trigger

() .

Utilizar manejadores de evento de teclado para reaccionar a pulsar una tecla por
el usuario con. keyup ( ) .

se pulsa una tecla

$ (document) .keyup(function(event)
(
switch (String.fromCharCode(event.keyCode))

break;

}
}lo
})

Implementar delegacin de evento para reducir el nmero de manejadores de


evento vinculados necesarios en una pgina.

}
})

/switcher-narrow/)

Resumen
Las posibilidades de uso que hemos tratado en este captulo nos permiten:

Permitir que mltiples libreras JavaScript coexisten en una sola pgina utilizando
. noConflict
().

Utilizar manejadores de evento de ratn para reaccionar al clic de un usuario


sobre un elemento de pgina con. bind () o . click () .

Observar contexto de evento para llevar a cabo diferentes acciones dependiendo


del elemento de pgina que se hace clic, incluso cuando el manejador est vinculado a varios elementos.

Alternativamente ampliar y contraer un elemento de pgina al utilizar. t oggle ().

Resaltar elementos de pgina bajo el cursor del ratn al utilizar . hover ( ) .

Influir en la propagacin de evento para determinar qu elementos obtienen


respuesta a un evento al utilizar . s topPropaga t ion () y . preventDefault(}.

Utilizados juntos, podemos utilizar estas posibilidades de uso para crear pginas bastante interactivas. En el siguiente captulo, aprenderemos cmo proporcionar feedback
visual para el usuario durante estas interacciones.

,
,

--."

.... '~. -; "~;-'""


<,

/~.........

"'" .

.' (~

.~.'"

"t;

t' !

. "'(j)'
'.

"'(3).

'I'~.'U""

-.

~"~

/~.', ~

~ ,.
..---.,,

. ~

","".

,/

l.'~O ..

>'--".

".

,,

.'

I ~..

.'

"(!l..

;'

~"

-::.

I~

'

~.

.~(':'"':"~~~"-"'I,

,~~'

'b.".,

r--....

..
'

'.

r-:.:
.1 '.'

~
<!>

1
/'~"

F"
.'~\-(!)".,.:
ti~,

:
()

o~'~

'

" .

x.,

'!\,.c;,.. "'r':'~.

."

"~

4:>

@l)~;/

-:",'f.5{. ..~,/

0...
'-..\ ,..--''.
/~~'

~'.'.@

. '.

....
_-'~<,

"~'/

'A

---_.-..

--'iW

'.~

' - --rsp --

.,

",

/'

._~

--::::'

,.::\.

'()

(@I;.--.,.

..

. -.......

''''1F

,_"

'V'
.., ''''''''
..'-..

'{

""

\,~ <.!l'\.'~ , ' ,

~.

'~.
' @)
,.'.; hg,~;.

O-

,.~:

.... tJ\,:.~ '.

'"

'. '.

\~,~

..
_

@r.-...., '"
{,

'.

---~.

'-

t,,,,

7\w,; "

1"\

..

r.) '...

..

,~~

~...,'
~it,/
\~,
~~-r.

'\

\ ../~'0-----..,- .~.'
,.~..
I

_\ '

fr~l.,~",
- .!~ ] ...
,

,~

"""

-~.

...
,.--~:\
~$C"\l\,
'1.:;:;>

..,

\-~!

A!>

, ~. ..''

:""'>',,,-,

.:

.~
~,~?.f~(~'
QP\ /'W \
. --",
. -, ~,
#"~.

\'1,.~../. /"'h'~h'
.'~
.'

". .'-"

.' ."/""",,, ... -~~'.". ~:~>~,

a.:;--..""','

>

. "

.'

fectos

Si las acciones dicen ms que las palabras, entonces en el mundo JavaScript, los efectos
hacen que las acciones digan an ms. Con jQuery, podemos aadir fcilmente impacto a nuestras acciones por medio de un conjunto de sencillos efectos visuales, e incluso
disear nuestras propias animaciones ms sofisticadas.
Los efectos jQuery aaden ciertamente atractivo, como es evidente cuando vemos
elementos que aparecen gradualmente en lugar de aparecer todos a la vez. Sin embargo,
tambin pueden proporcionar importantes mejoras de usabilidad que ayudan a orientar
al usuario cuando existe algn cambio en una pgina (especialmente comn en aplicaciones AJAX), En este captulo, exploraremos una serie de estos efectos y los combinaremos de formas interesantes,

Modificaciones CSS en lnea


Antes de pasar a los ingeniosos efectos jQuery, echemos un rpido vistazo a CSS. En
captulos anteriores hemos estado modificando la apariencia de un documento al definir estilos para clases en una hoja de estilo aparte y luego aadir o eliminar estas clases
con jQuery. Tpicamente, ste es el proceso preferido para aplicar CSS en HTML porque
respeta el rol de la hoja de estilo al tratar con la presentacin de una pgina. Sin embargo, existen momentos en los que necesitamos aplicar estilos que no se han podido fcilmente definir en una hoja de estilo. Afortunadamente, jQuery ofrece el mtodo, css ()
para tales ocasiones. Este mtodo acta como un get y un set, Para obtener el valor de
una propiedad de estilo, simplemente pasamos el nombre de la propiedad como una

E!II

Aprende jQuery 1.3

4. Efectos

cadena, como. css ( backgroundColor


') .Las propiedades de mltiples palabras se
pueden interpretar por jQuery cuando tienen guin, ya que se encuentran en notacin
CSS (background- color), o poniendo en mayscula la primera letra de cada palabra
excepto la primera, como en notacin DOM (backgroundColor).
Para establecer propiedades de estilo, el mtodo. css () se presenta de dos formas, una que toma una sola
propiedad de estilo y su valor y otra que toma un mapa de pares propiedad-valor:
I

.css('propertY','value')
.css({propertyl:
'valuel',

'property-2':

'value2'})

Desarrolladores JavaScript experimentados reconocern estos mapas jQuery como


objetos literales en JavaScript.

lIlJII

En esta versin del conmutador de estilo, estamos utilizando elementos <butt;on:>.


Hacer clic en los botones Bigger y Smaller aumentar o disminuir el tamao de texto
de <di v cla~s;" speech" , mientras que hacer clic en el botn Default restablecer
<di v c Las s e " speecnv s a su tamao de texto original.
Si todo lo que quisiramos fuera cambiar el tamao de fuente una sola vez a un valor
predeterminado, podramos seguir utilizando el mtodo. addClass () . Pero supongamos que ahora queremos que el texto contine aumentando o decreciendo incrementalmente cada vez que se hace clic en el botn respectivo. Aunque podra ser posible
definir una clase aparte para cada clic y pasar por ellos, un enfoque ms sencillo sera
calcular el nuevo tamao de texto cada vez al obtener el tamao actual y aumentarlo en
un factor establecido (por ejemplo, 40 por ciento).
Nuestro cdigo empezara con los manejadores de evento $ (document) . ready ()
y $ ( #swi t.che r= Lar-qe ') . click () :
I

Losvaloresnumricos no toman comillasmientras que los valoresde cadenaslo hacen.


Sinembargo, cuando se utiliza la notacin de mapa, las comillasno son necesarias para
nombres de propiedad si se escriben en notacin DOM.

$ (document) .ready(function()
(
$('#switcher-large')
.click(function()
}) ;

})

A continuacin, el tamao de fuente se puede descubrir fcilmente al utilizar el mtodo . css (): $ ( di v. speech
css ( fontSi ze
Sin embargo, puesto que el
valor devuelto incluir un px final, necesitaremos retirar esa parte para llevar a cabo
clculos con el valor. Igualmente, cuando pretendemos utilizar un objeto jQuery ms
de una vez, generalmente es una buena idea guardar en cach el selector al almacenar
el objeto jQuery resultante en una variable tambin.
I

Utilizamos el mtodo. css () de igual forma que hemos estado utilizando. addClass () ; es decir al encadenarlo a un selector y vincularlo a un evento. Para demostrar
esto, regresaremos al ejemplo del conmutador de estilo del captulo anterior, pero con
diferente HTML:
cdiv id=11switcher'l>
cdiv class="lahel'I>Text
Sizec/div>
<buttan id= switcher-default
>Defaultc/button>
<buttan id="switcher-large >Biggerc/button>
<buttan
id=llswitcher-small">Smallerc/button>
11

11

ll

</div>
cdiv class=l'speech">
<p>Fourscore and seven years ago our fathers brought forth
on this continent a new nation, conceived in liberty,
and dedicated
to the proposition
that all men are created
equal.</p>
</div>

Al vincular a una hoja de estilo con algunas reglas de estilo bsicas, la pgina inicialmente se parece a la figura 4.1.
Abraham Lincoln's Gettysburg Address

I )

EDefault'~@lrgger ~

smaller}

Fourscore and seven years ago our fathers brought forth on thls contlnent a new natlon, conceved In Ilberty, and dedlcated
to the proposltlon that all men are created equal.

Figura 4.1. Pgina con reglas de estilo bsicas aplicadas.

$ (document) .ready(function()
(
var $speech = $('div.speech')
$('#switcher-large')
.click(function()
var num = parseFloat($speech.css('fontSize'),

})
})

I )

10);

La primera lnea dentro de $ (document) . ready () ahora almacena una variable


para <di v c Las s "speech":>. Observe el uso de un $ en el nombre de la variable,
$speech. Puesto que $ es un carcter legal en variables JavaScript, podemos utilizarlo
como un recordatorio de que la variable est almacenando un objeto jQuery.
Dentro del manejador . cl ick ( ) , utilizamos par ses'Loat; () para obtener solamente
el nmero de la propiedad del tamao de fuente. La funcin parseFloat
() mira una
cadena de izquierda a derecha hasta que encuentra un carcter no numrico. La cadena
de dgitos se convierte en un nmero en coma flotante (decimal). Por ejemplo, convertira la cadena '12 en el nmero 12. Adems, quita los caracteres finales no numricos
de la cadena, de modo que 12px pasa a ser 12 tambin. Si la cadena empieza con un
carcter no numrico, parseFloat
() devuelve NaN,que significa No un Nmero (Not
a Number). El segundo argumento para parseFloa t () nos permite aseguramos de que
el nmero se interpreta como base 10 en lugar de octal u alguna otra representacin.
Todo lo que queda por hacer, si estamos aumentando en un 40 por ciento, es multiplicar num por 1 . 4 Yluego establecer el tamao de fuente al concatenar num y px
I

Text Slze

I :

IIEII

Aprende jQuery 1.3

4. Efectos

$ (document) .ready(function()
{
var $speech = $(!div.speech');
$('#switcher-large') .click(function()
{
var num = parseFloat($speech.css('fontSizer)
num *= 1.4;
$speech.css('fontSize',
num + 'px
j);
j);

10 );

l);

Laecuacinnum* = 1 .4 esun mtodoabreviadopara num=num* 1.4. Podemosutilizar


el mismo tipo de mtodo abreviado para las otras operaciones matemticas bsicas,
tambin: suma, num+= 1.4; resta, num-'= 1.4; divisin,num/= 1.4; y mdulo (resto
de la divisin),num%=1.4.

Recuerde del captulo anterior que podemos acceder a la propiedad id del elemento
DOM referenciado por this, que aparece aqu dentro de las sentencias if y else if.
Aqu, es ms eficiente utilizar thi s que crear un objeto jQuery slo para comprobar el
valor de una propiedad.
,
Es tambin interesante tener una furma de devolver el tamao de fuente a su valor
inicial. Para permitir que el usuario realice esto, podemos simplemente almacenar el
tamao de fuente en una variable inmediatamente cuando el DOM est listo. Luego
podemos utilizar este valor siempre que se hace die en el botn Default. Para gestionar
este clic, podramos aadir otra sentencia else if. Sin embargo, quiz una sentencia
swi tch sera ms apropiado.
) . ready (funct ion () {
var $speech = $('div_speech');
var defaultSize = $sp~ech.css(lfontSizel);
$('#switcher button') .click(function()
{
var num = parseFloat(
$speech.css('fontSize'),
switch (this.id) {
case 'switcher-large':
num *= 1.4;
break;
case 'switcher-small':
num 1= 1.4;
break;
default:
num = parseFloat(defaultSize,
10);
}
$speech.css('fontSize',
num + IpXI);

(documerit

Ahora cuando un usuario hace die en el botn Bigger, el texto se hace ms grande.
Otro clic, y el texto se hace todava ms grande, como se muestra en la fi~ura 4.2.
Abraham

lincoln'sGettysburg

Address

Text Slze

@oefaiHt, E'Big~e~,~,smalfe,

Fourscore and seven years ago our fathers brought forth on


this continent a new nation, conceived in liberty, and dedicated
to the proposition that all men are created equal.
Figura 4.2. Aumentar el tamao del texto.

Para hacer que el botn Smaller reduzca el tamao de la fuente, dividiremos en lugar
de multiplicar: num / = 1. 4. Mejor an, combinaremos los dos en un solo manejador
. click () en todos los elementos but.t.on dentro de <di v id=" switcher" >. Luego,
despus de averiguar el valor numrico, podemos multiplicar o dividir dependiendo del
ID del botn sobre el que se hizo die. Aqu tiene el aspecto que tiene el cdigo ahora:
$ (document) .ready(function()
{
var $speech = $('div.speech');
$ ('#switcher button') .click(function()
var num = parseFloat{
$speech.css('fontSize
if (this.id == 'switcher-large')
{
num *= 1.4
else if (this.id == 'switcher-small')
num 1= 1.4;

l)

$speech.css(!fontSize'{
})
j);

num + 'px) j

10 ) i

})

la );

j);

Aqu seguimos comprobando el valor de this. id Ycambiando el tamao de fuente


en base a ello, pero si su valor no es 'swi tcher-large'
ni ' switcher-small
',por
defecto se establecer en el tamao de fuente inicial.

Mtodos bsicos ocultar y mostrar


Los mtodos. hide () y . show () bsicos, sin ningn parmetro, se pueden considerar como mtodos abreviados para. css ( 'display'
r 'string'
), donde' string'
es el valor de visualizacin apropiado.
El efecto, como cabra esperar, es que el conjunto de elementos coincidente se ocultar o mostrar inmediatamente, sin animacin.
El mtodo . hide () establece el atributo de estilo en lnea del conjunto de elementos coincidente en di splay: none. Lo bueno de esto es que recuerda el valor de la propiedad display, normalmente block o inline, antes de que se cambiara a none.
Por el contrario, el mtodo . show () restaura el conjunto de elementos coincidentes
a cualquier propiedad de visualizacin visible que tuvieran antes de que se aplicara
display:none.

lIi!II

4. Efectos

Aprende jQuery 1.3

Para ms informacin sobre la propiedad display y cmo se representan sus valores


visualmente en una pgina Web, visite el Mozilla Developer Center en h t t Ps : / /
developer. mozilla. org/en/CSS/display/
y examinelosejemplosenhttps: / /
developer.mozilla.org/samples/cssref/display.html.

Text Sze

oefaUlt) ~:8igger) smaller~

Fourscore and seven years ago our fathers brougtbrorth on thls contlnent a new naton, concelved in liberty, and dedicated
to the proposltlon that all men are created equal.
read more

Figura 4.3. Ocultar el segundo prrafo.

Esta caracterstica de . show () y . hide () es especialmente de utilidad cuando se


ocultan elementos cuya propiedad display predeterminada se anula en una hoja de
estilo. Por ejemplo, el elemento <li> tiene la propiedad display:block
por defecto, pero podramos querer cambiarla a display: inline para un men horizontal.
Afortunadamente, utilizando el mtodo . show () en un elemento oculto como una de
estas etiquetas <1i >no lo restablecerar a su predeterminado display: block, porque
eso situara el <1i > en su propia lnea. En su lugar, el elemento se restaura a su estado
display: inline previo, conservando as el diseo horizontal. Una demostracin rpida de estos dos mtodos se puede establecer al aadir un segundo prrafo y un vnculo
de leer ms (read more) despus del primer prrafo en el HTML:
cdiv id="switcher't>
cdiv class=111abel">Text
Sizec/div>
ebutton
id=ltswitcher-defaultU>Defaultc/button>
ebutton
id=l1switcher-large1t>Biggerc/button>
ebutton id=l1switcher-smalltl>Smallerc/button>
</div>
cdiv class=rrspeech">
<p>Fourscore and seven years ago our fathers brought forth
on this continent a new nation, conceived in liberty,
and dedicated
to the proposition
that all men are
created
equal.
</p>
<p>Now we are engaged in a great civil war, testing whether
that nation, or any nation so conceived and so dedicated,
can long endure.
We are met on a great battlefield
of
that war. We have come to dedicate a portion of that
field as a final resting-place
for those who here gave
their lives that the nation might live. It is altogether
fitting
and proper that we should do this. But, in a
larger sense, we cannot dedicate, we cannot consecrate,
we cannot hallow, this ground.
</p>
<a href=II#" clasB="more">read
more</a>
</div>

Cuando el DOM est listo, el segundo prrafo se oculta:


$ (document) .ready(function()
$ ('p: eq (1) ,) .hide () ;

})

Luego, cuando el usuario hace dic en el vnculo read more al final del primer prra/ fo, ese vnculo se oculta y se muestra el segundo prrafo:
$ (document) .ready(function()
(
$('p:eq(l)
') .hide();
$ ('a.more') .click(furlction()
$ ( 'p :eq (1) ,) .show() ;
$(this) .hide();
return false;
}) ;

})

Observe el uso del return false para impedir que el vnculo active su accin predeterminada. Ahora el texto se parece a lo que se muestra en la figura 4.4:

-,

Text Slze

tDefauftq

~.Rigger'3

tSmaller,)

Foursc.ore and seven years ago our fathers brought forth on thls contlnent a new natlon, concelved in liberty, and dedlcated
to the proposltlon that al! men are created equal.
Now we are engaged tn a great dvH war, testlng whether that naton, or any nation so conceived and so dedicated, can long
endure. We are met on a great battlefleld of that war. We have come to dedlcate a portlon of that fleld as a final
restlng-place for those who here gavethelr
uves that the naton mlght Uve. It Is altogether fitting and proper that we
should do ttus. But~ in a larger sense, we cannot dedlcate, we cannot consecrate, we cannot hallow, this ground.

Figura 4.4. Mostrar todos los prrafos.

Los mtodos. hide () y . show () son rpidos y de utilidad, pero no son muy vistosos. Para aadir atractivo, podemos asignarles una velocidad.

Efectos y velocidad
Cuando incluimos una velocidad (o ms precisamente, una duracin) con . show ()
o . hide ( ) , se anima, es decir, ocurre durante un perodo especfico de tiempo. El mtodo. hide ( speed '), por ejemplo, reduce la altura, anchura y opacidad de un elemento simultneamente hasta que todos llegan a cero, en cuyo punto, se aplica la regla
CSS display: none. El mtodo. show ( speed ') aumentar la altura del elemento
de arriba a bajo, anchura de izquierda a derecha, y opacidad de O a 1, hasta que sus contenidos son visibles completamente.
I

y el discurso se parece a lo que aparece en la figura 4.3.

E!II

4. Efectos

Aprende jQuery 1.3

Aplicar velocidad

Esta vez cuando capturamos la apariencia del prrafo a la mitad, se puede parecer a
lo que se muestra en la figura 4.6:

Con cualquier efectojQuery, podemos utilizar una de las tres velocidades preestablecidas: 'slow', 'normal', y , fast '. Utilizar. show ( , slow' ) hace que el efecto mostrar se complete en .6segundos, . show ( 'normal' ) en.4 segundos, y . show ( , f as t ' )
en .2segundos. Para mayor precisin, podemos especificar un nmero de milisegundos,
por ejemplo . show ( 850) . A diferencia de los nombres de velocidad, los nmeros no
se sitan entre comillas.
Incluyamos una velocidad en nuestro ejemplo cuando mostramos el segundo prrafo
del Discurso de Gettysburg de Lincoln:
$ (document) .ready(function()
(
$ ('p,eq(l)') .hide ();
$ ('a. more') .click (function () {
$ ( 'p: eq (1) , ) . show ( "sLow ') ;
$ (this) .hide () ;
return false
)) ;

))

I (o::oe.ralt1 (.'8fgger.1 ( Smaller-)

Fourscore and seven years ago our fathers brought forth on thls contlnent
dedlcated to the proposltlon that al! men are created equal.

a new

natlon, concelved In Ilberty, and

Now we are en9aged in a great ovil war, testing whether that nation, or any nation so coocetved and so dedlcated, can
long endure. We are met on a great battlefleld of that war. We have come to dedlcate a partlon of that field as a final
restlng-place for those who here gave tnelr uves that the natlon mlght IIve. It is altogether fitting and proper that we
should do thls. But, in a larger sense, we cannot dedica te, we cannot consecrate, we cannor hallow, this ground.

La diferencia aqu es que el efecto. fadeln () empieza al establecer las dimensiones


del prrafo de modo que los contenidos pueden simplemente desvanecerse. Para reducir
gradualmente la opacidad podemos utilizar. fadeOut () .

Text Slze

tDeftwtrl} (81ggu-) ( Smaller9


Fourscore and seven years a90 our fathers brought
lo tne proposltton that all men are created equal.

forth on thls contlnent

a new

netlon, concelved In llberty, and dedlcated

Now we are engsged in a great cv war; testing whether that


nation, or any nation so concelved and so dedlcated, can long

Figura 4.5. Incluir velocidad en el ejemplo.

Aparecer

desaparecer de forma paulatina-

Aunque los mtodos . show () Y . hide () son llamativos, a veces pueden ser
demasiado buenos. Afortunadamente, jQuery ofrece un par de otras animaciones
precreadas para un efecto ms sutil. Por ejemplo, para hacer que todo el prrafo aparezca al aumentar gradualmente la opacidad, podemos utilizar. fadeln ( , slow' ) en
su lugar:
$ (document) .ready(function()
$ ('p: eq (1) ,) .hide () ;
$('a.more')
.click(function()
$ ('p:eq(l)') .fadeln(' a Low
$ (this) .hide () ;
return false
)) ;
;

!Text Slze

Figura 4.6. Todo el prrafo aparece gradualmente.

Cuando capturamos la apariencia del prrafo en aproximadamente la mitad del efecto, vemos algo como lo que se muestra en la figura 4.5:

))

EJI

(
r

Efectos compuestos
Algunas veces tenemos una necesidad de alternar la visibilidad de elementos, en
lugar de mostrarlos de una vez como hicimos en el ejemplo anterior. Alternar se puede
conseguir al comprobar primero la visibilidad de los elementos coincidentes y luego al
anexar el mtodo apropiado. Utilizando los efectos de aparecer y desaparecer gradualmente, podemos modificar el script de ejemplo para que se parezca a esto:
$ (document) .ready(function()
(
var $firstPara
= $('p,eq(l)
');
$firstPara.hide();
$ ( 'a. more' ) .click (function () {
if ($firstPara.is('
:hidden'))
$firstPara.fadeln('slow')
$(this) .text('read
less');
else (
$firstPara.fadeOut('slow')
$(this) .text('read
more');
return

))
))

false

Como hemos hecho anteriormente en este captulo, estamos guardando en cach


nuestro selector aqu. Observe tambin, que ya no ocultamos el vnculo sobre el que se
ha hecho clic; en su lugar cambiamos su texto.
Utilizar una sentencia if else es una forma perfectamente razonable de alternar la
visibilidad de elementos. Pero con los efectos compuestos de jQuery podemos dejar los
condicionales fuera (aunque, en este ejemplo, seguimos necesitando uno para el texto
de vnculo). jQuery proporciona un mtodo. toggle (), que acta como. show () Y

lImJI

4. Efectos

Aprende jQuery 1.3

. h i de () ,y como ellos, se puede utilizar con un argumento de velocidad o sin l. El otro


mtodo compuesto es . sldeTogg1e
(), que muestra u oculta elementos al incrementar o disminuir gradualmente su altura. Aqu tiene el aspecto que tiene el script cuando
utilizamos el mtodo. slideTogg1e
() :

( $link. text ()
$link.text{'read
el se {
$link.text('read

return

})
})

==

"read
less

more"

La segunda forma toma dos argumentos, un mapa de propiedades y un mapa de


opciones.
.animate((properties},

(options})

.,

",

De hecho, el segundo argumento engloba desde el segundo al cuarto argumento de la


primera forma en otro mapa, y aade dos opciones ms a la mezcla. Cuando ajustamos
los saltos de lnea por legibilidad, la segunda forma se parece a esto:

$ (document) .ready(function()
(
var $firstPara
= $('p:eq(l) ');
$firstPara.hide()
;
$ ('a.more') .click(function()
(
$firstPara.slideToggle('alow');
var $1ink = $(this);
if

.animate ({
propertyl:
property2:
) {

valuel' ,
'value2'
I

),

l);

duration:
'value',
easing:
value
I

more');

complete:
function ()
alert{'The animation
},
queue: boolean,
step: callback

false

})

Esta vez $ (ths) se habra repetido, por lo que lo estamos almacenando en la variable $1 Lnk por rendimiento y legibilidad. Tambin, la sentencia condicional comprueba
el texto del vnculo en lugar de la visibilidad del segundo prrafo, ya que solamente lo
estamos utilizando para cambiar el texto.

is finished. ') i

Por ahora, utilizaremos la primera forma del mtodo. anmate (), pero regresaremos
a la segunda forma ms adelante en el captulo cuando tratemos los efectos en cola.

Alternar el aparecer

Crear animaciones personalizadas


Adems de los mtodos de efectos ya incorporados, jQuery proporciona un potente
mtodo. anmate () que nos permite crear nuestras propias animaciones personalizadas con control detallado. El mtodo. anmate () se presenta de dos formas. La primera toma cuatro argumentos:
1. Un mapa de propiedades de estilo y valores, similar al I).1apa. css () tratado
anteriormente en este captulo.
- "

$ (document) .ready(function()
$ ('p: eq (1) ,) .hide () ;

4. Una funcin de rellamada opcional, que se tratar ms adelante en este captulo.


Juntos/los cuatro argumentos se parecen a esto:

animation

is finished.

'value2'},
');

desaparecer paulatino

$('a.more')
.click(function()
{
$ ('p: eq (1) ,) .animate ({opacity:
'toggle'},
var $link = $(this);
if ( $link. text () == "read more" ) (
$link.text('read
less');
else (
$link.text('read
more');

3. Un tipo de mejora opcional.

.animate((propertyl:
'valuel', property2:
speed, easing,
function()
(

Cuando hemos tratado los efectos compuestos, ha observado que no todos los mtodos tienen un mtodo correspondiente para alternar? Correcto: aunque los mtodos
de desplazamiento incluyen. sl deTogg1e (), no existe. fadeTogg1e () correspondiente para continuar con . f ade 1n () y . f adeOu t ( ) . La buena noticia es que podemos
utilizar el mtodo. anmate () para crear nuestra propia animacin de alternar. Aqu,
reemplazaremos la lnea. sldeTogg1e
() del ejemplo anterior con nuestra animacin
personalizada:

2. Una velocidad opcional, que puede ser una de las cadenas preestablecidas o un
nmero de milisegundos.

alert('The

})

return

'slow');

false

Como ilustra el ejemplo, el mtodo. anmate () proporciona valores abreviados convenientes para propiedades CSS, ' show', h i de " Y togg1e " para facilitar el camino
cuando los mtodos abreviados no son del todo apropiados para la tarea determinada.
1

lIlllII

4. Efectos

Aprende jQuery 1.3

Animar mltiples propiedades

derecho mientras se aumenta su altura en 20 pxeles y cambiar el ancho de borde en 5


pxeles. Por 10'tanto, hagamos eso con el cuadro <di v Ld " swi tcher" >. En la figura
4.7 tiene el asrecto que muestra antes de animado.

Con el mtodo. animate (), podemos modificar cualquier combinacin de propiedades simultneamente. Por ejemplo, para crear un efecto deslizar y desvanecer simultneamente cuando alternamos el segundo prrafo, simplemente aadimos el par
propiedad-valor de height al mapa de propiedades de . animate () :
$ (document) .ready(function()
{
$ ( 'p: eq (1) ,) .hide () ;
$('a.more') .click(function()
$ ('p:eq (1) ') .animate ({
opacity: 'toggle',
height:
'toggle'

Abraham Li

Fou,"core
to the propositlon

-'

})

) {

false

Adems, no solamente tenemos a nuestra disposicin las propiedades de estilo utilizadas para los mtodos del efecto abreviado, sino tambin otras propiedades como: 1eft,
t op, fontSize,
margin, padding, y borderWidth. Recuerde al script que cambie
el tamao de texto de los prrafos. Podemos animar el aumentar y disminuir el tamao
con slo sustituir el mtodo. animate () por el mtodo. css () :
$ (document) .ready(function()
{
var $speech
= $('div.speech');
var defaultSize = $speech.css('fontSize')
i
$('#switcher
button') .click(function()
{
var num = parseFloat(
$speech.css('fontSize'),
switch
(this. id) {
case 'switcher-large':
num *= 1.4;
break;
case 'switcher-small
num /= 1. 4;
break;
default:
num = parseFloat(defaultSize,
10);
t:

a new naton, ccncelved

In llberty, and dedlcated

4.7. Aspectodel cuadro sin animacin.

Con un diseo de ancho flexible, necesitamos calcular la distancia que necesita recorrer la caja antes de alinearse a la derecha de la pgina. Asumiendo que el ancho del prrafo es 100por cien, podemos restar el ancho de la caja Text Size del ancho del prrafo.
Aunque el mtodo. width () de jQuery ser de utilidad para dichos clculos, no tiene
en cuenta el ancho del relleno derecho e izquierdo o el borde derecho e izquierdo. En
jQuery versin 1.2.6,tambin tenemos el mtodo. outerWidth () a nuestra disposicin.
Esto es lo que utilizaremos aqu para evitar tener que aadir anchos de relleno y bordes.
Para el objetivo de este ejemplo, activaremos la animacin al hacer die en la etiqueta Text
Size, por encima de los botones. Aqu tiene el aspecto que debera tener el cdigo:
$ (document) .ready(function()
{
$('div.label')
.click (function () {
var paraWidth
= $('div.speech
p') .outerWidth();
var $switcher
= $(this) .parent();
var switcherWidth
= $switcher.outerWidth();
$switcher.animate({left:
paraWidth
- switcherWidth,
height:
'+=20px',
borderWidth:
'spx'}, 'slow');

})
10 );

brought forth on thls oontlnent

createc equal.

Figura

slow');

return

})

that al! men are

read more

},
var $link = $(this);
if ( $ link .text () == "read more"
$link.text('read
less');
else {
$link.text('read
more');

lmII

})

Observe que la propiedad height tiene += antes del valor del pxel. Esta expresin,
incorporada en jQuery 1.2, indica un valor relativo. Por lo tanto, en lugar de animar la
altura a 20 pxeles, la altura se anima a 20 pxeles mayor que la altura actual.
Aunque este cdigo aumenta con xito la altura del <di v y ensancha su borde, en
el momento la posicin 1eft no se puede cambiar. Necesitaremos habilitar cambiar su
posicin en el CSS.

}
$speech.animate({fontSize:
'slow') ;

})
})

num

"px

}.

Las propiedades adicionales nos permiten crear efectos mucho ms complejos, tambin. Podemos, por ejemplo, mover un elemento desde el lado izquierdo de la pgina al

Posicionar con CSS


Cuando se trabaja con. animate (), es importante recordar las limitaciones que
impone CSS en los elementos que deseamos cambiar. Por ejemplo, ajustar la propiedad
1eft no tendr efecto en los elementos coincidentes a menos que esos elementos tengan
su posicinCSSestablecida en relati ve o abso1ute. La posicin CSSpredeterminada

II!PI

,
4. Efectos
Aprende jQuery 1.3

para todos los elementos a nivel de bloque es static,


que describe de forma precisa
cmo permanecern estos elementos si intentamos moverlos sin primero cambiar su
valor position.

lIiD

embargo, esta vez, llevamos a cabo los tres efectos de forma secuencial, al situar cada
uno en su propio mtodo. animate () y encadenar los tres juntos:
$ (document) "teadY(function()
{
$('div.label')
.click(function()

,
(

var paraWidth
= $('div.speech
p') .outerWidth();
var $switcher
= $(this) .parent();
var switcherWidth
= $switcher.outerWidth();
$switcher

Para ms informacin sobre posicionamiento absoluto o relativo, consulte el artculo


de Joe Gillespie,Absolutely Relative en: http://www.wpdfd.com/issues/78/
absolutely_relative/.

.animate({left:

paraWidth

- switcherWidth},

"e Low " )

.animate({height:
'+=20px'},
'slow')
.anima te ({borderWidth:
'5px'}, 'slow');
}.);

Una mirada rpida a nuestra hoja de estilo muestra que ahora hemos establecido
<di v id=" swi tcher" > con posicin relativa:
#switcher
{
position:

j);

Recuerde que encadenar nos permite mantener los tres mtodos. animate () en la
misma lnea, pero aqu los hemos sangrado y situado cada uno en su propia lnea para
mayor legibilidad.
Podemos encolar cualquiera de los mtodos de efecto jQuery, no slo. animate (),
al encadenados. Podemos, por ejemplo, encolar efectos en <di v id=" swi tcher" > en
el siguiente orden:

relative;

Con el CSS tenido en cuenta, el resultado de hacer clic en Text Size, cuando la animacin se ha completado, se parecer a la figura 4.8.
AbrahamLincoln's

1. Desvanecer su opacidad a .5 con. fadeTo () .

Gettysburg Address

,.-

"-..,

TextSlze
(~~

2. Moverlo a la derecha con. animate

~BJgg3 (-'Smaller)

<,

() .

3. Pasar de nuevo a opacidad completa con. fadeTo () .

..-/'

4. Ocultarlo con. slideup


Fourscore and seven years ago our fathers brought (orth on thls contlnent a new naon, concelved In liberty, end dedlcated
to the proposltk>n that.1I men are creeted equa!.

() .

5. Mostrarlo una vez ms con. slideDown ().

read more

Figura

4.8. Posicionarel cuadroa la derecha.

Todo lo que necesitamos hacer es encadenar los efectos en el mismo orden en nuestro cdigo:
$ (document)

Efectos simultneos

frente a "en cola"

.click(function()

var paraWidth
= $('div.speech
p') .outerWidth();
var $switcher
= $(this) .parent();
var switcherWidth
= $switcher.outerWidth();
$switcher

El mtodo. animate (), como acabamos de descubrir, es de mucha utilidad para


crear efectos simultneos en un conjunto determinado de elementos. Sin embargo, existen momentos en los que deseamos encolar nuestros efectos, haciendo que ocurran uno
detrs de otro.

.fadeTo('fast',O.5)
.animate({
},

'left':
'slow')

paraWidth

- switcherWidth

.fadeTo('slow',l.O)
.slideUp ('slow' )
.slideDown('slow')

Trabajar con un solo conjunto de elementos


})

Cuando se aplican mltiples efectos al mismo conjunto de elementos, encolados se


realiza al encadenar esos efectos. Para demostrado, moveremos de nuevo el cuadro Text
Size a la derecha, aumentaremos su altura y aumentaremos el ancho de su borde. Sin

.ready(function()

$('div.label')

})

Pero, qu sucedera si queremos mover el <di v a la derecha al mismo tiempo que


se desvanece a media opacidad? Si las dos animaciones ocurrieran a la misma velocidad,

----------------

ll!!II

4. Efectos

Aprende jQuery 1.3

podramos simplemente combinarlas en un solo mtodo . animate () . Pero en este


ejemplo, desvanecer utiliza la velocidad fast
mientras que mover a la derecha utiliza la velocidad slow '. Aqu es donde la segunda forma del mtodo. animate ()
es de utilidad:
I

(document) .ready(function()
{
$('div.label')
.click(function()

$ (document) .ready(function()
{
$('div.label')
.click(function()
{
var paraWidth
= $('div.speech
p') .outerWidth()
var $switcher
= $(this) .parent();
var switcherWidth
= $switcher.outerWidth();

var
var

;
},

"

'left': paraWidth
"e Low! )

- switcherWidth

1,

#fOO

Cuando se da una funcin de rellamada, como aqu, el mtodo . queue () aade la


funcin a la cola de efectos para los elementos coincidentes. Dentro de la funcin, establecemos el color de fondo en rojo y luego aadimos el mtodo . dequeue ( ) . Incluir
este mtodo . dequeue () permite que la cola de animacin prosiga donde lo dej y
complete la cadena con la siguiente lnea . s 1i deDown ( S 1ow
Si no hubiramos
utilizado . dequeue ( ) , la animacin se hubiera detenido.
I

I )

Msinformaciny ejemplospara. queue () y . dequeue () se encuentran disponibles


en http://docs.jquery
. com/Effects.

{
p') .outerWidth()

$switcher
= $(this) .parent();
switcherWidth
= $switcher.outerWidth();

- switcherWidth

}, 'slow')
.fadeTo('slow',l.O)
.slideUp('slow')
.css('backgroundColor','#fOO')
.slideDown('slow') ;
})

() ;

,slideDown('slow')

})

$switcher
.fadeTo('fast',0.5)

})

$switcherl'"uterWidth

})

El segundo argumento, un mapa de opciones, proporciona la opcin queue, que


cuando se establece en fal se hace que la animacin empiece simultneamente con la
anterior.
Una ltima observacin sobre encolar efectos en un solo conjunto de elementos es que
encolar no se aplica automticamente a otros mtodos no de efectos como. css () . Por lo
tanto, supongamos que queremos cambiar el color de fondo de <di v id=" swi tcher" >
a rojo despus de . slideUp () pero antes de slideDown (). Podramos intentar hacerlo as:

paraWidth

.fadeTo('slow'
,1.0)
.slideUp (,s Low ')
.queue (function () {
$switcher

})

.animate({
'left':

$ ('div.speech
p') .outerWidth()
$(this) .parent();

.fadeTo('fast',0.5)
.animate({

var
var

. esa ( 'backgroundColor
.dequeueJ);

$ (document) .ready(function()
{
$('div.label')
.click(function()
var paraWidth
= $('div.speech

paraWidth
$switcher

var switcherWidth
$switcher

$switcher
.fadeTo('fast'
,0.5)
.animate({
'left': paraWidth - switcherwidth
}, {duration:
'slow', queue: false})
.fadeTo('slow',l.O)
.slideUp (,slow' )
.slideDown('slow')
;

})

})

lIiD

Sin embargo, aunque el cdigo de cambio de fondo se sita en la posicin correcta


en la cadena, ocurre inmediatamente con el dic.
Una forma en la que podemos aadir mtodos no de efecto a la cola es utilizar el
mtodo denominado . queue ( ) . Aqu tiene el aspecto que tendra en el ejemplo que
estamos desarrollando:

Descubriremos otra forma de encolar los mtodos de no efecto segn examinamos


los efectos con mltiples conjuntos de elementos.

Trabajar con mltiples conjuntos de elementos


A diferencia de con un solo conjunto de elementos, cuando aplicamos efectos a diferentes conjuntos, estos ocurren casi al mismo tiempo. Para ver estos efectos simultneos
en accin, desplazaremos un prrafo hacia abajo mientras deslizamos otros hacia arriba. En primer lugar, aadiremos la parte restante del Discurso de Gettysburg al HTML,
dividindolo en dos prrafos.
c::::div id=I1Switcherll:;:.
<div

class=111abel >Text

<button
<button
<button
</div>

ll

Size</div>

id=lIswitcher-defaultll>Default</button>
id=lrswitcher-largetl>Bigger</button>'
id=tlswitcher-small">Smaller</button>

lI!IiI

Aprende jQuery 1.3

4. Efectos
.click(function()
{
$(this) .slideUp('slow')
.next () . slideDown (1 s Low "} ;

cdiv class="speech">
<p>Fourscore and seven years a90 our fathers brought forth
on this continent a new nation, conceived in liberty, and
dedicated to the proposition that a11 men are created
equal.
</p>
<p>Now we are engaged in a great civil war, testing whether
that nation, or any nation so conceived and so dedicated,
can long endure. We are met on a great battlefield of
that war. We have come to dedcate a partian of that
field as a final resting-place
for those who here gave
their lives that the nation might live. It is altogether
fitting and proper that we should do this. But, in a
larger sense, we cannot dedcate, we cannot consecrate,
we cannat hallow, this ground.
</p>
<a href="#"
class="moreu>read
maree/a>
<p>The brave men, living and dead, who Btruggled
here have consecrated it, far above our poor
power to add or detracto The wor1d wi11 1ittle
note, nor long remember, what we say here, but it
can never forget what they did hare. It ia for ua
the living, rather, te be dedicated here to the
unfinished work which they who fought here have
thus far so nobly advanced.
</p>
<p>It is rather for ua te be here dedicated to the
great task remaining before us-that from
these honored dead we take increased devotion to
that cause for which they gave the 1ast fu11
measure of devotion-that we here highly
resolve that these dead shall not have died in
vain-that this nation, under God, shall
have a new birth of freedom and that government
of the people, by the people, for the people,
sha11 not perish from the earth.
</p>
</div>

A continuacin, para ayudamos a ver qu sucede durante el efecto, asignaremos al


tercer prrafo un borde de 1 pxel y al cuarto prrafo un fondo gris. Tambin ocultaremos el cuarto prrafo cuando el DOM est listo:

})

$('p,eq(3) ') .css('backgroundCol~',

})

'#eee') .hide();

Una captura de estos dos efectos confirma que, de hecho, se producen prcticamente
al mismo tiempo, como muestra la figura 4.9:
e brave men, livIng and dead, wha stnJggled hera have consecrated It, far above our poor power to add or detract.
rld wlll IIttle note nor Ion
m
sa h r
I
e e
wh t th
did here. It Is ~ rus

~~H~lii~~:w~"t~;~\t~ -

1~~~~']j~~~~

The

Figura 4.9. Los efectos ocurren al mismo tiempo.

El tercer prrafo, que empez visible, est a mitad de camino en el desplazarse hacia
arriba al mismo tiempo que el cuarto prrafo, que empez oculto, est a mitad de camino en el desplazarse hacia abajo.

Rellamadas
Con el objetivo de permitir encolar efectos en diferentes elementos, jQuery proporciona una funcin de rellamada para cada mtodo efecto. Como hemos visto con los
manejadores de evento y con el mtodo . queue ( ) , las rellamadas son simplemente funciones pasadas como argumentos de mtodo. En el caso de los efectos, aparecen como
el ltimo argumento del mtodo.
Si utilizamos una rellamada para encolar los dos efectos de desplazamiento, podemos hacer que el cuarto prrafo se desplace hacia abajo antes de que el tercer prrafo
se desplace hacia arriba. Veamos primero cmo configurar el mtodo. slideDown ()
con la rellamada:
$ (doeument) .ready(funetion()
$ ( "p :eq (2) , )
_css('border',
'lpx salid #333')
.eliek(funetion()
{
$(this) .next() .slideDown('slow',function()
// el cdigo aqu se ejecuta despus de que el desplazamiento
// hacia abajo del tercer prrafo ha terminado

$ (doeument) .ready(funetion()
{
$ ( 'p,eq (2) , ) . ess ('border', 'lpx sol id #333');
$ ("p : eq (3) ,) .ess ('baekgroundColor',
'#eee ') .hide ();

})

lIiiI

})

})

$('p,eq(3) ') .ess('baekgroundColor',

'#eee') .hide();

j);

Por ltimo, aadiremos el mtodo. click () al tercer prrafo de modo que cuando
se hace clc, el tercer prrafo se desplaza hacia arriba (y fuera de la vista), mientras que
el cuarto prrafo se desplaza hacia abajo (a la vista):
$ (doeument) .ready(function()
$ ('p,eq(2)')
.ess('border',

'lpx sol id #333')

Sin embargo, necesitamos tener cuidado aqu sobre qu es lo que se va a desplazar


hacia arriba. El contexto ha cambiado para $ (thi s) porque la rellamada est dentro
del mtodo. slideDown (). Aqu, $ (this) ya no es el tercer prrafo, como era en el
momento del mtodo. click () i en su lugar, puesto que el mtodo. slideDown ()
est anexado a $ (thi s) . next ( ), todo dentro de ese mtodo ahora ve $ (thi s)

lIiII

4. Efectos

Aprende jQuery 1.3

como el siguiente hermano, o el cuarto prrafo. Por lo tanto, si situamos $ (this) .


slideUp ( slow ') dentro de la rellamada, acabaremos ocultando el mismo prrafo
que hemos acabado de poner visible.
Una forma sencilla de mantener la referencia de $ (thi s) estable es almacenarla en
una variable dentro del mtodo. c Li ck (), como var $thirdPara
= $ (this) .
Ahora $thirdPara
har referencia al tercer prrafo, fuera y dentro de la rellamada.
Aqu tiene el aspecto del cdigo utilizando nuestra nueva variable:

J.

'slow')
.fameTo('slow',l.O)
.slideUp('slow',
function()
!$switcher

$( document) .ready(function()
(
var $thirdPara
= $ ('p:eq(2) ');
$thirdPara
.css('border',
'lpx solid #333')
.click(function()
{
$ (this) .next () .slideDown ( 'slow' ,function
$thirdPara.slideUp('slow')
;

})
})

.css('backgroundCola~"

'#fOO');

})
-slideDown('slowt)

} );
})

Aqu de nuevo, el color de fondo de <di v id= swi tcher


> cambia a rojo despus
de desplazarse hacia arriba, y antes de que se desplace hacia abajo.
11

11

En pocas palabras

()

$ ('p: eq (3) ') .css ('backgroundColor',


})

lID

'#ccc'). hide () ;

Utilizar $thirdPara
dentro de la rellamada . slideDown () se basa en las propiedades de cierres. Trataremos este importante tema, aunque difcil de dominar, en el
Apndice C.
Esta vez, una captura a mitad de camino durante los efectos revelar que tanto el
tercer como el cuarto prrafo son visibles, el cuarto ha terminado de deslizarse hacia
abajo y el tercero est a punto de empezar a desplazarse hacia arriba, como se ve en la
figura 4.10.
e breve men, living Bnd dead, who struggled here have consecrated it, far above our poor power to add or detracl The
lrtd wlll IIttle note, nor long remcmber, what we say here, but It can never forget what they dld here. lt 15far us the
'living, rather, to be dedlcated here to the unflnlshed wor1c whlch they who fought here have thU5 far so nobly advanced.

Figura 4.10. Los dos prrafos son visibles.

Ahora que hemos tratado las rellamadas, podemos regresar al cdigo anterior en este
captulo en el que encolamos un cambio de color de fondo cerca del final de una serie de
efectos. En lugar de utilizar el mtodo. queue ( ) , como hicimos anteriormente, simplemente podemos utilizar una funcin de rellamada:
$ (document) .ready(function()
(
$('div.label')
.click(function()
{
var paraWidth
= $('div.speech
p') .outerWidth()
var $switcher
= $(this) .parent();
var switcherWidth
= $switcher.outerWidth();
$switcher
.fadeTo('slow'
,0.5)
.animate({
'left': paraWidth
- switcherWidth

Con todas las variaciones a considerar cuando se aplican efectos, puede resultar difcil recordar si los efectos ocurrirn simultneamente o de forma secuencial. Un breve
detalle podra ayudar:
1. Efectos en un solo conjunto de elementos son:

2.

Simultneos: Cuando se aplican como mltiples propiedades en un solo


mtodo. animate () .

En cola: Cuando se aplican en una cadena de mtodos, a menos que la opcin


queue se establezca en falseo

Efectos sobre mltiples conjuntos de elementos son:

Simultneos: Por defecto.

En cola: Cuando se aplican en la rellamada de otro efecto o dentro de la


rellamada del mtodo . queue ( ) .

Resumen
Al utilizar los mtodos de efectos que hemos explorado en este captulo, ahora deberamos poder aumentar y disminuir incrementalmente el tamao del texto al utilizar el
mtodo. ess () o . animate () .Tambin deberamos poder aplicar varios efectos para
ocultar y mostrar gradualmente elementos de pgina de diferentes formas y tambin
animar elementos, simultneamente o de forma secuencial, en una serie de formas.
En los cuatro primeros captulos del libro, todos nuestros ejemplos han implicado
manipular elementos que se han insertado directamente en el HTML de la pgina. En el
siguiente captulo, exploraremos formas en las que podemos utilizar jQuery para crear
nuevos elementos e insertarlos en el DOM all donde elijamos.

\,

/'

Manipul
D

.
cron
'"

Como un mago que hace aparecer un ramo de flores de su chistera, jQuery puede
crear elementos, atributos y texto en una pgina Web, como por arte de magia. Pero,
espere, hay mucho ms. Con jQuery, tambin podemos hacer desaparecer cualquiera
de estas cosas. Y,podemos tomar ese ramo de flores y transformarlo en una paloma con
<divclass="magic"
id="flowerstodove">dove</div>.

Manipular

atributos

A lo largo de estos cuatro captulos del libro, hemos estado utilizando los mtodos
. addClass () y . removeClass () para demostrar cmo podemos cambiar la apariencia
de elementos en una pgina. Efectivamente, lo que estos dos mtodos hacen es manipular el atributo de clase (o, en jerga de programacin DOM, la propiedad className).
El mtodo. addClass () crea o aade al atributo, mientras que. removeClass () lo
elimina o lo acorta. Aada a estos el mtodo. toggleClass
() que alterna entre aadir
o eliminar una clase, y tenemos una forma eficiente y robusta de gestionar clases.
No obstante, el atributo class es slo uno de los varios atributos a los que podemos necesitar acceder o cambiar: por ejemplo, id y rel y href. Para manipular estos
atributos, jQuery proporciona los mtodos. attr () y . removeAttr (). Podramos
incluso utilizar. at tr () y . removeAt tr () para modificar el atributo class, pero los
mtodos especializados. addClass () y . removeClass () son mejores en este caso
porque gestionan correctamente casos donde mltiples clases se aplican a un solo elemento, como <di v c Las s " first
second" >.

mi

5. Manipulacin

Aprende jQuery 1.3

DOM

lID

Atributos que no son clase

atributo comn para todos los vnculos, podramos hacerlo con una sola lnea de cdigo
dentro de nuestro manejador $ (document)
. ready () :

Algunos atributos no se pueden manipular tan fcilmente sin la ayuda de jQuery.


Adems, jQuery nos permite modificar ms de un atributo de cada vez, similar a la forma
en que hemos trabajado con mltiples propiedades
CSS utilizando el mtodo . e s s () en
el captulo anterior. Por ejemplo, podemos establecer fcilmente los atributos id, re 1, y
tit1e
para vnculos, todos a la vez. Empecemos con algo de HTML de ejemplo:

$ (document) .,ady(function()
{
$ (!div.chapter a!) .attr({/rel!:

<hl id=tlf-titlell>Flatland: A Romance of Many Dimensions</hl>


<div id=tlf-authortl>by Edwin A. Abbott</div>
<h2>Part 1, Section 3<!h2>
<h3 id=tlf-subtitlel!>
Concerning the Inhabitants of Flatland
<!h3>
<div id=tlexcerpttl>an excerpt</div>

})

lexternal/});

Esta tcnica funciona porque queremos que el nuevo atributo re1 tenga el mismo
valor para cada vnculo. Sin embargo, a menudo los atributos que aadimos o cambiamos deben tener diferentes valores para cada elemento. Un ejemplo de esto es que para
cualquier documento
dado, cada id debe ser nico si queremos que nuestro cdigo
JavaScript se comporte de forma predecible. Para establecer un id nico para cada vnculo; abandonamos
la solucin de una lnea en favor del mtodo. each () de jQuery.
$ (document) .ready(function()
{
$ (!div.chapter a!) .each(function(index)
$(this) .attr({
!rel!: !external!,
lid!, !wikilink-! + index

<div class="chapter">
<p class="squaretl>Our Professional Men and Gentlemen are
Squares (to which class 1 myself belong) and Five-Sided
Figures or <a
href=''http://en.wikipedia.org/wiki/Pentagonu>pentagons

})
})
})

<la>.
<!p>
<p class=tlnobility hexagonl!>Next above these come the
Nobility, of whom there are several degrees, beginning at
Six-Sided Figures, or <a
href=''http://en.wikipedia.org/wiki/Hexagontl>Hexagons</a>,
and from thence rising in the number of their sides till
they receive the honourable title of <a
href="http: !!en.wikipedia.org!wiki!Polygon"
>Polygonal< la>,
or many-Sided. Finally when the number of the sides
becomes so numerous, and the sides themselves so small,
that the figure cannot be distinguished
from a <a
href=''http://en.wikipedia.org/wiki/Circle''>circle</a>,
he
is included in the Circular or Priestly arder and this is
the highest class of all.

El mtodo.
each (), que acta como un iterador explcito, es en realidad una forma
ms conveniente del bucle foro Se puede emplear cuando el cdigo que queremos utilizar en cada elemento en el conjunto de elementos coincidentes del selector es demasiado complejo para la sintaxis de iteracin implcita. En nuestra situacin, a la funcin
annima del mtodo . each () se le pasa un ndice que podemos anexar a cada id.
Este argumento de ndice acta como un contador, empezando en para el primer vnculo y aumentando
en 1 con cada vnculo sucesivo. De esta forma, establecer el id en
/wikilink/ + index proporciona
al primer vnculo un id de wiki1ink0, al segundo un id de wiki1ink-l,
etc.

<!p>

De hecho, podramos haber optado por iteracin implcita aqu, porque el mtodo
. a t t r () puede tomar una funcin como su segundo argumento, similar a la forma en
que el mtodo . f i 1t er () puede hacerla con su nico argumento como vimos en un
captulo anterior (vase http://docs.j
query. com/Attributes/attr#keyfn
para detalles). Sin embargo, utilizar. each () parece ms conveniente para nuestras
necesidades.

<p><span class="pull-quote">It
is a <span class="droptl>Law
of Nature<!span>
with us that a male child shall have
<strong>one more side</strong>
than his father</span>,
so
that each generation shall rise (as a rule) one step in
the scale of development and nobility. Thus the son of a
Square is a Pentagon the son of a Pentagon, a Hexagon
and so on.
<!p>
<!-- ...
cdigo contina ..
<!div>

Ahora podemos pasar por cada uno de los vnculos dentro de <di v c.l ass chapter
>
Y aplicarles atributos uno a uno. Si solamente necesitramos
establecer un valor de
11

11

Utilizaremos el atributo ti t1e para invitar a personas a aprender ms sobre el trmino


vinculado en Wikipedia. En el ejemplo HTML, todos los vnculos apuntan a Wikipedia.
Sin embargo, es probablemente
una buena idea hacer que la expresin de selector sea
un poco ms especfica, seleccionando
solamente vnculos que contienen wikipedia
en el href, slo en caso de que decidamos aadir un vnculo no Wikipedia al HTML en
un momento posterior:

II!I

5. Manipulacin

DOM

Aprende jQuery 1.3

$ (document) .ready(function()
{
$ (!div.chapter
a [href*=wikipediaJ!)
.each(function(index)
var $thisLink
= $(this);
$thisLink.attr({
!rel!: !external!,
!id!, !wikilink-!
+ index,
!title!,
!learn more about ! + $thisLink.text()
}) ;
}) ;
}) ;

$ (document) .ready(function()
{
$(/<a href,,"#top">back
to top<!a>!);
$ (/<a id="top"><!a>!);
}) ;
r~-::J'

! at Wikipedia!

lI

I1

la funcin factory

$0

En la figura 5.1 tiene cmo se muestra la pgina en este punto.


Flatland: A Romance of Many Dimenslons
by Edwln A. Abbott

Una cosa que merece la pena destacar aqu es que ahora estamos almacenando
$ (this)
en una variable denominada $thisLink,
simplemente porque acabamos
utilizndola ms de una vez. Con estos tres atributos establecidos, el HTML del primer
vnculo, por ejemplo, ahora se parece a esto:
ea href=''http://en.wikipedia.org/wiki/Pentagon"
id= wikilink-O
title="learn
more about
Wikipediall>pentagons</a:>

II'BI

Par1 1, Section 3
Concernlng the Inhabltants
an excerpt

of Flatland

Ou', Professlonal Men and Gentlemen are Squares (to whlch class I myself belong)
and Flve-Slded Figures o, Pentagons.
Next above these come the Noblllty, of whom there are several degrees, beglnnlng
at SixaSlded Figures, or ~
and from thence rlslng In the number ef thelr
sldes tili they recelve the honourable tltle of ~,
or many-Slded. Finaily
when the number of the sldes beoomes so numerous, and the sldes themselves so
small, that the figure cannot be dlstingulshed from a~,
he Is ncluded In the
Circular or Pnestly arder; and thls is the hlghest dass of all.

rel=flexternalr,
Pentagons
at

revisada

Desde el principio de este libro, hemos venido utilizando la funcin $ () para acceder
a elementos en un documento. En cierto sentido, esta funcin se encuentra en la base de
la biblioteca jQuery, ya que se utiliza cada vez que anexamos un efecto, evento, o propiedad a un conjunto coincidente de elementos.
An ms, la funcin $ () tiene todava un truco ms dentro de su parntesis, una caracterstica tan potente que puede cambiar no solamente la apariencia visual sino tambin
los contenidos de una pgina. Con slo insertar un fragmento de cdigo HTML dentro
de los parntesis, podemos crear una estructura DOM enteramente nueva de la nada.

It Is a taw of Nature wlth us that a male chlld shall have one more slde than hls
father, so that each generatlon shall rse (as a rule) ene step In the scale of
develapment and noblllty. Thus the son of a Square Is a Pentagon; the son of a
Pentagon, a Hexagon; and so on.
But this- ruJe applies not aiways to the Tradesman, and stlll less often to the
Soldlers, and to the Werkmen; whe indeed can hardly be sald to deserve the name
of human Figures, slnce they have not all thelr sldes equel, Wlth them therefore
the Law of Nature does nat hold; and the son of an Isesceles (Le. a Trlangle with
two sfdes equal) remalns Isosceles stlll. Nevertheless, aU hope 15 not such out,
even fi"om the lsosceles, that hls posterltv may ultlmately rise above hls degraded
condltion ....
Rarely-In
proportlon te the vast numbers of Isesceles blrths-Is
a genulne and
certlflable Equal-Slded Trlangle produced fi"om Isosceles parents. "WhDl.ud ofa
certtjlCtlle?" a Space1a;d crtdc may ast.' "/$ 1101lhe prrJC1'f!allon of SqllQn Son G ~rt!ftctJ(efrom
Narure hose/f. pnnoJng lile EquaJ...Jldedlll!Ss 01 Ih~ Fatlrer?" I reply ,hal no Lady olO1ly posmon wlll
marry an uncerlifo'd 1HiJngle.. Squan offtprl'W II(JJ sometlmllS resulted from a slightly 'TmplaT
Q

Figura 5.1. Prrafos sin vnculos para volver arriba.


)

"

Deberamos recordar, una vez ms, el peligro inherente de poner cierta funcionalidad,
atractivo visual o informacin textual disponible solamente a aquellos con navegadores
Web que pueden (o tienen habilitado) utilizar JavaScript. La informacin importante
debera estar accesible a todos, no solamente a las personas que parece que estn
utilizando el software correcto.

Pero, dnde estn los vnculos para volver arriba y el ancla? No deberan aparecer
en la pgina? La respuesta es no. Aunque las dos lneas crean los elementos, todava no
aaden los elementos a la pgina. Para hacer esto, podemos utilizar uno de los muchos
mtodos de insercin jQuery.

Insertar nuevos elementos


Una caracterstica que normalmente se ve en las pginas FAQ es el vnculo volver
arriba (back io tap) que aparece despus de cada par pregunta-respuesta. Se podra decir
que estos vnculos no sirven a ninguna finalidad semntica y por lo tanto se pueden
incluir va JavaScript de forma legtima como una mejora para un subconjunto de los
visitantes a una pgina. Para nuestro ejemplo, aadiremos un vnculo "volver arriba"
despus de cada prrafo, as como el ancla al que nos llevarn estos vnculos. Para empezar, simplemente creamos los nuevos elementos:

jQuery tiene dos mtodos para insertar elementos antes de otros elementos:
. insertBefore
() y . before ( ) . Estos dos mtodos tienen la misma funcin; su diferencia se encuentra solamente en cmo se encadenan a otros mtodos. Otros dos mtodos. insertAfter
() y . after (), mantienen la misma relacin entre s, pero como
sugiere su nombre, insertan elementos detrs de otros elementos. Para los vnculos de
volver arriba utilizaremos el mtodo. insertAfter
() :

lmJI

5. Manipulacin

DOM

Aprende jQuery 1.3

$ (document) .ready(function()
{
$ (!<a href="#top">back
to top<!a>/)
.insertAfter(/div.chapter
p/)
$ (!<a id="top"><!a>!);

})

$ (document) .ready(function()
{
$(/<a href="#top">back
to top<!a>!)
.insertAfter(!div.chapter
p!);
$ (/ <a id= "t.op" name t op" ></a>/)
.prependTo(/body!);

lIf.I

ti

) ;

El mtodo. after () realizara lo mismo que. insertAfter


(), pero con la expresin selector precediendo el mtodo en lugar de a continuacin. Utilizando. after (),
la primera lnea dentro de $ (document) . ready () se parecera a esto:
$ (!div.chapter

p!) .after(/<a

href="#top">back

to top<!a>!);

Con. insertAfter
(), podemos continuar actuando sobre el elemento <a> creado al
encadenar mtodos adicionales. Con. after (), los mtodos adicionales actuarn sobre
los elementos coincidentes por el selector $ (/ di v . chapter p /) en su lugar.
Por lo tanto, ahora que hemos insertado los vnculos en la pgina (y en el DOM) despus de cada prrafo que aparece dentro de <di v c La s s chapter" >, aparecern los
vnculos back to top, como se ve en la figura 5.2.
e

"

Flatland: A Romance of Many Dlmenslons


by Edwln A. Abbott

Part 1, Section 3

Este cdigo tradicional inserta el ancla al principio del body: en otras palabras, al
principio de la pgina. Ahora, con el mtodo. insertAfter
() para los vnculos y el
mtodo . prependTo () para el ancla, tenemos un conjunto plenamente operativo de
vnculos back to top para la pgina.
Con vnculos as, no tiene mucho sentido hacer que aparezcan cuando el principio
de la pgina sigue siendo visible. Una mejora rpida al script empezara los vnculos
solamente despus del cuatro prrafo, por ejemplo.
Esto se consigue rpidamente con un pequeo cambio a la expresin selector:
. insertAfter
(/ di v. chapter p: gt (2) /) . Por qu e12 aqu? Recuerde que el indexado de JavaScript empieza en O; por lo tanto, el primer prrafo se indexa como O, el
segundo es 1, el tercero es 2, y el cuatro prrafo es 3. Nuestra expresin selector empieza
insertando los vnculos despus de cada prrafo cuando el ndice alcanza 3, porque se
es el primero mayor que 2.
El efecto de este cambio es ahora evidente, como se ve en la figura 5.3.

Concernlng the Inhabltants o, Flatland


lln excerpt
Our Professlonal Men and Gentlemen are Squares (to whlch
and Flve-Slded FIgures or Pent.agons.

dass 1 myself belong)

Flatland: A Romance of Many Dimensions

by Edwin A. Abbott

Next above these come the NobUity, af whom there are several degrees, begfnnlng
at SlxSlded Figures, or Hexagons and from then.ce r1slng In the number of their
sldes tlll they receve the honourable tltle of Polygonal, or many-Slded. Flnally
when the number o, the sldes becomes so numerous, and the sldes themselves so
small, that!he figure cannot be dlstlngulshed from o clrde, he 15Included In the
Circular or Prfestiy arder; .nd thls Is the hlghest dass of all.

Part 1, Section 3
concerning the Inhabltants of Flatland
an excerpt
Qur Professlonal Men and Gentlemen are Squares (to whlch
and Five-Sided Figures or Pentagons.

class 1 myself belong)

back te toa
It Is a Law of Nature wl!h us that a male chlld shall have one more Ilde than hls
father, 50 that each generatlon shall rlse (es a rule) one step in the scale of
development and noblllty. Thus the son of a Square 15a Pentagon; the son of a
Pentagon, a Hexagon; and so on.
b.ck te top
But thls rule applles not always te the Tradesman, and stlll less often lo the
Soldlers, and to the Workmen; who Indeed can hardly be sald te deserve the name
of human Figures, slnce they have not all thelr sldes equa, Wlth them therefore
the tsw of Nature does not hold and the son of en Isosceles (Le. a Trlangle wlth
two sldes equal) remains Isosceles stllI. Nevertheless( al! hope 15not such out,
even lrom the lsosceles, !hat hs posterlty m.y ultlmately rse abave hls degraded
condton ....

~
Rarely-In

proportlon

te !he vas! numbers

01 lsosceles blrths-Is

a genulne and

Figura 5.2. Los vinculas para volver arriba despus de cada prrafo.

Desafortunadamente, los vnculos no funcionan todava. Todava necesitamos insertar el ancla con id= 11 top". Para esto, podemos utilizar uno de los mtodos que inserta
elementos dentro de otros elementos.

Next above these come the Nobilttv, of whom there are several degrees, beginnlng
at Slx-Slded Figures, or ~
end from thence rislng In the number of thelr
sldes till they receive the honourable tltle of ~,
or many-Slded. Fln.lly
when the number of the sldes becomes so numerous, and the sldes themselves so
small, that the figure cannot be dlstlngulshed from elrele, he Is included in the
Clreular or Prfestiy arder; and !hls Is tne hlghest dass al all.
lt is a l..aw of Neture with us that a male chlld shall have one more .Ide than his
father, so that each generation shall rise (as a rule) one step In the scale Q'f
development and noblllty. Thus the son of a Square Is a Pentagon; the son of a
Pentagon, a Hexa.gon; and so on.
But this rule applles not .Iways to the l'rBdesman, and stlll tess often to tne
Soldle'rs, and to the Workmen; who Indeed can hardly be said te deserve the name
of human Figures, slnce !hey have not .11 thelr sldes equal. WI!h them therefore
!he Law of Noture does not hold; and the son al an tsoscetes (Le. a Trl.ngle wlth
two sldes equal) remalns Isosceles stlll. Nevertheless, ali hope 15not such out,
even from the lsosceles, !hat hls posterlty m.y ultlmately rse above hls degraded
condltlon ....

~
P.arely-In
certlfiable

proportlon lo the vas! numbers o/ lsosceles blrths-is


a genulne and
Equ.I-Slded Trl.ngle produced from Isosceles parents. "WhOlndofa

Figura 5.3. Mejorar el script.

mi

5. Manipulacin

DOM
Aprende jQuery 1.3

Mover elementos
Con los vnculos back lo top, hemos creado nuevos elementos y los hemos insertado
en la pgina. Tambin es posible tomar elementos de un lugar en la pgina e insertarlos
en otro lugar. Una aplicacin prctica de este tipo de insercin es el posicionamiento
dinmico y formato de notas a pie de pgina.

Cada uno de estos prrafos tiene un solo pie de pgina dentro de <span
class=" f oot.not;e "></span>. Al codificar elHTML de esta forma, podemos preservar
el contexto del pie de pgina. Con una regla CSS aplicada a la hoja de estilo para poner
en cursiva los pies de pgina, los tres prrafos se parecen a lo que aparece en la siguiente figura.

Un pie de pgina ya aparece en el texto Flatland original que estamos utilizando para
este ejemplo, pero tambin designaremos un par de otras partes del texto como pies de
pgina para la finalidad de esta explicacin:

Ra.rely-ln proportlon to the vast numbers of tsoscetes blrths-Is a genulne and


certlfiable Equal-Slded 1)-langle produced from lsosceles parents. "Whal need ojo
curtftcaJtJ?" Spau'land crltlc may asA: "'$ no' me prot:rmlJon ojo Squ012 Soll a certiflCluefrom
NlJJrJJW heNfl/j provng me EqUIJ/aJidednesS
011M FOllter?" / rtply that 110 Lody o/any posttton wl/l
mar", Q1I uncenljluJ ntangle. Stutm! offspT1g ha.r sometimes ruultedfrom a sllghtly Irregular
TrlDllglt; but In almos! e\!O)' meA case the lrngularlty oltltejll'lt gvJUOri01I
vtsued 011 tire third;
whJclt e.lllter faJu 10 altatn the PellIogonaJ rani; 01' relapsl!J U) me Triangular. Such a blrth
requlres, as Its antecedents, not only a series o, carefully arranged Intermarriages,
but also a long-contlnued exerclse of frugallty and self-control on the part of the
would-be ancestors of the comlFlg Equll!lteral, and a patlent, systematlc, and
contlnuous development of the lsosceles Intellect through many generatlons.
Q

ts

proportion to the vast numbers oE Isosceles


births&mdash;is a genuine and certifiable Equal-Sided

<p>Rarely&mdash;in
Triangle

produced

from Isosceles

parents.

<span

ll

class=lIfootnote >IIWhat need of a certificate?!I a Spaceland


critic may ask: !lIs not the procreation of a Square Son a

certificate from Nature herself, proving the Equalsidedness


of the Father?" I reply that no Lady of any position will

marry

The blrth af a Ttue Equllateral Trtangle from Isosceres parents 15the subject of
rejolclng In our country for many furlongs round. After a strict exemrnetton
conducted by the Sanltary and SOCial Board the Infant, If certlfled as Regular, is
wlth solemn ceremonial admltted Into the class of Equllaterals. He Is then
Immedlately taken from hls proud yet sorrowlnq parents and adopted by some
chlldless Equllateral. TIu: Equllreral ts bowuJ by oaUt never ro pumil Me: child henceforth 10 enter
tus former hom~ or so mucJt as 10 /001: uptm Itls 1'f!la()1Uagaln./or fear test JJrBfreshly deveJ~
o~
nJd)t, lryfOrCB ofunconrclow
tmilation.fa/l bacJc agah'llnlo his hmxJtrary leve!

an uncertified

Triangle.

Sguare

offspring

has

sometimes resulted from a slightly Irregular Triangle;


but in almost every such case the Irregularity of the
first generation

is visited

on the third; which

either

fails to attain the Pentagonal rank, or relapses to the


Triangular.</span>

Such a birth

requires,

as its

antecedents, not only a series of carefully arranged


intermarriages,
but also a long-continued
exercise of

frugality and self-control on the part of the would-be


ancestors of the coming Equilateral, and a patient,
systematic,

and continuous

development

How admira ble Is the Law of Compensatlon 1And how pgrfecl a proof of ,he MlUrat ftmess
ando 1 may olmost soy. rhe:dJvfne orlgin o/Ilre artnocrattc consrlRltion of the Sratl!f ofFlaltand! By a
judldous use of thls Law of Nature, the Pofygons and arcles are almost always
able to stie sedltlon In Its very cradle, taklng advantage of the lrreprasslbte and
boundless hopefulness of the human mlnd ....

of the Isosceles

intellect through many generations.


</p>
<p >The birth of a True Equilateral Triangle from Isosceles
parents is the subject af rejoicing in Our country for many
furlongs raund. After a strict examination conducted by the
Sanitary and Social Board, the infant, if certified as
Regular, is with salemn ceremonial admitted into the class

of Equilaterals. He is then immediately taken from his


proud yet sorrowing parents and adopted by some childless
Equilateral.

<span class=lIfootnote">The

Equilateral

is

bound by oath never to permit the child henceforth to enter


his former

horne or so much as to look upon his relations

again, for fear lest the freshly developed organism may, by


force of unconscious

imitation,

fall back again

into his

hereditary level.</span>
</p>
<p>How admirable

is the Law of Compensation!

class=tlfootnotell>And how perfect

a proof

<span
of the natural

fitness and, I may almost say, the divine origin of the


aristocratic constitution of the States of Flatlandl</span>
By a judicious use of this Law of Nature, the Polygons and
Circles are almost always able to stifle sedition in its
very cradle, taking advantage of the irrepressible and
boundless hopefulness of the human mind.&hellip;
</p>

lIlII

Figura 5.4.

Destacar los pies

de pgina.

Ahora podemos tomar los pies de pgina e insertar los entre <di v e 1as s ="chapt e r ">
y <di v .i d "footer" >. Recuerde que incluso en casos de iteracin implcita, el orden
de insercin est predefinido, empezando al principio del rbol DOM y descendiendo.
Puesto que es importante mantener el orden correcto de los pies de pgina en su nuevo
lugar en la pgina, deberamos utilizar. insertBefore
(/#footer /) .
Esto situar cada pie de pgina directamente antes de <di v Ld " footer" > de modo
que el pie de pgina 1 se sita entre <di v class=" chapter" >y <di v I d "footer" ,
el pie de pgina 2 se sita entre pie de pgina 1 y <di v .i.d"footer" , etc. Utilizar
. insertAfter
(/ di v . chapter /) , por otro lado, hara que los pies de pgina aparezcan en orden inverso. Hasta el momento, nuestro cdigo se parece a esto:
$(d ocument) .ready(function() {
$(/span.footnote/) .insertBefore(/#footer/) ;
j);

Desafortunadamente, sin embargo, nos hemos encontrado con un gran problema. Los
pies de pgina estn en etiquetas span, lo que significa que se muestran inline por
defecto, uno detrs de otro sin separacin, como aparece en la figura 5.5.

lIfIiI

5. Manipulacin

DOM

itWltat nud ola cmij'tC4te'" a Spaulllllli crltic may osk: "ls nol the procnoIion ola Stuan Son a ceniftt:(JUj'rom NtlR1r6 herset; pl'OWng me
Equal-sldednes!
o/tAl! FtJJ.htrrl" I rq1/y that no Lady 01 any pasitlan wUJmarry 1m uncemfed 1Hangle. SqutllY. offiprflrg haJ sometJmes 1'e$ultm
from a sllghlJ)' lrrtJgwlar THangle; bUl tn almost f1W!1'JI sucn case ,he I~gularltyofthefirsr
genuarton ts vtsued on th! rhlrr/: whlch elthu /a/ls lo
anatn Ie Pentagona/ ranA;, OT reiapser 10 rhe THonguJar.T1tJ! EquJlacuaJ ir bound by oath never to permu flte child hl!Jlcefortlt lO en/u hts former
home 07 $0 mua. tU 10 1001 upon hls relatlcms agaJ.n.for fear #.SIrhefreshly dtveloped mganlsm may. by force o!tmeon.sdous
imflOt/on,faJl back
again 11IlO h1s ht.redltary leveJ.A.nd Jww perfect a proofofthe naturalftmen and.l may ahnosr soy, the divIne origtn o/Ihe ortnocranc conslftutiorl
oIrA.Sr.ru
ofFIarrd/

Figura

,
Aprende jQuery 1.3

IEII

no utilizar un elemento que los numere por nosotros automticamente? Hemos asignado
a la lista un Il) de notes y lo hemos insertado detrs de d v class="chapter">.

"

Marcar, numerar

vincular el contexto

5.5. Pies de pgina sin separacin.


Ya estamos listos para marcar y numerar el lugar desde el que sale el pie de pgina:

Una solucin a este problema es modificar el CSS, haciendo que los elementos c spari se muestren como bloques, pero solamente si no estn dentro de -cd i v
c l a s s e " chapter" >:
span.footnote
font-style,

(
italic;

font-family:
"Times New Reman",
display: block;
margin: lem O;

Times,

serif

)
.chapter span.footnote
display:
inline;

$(doc ument) .ready(function()


{
$(/<01 id="notes"></ol>/)
.insertAfter (/div.chapter/)
$ (/span.footnote/) .each(function(index)
$(this)
.before(
[/<a href=lI~foot-note-/,
index+l,
/" id="context-j,
Lndex- j ,
In class="context">/,
/<sup>/ + (index+l) + /</sup>/,
/</a>/
l.join(j/)

Los pies de pgina estn empezando ahora a tomar forma, como muestra la figura 5.6.

})

)l;
"mrat nn!d ola certJ.flcateP" a Spacelt11td cruc mayo..rk: "b 1t00lhept'OCJ'Mlion o/a Squore Son a certtjicfIkfrom NlJIU1'8lime//, p10Vlng tlJe
Equal,sJdednas ofth! Fatlter'" 1nrply tltat no Lady ofany posfdan will many cm uncsrtifted Triangle. Square offiprlng has somlfimu reJulted
fromas/lg}lrly 1""KU/(JJ' 1HlI1Igl.; bur In olm." every suc cos. rh, JrreguJarlry oflb.flrsrgenuaJm
ts vis/red lb. thJJT/;wMch drher f.11s ro
attaln th~ PentagOllaJ nm.t:, or ~
ta te 1Hl11IguJar.
lle
fear

bound by 0iJl.JJnevu 10 pmnJ/ lJte chtJd lIeru:efMIt 10 enrer hlsformt:r homs


est lb.;"'hlydeve/oped
cvgan/sm lIUl)! by fo"," ofWlCO=_
Imlrorton.fall bockagaln

EquJlaJeroIls

And how peifllCr. proof ofrh. noJural /1m ess and. 1 may

Figura

tzImMt

or so m,wch a! ID look. upo.n hu rekutOlU


Into A/s hendluuy I...,L

soy. rh. divino or/gbl oflb. orl3rocratJc conninaJn ojrk

agalll,

{01

Sr.U$ ofFltJJland/

5.6. Los pies de pgina toman forma.

Al menos ahora son pies de pgina distintos; an as todava se puede trabajar mucho
con ellos. Una solucin de pie de pgina ms robusta sera:
1. Marcar la ubicacin en el texto de dnde sale cada pie de pgina.
2. Numerar cada ubicacin, y proporcionar un nmero coincidente para el propio
pie de pgina.
3. Crear un vnculo desde la ubicacin de texto a su pie de pgina coincidente, y
desde el pie de pgina de vuelta a la ubicacin de texto.
Estos pasos se pueden conseguir desde el mtodo . each ( ) ; pero primero estableceremos un elemento contenedor para las notas en la parte inferior de la pgina:
$ (document)
$(/<01

.ready(function()
id="notes"></ol>/)

{
.insertAfter(/div

chapter/);

)) ;

Parece suficientemente razonable utilizar una lista ordenada <01 id= "notes" ></
01> para los pies de pgina; despus de todo, queremos que estn numerados. Por qu

AqU empezamos con el mismo selector que hemos utilizado con el ejemplo ms sencillo de pie de pgina, pero le encadenamos el mtodo . each ( ) . Dentro de . each ( )
empezamos con $ (thi s) , que representa cada pie de pgina en sucesin, y le encadenamos el mtodo. before () . El resultado de la tabla unida dentro del parntesis del mtodo. before () es un vnculo superndice, que se insertar antes de cada pie de pgina
span. El primero, por ejemplo, se parecer a esto cuando se inserta en el DOM:
ea

href="#foot-note-l"

id="context-l"

class=!lcontextn><SUP>l</sup></a>

La sintaxis puede parecer familiar a primera vista, por lo que dediquemos un momento a investigar lo que est sucediendo. Dentro de los parntesis del mtodo. before (),
empezamos con un par de corchetes cuadrados, [ ], que representan una tabla literal.
Todo elemento dentro de la tabla va seguido de una coma (excepto, muy importante, el
ltimo elemento). Hemos situado cada elemento en su propia lnea por legibilidad. Luego,
una vez que se construye la tabla, lo convertimos a una cadena de nuevo al utilizar el
mtodo JavaScript . j oin () . Este mtodo toma una cadena vaca como su argumento,
representado por un par de comillas sencillas, porque no queremos que aparezca nada
entre cada elemento de tabla cuando se muestra como HTML.
Observe el uso de Lnde x- L. Puesto que el contador empieza en 0, aadimos 1 para
empezarlos atributos href en #footnote-1,
los atributos iden #context -1 yel texto
del vnculo en 1. El href es particularmente importante porque debe coincidir exactamente con el atributo id del pie de pgina (no incluido el # por supuesto).
Para estar seguro, el mismo resultado se puede conseguir con una cadena concatenada extensa en lugar de una tabla unida:

mi

5. Manipulacin

DOM
Aprende jQuery 1.3

.before (/<a href="#foot-note_/


+ (Lndex-i
/n id=ucontext_/ + (index+l) +
/n class=lIcontexclI><sup>/
+
(index+l) + /</sup></a>/);

j )

+
$(this)
.befo!:"e(
[/<a href="#foot-note-/.
i,ridex+l,

An en este caso, la tcnica de tabla parece ms manejable.

/" id="context-/.
index+l,
/It class=lIcontextll>/,

Mucho se ha escrito en la Web sobre las diferencias de rendimiento entre tablas unidas
y cadenas concatenadas. Para aquellos que sean muy curiosos, el siguiente artculo
trata una serie de pruebas utilizando las dos tcnicas: http://www.sitepen.com/
blog/200B/OS/09/string-performance_an_analYSis/.
Sin embargo, en la mayora de situaciones, estas diferencias son imperceptibles. Si el
rendimiento de un script es un problema, existen una serie de otras reas que tienen
mucho mayor impacto (como guardar selectores en cach, que ya hemos tratado).
Nuestros tres marcadores de pie de pgina vinculados ahora se parecen a lo que
aparece en la figura 5.7.

Rarely-In

proportlon te the vest numbers of Isosceles blrths-Is

~
The blrth cf a True Equllateral TtIangle from I",sceles parents Is the subject of
rejolcln9 In our country for many furfongs round. Arter a strfct examlnatlo
conducted by Ihe Sanltary end Social Board. the Infant. If
gu ar, I
wlth solernn ceremonial admltted loto the d
eraIs. He 15 the
Immedlately taken I'rom hls
ng parents and ad~
chlldless Equll.teral. :

/<sup>/
+ (index+l)
/</a>/
J .join(//l

+ /</sup>/.

)
.appendTo(/#notes/)
)l;
)l;

Es importante recordar que . appendTo () se sigue encadenando a $ (t h i s) r por


lo que jQuery dice, Anexar el pie de pgina al elemento con un ID de /notes/. Para cada uno
de los pies de pgina que hemos movido, anexamos otro vnculo, ste de vuelta al nmero en el texto:
$ (document) .ready(function()
{
$(/<01 id="notes"></ol>/)
.insertAfter(/div.chapter/);
$ (/span.footnote/)
.each(function(index)
{
$ (this)
.before(
[/<a href="#foot-note-/.
index+l,

a genuine and

certlfiable Equal-Slded 'lrlangle produced I'rom lsosceles parents. ~ Such a blrth


requlres, as Its antecedents, not only a series o., ClIrefully arrnnged ~rmarr1ageSI
but afso a long-contlnued exerclse of frugallty and self..control on the
of the
would-be ancestors of the COmlng Equllateral, and a patlen~ systematlc,' d
contlnuous development of the lsosceles nteect through many generatloi

/" id="context-/.
index+l,
/11 class="context">/,
/<sup>/ + (index+l)
/</a>/
.join (//)
Tres marcadores
de pie de pgina

How admIrable 15 the Law of Compensatlonl ~ By a JUdlclous use of thls law of


Nature. the Polygons and Clreles are almost always able to stIfle sedltlon In Its
very cradle, taklng advantage of the irrepres51ble and boundless hopefulness of
the human mlnd ....

Figura 5.7. Marcadores

de pie de pgina vinculados.

+ /</sup>/.

.appendTo(/#notes!)
.append ( /&nbsp; a href="#context-/
/">contextc/a/
);

})

+ (index+l)

}l;

Observe que el href apunta al id del marcador correspondiente. En la figura 5.8


puede ver los pies de pgina de nuevo con un vnculo anexado a cada uno.

Anexar pies de pgina


El siguiente paso es mover los elementos e span c Las s e footnote" , como hicimos
con el ejemplo ms sencillo. Sin embargo, esta vez, los dejamos en los recin creados <01
id: "notes" >. Utilizaremos. appendTo () aqu, de nuevo para mantener la ordenacin
adecuada, ya que cada pie de pgina sucesivo se insertar al final del elemento:
$ (document)

.ready(function()

$(/<01 id="notes"></ol>/)
,insertAfter
$ (/span.footnote/)
.each(function(index)

mi

(/div. chapter/)
(

- o.>qlM.U
.-._-- .
. (''''''_ _n rl!rtlflcat1?jrom
"WhaJ need of a cenJflcate'/" a SpactlandcrltJc maytl$k: "13not te procreanon OJO
_
~
NallIn Aenel[. provmg tA. Equal-ndednen o/tIoe Fatlo ,. 1 ,..ply thar no lAdy 01 a.y posUton wIll"""'l' an uncorifled
Tnangle. Square offiprlng hiB $ometJmts raultedjrom tJ sllghlly Irregular 1Hanglf!!: bu( In olmosllNf:l'Y such CQ.Jf!! 1M
IrreguJrlty ofth~ firsl general10n l.r vtslled 011tIu: thtrd; whlcn eitlrer lall~(o anatn u.e Penlog01lal ral'l~ or reJapses (O
th. Triallgul"" (r!1I!!mJ

Th.e EqullatertJt ts botmd by oalll nn>er fO pmnlf 1M eA/id hencelonh 10 en(eF~"l.rlomtulok]8 MCM-BiD
~
hb ",10/10113 agabl,lor fear les/ tM fraAIy deve/oped organ/sm '"".Y.
o(un co
(U=rf8I'
agamlnlO h/s huedItary Ieve/.

V",

(~4

And how pofect a proof olthe noJur)jlm~


tIo. Sta/es 01 FztlandJ (WJm)
;.

ss1 . r7

M""

!
. S;. Iki Yv"

w;'o/f!

.:_

orlgt. 01 tIo. arlstOCNlt1c constuutum al

Figura 5.8. Pie de pgina con vnculo para volver al texto.

vnculos
anexados

181

5. Manipulacin

'1
L,

DOM

Aprende jQuery 1.3

lfD

Lospies de pgina todava carecen de sus nmeros, sin embargo. Aunque se han situado dentro de un <01>, cada uno se debe situar individualmente en su propio <li>.
Losotros mtodosjQuerypara envolverelementosson .wrapAll () y .wraplnner () .
Vasehttp://docs
. jquery. com711anipulation/wrapAll
andhttp://docs
.
j query. com/Manipulation/wraplnner
para ms informacin.

Situar elementos alrededor de otros


El mtodo principal de jQuery para situar elementos alrededor de otros elementos es
el denominado. wrap (). Puesto que queremos que cada $ (this) se site en <li></
1i , podemos completar nuestro cdigo de pie de pgina de esta forma:

Copiar elementos
,l

(document) .ready(function()

Hasta el momento en este captulo hemos insertado elementos recin creados, movido elementos desde una ubicacin en el documento a otra, y situado nuevos elementos
alrededor de existentes. Algunas veces, sin embargo, podemos querer copiar elementos. Por ejemplo, un men de navegacin que aparece en el encabezado de la pgina se
podra haber copiado y situado en el pie de pgina tambin. De hecho, siempre que se
pueden copiar elementos para mejorar una pgina visualmente, es una buena oportunidad de utilizar un script. Despus de todo, por qu escribir algo dos veces y duplicar
nuestra oportunidad de error cuando podemos escribirlo una vez y dejar que jQuery
haga el trabajo difcil?
Para copiar elementos, el mtodo. clone () de jQuery es justo lo que necesitamos;
toma cualquier conjunto de elementos coincidentes y crea una copia de ellos para uso
posterior. Como con el proceso de creacin de elementos que hemos explorado anteriormente en este captulo, los elementos copiados no aparecern en el documento hasta
que aplicamos uno de los mtodos de insercin. Por ejemplo, la siguiente lnea crea una
copia del primer prrafo dentro de <di v c La s s "chapter" :

$ (/<01 id="notes"></ol>/) .insertAfter (/div.chapter/) ;


$ (/span.footnote/) .each(function(index)
{
$ (this)
.before(
[/<a href="#foot-note-/,
ndex-s j ,

/11
id= 11context _/ ,
index+l,
/11
class=trcontextll>/,

/<sup>/ + (index+l)
/</a>/
J .join(/ j)

/</sup>/,

.appendTo(/#notes/)
.append(
.wrap(/<li

})
})

/&nbsp; a href="#context-/
/">context</a/
)
id="foot-note-j
+ (index+l)
/ ></li>/);

+ (Lndex-s

j )

$ (/div.chapter

Ahora cada uno de los elementos <li> viene completo con un id que coincide con
el href del marcador. Al final, tenemos un conjunto de pies de pgina numerados y
vinculados, como se ve en la figura 5.9.
1.

2.

Hasta el momento, el contenido de la pgina no ha cambiado (vase la figura 5.10).


Conc:ernlng the Inhabltants
an excerpt

Next abcve these come the Noblllty, of whom there are several degrees, beglnnlng
at SIx-Slded Figures, or Hexagons. and from thenca rlslng In the number of thelr
sldes tlll they receJve the honourable tltle of Polygonal, or many-Slded. Finally
when the number of the sldes becomes so numerous, and the sides themselves so
small, that the figure cannot be dl5tlngulshed from a elrele, he 15Induded In the
Circular or Pnestly arder; and thls 15the hlghe5t dass of all.

ne

Equila/.eral ts bound by oatlt ne.oey IDpermiJ me child hencefanll to emer h.isformer home 01'so much ar lb loot
upo1J his relations again, lor 'fear lest tbe ~hly
developed organism may.1Jyforce ofunconsciow imiltJtiOll,jall bad
again tmo bis fwoeditoJy <veI. (cenee.u)

3. AM bow perfea a p1"Of)f ofthe 1Jt11JUal~


lbe Stases al FlaJlandl (con,ml

It Is a Law of Nature wlth U5 that a male chld 5han have one more slde than his
father, so that eech generatJon sha rtse (as a rule) one step In the sea te of
development and 'nobllltv. Thus the son of a SQuare is a Pentaoon; the son of a

1111d.
lmay almost say, (he dtvJne orlgin O/Me artuocraitc constuuan o/

Figura 5.10. Preparado para crear una copiadel primerprrafo.

Figura 5.9. Pies de pginanumeradosy vinculados.


Por supuesto, los nmeros se podran haber insertado antes de cada pie de pgina
de igual forma que en los prrafos, pero existe algo profundamente satisfactorio acerca
de tener cdigo semntico generado de forma dinmica por JavaScript.

of Flatland

our Professlonal Men and Gentlemen are Squares (to whlch ctass 1 myself belong)
and Five-Slded Figures or Pentagons.

"W'1JIn.need al centftcare'!" a Spac.eltmd crma may llfl: "151JOI the procreado71 of a Square Son cutiftcatefrr>m
Nmure Iferselj; provmg ,he Equalwsfdedness o/tire FtnlJerJ" f rep1y rhar no Lody 01 any postuon wJll marry an uncertified
ttiangle. Square offsprlJrg has!fCmet!mes resultedfrom a sJightJy Irregular 1Tiang/e; buzin almos! every sud case te
IrreguJarity ofdie finl generalion iI vJsUed on tire thtrrJ; wh.ch etthu fails to attatn me Penragonal ran~ 01'reJapsu fa
lb. Tri<mgrtlar. Cco_,)
Q

p,eq(O)/) .c1one();

Para continuar el ejemplo, podemos hacer que el prrafo cIonado aparezca antes de
<di v class=" chapter" :
$ (/div.chapter

p,eq(O)/) .clone() .insertBefore(/div.chapter/);

l:ImI

5. Manipulacin

DOM

Aprende jQuery 1.3

Ahora el primer prrafo aparece dos veces, como se ve en la figura 5.11, y puesto que
la primera instancia ya no est dentro de <di v c La s s
chapter"
, no retiene los estilos asociados con el di v (ms notablemente, la anchura).
e

Concernlng the Inhabltants


sn excerpt

"

lEiI

Observe que el prrafo empieza con span c La s s "pull-quote"


>. sta es la.clase
a la que nos dirigiremos para clonar. Una vez el texto copiado dentro de ese c span se
pega en otro lugar, necesitamos modificar sus propiedades de estilo para separarlo del
resto del texto.
e'.

of Flatland

Our Professlonal Men and Gentlemen are Squares (to whlch class 1 myself belong) and Five-Slded Figures or Pentagons.
Our ProfessJonal Men and Gentlemen are Squares (to whlch
and Flve-Slded Figures or Pentaaons.

dass 1 myself belong)

Para conseguir este tipo de estilo, aadiremos una clase pulled


al ap an copiado
/ y asignaremos a la clase la siguiente regla de estilo en la hoja de estilo:

Next above these come the Nobillty, of whom there are several degrees, beglnnlng
at Stx-Sded Figures. or Hexagons and from thence rfslng In the number of thelr
sldes tlll they reeetve the honourable tltle of Polygonal, or many-Slded. Flnally
when the number of the sldes becomes so numerous, and the sldes themselves so
small, that the ftgure eannot be dlstingulshed from a clrde, he 15induded In the
Circular or Prtestly order; and thls 15the hlghest dess of all.

It Is a L2w o, Nature with us that a maie chltd shatl haya one more slde than his
father, so that each generatlon shaU nse (as a rute) one step In the scale of
development and noblllty. ThU!~the son at a Square 15a Pentagon; the son of a

Figura 5.11. El prrafo se muestra dos veces.

,~

Por lo tanto, utilizando una analoga con la que la mayora de la gente debera estar
familiarizada,
. clone () es a los mtodos de insercin como copiar es a pegar.

Clonar con eventos


El mtodo.
clone () por defecto no copia ningn evento que est vinculado al
elemento coincidente o cualquiera de sus descendientes. Sin embargo, puede tomar
un solo parmetro booleano que, cuando se establece en true, clona eventos tambin:
. el one (t rue) . Este adecuado clonado de evento nos permite evitar tener que tratar con
volver a vincular eventos manualmente, como se ha tratado en un captulo anterior.

Clonar citas
Muchos sitios Web, como sus equivalentes impresos, utilizan citas para enfatizar pequeas partes de texto y atraer la atencin del lector. Podemos conseguir esto fcilmente
con el mtodo. clone () . En primer lugar, echemos otro vistazo al tercer prrafo de
nuestro texto de ejemplo:
<p>
<span class=!lpull-quote >It
is a Law of Nature
<span class="drop!l>with us</span> that a male child shall
have <strong>one more side</strong>
than his father</span>,
so that each generation shall rise (as a rule) one step in
the scale of development and nobility. Thus the son of a
Square is a Pentagon the son of a Pentagon, a Hexagon and
so on.
</p>
1l

Una desviacin CSS

.pul led {
background,
#e5e5e5;
position: absolute
width, 145px;
t op : -20px;
right, -180px;
padding, 12px 5px 12px 10px;
font: italic 1.4em "Times New Roman",

Times,

serif

La cita ahora recibe un fondo gris claro, algo de relleno, y una fuente diferente.
An ms importante, se posiciona de forma absoluta, 20 pxeles por encima y 20 pxeles a la derecha del ancestro posicionado (absolute
o relative)
ms cercano en
el DOM. Si ningn ancestro tiene posicionamiento
(aparte de static)
aplicado, la
cita se posicionar relativa al documento <body>. Debido a esto, necesitamos aseguramos en el cdigo jQuery que el elemento padre de la cita clonada tiene establecida
position:relative.
Aunque el posicionamiento
superior es bastante intuitivo, puede no quedar claro al
principio cmo se posicionar la cita 20 pxeles a la izquierda de su padre posicionado .
Derivamos el nmero primero del ancho total del cuadro de cita, que es el valor de la
propiedad width ms el relleno izquierdo y derecho, 145 px + 5 px + 10 px, o 160 px.
Luego establecemos la propiedad right
de la cita. Un valor de O alinear el lado derecho de la cita con el de su padre. Por lo tanto, para situar su lado izquierdo 20 px a la
derecha del padre, necesitamos moverlo en una direccin negativa 20 pxeles ms que
su ancho total, o -180 px.

De vuelta al cdigo
Ahora podemos llegar a jQuery. Empecemos con una expresin selector para todos
los elementos c s pari c La s s e "pull-quote"
, y anexemos un mtodo. each () de
modo que podemos llevar a cabo mltiples acciones segn pasamos por ellos:
$ (document) .ready(function()
(
$ (/span.pull-quote/) .each(function(index)
// ...
}) ;
}) ;

''-.....,

lfllI

5. Manipulacin

Aprende jQuery 1.3

DOM

A continuacin, encontramos el prrafo padre de cada cita y aplicamos la propiedad


CSSposi tion:
$ (document) .ready(function()
(
$ (/span.pull-quote/)
.each(function(index)
(
var $parentParagraph
= $(this) .parent(/p/);
$parentParagraph.css(/position/,
/relative/);
)
)

Una vez ms, almacenamos cualquier selector que utilizaremos ms de una vez en
una variable para mejorar rendimiento y legibilidad.
Ahora podemos estar seguros de que el CSS est establecido y listo para la cita. En
este punto podemos clonar cada e span, aadir la clase pulled a la copia, e insertarla
al principio del prrafo:
$ (document) .ready(function()
(
$ (/span.pull-quote/)
.each(function(index)
(
var $parentParagraph
= $(this) .parent(/p/);
$parentParagraph.css(/position/,
/relative/);
$(this) .clone()
.addClass(/pulled/)
.prependTo($parentParagraph);
)
})

Puesto que estamos utilizando posicionamiento absoluto para la cita, la ubicacin


dentro del prrafo es irrelevante. Siempre y cuando permanezca dentro del prrafo, se
posicionar en relacin con la parte superior y derecha del prrafo, basndose en nuestras reglas CSS. Si, sin embargo, quisiramos aplicar un float a la cita en su lugar, su
ubicacin dentro del prrafo afectara a su posicin vertical. El prrafo, junto con su cita,
ahora se parece a la figura 5.12.
Circular ar

Prtestiy areler; and tIlls Is the hfghest dass of all.

It Is a Law of Naturo wlth us that a male chlld shall have one more ,"Ide than hls
father, so that each generatlon shan rlse (as a rule) one step In the sea le of
development and noblllty. Thus the son of a Square 15 a Pontagan; rhe son of a
Pentagon,

a Hexagon;

and so on.

But thls rule applles not always to the Tradesman, and stlll less aften to the
Soldlers, and to the Workmen; who Indeed can hardly be sald to deserve the name
of human figures, slnce they have not all thelr sldes equat. Wlth them therefore
tIle Law of N.turo does not hold; and the son af an !soscsles (I.e. a Triangle wlth

Figura 5.12. Posicionarla cita en el prrafo.


ste es un buen comienzo, pero las citas tpicamente no guardan formato de fuente
como hace sta con el texto en negrita one more side. Lo que queremos es el texto de
span c l as s "pull-quote"
, quitado de cualquier e s t r onq>, <em>, <a hr ef u
otra etiqueta en lnea. Adems, sera bueno poder modificar la cita un poco, eliminado
algunas palabras y reemplazndolas con elipsis. Para esto, hemos situado algunas palabras de texto en el ejemplo en una etiqueta <span>: <span c l as s "drop" swi t h
us c z apan >.

1m

Aplicaremos la elipsis primero, y luego reemplazaremos todo el HTML de cita.con


una versin de slo texto:
$ (document) .rdady(function()
(
$ (/span.pull-quote/)
.each(functiod'index)
(
var $parentParagraph
= $(this) .parent(/p/);
$parentParagraph.css(/position/,
/relative/);
var $clonedCopy
= $(this) .clone();
$clonedCopy
.addClass(/pulled/)
.find(/span.drop/)
,..
.html{/&hellip;/)
.end()
.prependTo($parentParagraph);
var clonedText
= $clonedCopy.text();
$clonedCopy.html(clonedText);
)
)

Por lo tanto, empezamos el proceso de donado esta vez al almacenar el don en una
variable. La variable es necesaria esta vez porque no podemos trabajar en ella completamente dentro de la misma cadena. Observe, tambin, que despus de encontrar <span
c Laas vdr op:' >y reemplazar su HTML con unaelipsis (&hellip;), utilizamos. end ()
para regresar de la ltima consulta, . f ind (/ span . drop / ) . De esta forma, estamos insertando toda la copia, no solamente la elipsis, al principio del prrafo.
Al final, establecemos una variable ms, clonedText, a los contenidos de slo texto
de la copia; luego utilizamos estos contenidos de slo texto como un sustituto para el
HTML de la copia. Ahora, la cita se parece a la figura 5.13. Evidentemente, se ha aadido otro -cs pa n c Las s "pull-quote"
> al prrafo posterior para asegurarse de que el
cdigo funciona para mltiples elementos.
e

Embellecer las citas


Las citas ahora funcionan segn lo esperado, con elementos hijo quitados y elipsis
aadidas donde debera dejar de aparecer texto. Puesto que uno de los objetivos es aadir
atractivo visual, sin embargo, haramos bien al asignar a las citas esquinas redondeadas
con sombra. Sin embargo, la altura variable de los cuadros de citas es problemtica porque necesitaremos aplicar dos imgenes de fondo a un solo elemento, lo que es imposible
para cada navegador en el momento excepto las versiones ms recientes de Safari.
Para superar esta limitacin, podemos situar otro <di v alrededor de las citas:
$ (document) .ready(function()
{
$ (/span.pull-quote/)
.each(function(index)
(
var $parentParagraph
= $(this) .parent(/p/);
$parentParagraph.css(/position/,
/relative/);
var $clonedCopy
= $(this) .clone();
$clonedCopy
.addClass(/pulled/)
.find(/span.drop/)

11m

5. Manipulacin

DOM
Aprende jQuery

.html(/&hellip;/)
.end ()

.wrap{/<div clasS="pulled-wrapperll></div>/);
var clonedText
= $clonedCopy.text();
$clonedCopy.html(clonedText)
;

})

rcular or

But this rule applles not always to the Tradesman, and stlll less aften to the
Soldlers, and te the Workmen; who Indeed can hardly be sald to deserve the name
of human Figures, slnce they nave not all thelr sldes equal. Wlth them therefore
the ~w of Nature does not hold; and the son of an lsosceles (Le. a Tnangle wlth
Me sldes equal) remalns IsosceJes stffl. Nevertheless, 811hope 15not such out,
even from the Isosceles, that hls posterlty may ultlmately rse above hls degraded
condltlon ...,

lt is a Law of Nature
._:<tata male chi/d
shl/ have (in" mere
sitie than hiSfather

It ts a L..awo, Nature wlth us that a male chlld shall heve one more slde than his
father, so that each generatlon shall rfse (as a rule) one step In the seale of
development and noblllty, Thus the son of a Square 15 a Pentagon; the son of a
Penrngon, a Hexagon; and so on.
But thls rule applles not always to the Tradesman, and stlflless often to the
Soldlers, 8'1d to the workmen; who Indeed can hardly be sald to deserve the name
of human Figures, slnee they have nat all thelr sldes equal. Wlth them therefore
the Law of Nature does not hold; and the son ot an Isosceles (I.e. a Trlangle wlth
two sldes equal) remalns Isoseeles stIl1. Nevertheless, al! hope Is not such out,
even from the tsoscetes, that hls posterlty may ultlmately rtse ebove hls degraded
condlton. ..

proportlon

to the vast numbers

of lsosceles blrths-Is

a genulne and

certlRable Equal-Slded Trlangle produced from lsosceles parents. :. Such a blrth


requlres, as Its antecedents. not only a series ot carefully arT"i5lngedIntermamages,
but elso a Iong-conttnued exerose of frug.lity
.nd self-control on the part of the
wouldbe ancest:ors ot the comlng Equl1ateral~ and a patent, systematlc, and
contlnuous development of the Isosceles Intelled through many generatlons.

Rarely-In

proportion

to the vast numbers of lsosceles blrths-is

a genulne and

certiflable Equal-Slded Trlangle produced from [sosceles parents. :. Such a blrth


requlres, as Its antecedents, not only a series of carefulty 8rT"i51ngedIntermarrtages,
but also a kmg~continued exerdse of frugallty and se'f..control on the part of the
woud-be ancestors of the eomlng EquUateral, and a panent, systematlc, and
contlnuous development of the lsosceles Intellect through many generations.
bad< to top

The bfrth of a 'nue E.qullateral Tnangle from Isoscees parents Is the subject of
rejo1dng In our country for many furtongs round. After a str1ct examlnatlon
conducted by the S.nltary and Social Board, the Infant, II cert,"ed as Regular, Is
wft:h solemn ceremonJaI admltted Into the cass of EqulJaterals. He 15then
Immedlately taken from hls proud yet sorrowlng parents and adopted by some
chlldless Equll.teral. :

The blrth of 1hJe Equllateral Tnangle from lsosceles perents Is the subJect of
reJolclng in our cauntry for many fur10ngs round. After a strct examinatlon
conducted by the Sanltary and Social Board, the Infant, II certlfied as Regular, Is
wlth solemn ceremonial admltted loto the class of Equliate~is.
He 15then
frnmedlately taken from his proud yet sorrowlng parents and adopted by some
chlldless Equlleterat.

de slo texto en la cita.

How admirable

Is the Law of Comoensatlonl

background,
url(pq-top.jpg)
position:
absolute
width, 160px;
right, -lBOpx;
padding-top,
lBpx;

no-repeat

left

top;

background,
url(pq-bottom.jpg)
position:
relative
display,
block;
width, 140px;

italic

24px

1.4em

'

3 By a ludldous

use 01 thls Law 01

"

Mtodos de manipulacin DOM

no-repeat

left

bottom;

1. Para crear nuevos elementos desde HTML, utilizar la funcin factory $ ( ) .


2. Para insertar nuevos elementos dentro de cada elemento coincidente, utilizar:

lOpx;

"Times

ftyrn Il!fiCr~
prentsJ,(lhe

Los amplios mtodos de manipulacin DOM que proporciona jQuery varan de


acuerdo a su tarea y su ubicacin. El siguiente esquema puede servir como un recordatorio de qu mtodos se pueden utilizar para llevar a cabo cualquiera de estas tareas,
casi en cualquier lugar.

O lOpx

l:quiTrd'a/:iH,.gle

Figura 5.14. Citas mejoradas.

Tambin necesitamos modificar el CSS,por supuesto, para tener en,cuenta el nuevo


<di v y las dos imgenes de fondo:
.pulled-wrapper

:. '_ '".> ,. /,'


; 11re bidh.of a);UI!"

subject olrejoicing
I
inOlP"oo~";
... ~,

~
Figura 5.13. Contenidos

font:

~, Ik,
11 is aEa'w ofNq{ure
... thot li'4nak child
shall halk one more
sitie thanhis father

~rely-In

padding,

ess or a

lt 15a Law of Nature wlth us that a male chlld 5hall have one more slde than hls
tather, so that each generatlon shall rtse (as a rule) one step In the scale of
development and noblllty. Thus the SOn of a Square Is a Pentagon; the son of a
Pentagon, a Hexagon; and so on.

.pulled

IBII

Aqu, algunas de las reglas anteriormente aplicadas a e apan c La s s "pu Ll ed" > se
aplican a <di v class= "pulled-wrapper"
> en su lugar. Un par de ajustes de ancho
y relleno toman en cuenta el diseo de los bordes de la imagen de fondo, y la regla. pulled tiene sus propiedades pos t o y display modificadas para que aparezcan correctamente para todos los navegadores.
En la figura 5.14 tiene un aspecto final de las citas recin adornadas en su hbitat.

.prependTo($parentparagraph)

})

1.3

New

Roman",

Times,

serif

. append ()

. appendTo ( )

lB

5. Manipulacin

DOM

.prepend

()

.prependTo ()

3. Para insertar nuevos elementos adyacentes a cada elemento coincidente, utilizar:

. after

()

.insertAfter()

. before

.insertBefore()

()

4. Para insertar nuevos elementos alrededor de cada elemento coincidente, utilizar:

. wrap ()

. wrapAll ()

. wraplnner

()

5. Para reemplazar cada elemento coincidente con nuevos elementos o texto, utilizar:

. html ()

. text

.replaceAll()

.replaceWith()

()

6. Para eliminar elementos dentro de cada elemento coincidente, utilizar:

. empty ()

7. Para eliminar cada elemento coincidente y descendientes del documento sin


eliminarlos en realidad, utilizar:

. remove ()

Resumen
En este captulo hemos creado, copiado, reorganizado y embellecido contenido utilizando los mtodos de modificacin DOM de jQuery. Hemos aplicado estos mtodos a
una sola pgina Web, transformando un conjunto de prrafos genricos en un extracto
con pie de pgina, citas, vinculado y con estilo.
El apartado de tutorial del libro est casi acabado, pero antes de pasar a examinar ejemplos ms complejos, realicemos un viaje al servidor va los mtodos AJAX de jQuery.

"':,

,,

'.
I

.'

6
AIAX

En los ltimos aos, ha resultado comn juzgar sitios basndose en su uso en tecnologas especficas. Una de las palabras de moda ms destacadas utilizadas para describir nuevas aplicaciones Web es "realizado con AJAX". Esta etiqueta se ha utilizado para
significar muchas cosas diferentes, ya que el trmino engloba un grupo de posibilidades
de uso y tcnicas relacionadas.
Tcnicamente, AJAX es un acrnimo para Asynchronous JavaScript and XML (Iavaficript
asncrono y XML). Las tecnologas implicadas en una solucin AJAX incluyen:

JavaScript, para capturar interacciones con el usuario u otros eventos relacionados


con el navegador.

El objeto XMLHttpReque s t , que permite que las peticiones se realicen al servidor


sin interrumpir otras tareas de navegador.

Archivos XML en el servidor, o a menudo otros formatos de datos similares como


HTMLoJSON.

Ms JavaScript, para interpretar los datos desde el servidor y presentarlo en la


pgina.

La tecnologa AJAX ha sido aclamada como el salvador del escenario Web, transformando pginas Web estticas en aplicaciones Web interactivas. Han surgido muchos
marcos de trabajo para ayudar a los desarrolladores a domado, debido a las inconsistencias en las implementaciones de los navegadores del objeto XMLHttpRequest; jQuery
no es ninguna excepcin.
Perrntanos ver si AJAX puede realmente realizar milagros.

lmI

6.AJAX

Aprende jQuery 1.3

lIiI

Cargar datos bajo demanda


Por debajo de todo este alboroto, AJAX es meramente un medio de cargar datos
desde el servidor al navegador Web, o cliente, sin un refresco de pgina visible. Estos
datos pueden adoptar muchas formas, y tenemos muchas opciones para lo que hacer con
ellos cuando llegan. Veremos esto al llevar a cabo la misma tarea bsica de muchas formas.
Vamos a crear una pgina que muestra entradas de un diccionario, agrupadas por
la letra inicial de la entrada de diccionario. El HTML que define el rea de contenido de
la pgina se parecer a esto:
cdiv id="dictionaryU>
</div>

S, de verdad. Nuestra pgina no tendr contenido con el que empezar. Vamos a


utilizar varios mtodos AJAX de jQuery para completar este <di v con entradas de
diccionario.

Como siempre, una implementacin del mundo real debera utilizar mejora progresiva para hacer que la pgina funcione sin requerir JavaScript. Aqu, para simplificar
nuestro ejemplo, los vnculos no hacen nada hasta que los aadimos comportamientos
conjQuery.

Aadir HTMl

/----------------------------------------------------------------------Las aplicaciones AJAX a menudo no son ms que una peticin de un bloque de HTML.
Esta tcnica, algunas veces referida como AHAH (Asynchronous HITP and HTML, o HTIP
asncrono y HTML), es casi trivial de implementar con jQuery. En primer lugar necesi- tamos insertar algo de HTML, que situaremos en un archivo denominado a, htrnl junto
con nuestro documento principal. Este archivo HTML secundario empieza as:
cdiv class=lIentryll>
class="term">ABDlCATIONc/h3>
<div class="part">~.</div>
<div c1ass="definition">
An act whereby a sovereign attests his sense of the high
temperature of the throne.
<div c1ass=!lquote">
<div class=l1quote-1inell>Poor Isabe11ats Dead, whose
abdication</div>
cd ,v c Las s s vquot.evLane " >Set al1 tongues wagging in the
Spanish nation.</div>
<div c1ass=l1quote-linel1>For that performance
ttwere
unfair to scold her:</div>
<div c1ass="quote-1inel1>She
wise1y 1eft a throne too
ch3

Vamos a necesitar una forma de activar el proceso de carga, por lo que aadiremos
algunos vnculos para nuestros manejadores de evento:
class="letters '>

cdiv

cdiv

class="letter
id="letter-a'1>
ch3>ca href="#">Ac/a><!h3>
</div>
cdiv

1!

id='lletter-brr>
href="#">Bc/a></h3>

class='1letter'l

ch3><a
c/div>

cdiv class="letter"
id="letter-c11>
ch3><a
href=II#II>Cc/a></h3>

</div>
cdiv

hot to hold her.</div>

class=llletter
id="letter-d">
<h3>ca
href="#ll>Dc/a></h3>

<div c1ass=lIquote-1inel1>To History she'11 be no royal


ridd1e &mdashi</div>
<div c1ass=lIquote-1ine">Mere1y
a p1ain parched pea that

11

c/div>

</div>

jumped the griddle.</div>

Al aadir algunas reglas CSS, obtenemos

<div class="quote-author">G.J.</div>
</div>

una pgina que se parece a la figura 6.1.

</div>
The Devll's Dlctlonary

</div>

by Amorosa Blerce

<div class=t'entrytt>
<h3 class=!lterrn">ABSOLUTE</h3>
<div class="part >adj.</div>
<div class="definition">
Independent,
irresponsible.
An absolute rnonarchy is one
in which the sovereign does as he pleases so long as he
pleases the assassins. Not rnany abso1ute monarchies are
ll

c.

left, most of them having been replaced by limited


monarchies, where the sovereign's power for evil (and for
good) is greatly curtai1ed, and by repub1ics, which are

Figura 6.1. Aadir reglas CSS a la pgina.

governed by chanceo
</div>

Ahora nos podemos

centrar en tener contenido en la pgina.

</div>

IEI

6.AJAX

Aprende jQuery 1.3

La pgina contina con ms entradas en esta estructura HTML. Si lo presentamos,


esta pgina es bastante sencilla, como muestra la figura 6.2.

IBI

The Davll's Dictlonary


by Ambrose Bleroe

ABDICATION

ABDICATION

A
n.

An act whereby a soverelgn attests hls sensa of the hlgh temperatura

An act whereby a sovereign attests bis sense of the high temperature of!he throne.
Poor IsabelIa's Dead, whose abdication
Set aIl tongues wagging in the Spanish nation.
For that performance 'twere unfair to scold her:
She wisely lett a throne 100 hot to hold her.
lb History she'll be DO roya! riddle _
Merely a plain parched pea that jumped tbe griddle.

",
n.
or the throne.

Poor lsabefla's Dead, whose abdlcatlon


Set all longue. wagglng In lile Spenlsh nanco.
For Ihat performance 'twere unfalr to scold her:
She wlsely left a throne too hot 10 hold ner,
To Hlstory sha'lI be no royal rlddle Merely a plaln parched pea !hat lumpad lile grlddle.
G.J.

,(!

GJ.

ABSOLUTE
Indepen~ent.
so long as he
been replaced
curtaJled, and

ABSOLUTE
adj.
lndependent, irresponsible. An absolute monarchy is one in which the sovereign does as he pleases so long as be
pleases the assassins. Not many absolute monarchies are left, most of them baving been replaced by l.Gnited
monarches, where!he sovereign's power for evil (and for good) is greatly curtailed, and by republics, which are
governed by chanceo

.dj.
Irresponslble. An absoluta monarchy is one In whtch the soverelgn does as he peeses
plsases the assasslns. Not many absoluta monarchles are le. mast of them havtng
by IImlted monarchles. where lile soverelgn's power Ior evll (and for 9000) is greatly
bY republlcs, Whlch are govemed by chanceo

ACKNOWLEDGE

v.l

To confess. Ac:knowledgement

AFFIANCED

ACKNOWLEDGE

of one another's faufts 15!he htghest duty Imposed

by our leve ot truth.

pp.

Fltted wlth an ankle-ring for !he bell-and-chaln.

Figura 6.3. El navegador

v.t.

muestra el nuevo HTML,

lb confess. Acknowledgemenr of one anotber's faults is the bighest duty imposed by our love of trutb.

Figura 6.2. Presentar la estructura HTML.

Observe que a. html no es un verdadero documento HTML; no contiene ningn


<html>, <he ad , o <body , que son normalmente obligatorios. Normalmente denominamos a un archivo as un fragmento; su nica finalidad es insertarse en otro documento
HTML, lo que abordaremos ahora:
$ (document) . readyIfunction()
{
$ (, #letter-a
a') . click (function
$ ( '#dictionary'
return false

()

) ,load ( 'a. html ' ) ;

});

})

Cuando probamos este ejemplo, las definiciones de diccionario aparecern probablemente de forma instantnea cuando se hace die en el botn. Esto es un riesgo de trabajo
en nuestras aplicaciones a nivel local; es dificil dar cuenta de los retrasos al transferir
documentos por la red. Suponga que hemos aadido que se muestre un cuadro de alerta
despus de cargarse las definiciones:
$ (document) . ready (function () {
$('#letter-a
a') .click(function()
{
$ ( '#dictionary'
) .load I ' a. html ' ) ;
alert ( Loaded!
i
return false
I

})

}) ;

El mtodo .load () hace todo el trabajo por nosotros. Especificamos la ubicacin


destino para el fragmento HTML al utilizar un selector jQuery normal, y luego pasamos
la URL del archivo a cargarse como un parmetro al mtodo. Ahora, cuando se hace clic
en el primer vnculo, se carga el archivo yse sita dentro de <di v id= "dictionary"
>.
El navegador mostrar el nuevo HTML tan pronto como se inserta, como muestra la figura 6.3.
Observe que el HTML ahora tiene estilo, mientras que antes era plano, Esto se debe a
las reglas CSS en el documento principal; tan pronto como se inserta el nuevo fragmento
HTML, las reglas se aplican tambin a sus etiquetas.

Podramos asumir por la estructura de este cdigo que la alerta solamente se puede
mostrar despus de que se haya realizado la carga. La ejecucin JavaScript es normalmente sncrona, trabajando en una tarea detrs de otra en secuencia estricta.
Sin embargo, cuando se prueba este cdigo determinado sobre un servidor Web de
produccin, la alerta habr posiblemente ido y venido antes de que la carga se haya
completado, debido a retraso de red. Esto sucede porque todas las llamadas AJAX son
por defecto asncronas. De lo contrario, tendramos que llamado SJAX. Carga asncrona significa que una vez que se lanza la peticin HTTP para recuperar el fragmento
HTML, se reanuda inmediatamente la ejecucin del cdigo sin esperar. Cierto tiempo
despus, el navega dar recibe la respuesta del servidor y lo gestiona, ste siempre es un
comportamiento deseado; es poco amable bloquear todo el navegador Web mientras se

III!I

6. AJAX

Aprende jQuery 1.3

espera a que se recuperen los datos. Si las acciones se deben retrasar antes que se haya
completado la carga, jQuery proporciona una rellamada para esto. A continuacin se
proporciona un ejemplo.

l1definitionll:
IIA convenient
deity invented
"guote": [
"Ls public worship, then, a a i.n
"Thkt fer devotions paid to Bacchus" ,
"The lictors
dare to run ti':s in, 11,
"And resolutely thump and whack US?11
] ,
vaut.hor v. "Jorace"
i

Trabajar con objetos JavaScript

I!II

by the ... ,

:',

),

Extraer HTML bien formado bajo demanda es muy conveniente, pero hay momentos
en los que queremos que nuestro script pueda procesar datos antes de que se muestren.
En este caso, necesitamos recuperar los datos en una estructura que podemos recorrer
con JavaScript.

(
"term":
"part":

"BACKBITE"

.t.

I1V

"definition":

"To speak

of

a man as you find

him when ..

),

Con los selecto res de jQuery, podramos recorrer el HTML que recibimos y manipularlo, pero primero se debe insertar en el documento. Un formato de datos JavaScript
ms nativo puede significar incluso menos cdigo.

(
"term":

"BEARD1',

"pa r t :':

IIn.lI,

"definition

ll:

"The hair that is commonly

cut off by.

),

Recuperar un objeto JavaScript


Como a menudo hemos visto, los objetos JavaScript son simplemente conjuntos de
pares clave-valor, y se pueden definir sucintamente utilizando llaves (O). Las tablas
JavaScript, por otro lado, se definen en el momento con corchetes ([l). Al combinar estos
dos conceptos, podemos fcilmente expresar algunas estructuras de datos muy complejas y ricas.

Para recuperar los datos, utilizaremos el mtodo $ . getJSON ( ) r que busca el archivo
y lo procesa, proporcionando el cdigo llamante con el objeto JavaScript resultante.

El trmino JavaScript Object Notation (JSON) se acu por Douglas Crockford para
sacar provecho de esta sencilla sintaxis. Esta notacin puede ofrecer una alternativa
concisa al formato XML:

En este punto, todos los mtodos jQuery que se han utilizado se han anexado a un
objeto jQuery que hemos creado con la funcin factory $ ( ) . Los selectores nos han permitido especificar un conjunto de nadas DOM con los que trabajar, y los mtodos han
operado sobre ellos de alguna forma. Esta funcin $ . getJSON ( ) , sin embargo, es diferente. No existe elemento DOM lgico al cual se pueda aplicar; el objeto resultante se
tiene que proporcionar al script, no incluido en la pgina. Por esta razn, getJSON () se
define como un mtodo del objeto global jQuery (un solo objeto denominado j Query
o $ definido una vez por la biblioteca jQuery), en lugar de una instancia individual de
objeto jQuery (los objetos que creamos con la funcin $ ( ) ).
Si JavaScript tuviera clases como otros lenguajes orientados a objetos, llamaramos a
$. getJSON () un mtodo de clase. Para nuestros fines, haremos referencia a este tipo
de mtodo como una funcin global; de hecho, son funciones que utilizan el espacio de
nombre jQuery para no entrar en conflicto con otros nombres de funcin.
Para utilizar esta funcin, le pasamos el nombre de archivo como antes:

"key": "va Lue :',


"key 2":
"array" ,
"of" ,
"items"

Para informacin sobre algunas de las ventajas potenciales de JSON, as como implementaciones en muchos lenguajes de programacin, visite http://j
son. org/.
Podemos codificar nuestros datos utilizando este formato de muchas formas.
Situaremos algunas entradas de diccionario en un archivo JSON que denominaremos
b . j son, que empieza de la siguiente forma:

Funciones jQuery globales

$ (document] .ready(function()
(
$('#letter-b a') .click(function()
$ . getJSON ('b.j son' ) ;
return false

})
})

IItermll:

I1BACCHUSll,

"par t

IIn.

v.

Este cdigo no tiene efecto aparente cuando hacemos clic en el vinculo. La llamada de
funcin carga el archivo, pero no le hemos dicho a JavaScript lo que hacer con los datos
resultantes. Para esto, necesitamos utilizar una funcin de rellamada.

IIEI

Aprende jQuery 1.3

6.AJAX

La funcin $. getJSON () toma un segundo argumento, que es una funcin a invocar cuando la carga est completa. Como se ha mencionado antes, las llamadas AJAX
son asncronas, y la rellamada proporciona una forma de esperar a que se transmitan los
datos en lugar de ejecutar el cdigo. La funcin de rellamada tambin toma un argumento, que se completa con los datos resultantes. De modo que podemos escribir:
$ (document) .ready(function(}
{
$ ('#letter-b
a') .click (function () {
$.getJSON('b.json',
function(data}
)l;
return false

}}
}}

Aqu estamos utilizando una funcin annima como nuestra rellamada, como ha sido
comn en nuestro cdigo jQuery por brevedad. Se podra igualmente proporcionar una
funcin con nombre como la rellamada.
Dentro de esta funcin, podemos utilizar la variable da t a para recorrer la estructura
de datos segn sea necesario. Necesitaremos pasar por la tabla de alto nivel, creando el
HTML para cada elemento. Podramos hacer esto con un bucle estndar for, pero en su
lugar introduciremos otra de las funciones globales de utilidad de jQuery, $ . each ( ) .
Hemos visto su homlogo, el mtodo . each ( ) , en el captulo anterior. En lugar de trabajar en un objeto jQuery, esta funcin toma una tabla o mapa como su primer parmetro y una funcin de rellamada como su segundo. Cada vez que se pasa por el bucle,
el ndice actual de iteracin y el elemento actual en la tabla o mapa se pasan como dos
parmetros a la funcin de rellamada.
$ (document) .ready(function(}
{
$ ('#letter-b
a') .click (function () {
$.getJSON('b.json',
function(data}
$('#dictionary')
.empty(};
$.each(data,
function(entrylndex,
entry}
{
var htrnl = '<div class=lIentry">';
htrnl += I <h3 c l a ss "term" > I + entry [1 term 1] + I </h3:> I i
htrnl += "c d.i.v c las se vpar t vs ' + ent.xy l vpe r t t l + l</div>l
html += '<div class="definition">,
i
~
htrnl += entry['definition'] i
html += '</div>1 i
html += '</div>' i
$('#dictionary')
.append(html};
)l;

}}

return

DBI

Este enfoque supone que los datos son seguros para el consumo de HTML; no debera
contener ningn carcter < perdido-por ejemplo.

Todo lo que queda es gestionar las entradas con citas, lo que lleva otro bucle
$. each ():
$ (document) .ready(function(}
{
$('#letter-b
a') .click(function(}
{
$.getJSON('b.json',
function(data}
$('#dictionary')
.empty();
$.each(data,
function(entrylndex,

entry}

var htrnl = '<div c La s s e vent zy"> ,;


htrnl += "ch S class="term >'
+ entry{'term']
+ '</h3>';
html += '<div claS9="part">'
+ en t r y l t par t t l + '<!div>';
htrnl += '<div class="definition":>, ;
html += entry['definition'J;
if (errt r y l t quot.e t l ) {
html += l<div
c Las ss vquoce's ".
$.each(entry['quote'J,
function(linelndex,
line} {
htrnl += '<div class=ttquote-line >'
+ line + l</div>'
ll

ll

}}
if
'</div>'

(entry [,author' J) {
htrnl += '<div class="quote-author">,

entry['author

1
]

}
html

+=

'</div>';

htrnl += '</div>'
htrnl += '</div>';
$('#dictionary')

.append(html)

}l;

}}

return
})
}}

false

Con este cdigo en su lugar, podemos hacer clic en el vnculo B y confirmar nuestros
resultados, como se ve en la figura 6.4.

false;

}l;

})

Antes del bucle, vaciamos <di v id= "dictionary"


> de modo que podamos rellenado con nuestro HTML recin construido. Luego utilizamos $ . each () para examinar
cada elemento en turno, construyendo una estructura HTML utilizando los contenidos
del mapa de entrada. Por ltimo, convertimos este HTML en un rbol DOM al anexado
al d i v .

El formato JSON es conciso, pero no tolerante. Cada llave, corchete, comillas, y coma
debe estar presente y tenida en cuenta, o el archivo no se cargar. En la mayora de los
navegado res, no recibiremos ni siquiera un mensaje de error; el script simplemente
fallar en silencio.

mi

6.AJAX

Aprende jQuery 1.3

Los scripts que se van a buscar de esta forma se ejecutan en el contexto global de la
pgina actual. Esto significa que tienen acceso a todas las funciones y variables definidas globalmente, entre otras jQuery. Podemos por lo tanto seguir el ejemplo JSON para
preparar e insertar HTML en la pgina cuando se ejecuta el script, y situar este cdigo
'
en e. J. s:

The Devll's Dlcttonary


by Ambroso BI""'"

BACCHUS

n.

A convenrent delty Invented by Ihe andents as an excuse tor gertlng drunk.

var entries

Is pu.bllc worshlP. !hen, a sin,


That ror devotlons pald 10 Bacchus
Tha lIoto dare 10 run us In,
And resolutely thump and whack us?

!";

lI!iI

"t.e rmv :
"pa r t !':

Jorace

CALAMITY

"

IIn.lI,

"definition":

tiA

more than commonly plain

and ...

11

L
BACKBrrE

v.l,

"t.e rmv. 11 CANNIBAL " ,


"pa r t.:' . IIn. ",
IIdefinitionll:
!lA gastronome

To speak 01 a man as you find hlm whon he can' find you.

BEARD

n.

Tha halr tIlalls


!he hoad.

oommonly

n.

school

who..

"CHILDHOOD"

01 hls f1tends.

IIn.lI,

1Idefinitionll:

ano who has rellad on tIle ssslstanoe

the old

{
"t.e rmv.
"par t v:

BEGGAR

of

cut off by !hose who justly execrate tIle absurd Chlne custom 01 shavlng

I1The

period

of

human life

intermediate

of

operated

...

11

L
{

BELLAOO.NNA

n.

"t.e rrnv.
"pa r t v.

6.4. Comprobar las entradas.

"de f .ni t i.onv . "An

~ It"lI.,

Figura

IICLARIONETII,
IIn.lI,

instrument

torture

by ..

}.
(
"term":
IIpartl!:

Ejecutar un script

nCOMFORTrr,
"n.lI,

"definition":

"A state

of

mind produced

by.

i.
De vez en cuando no queremos recuperar todo el JavaScript que necesitaremos cuando la pgina se carga por primera vez. Podramos no saber qu scripts sern necesarios
hasta que ocurre alguna interaccin de usuario. Podramos introducir etiquetas < ser ipt >
en el momento cuando se necesitan, pero una forma ms elegante de incorporar cdigo
adicional es hacer que jQuery cargue el archivo . j s directamente."
Incorporar un script es tan sencillo como cargar un fragmento HTML. En este caso,
utilizamos la funcin global $ . getScript (), que, como sus hermanos, acepta una URL
que localiza el archivo de script:

(
rrterrnrr: rrCORSAIRII,
IIpartll:
IIn.",
"de f .n i t Lono.

})

of

the

seas.

rr

1;
var

html

$.each(entries,
html
htrnl
htrnl
html

$ (docurnent) .ready(function()
{
$('#letter-c
a') .click(function()
$ . getScript
( 'c. j s ') ;
return
false

})

"A politician

html

})

function()

+=
+=
+=
+=

'<div class="entry">','
'<h3 class="term">'
+ t hi s l t t e rm "I + r</h3>'
'<div class=r'part">
+ this['partt]
+ t</div>t;
'<div class=ttdefinition,,>r
+ t h .s lt de f .n i t i on t l +
+= '</div>';
I

'</div>';

$('#dictionary')

En nuestro ltimo ejemplo, necesitbamos procesar los datos de resultado de modo


que pudiramos hacer algo de utilidad con el archivo cargado. Con un archivo de script,
sin embargo, el procesamiento es automtico; el script simplemente se ejecuta.

.htrnl(htrnl);

Ahora hacer dic en el vnculo


la figura 6.5.

e tiene el resultado

esperado, como se puede ver en

l!nI

6.AJAX

The Devll's Dlctlonary


by Ambrose

CAlAMJTY

A more than oommonly pIaln and unmlstakable remlnder !hat the affalrs of th1s IIte are not o( our own
orde~ng. CaIBmltl8s are 01 lwo klnds: mlstortuoo lo ourselves, and good fortune lo othOlS.

n.

CANNIBAL

<line:>Would fly abandoned


</line>

A gastronome
of the old schoor Who preserves !he simple tastes and adheres to the nab.lral dlet of
!he
pro'POr!< pertod.

n.

advances.

;'

ti

n.

An I""trument 01 torture cperated by a persen wllh cotton In hls eara. There are lwo Instrumenls !ha!
are '"'""" !han a clanonet -lwo
cJanonets.

COMFORT

grass

<entry terrn="DIElI part="n. >


<definition>
The singular of "dice.u We seldorn hear the word,
because there is a prohibitory proverb, "Never say
die.
At long intervals, however, Borne one says: "The
die is cast,lI which is not true, fer it is cut. The
werd is found in an irnmortal ceuplet by that eminent
poet and demestic economist, Senator Depew:
</definition>
<quote>
<line>A cube of cheese no larger than a die</line>

TI1& portod 01 human Iffe Int""""dlole


belwaen !he Idlocy 01 Intancy and Ih. toJly ot YOUth-lwo
removes trcm the sin of manhood and three from the remorne of age.

CLARlONET

Virtue's

</guote>
</entry>

n.

CHfLDHOOD

l!iI

<line>All hail, Delusion! Were it not for thee</line>


<line~The world turned tapsy-turvy we should see
</line>
<lin~>For Vice, respectable with cleanly fancies,
</line>
~,

BIe"",

Aprende jQuery 1.3

"

n.

<line>May bait the trap to catch a nibbling mie.</line>


</guote>

A stat. 01 mlnd ProdUoed by contemplafton 01 B nelghbol's uneesJnass.

</entry>
</entries>

Figura 6.5. Resultado de ejecutar el script.

Cargar un documento XMl


XML es parte del acrnimo AJAX, pero en realidad no hemos cargado ningn XML
todava. Hacerla es sencillo, y sigue la tcnica JSON bastante de cerca. En primer lugar,
necesitaremos un archivo XML d . xml que contiene datos que deseamos mostrar:
version="l.
<entries>
<Pxm l

O" encoding::;IIUTF_8 ?>

c::entry term="DEFAME"
<:definition>

11

Estos datos se podran expresar de muchas formas, por supuesto, y algunas reflejaran
de forma ms aproximada la estructura que hemos establecido para el H1ML o JSON
utilizado anteriormente. Aqu, sin embargo, estamos ilustrando algunas de las caractersticas del XML diseado para que sea ms legible para las personas, corno el uso de
atributos para term y part en lugar de etiquetas.
Empezaremos nuestra funcin de una manera familiar:
$ (document) .ready(function() {
$('#letter-d a') .click(function() (
$.get('d.xml', function(data) (

part="V.t,,,>

})

return

To lie about another. To tell the truth about another.


</definition>
</entry>
term=IIDEFENCELESs"
c::definition>

<entry

})

false

part="adj.lI>

Unable to attack.
</definition>
</entry>
<:entry term=IIDELUSION" part="n.rr:>
<definition>

The father of a most respectable family, comprising


Enthusiasm, Affection, Self-denial, Faith, Hope,
Charity and many other goodly sons and daughters.
</definition>
<guote author=uMumfrey

})

Mappel >
U

Esta vez es la funcin $ . get () la que hace nuestro trabajo. En general, esta funcin
simplemente va a buscar el archivo en la URL facilitada y proporciona el texto plano para
la rellarnada. Sin embargo, si la respuesta se sabe que es XML debido a su tipo MIME
proporcionado por el servidor, a la rellamada se le pasar el rbol XML DOM.
Afortunadamente, corno ya hemos visto, jQuery tiene considerables posibilidades
transversales DOM. Podemos utilizar. find (), . filter () y otros mtodos transversales en el documento XML igual que haramos en HTML:
$ (document) .ready(function() (
$ (,#letter-d a') .click (function () (
$.get('d.xml', function(data) {

r
IIII

6,AfAX

,
$('#dictionary') ,empty{);
$ (data) ,find{'entry') ,each{function{)
var $entry = $(this);
var html = 'cdiv class=uentryu>,;
html += "<hS class=lItermtr>,
+ $entry.attr( "t.e
rrn')
+ '</h3>';
html

"<di.v class="part >'


+ $entry.attr('part')
Zd i.v'i
htrnl += 'cdiv class="definition">';
html += $entry,find{'definition')
,text{);
var $quote = $entry,find{'quote');
if ($quote,length) (
html += 'cdiv class=lIquotell>'
$quote,find{'line') ,each{function{)
html += 'cdiv class="quote-line">,
+ $ (this) .t.ext() + '</div>';
}) ;
+

+=

The Oevll's Dlctlonary


by Ambrosa BiefVe

"
A

l1

"c

DANCE

v./,

To leap about lo the sound af tlttarlng rnuslc, preferably wltIl erms at>out your nelghllor's _
or
deughter, Them are many klnds af dances, bu! all !hose nlQulnng !he psrtlclpatlon af tI1e two sexes
hava two characterlstlcs In oommon: tIley are consplcuously Innocen~ and wannly Ioved by lile
vldous.

DAY n,
A Penod of twenty-Iour hou/'S, mosUy mlsspent Thls pertod Is d1v1dedInto two psrts, tIle day prcper
and tIle nlgh~ or day Improper tI1e formar devuted te slns af business, tI1e latler oonsecmted to tIle
other sort These two klnds ot social actMty overfap,

DEBT

n,

Ao Ingenlous substituta ter the maln and whlp 01tila slBve-dr1ver.

if ($quote,attr{'author'))
(
html += 'cdiv class="quote-authortl>
,
+ $quote.attr('authort)
+ 'c/div>'

As, pen! In sn SQUanum, !he troutlet


SWlms round and round hJg tank to flnd en ouUet,
Presslng hls nose sgalns! !he glasa !he! holds hlm,
Nor ever seas !he prison that enfolds hlm;
SO !he pool' debtDr, seelng nsught sround hlm,
Ya! feels tI1e narrow IImIts !ha! Impound hJm,
Gr1eves al hl5 debt and s!lldles to evade It,
And Hnds a! last he mlgh! as wel have psld Il
,I
Bar10WS, Vode
1

}
htrnl += 'c/div>'

Aprende jQuery 1,3

}
htrnl += '<!div>'
html += 'c/div>';
$('#dictionary') ,append(${html));
}) ;
}l;
return false;

Figura 6.6.

Mejorarla pgina con XML.

});
});

The Oavll's Dlctlonary


by Ambrose Blerte

Esto tiene el efecto esperado cuando se hace clic en el vnculo D, como se ve en la


figura 6.6.
ste es un nuevo uso para los mtodos transversales DOM que ya conocemos, arrojando algo de luz sobre la flexibilidad del soporte de selector CSS de jQuery. La sintaxis
CSS se utiliza normalmente para ayudar a mejorar pginas HTMl" y por lo tanto los
selectores en archivos. css estndar utilizan nombres de etiquetas HTML como di v y
body para localizar contenido, Sin embargo, jQuery puede utilizar nombres de etiqueta XML arbitrarios, como entry y definition
aqu, tan fcilmente como las HTML
estndar.
El motor selector avanzado dentro de jQuery facilita encontrar partes del documento
XML en situaciones mucho ms complicadas, tambin. Por ejemplo, suponga que quisiramos limitar las entradas mostradas a aquellos que tienen citas que a su vez tienen
autores de atributo. Para hacer esto, podemos limitar las entradas a aqullas con elementos -cquot.e s anidados al cambiar entry por entry:has
(guate}, Luego podemos
limitar adems las entradas a aqullas con atributos authar en los elementos <guate>
al escribir entry: has (quate [autharl
). La lnea con el selector inicial ahora dice:
$ (data) ,find('entry:has{quote(author))

') ,each{function{)

{;

DEBT

n.

An Inganlous substttute for tIle chaln end whlp 01 !he sIa_er,


As, pan! In en SQUanum, !ha troutlet
swtms round en<! round hls
lo flnd an ootie!,
Presslng hIs nasa agalnst!he glass tila! holds hlm,
Nor ever seas the pr1son that oorolds hlm;
SO !he poor deIrtor, seelng naugh! around hlm,
Ya! feels tI1e ll8!TOW Ilrnlts tila! Impound hlm,
GrieVes at hl5 debt and studles to evade It,
And nnds a! las! he mlgh! as weU havo psld Il
Bar10WS, \Iode

"'"k

DELUSION

n.

The la!her 01 e mas! respsctable famlly, oomprlslng Entlluslssm,


Chenly and meny other goodly 5005 and daughters,

AIfecIIon, SeW..oonlal, FaI!h, Hope,

AlI hall, Ooluslool Were H no! Ior!hae


The worId turnad topsy-turvy we should seo;
For \/Ice, respectallI8 wltIl cleanly fancles,
WOUkl fty abandonad V1r!ue's gross s<!Vences,
Mumfl1ly Mappel

Esta nueva expresin selector limita las entradas devueltas segn corresponde, como
muestra la figura 6.7.

Figura 6.7.

Limitarlas entradas mostradas,

ID

lE.iI

Aprende jQuery 1.3

6. AJAX

mi

Elegir un formato de datos

Pasar datos al servidor

Hemos examinado cuatro formatos para nuestros datos externos, cada uno de los
cuales se gestiona de forma nativa por las funciones AJAX de jQuery. Tambin hemos
verificado que los cuatro pueden gestionar la tarea en cuestin, cargando informacin
sobre una pgina existente cuando el usuario lo solicita y no antes. Cmo, entonces,
decidimos cul utilizar en nuestras aplicaciones?

Nuestros ejemplos hasta este punto se han centrado en la tarea de recuperar archivos de datos estticos del servidor Web. Sin embargo, la tcnica AJAX entra en juego
solamente cuando el servidor puede configurar dinmicamente los datos basndose
en la entrada desde el navegador. Nos ha ayudado jQuery en esta tarea tambin; todos
los mtodos que hemos tratado hasta el momento se pueden modificar de modo quela
transferencia de datos se convierte en una calle de doble sentido.

Los fragmentos HTML requieren muy poco trabajo para implementar. Los datos
externos se pueden cargar e insertar en la pgina con un solo mtodo, que no
requiere ni siquiera una funcin de rellamada. Los datos no se estructuran necesariamente en una forma que los hagan reutilizables para otras aplicaciones. El
archivo externo est estrechamente unido a su contenedor.

Los archivos JSON estn estructurados para reutilizacin sencilla. Son compactos
y fciles de leer. La estructura de datos se debe recorrer para extraer informacin
y presentarla en la pgina, pero esto se puede realizar con tcnicasJavaScript estndar. Puesto que los archivos se pueden analizar con una sola llamada al eval ()
de JavaScript, leer un archivo JSON es extremadamente rpido. Cualquier uso
de eval () implica riesgos inherentes, sin embargo. Errores en el archivo JSON
pueden causar fallo silencioso o incluso efectos secundarios en la pgina, de modo
que los datos se deben elaborar cuidadosamente por alguien de confianza.

Los archivos JavaScript ofrecen lo ltimo en flexibilidad, pero no son realmente un


mecanismo de almacenamiento de datos. Puesto que los archivos son especficos
del lenguaje, no se pueden utilizar para proporcionar la misma informacin a
sistemas dispares. En su lugar, la posibilidad de cargar un archivo JavaScript
significa que los comportamientos que apenas se necesitan se pueden separar en
archivos externos, reduciendo el tamao del cdigo a menos que y hasta que sea
necesario.

Los documentos XML son los reyes de la portabilidad. Puesto que XML se ha
convertido en la lingua franca del mundo del servicio Web, proporcionar datos en
este formato permite que los datos se puedan reutilizar en cualquier parte. Por
ejemplo, Flickr (http://flickr.com/),
del.icio.us (http://del.
icio. us /)
yUpcoming (http://upcoming
. org/) todos exportan representaciones XML
de sus datos, lo que ha permitido que surjan muchas interesantes aplicaciones
de sus datos. El formato XML es algo voluminoso, sin embargo, y puede ser algo
ms lento de analizar y manipular que otras opciones.

Con estas caractersticas en mente, normalmente es ms sencillo proporcionar datos


externos como fragmentos HTML, siempre y cuando los datos no se necesiten en otras
aplicaciones tambin. En casos donde los datos se reutilizarn, JSON a menudo es una
buena eleccin debido a su rendimiento y tamao. Cuando la aplicacin remota no se
conoce, XML proporciona la mayor garanta de interoperabilidad posible. Ms que cualquier otra consideracin, debemos considerar si los datos ya estn disponibles. Si es as,
es probable que est en uno de estos formatos, tenemos que tomar una decisin.

Puesto que demostrar estas tcnicas requiere interaccin con el servidor Web, necesitaremos utilizar cdigo del lado del servidor por primera vez aqu. Losejemplos facilitados
utilizarn el lenguaje de script PHP, que est ampliamente utilizado as como disponible
gratuitamente. No trataremos cmo configurar un servidor Web con PHP aqu; ayuda
sobre ello se puede encontrar en los sitios Web de Apache (http : // apache. org/) O
PHP (http://php
.rie t z ), O desde la empresa de hospedaje de su sitio.

llevar a cabo una peticin GET


Para ilustrar la comunicacin entre cliente y servidor, escribiremos un script que
solamente enva una entrada de diccionario al navegador en cada peticin. La entrada
elegida depender de un parmetro enviado desde el navegador. Nuestro script extraer
sus datos de una estructura de datos interna como sta:
?php
$entries = array(
'EAVESDROP' => array(
part
=>
V.i.
<

I,

'definition' => 'Secretly to overhear a catalogue


crimes and vices of another or yourself.
guate , => array(
1,

lady with one of her ears applied',


'To an open keyhole heard, inside,l,
'Two female gossips in converse free &mdash
'The subject engaging them was she.',
'ftI think,tI said ene, lIand rny husband
thinks
'That she\ls a prying,
inquisitive
minx!1l1,
'As seon as no more of it she could hear
'The lady, indignant,
removed her ear.,
IIII will not stay, ti she said, with a pout,
I"To hear rny character
lied about!
lA

1,

1,

ti

)
I

,
author ,

=>

ICopete

'EDIBLE'

=>

array(

Sherany',

1,

of the

ID

6.AJAX

,,
part

'adj.

=>

Aprende jQuery 1.3

1m

1,

'definition
=> 'Good to eat, and wholesome
to digest, as
a worm to a toad, a toad to a snake, a snake to a pig,
a pig to aman,
and a rnan to a worm.
)

EAVESDROP'

'EDUCATION'
=> array(
'part r => "n ,
I

'definition'
=> 'That which
discloses
to the wise
disguises
frorn the foolish
their lack of
understanding.
I

and

s ,

,..

?>

En una versin en produccin de este ejemplo, los datos probablemente se almacenaran en una base de datos y se cargaran bajo demanda. Puesto que los datos son parte
del script aqu, el cdigo para recuperarlo es bastante sencillo. Examinamos los datos
que se han publicado y diseamos el fragmento HTML a mostrar:
<?php

vJ.
.'
Secretiy lo overhear a catalogue of the crimes and Vltes of another or yourself.
A lady with one ofherears appJied
10 an open keyhole heard, nside,
Two female gossps in converse free The subject engaging them was sbe.
'1 think,' said one, 'and my husband thinks
'Iba! sbe's a prying, inquisitive minx!"
As soon as DO more of it she couId hear
The lady, indignant, removed her ear.
"I will no! stay,' she said, with a pout,
"Io hear my character lied about!'
Gopete Shenmy

Figura 6.8. Fragmento correspondiente

.'

$terrn = strtoupper($_REQUEST['terrn']);
if (isset ($entries [$terrn])) {
$entry = $entries[$terrn];
$html = 'cdiv class="entryn>,
$html .= 'ch3 claS9=lItermll>'
$html .= $terrn;
$htrnl .= '</h3>';

;
i

$htrnl .= 'cdiv class="part">I;


$htrnl .= $entry ['part '] ;
$htrnl .= '</div>';
$htrnl .= '<div c1ass="definitionn>,
i
$htrnl .= $entrY['definition'];
if (isset ($entry [,guote' ] )) {
$htm1 .= '<di v c las s quate 11>I;
foreach
($entrY['guote']
as $line)
{
$htm1 .= '<div c1ass="Quote-1ine">'.
)
'1

if

(isset ($entry

r: author'

$htrn1 .= '<div
.'</div>l

$line

.'</div>l

] )) {

c1ass="quote-author">

I. $entry

.=

Una vez ms, observamos la ausencia de formato que ya vimos con los fragmentos
HTML anteriores, porque las reglas CSS no se han aplicado.
Puesto que estamos mostrando cmo se pasan los datos al servidor, utilizaremos
un mtodo diferente para solicitar entradas aparte de los botones solitarios que hemos
venido utilizando hasta el momento. En su lugar, presentaremos una lista de vnculos
para cada trmino, y haremos que un dic en cualquiera de ellos cargue la definicin correspondiente. El HTML que aadiremos para esto se parece a lo siguiente:
<div c1ass="letter'l
id=l'letter-e">
<h3>E</h3>
<u1>
<li><a href="e.php?term=Eavesdrop">Eavesdrap</a></li>
<li><a href="e.php?term=Ediblell>Edib1e</a></li>
<li><a href="e.php?term=Education">Education</a></li>
<li><a href="e.php?term=E1oquencell>E1oquence</a></1i>
<1i><a href="e.php?term=E1ysiumll>E1ysium</a></1i>
<li><a href="e.php?term=Emancipation >Emancipation</a>
</lb
<1i><a href="e.php?term=Emotionrr>Emotion</a></li>
<li><a href=lIe.php?term=Enve1ope">Enve1ape</a></li>
<li><a href=lle.php?term=Envy">Envy</a></li>
<1i><a href=ne.php?term=Epitaphrr>Epitaph</a></li>
<1i><a href=lIe.php?term=Evangelistll>Evange1ist</a></li>
</ul>
</div>
1t

[ 'author' ]

)
$html

a la peticin.

'</div>';

)
$htrnl .= '</div>';
$htrnl .= '</div>';
print ($htrnl) ;
?>

Ahora las peticiones a este script, que denominaremos e . php, devolvern el fragmento HTML correspondiente al trmino que se envi en los parmetros GET. Por ejemplo, cuando se accede al script con e. php?term:eavesdrop,
recibimos lo que se ve
en la figura 6.8.

Ahora tenemos que conseguir que nuestro cdigo JavaScript invoque el script PHP
con los parmetros correctos. Podramos hacer esto con el mecanismo . load () normal, anexando la cadena de consulta la URL y buscando datos con direcciones como
e . php? t e rme eave sd.rop directamente. En su lugar, sin embargo, podemos hacer que
jQuery construya la cadena de consulta basndose en un mapa que proporcionamos a
la funcin $ . get ( ) :

IDI

Aprende jQuery 1.3

6.AJAX

$ (document) .ready(function()
{
$ (' #letter-e
a') .click (function () {
$.get('e.php',
('term': $(this) .text()},
$('#dictionary')
.html(data);
}) ;
return false

})
})

function(data)

1m

AJAX, incluso esta distincin es invisible para el usuario medio. Por lo general, la,nica
razn para elegir un mtodo frente a otro es ajustarse a las normas del cdigo del lado
del servidor, p proporcionar amplias cantidades de datos transmitidos; GET tiene un lmite ms estricto, Hemos codificado.nuestro ejemplo PHP para hacer frente igualmente
bien con cualquiera de los mtodos, por lo que podemos cambiar de GET a POST con
slo cambiar la funcin que invocamos:

$ (document)

Ahora que hemos visto otras interfaces AJAX que proporciona jQuery, la operacin
de esta funcin parece familiar. La nica diferencia es el segundo parmetro, que nos
permite proporcionar un mapa de claves y valores que forman parte de la cadena de
consulta. En este caso, la clave es siempre term pero el valor se toma del texto de cada
vnculo. Ahora, hacer clic en el primer vnculo en la lista hace que aparezca su definicin, como muestra la figura 6.9.

.ready(function()
{
$('#letter-e
a') .click(function()
{
$.post('e.php',
('term':
$(this) .text()},
$('#dictionary')
.html(data);

,/

function(data)

.
return

})
})

false

Los argumentos son los mismos, y la peticin ahora se realizar por medio de POST.
Podemos simplificar an ms el cdigo al utilizar el mtodo. load (), que utiliza POST
por defecto cuando se proporciona con un mapa de argumentos:

Tha Davll's Dlctlonary


by Ambrose Bleroo

"
EAVESDROP

A
S
k

~
~
~
~
~
Emanoioeuon
~
~
~
~
~

&!creUy te>ave""'.r

v.1.
a catalogue of 1ho crtmes aOO vlces 01 ena1her or yourseW.

A lady wt1h oroe or he< ea", app/Ied


To an opan keyhole heare!, Inslde,
Twolemale gossIps In conve"," fleeThe SUb)ed engaglng 1hem was she.
"11II1nk," saJd one, "and my husband 1hInks
TIla! .he's a pryIng, InqUlsltlve mlnXl"
As soon es no more o, tt she 00UId hear
The lady, Indignen!, removed her ear.
, wm oot _tay; she sald, wt1h a pout,
"ro hear my character Dad 8boutf"

.:~,
~,

$ (document) .ready(function()
{
$('#letter-e
a') .click (function () {
$ (,#dictionary' ) .load ('e.php', {, term':
return false
}) ;

})

$ (this) .text () }) ;

Esta versin reducida funciona de igual forma cuando se hace clic en un vnculo,
como muestra la figura 6.10.
GopeIaS"",,"ny

Tha Oavll's Dlctlonary


byAmbroseBleroe

EMANCIPATION

A
Figura 6.9. Hacer clic en un vnculo para mostrar su definicin.

Todos los vnculos aqu tienen direcciones asignadas, aunque no las estamos utilizando
en el cdigo. Esto proporciona un mtodo alternativo para navegar por la informacin
para usuarios que tienen desactivado JavaScript o no disponible (una forma de mejora
progresiva). Para impedir que se puedan seguir de forma normal cuando se hacen clic,
el manejador de evento tiene que devolver falseo

Llevar a cabo una peticin POST


Las peticiones HTTP que utilizan el mtodo POST son casi idnticas a las que utilizan
GET. Una de las diferencias ms visibles es que GET sita sus argumentos en la cadena
de consulta de la URL, mientras que las peticiones POST no. Sin embargo, en llamadas

n.

A bondman's cI1angelillm

!he tyranny a' anolher lo lile despotlsm of hlmself.

He was a atave: at word he went and cama;


HIs !ron ooIlar cut hlm lo 11I. bona.
Then Llberty sed hls ownafs name,
11ghtened 1he I1veIS 800 1nsa1bed hls own.
G.J.

Ea """,
Edlble
E<lucatlon

Enve!ope

~
~
~

Figura 6.10. Peticin realizada con POST.

lmI

6.AJAX
Aprende jQuery 1.3

Serializar un formulario

$ (document) .ready(function()
{
$('#letter-~
form') .submit(function()
$ ( '#dictionary'
) .load ( 'f. php' ,
{ ,tetm': $ ( ,input [name=" term"] ,) .val () } ) ;
return Pfalse
.l:.,
j);

Enviar da tos al servidor a menudo implica que el usuario rellene formularios. En lugar
de basarse en el mecanismo normal de envo de formulario, que cargar la respuesta en
toda la ventana del navegador, podemos utilizar el conjunto de herramientas AJAX de
jQuery para enviar el formulario de forma asncrona y situar la respuesta dentro de la
pgina actual. Para probar esto, necesitaremos construir un formulario sencillo:
cdiv class="letter"
<h3>F</h3>
cform>

})

$ (document) .ready(function()
{
$('#letter-f
form') .submit(function()
$.get('f.php',
$(this) .serialize(),
$ ('#dictionary')
.html(data);

Esta vez devolveremos un conjunto de entradas del script PHP al buscar el trmino
de bsqueda facilitado como una subcadena de un trmino de diccionario. La estructura
de datos ser del mismo formato que antes, pero la lgica ser un poco diferente:
if

($entries

as $term

(strpos($term,
!== FALSE)
$html =
$htrnl .=
$html .=
$html .=
$htrnl
$html
$html

=> $entry)

strtoupper($
(

REQUEST['term']))

.,-

.=

'cdiv

class="quote-line">'.

$line

.'c/div>'

)
$html
$html

I</div>'
r

</div>

FIDDlE n.
An lns1Jument 10 nckle hUman 06'" by f11ctIon af. ho,.e'8 taH en th8 en!mll. ola cal
To Reme B81d Non>: "~Io smoJ<eyou tum
Ishall not ceaselo flddle wt11ieyou bUm."
To Nero Rome replled: "Pmy do your won~
"Ils rrry excuse that you wem IIddllng nn;t"
onn Pludge

~
.o

$html .= 'cdiv clasS="quote-author">'.


$entry f ' author J . c/div> i
I

as $line)

(isset($entrY['author']))

false;

Ahora el mismo script funcionar para enviar el formulario, incluso a medida que
aumente el nmero de campos. Cuando realizamos una bsqueda, las entradas coincidentes se muestran, como se ve en la figura 6.11.

)
if

})

function(data)

;.,

$htrnl .= 'cdiv class="definitionll>'


$html .= $entry['definition'];
if (isset($entrY['guote']))
(
($entrY['guote']

})

return

.= 'cdiv class="part">'
.= $entry['part'];
.= '</div>';

$html

})

'cdiv class="entry">';
'ch3 class=l1term">'
$term;
'</h3>';

foreach

Este cdigo tiene el efecto pretendido, pero buscar campos de entrada por nombre y
anexarlos a un mapa uno a uno es complicado. En particular, este enfoque no se escala
.' bien ya que el formulario se vuelve muy complejo. Afortunadamente, jQuery ofrece un
mtodo abreviado para ello. El mtodo. serialize () acta sobre un objeto jQuery y
traduce los elementos DOM coincidentes en una cadena de consulta que se puede pasar
junto con una peticin AJAX. Podemos generalizar nuestro manejador de envo de la
siguiente forma:

id="letter-f">

cinput
type="text"
name=lItermll value=1I1I id="termll />
<input
type=lIsubmit"
name="searchl1
value=="searchl1
id="search" />
</form>
</div>

foreach

ID

~
~
~
~
~
ErnancipI!!!on
~
~
~Jlh
~

;
t ;

FIDEllTY n.
A vlrtue pecuHar ID !hose who ara about ID be betreyed.

Enve!ooe

print($html);

La llamada a strpos () analiza la palabra para la cadena de bsqueda facilitada.


Ahora podemos reaccionar a un envo de formulario y disear los parmetros de consulta apropiados al recorrer el rbol DOM:

~....=:.=J
~

rc~

Figura 6.11. Mostrar entradas coincidentes.

1m

Aprende jQuery 1.3

6.AJAX

Estar pendiente de la peticin


Hasta el momento, ha sido suficiente para nosotros realizar una llamada a un mtodo
AJAX y esperar pacientemente la respuesta. Sin embargo, a veces, es de utilidad saber
un poco ms sobre la peticin HTTP a medida que progresa. Si surge dicha necesidad,
jQuery ofrece un conjunto de funciones que se pueden utilizar para registrar rellamadas
cuando ocurren varios eventos relacionados con AJAX.
Los mtodos. aj axStart () y . aj axStop () son dos ejemplos de estas funciones, y se pueden anexar a cualquier objeto jQuery. Cuando una llamada AJAX empieza
con ninguna otra transferencia en progresos, la rellamada . aj axStart () se activa.
Por el contrario, cuando termina la ltima peticin activa, la rellamada anexada con
. aj axStop () se ejecutar. Todos los observadores son globales, en la medida que se
invocan cuando ocurre cualquier comunicacin AJAX, con independencia del cdigo
que lo inicie. Podemos utilizar estos mtodos para proporcionar informacin al usuario
en el caso de una conexin de red lenta. El HTML para la pgina puede tener un mensaje de carga anexado:

lImI

Sin embargo, en consonancia con el espritu de la mejora progresiva, no situaremos


este cdigo HThiL directamente en la pgina. Solamente es relevante para nosotros cuando JavaScript est disponible, por lo que lo insertaremos utilizando jQuery:
$ (document) .ready(function()
{
".
$ ( t c d i v id=" loading" >Loading ... </div>'
.insertBefore('#dictionary')

})

Nuestro archivo CSSproporcionar a este <di v una regla de estilo display:


none;
de modo que el mensaje est oculto inicialmente. Para mostrarlo en el momento correcto,
"'simplemente lo registramos como un observador con. aj axStart ():
$ (docu ment) .ready(function()

{
$ ( '<di v id= "loading
>L~ading... </div>
.insertBefore('#dictionary')
.ajaxStart(function()
{
$ (this) . show () ;
ll

})
})

t )

<div id=lIloadinglr>
Loading ...
</div>

Podemos encadenar el comportamiento de ocultar en esto:

Este mensaje es slo una parte de HTML arbitrario; podra incluir una imagen GIF
animada para proporcionar un ihrobber, por ejemplo. En este caso, aadiremos algunos
estilos al archivo CSS, de modo que cuando se muestra el mensaje, la pgina se parece
a la figura 6.12.
The D.vll's Dlctionary

$ (document) .ready(function()
{
$ ( <di v id= IIloading ti >Loading ... < / di v ' )
.insertBefore('#dictionary'l
.ajaxStart (function()
(
$ (this) .show () ;
}).ajaxStop(function()
$ (this) .hide ();
}) ;
I

})

by Ambrose Blerce

Voilli.! Tenemos nuestra informacin de carga.


Una vez ms, observe que estos mtodos no tienen relacin con las formas determinadas con las que empiezan las comunicaciones AJAX.. load () anexado al vnculo A
y . getJSON () anexado al vnculo B hacen que ocurran estas acciones.
En este caso, este comportamiento global es deseable. Si necesitamos ser ms especficos, sin embargo, tenemos algunas opciones a nuestra disposicin. Algunos de los mtodos de observador, como. aj axError ( ) , envan a su retrollamada una referencia al
objeto XMLHttpRequest. Esto se puede utilizar para diferencia una peticin de otra, y
proporcionar diferentes comportamientos. Una gestin ms especfica se puede conseguir
al utilizar la funcin de bajo nivel $ . aj ax ( ) , que trataremos un poco ms adelante.
La forma ms comn de interactuar con la peticin, sin embargo, es la rellamada success. Ya la hemos utilizado en varios de nuestros ejemplos para interpretar los datos que
proceden del servidor y completar la pgina con los resultados. Se puede utilizar para
otro tipo de informacin, tambin. Considere una vez ms nuestro ejemplo .load ( ) :

A
B

e
Q
E

~
~
~
~
~
Emancfpa1!on
E!!!2l!lm

~
~
~

];00

Figura 6.12. Proporcionar

informacin al usuario.

$ (document) .ready(function()
{
$('#letter-a
a') .click(function()
$('#dictionary')
.load('a.html');

lmiI

Aprende jQuery 1.3

6.AJAX

return

false

nunca cambia. En este caso, anexaremos el manejador click


. 1i ve () y capturando nuestros clics de esta forma:

p;
p;

Podemos crear una pequea mejora aqu al hacer que el contenido cargado aparezca
gradualmente a la vista en lugar de aparecer de repente .. load () puede hacer que se
active una rellamada cuando se termine:

$ (document) .r~dy(function()
{
$ (' . t.erm ") .live ('click',
function O. (
$(this) .siblings(' .definition')
.slideToggle()

function()

al documento utilizando
'

});

})
$ (document) .ready(function()
{
$('#letter-a
a') .click(function()
(
$('#dictionary') .hide() .load('a.html',
$ (this) .fadelnO;
}) ;
return false

lIlIII

El mtodo . 1i ve () le dice al navegador que observe todos los clics en cualquier parte
,de la pgina. Si (y slo si) el elemento en el que se ha hecho clic coincide con el selector
" . term, entonces el manejador se ejecuta. Ahora el comportamiento de alternar ocurrir
en cualquier trmino, incluso si se aade por una transaccin AJAX posterior.

p;
})

En primer lugar, ocultamos el elemento destino, y luego iniciamos la carga. Cuando


la carga est completa, utilizamos la rellamada para mostrar el elemento recin incorporado al desvanecerse.
.'

AJAX Y eventos
Suponga que quisiramos permitir que cada nombre de trmino de diccionario controlara la visualizacin de la definicin que sigue; hacer clic en el nombre del trmino
mostrara u ocultara la definicin asociada. Con las tcnicas que hemos visto hasta el
momento, esto debera ser bastante sencillo:
$ (document) .ready(function()
{
$ (, .term' ) .click (function O (
$(this) .siblings(' .definition')

})

.slideToggle();

Cuando se hace clic en un trmino, el cdigo encuentra hermanos de! elemento que
tienen una clase def ini t ion, y la desliza hacia arriba o hacia abajo segn sea el caso.
Todo parece en orden, pero un clic no hace nada con este cdigo. Desafortunadamente,
los trminos todava no se han aadido al documento cuando hemos anexado los manejadores el i ck. Incluso si consiguiramos anexar manejadores el i ck a estos elementos, una vez que hacemos clic en una letra diferente los manejadores dejaran de estar
anexados.
ste es un problema comn con reas de una pgina completada por AJAX. Una
solucin popular es volver a vincular manejadores cada vez que se refresca el rea de
pgina. Sin embargo, esto puede ser complicado ya que el cdigo de vinculacin de
evento se tiene que invocar cada vez que cualquier cosa hace que la estructura DOM de
la pgina cambie.
Una alternativa a menudo superior se present en un captulo anterior. Podemos
implementar delegacin de evento, vinculando el evento a un elemento ancestro que

-Limitaciones de seguridad
Para su utilidad en la elaboracin de aplicaciones Web dinmicas, XMLHttpRequest
(la tecnologa de navegador subyacente detrs de la implementacin AJAX de jQuery)
est sujeta a lmites estrictos. Para impedir varios ataques cross-site scripting (XSS),generalmente no es posible solicitar un documento de un servidor que no sea el que alberga la pgina original.
sta es por lo general una situacin positiva. Por ejemplo, algunos citan la implementacin del anlisis JSON al utilizar eval () como inseguro. Si cdigo malicioso est
presente en el archivo de datos, se podra ejecutar por la llamada eval ( ) . Sin embargo,
puesto que el archivo de datos debe residir en el mismo servidor que la propia pgina
Web, la posibilidad de incorporar cdigo en el archivo de datos es en gran medida equivalente a la psbilidad de incorporar cdigo en la pgina directamente. Esto significa
que, para el caso de cargar archivos JSON de confianza, eval () no es una preocupacin
se seguridad significativa.
Sin embargo, existen muchos casos, en los que sera beneficioso cargar datos desde
una fuente de terceros. Existen varias formas de solucionar las limitaciones de seguridad
y permitir que esto suceda.
Un mtodo es basarse en el servidor para cargar los datos remotos, y luego proporcionarlos cuando los solicite el cliente. Se trata de un enfoque muy potente ya que el
servidor puede llevar a cabo pre-procesamiento en los datos segn se necesite. Por ejemplo, podramos cargar archivos XML que contienen feeds de noticias RSS desde varias
fuentes, agregarlas en una sola feed en el servidor y publicar este nuevo archivo para el
cliente cuando se solicita.
Para cargar datos desde una ubicacin remota sin implicacin del servidor, tenemos que actuar de forma diferente. Un enfoque popular para el caso de cargar archivos
JavaScript del exterior es incorporar etiquetas <script>
bajo demanda. Puesto que
jQuery puede ayudamos a insertar nuevos elementos DOM, es sencillo realizar esto:
$(document.createElement('script'))
.attr('src',
'http://example.com/example.js')
.appendTo('head')
;

llifI

6. AJAX

Aprende jQuery 1.3

De hecho, el mtodo $. getScript


() se adaptar automticamente a esta tcnica
si detecta un host remoto en su argumento URL, por lo que incluso esto se gestiona por
nosotros.
El navegador ejecutar el script cargado, pero no existe mecanismo para recuperar
resultados del script. Por esta razn, la tcnica requiere cooperacin del host remoto. El
script cargado debe tomar alguna accin, tal como establecer una variable global que
tiene un efecto sobre el entorno local. Los servicios que publican scripts que son ejecutables de esta forma tambin proporcionarn una API con la que interactuar con el script
remoto.
Otra opcin es utilizar la etiqueta H1ML <frame> para cargar datos remotos. Este
elemento permite que se utilice cualquier URL como la fuente para sus datos a buscar,
incluso si no coincide con el servidor de la pgina host. Los datos se pueden cargar y
mostrar fcilmente en la pgina actual. Sin embargo, manipular los datos normalmente requiere la misma cooperacin necesaria para el enfoque de etiqueta e ac r p t s: los
scripts dentro de e i f r arne necesitan proporcionar explcitamente los datos a objetos
en el documento padre.

$.getJSON(url + '?callback=?I, function(data)


$I'#dictionary')
.emptyl);
$.eachldata,
functionlentrylndex,
entry)
{
V!ar htrnl = '<:div class="entry">';
html += <h3 class= rt termJ; > I + entry [1 term 1]
+

ll

ll

l)

}
html

J .' 1'. $data

.')');

Aqu, $data es una variable que contiene una representacin de cadena de un archivo JSON. Cuando se invoca este script, el parmetro de cadena de consulta callback
se anexa al archivo resultante que se devuelve al cliente.
Para demostrar esta tcnica, solamente necesitamos modificar ligeramente nuestro
ejemplo JSON anterior para invocar esta fuente de datos remota en su lugar. La funcin
$ . getJSON () hace uso de un carcter de marcador de posicin especial, ?, para conseguir esto.
$Idocument)

.readYlfunctionl)

var url = 'http://examples.learningjquery.com/jsonp/g.php';


$ I '#letter-g
a') .clicklfunction()
{

'</div>'

htrnl += '</div>';
htrnl += '</div>';
$I'#dictionary')
.appendIhtml)
))

pz i nt, I$_GET ['callback'

+=

Utilizar JSONP para datos remotos

?>

"

<?php

</h3>';

html += 'cdiv class="part >'


+ ent ry I t par t l
+ r </div> 1;
html += '<div class="definition">, ;
htrnl += entry[tdefinition'l;
if lentry t: quote' J) {
htrnl += '<div
class="quote">'
.eachlentry['quote'J,
functionllinelndex,
line)
html += '<div class="quote-line">'
+ line
+
</div>';
)) ;
if lentry['author'J)
html += '<div class="quote-author >'
+ entry['author
+ '</div>';

La idea de utilizar etiquetas sc r pt s para ir a buscar archivos JavaScript desde


una fuente remota se puede adaptar para recuperar archivos JSON desde otro servidor
tambin. Para hacer esto, necesitamos modificar algo el archivo JSON en el servidor, sin
embargo. Existen varios mecanismos para hacer esto, uno de los cuales se soporta directamente por jQuery: JSON with Padding, o JSONP.
El formato de archivo JSONP consta de un archivo JSON estndar que se ha situado
entre parntesis y precedido con una cadena de texto arbitrario. Esta cadena, el "relleno", se determina por el cliente que solicita los datos. Debido a los parntesis, el cliente
puede hacer que se invoque una funcin o que se establezca una variable dependiendo
de lo que se enve como cadena de relleno.
Una implementacin PHP de la tcnica JSONP es bastante sencilla:

lIliI

})

return

})
})

false

Normalmente no se nos permitira ir a buscar JSON desde un servidor remoto (examples .lear~ingj
query. com en este caso). Sin embargo, puesto que este archivo est
configurado para proporcionar sus datos en el formato JSONP, podemos obtener los
datos al anexar una cadena de consulta a nuestra URL, utilizando? como un marcador
de posicin para el valor del argumento callback. Cuando se realiza la peticin, jQuery
reemplaza la ? por nosotros, analiza el resultado, y lo pasa a la funcin de xito como
data como si esto fuera una peticin JSON local.
Observe que las mismas precauciones de seguridad se mantienen aqu como antes;
cualquier cosa que el servidor decida devolver al navegador se ejecutar en el ordenador del usuario. La tcnica JSONP solamente se debera utilizar con datos procedentes
de una fuente de confianza.

Opciones adicionales
El cuadro de herramientas AJAX proporcionado por jQuery est bien surtido. Hemos
tratado varias de las opciones disponibles, pero simplemente nos hemos quedado en
la superficie. Aunque existen muchas variantes a tratar aqu, proporcionaremos una
visin de conjunto de algunas de las formas ms destacadas de personalizar las comunicaciones AJAX.

lIiDI

Aprende jQuery 1.3

6. AJAX

lID

$.aj axSetup I(
url: ra.ht~lll
type: 'POST r ,
dataType: 'html'

El mtodo AJAX de bajo nivel


Hemos visto varios mtodos que inician todas las transacciones AJAX. Internamente,
jQuery mapea cada uno de estos mtodos en variantes de la funcin global $ . aj ax ( ) .
En lugar de suponer un tipo determinado de actividad AJAX, esta funcin toma un mapa
de opciones que se pueden utilizar para personalizar su comportamiento.
Nuestro primer ejemplo carg un fragmento HTML utilizando $ ( '#dictionary' ) . load ( , a. html ' ) . Esta accin se podra conseguir con $ . aj ax () de la siguiente forma:

});

$.ajaxl{
type: 'GET'
success: functionldata)
(
$I'#dictionary') .htmlldata);
}
}) ;

".,

"

$.ajax({
url: r a. htrnl '
type: 'GET',
dataType: 'html',
success: functionldata)
(
$I'#dictionary') .htmlldata);
I

Esta secuencia de operaciones se comporta igual que nuestro ejemplo $ . aj ax () anterior. Observe que la URLde la peticin se especifica como un valor predeterminado
por
la llamada $. aj axSetup
(), por lo que no se tiene que proporcionar cuando se invoca
$ . aj ax () . Por el contrario, se asigna al parmetro type un valor predeterminado
de
POST, pero esto se puede anular en la llamada $ . aj ax () a GET.

Cargar partes de una pgina HTML

});

"
Necesitamos especificar explcitamente el mtodo de peticin, el tipo de datos que
se devolver y lo que hacer con los datos resultantes. Claramente, esto es un uso menos
eficiente de esfuerzo de programador; sin embargo, con este trabajo adicional viene una
gran cantidad de flexibilidad. Algunas de las posibilidades de uso especiales que vienen
con utilizar una llamada $ . aj ax () de bajo nivel incluyen:

Impedir que el navegador guarde en cach respuestas del servidor. Esto puede
ser de utilidad si el servidor produce sus datos dinmicamente.

Registrar funciones de rellamada separadas para cuando la peticin se completa


con xito, con un error, o en todos los casos.

Suprimir los manejadores globales (como los registrados con $. aj axStart


que se activan normalmente por todas las interacciones AJAX.

Proporcionar
remoto.

un nombre de usuario y contrasea

para autenticacin

La primera y ms sencilla tcnica AJAX que hemos tratado fue ir a buscar un fragmento HTML y situarlo en una pgina. Algunas veces, sin embargo, el servidor ya proporciona el HTML que necesitamos, pero est rodeado por una pgina HTML que no
queremos. Cuando no es conveniente hacer que el servidor proporcione los datos en el
formato que deseamos, jQuery puede ayudamos en el lado del cliente.
Considere un caso como nuestro primer ejemplo, pero en el que el documento que
contiene las definiciones de diccionario es una pgina HTML completa como sta:
xmlns= '~http://www . w3 .org/1999/xhtml
xml: lang= 11en"
lang=11 entt>
<head>
<meta http-equiv=I1Content-Type"
content="text/htrnl
charset=utf-8 />
<title>The Devil's Dictionary:
H</title>

e ht.m'L

())

l1

con el host

<link rel=lIstylesheetll
href=lIdictionary.cssll
type=lItext/csslI media=lIscreenll />
<!head>
<body>
<div id=lIcontainerll>
<div id=lIheader >
<h2>The Devil's
Dictionary:
H</h2>
<div class=lIauthorll>by
Ambrose
Bierce</div>
<!div>

Para detalles sobre utilizar stas y otras opciones, consulte la Gua de referencia jQuery
o consulte la referencia API online (http://docs.j
query. com/Aj ax/j Query.
ajax).

rt

Modificar opciones predeterminadas

<div id=lIdictionary">
<div class="entry">
<h3 class="te::rm">HABEAS
CORPUS</h3>
<div class="part">n.</div>
<div class="definition">
A writ by which aman
may be taken out of jail
when confined
for the wrong crime.

La funcin $ . aj axSetup
() nos permite especificar valores predeterminados
para
cada una de las opciones utilizadas cuando se invocan los mtodos AJAX. Toma un
mapa de opciones idnticas a las disponibles para $. aj ax () , y hace que estos valores
se utilicen en todas las siguientes peticionesAJAX a menos que se anulen.

lIiII

Aprende jQuery 1.3

6. AJAX

c/div>
cjdiv>

Para eliminar estos elementos extraos, podemos utilizar una nueva caracterstica del
mtodo .load () . Cuando se especifica la URL del documento a cargar, tambin podemos proporciqnar una expresin de selector jQuery. Si est presente, esta expresin se
utiliza para localizar una parte del doc,umento cargado. Solamente la parte coincidente
del documento se inserta en la pgina. En este caso, podemos utilizar esta tcnica para
extraer solamente las entradas de diccionario del documento e insertarlas:

cdiv class=tlentryll>
ch3 class=lIterml1>HABITc/h3>

cdiv class="part">n.c/div>
cdiv class="definition">
A shackle for the free.
c/div>
</div>
</div>

$ (document) .ready(function()
{
$('#letter-h
a') .click(function()
$('#dictionary/).load('h.html
/

</div>
</body>
</htmb

})

$ (document) .ready(function()
{
$ ('#letter-h
a') .click(function()
{
$('#dictionary')
.load('h.html');
return false

})

return

})

Podemos cargar todo el documento en nuestra pgina utilizando el cdigo que hemos
escrito anteriormente:

})

llliI

false

.entry');

Ahora las partes irrelevantes del documento se excluyen de la pgina, como mues, tra la figura 6.14.
The Devll's Dlctlonary

"

by Ambmse BIerce

HABEAS CORPUS

n.

A wrtt by whlch a men may be taken out 01aft when conftned for tl1e wrong orIme.

Sin embargo, esto produce un efecto extrao debido a las piezas de la pgina HTML
que no queremos incluir, como se ve en la figura 6.13.

lO

HABIT
A

The Devll's Dlctlonary


by Ambrose

BIerce

E'<llble

EducaUOn

The Devil's D.ictlonary: H

lO

by Ambrose BIerce

HABEAS CORPUS

~
~
IDoo'
~
~
F

HALF

!he free.

n.

Oneoftwoequal
parislnlo whIch a tIllng may be dlvlded, orconsldered asdlvlded.ln
tIlefllurteenll1
oentury B heated dlscusslon arose among theoIoglsts ami phllooophe rs as lo _
Omnlsdence
oould patt en object InID II1ree halves; olld !he pIous Father Aldrovlnus pubDcIy pmyed In th8
calhedral al Rouen lila! God would derroostrate 111.aHlrmatIve 01 tIle proposItion In SOOle slgnal 8lld
unm_1e
way, and parUcular1y (If tt should pIease HIm) upon th8 body 01 tila! hardy blasphemer,
ManutJus Prodnus. who malntalned the nega1tve. ProcfnUs, however, was spared 10 die of the bita of
a >1per.

HANO
A

n.

singular InslJUment wom

at !he

eml 01!he human snn and oornmonly thrUst In!o somebody's

pocIcet

A writ by which aman may be taken out of jaD when confined fer the wrong Clime.

~
~
~
~
~
Emanc!patlon
~
Eswe!ooe
IDoo'

l!!!m!!
Evana.lIs!

n.

E!oquence
Elvslum
Emenc!oa1!on

n.

shackle lo<

HAPPINESS

HABIT

n.

Figura 6.14, Pgina resultante.

A shackle ter !he free.

HALF

n.

One of two aqual parts Into whlch s Ihing may be dlvided, o, consldered as divided.
In Ihe fourtsenlh cenlury a healed disaJsslon arase amongllleotogists aOO
phcsopbers as lo whetherOmniscience
could part en object Into Ihree halves; and
lhe pious Falhe, Aldrovinus publlcJy prayed In !he call1edral al Rouen !ha! God
would demonslrale lile aflirmalive of lile prcposition in some signsl aOO
unmlstakable wav. and particularlv CIf itshould pisase Him} ueon lile bodv of Ihal

Figura 6.13. Pgina con HTML que no se quiere incluir.

n.

Resumen
Hemos aprendido que los mtodos AJAX proporcionados por jQuery nos pueden
ayudar a cargar datos en formatos muy diferentes desde el servidor sin un refresco de
pgina. Podemos ejecutar scripts desde el servidor bajo demanda, y devolver datos al
servidor.

ID

6.AJAX

Tambin hemos aprendido cmo tratar con desafos comunes de tcnicas asncronas
de carga, como mantener manejadores vinculados despus de que ha ocurrido una carga
y cargar datos desde un servidor de terceros.
Esto termina la parte de tutorial del libro. Contamos con las herramientas principales
ofrecidas por jQuery: selectores, eventos, efectos, manipulacin DOM y peticiones de
servidor asncronas. stas no son las nicas formas en las que jQuery puede ayudamos;
trataremos algunas de las muchas posibilidades de uso conferidas por plug-ins jQuery
en captulos posteriores. Pero primero, examinaremos algunas combinaciones de estas
tcnicas que mejoran nuestras pginas Web en nuevas e interesantes formas.

ri

"

./

"

"

.'

7
Manip_ulacin
de tabla

En los seis primeros captulos, hemos explorado la librera jQuery en una serie de tutoriales que se han centrado en cada uno de los componentes jQuery y utilizado ejemplos
como una forma de ver esos componentes en accin, Desde el captulo 7 al 9 invertimos
el proceso; empezaremos con ejemplos de problemas del mundo real, y veremos cmo
podemos utilizar mtodos jQuery para solucionarlos.
Aqu, utilizaremos un librera online como nuestro sitio Web modelo, pero las tcnicas que preparamos se pueden aplicar a una amplia variedad de otros sitios tambin,
desde weblogs a portfolios, desde sitios empresariales dirigidos al mercado a intranets
corporativas. El captulo 7 y 8 se centran en dos elementos comunes de la mayora de
sitios (tablas y formularios), mientras que el captulo 9 examina un par de formas para
mejorar visualmente conjuntos de informacin utilizando barajadores y rotativos.
Puesto que el movimiento de los estndares Web se ha vuelto muy generalizado en
los ltimos aos, el diseo basado en tabla se ha ido abandonando en favor de diseos
basados en CSS. Aunque las tablas a menudo se empleaban como una medida necesaria en los aos 90 para crear diseos de mltiples columnas y otros diseos complejos,
nunca se pensaron para utilizarse de esa forma. Por otro lado, CSS es una tecnologa
expresamente creada para estas tareas de presentacin.
Pero ste no es el lugar para una discusin ampliada sobre el papel adecuado de las
tablas. Basta decir que en este captulo utilizaremos jQuery para aplicar tcnicas para
aumentar la legibilidad, usabilidad y atractivo visual de contenedores de datos tabulares
marcados semnticamente. Para un mayor detalle sobre aplicar HTML semntico yaccesible a tablas, un buen lugar en el que empezar es la entrada de blog de Roger J ohansson,
"Bring on the Tables" en http://www
. 456bereastreet.
com/archive/200410/
bring_on_the_tables/.

7. Manipulacin de labIa

Aprende jQuery 1.3

Algunas de las tcnicas que aplicamos a tablas en este captulo se pueden encontrar
en plug-ins como Table Sorter de Christian Bach. Para ms informacin, visite el jQuery
Plugin Repository en http://plugins
. j query. com/.
En este captulo, tratamos:

Paginacin

Descripciones emergentes

Impedir que la pgina se refresque

Contraer y expandir filas

Esta configuracin es sencilla, pero requiere que la pgina se refresque para cada
operacin de ordenar. Como hemos visto, jQuery nos permite eliminar esos refrescos de
pgina al utilizar mtodos AJAX. Si tenemos los encabezados de columna configurados
como vnculos como antes, podemos aadir cdigo jQuery para cambiar esos vnculos
por peticiones AJAX:

Filtrado

y paginar

Dos de las tareas ms comunes realizadas con datos tabulares son ordenar y paginar.
En una tabla extensa, ser capaz de reorganizar la informacin que estamos buscando es
de un valor incalculable. Desafortunadamente, estas operaciones de utilidad pueden ser
de lo ms difcil de poner en accin.
En primer lugar, examinaremos lo que se necesita para llevar a cabo una ordenacin
de tabla, reordenando datos en una secuencia que es de ms utilidad para el usuario.

Ordenacin del lado del servidor


Una solucin comn para ordenacin de datos es llevarla a cabo en el lado del servidor. Los datos en tablas a menudo proceden de una base de datos, lo que significa que
el cdigo que lo extrae de la base de datos puede solicitarlo en un orden determinado
(utilizando, por ejemplo la clusula ORDERBY del lenguaje SQL). Si tenemos cdigo del
lado del servidor a nuestra disposicin, es muy sencillo empezar con una ordenacin
predeterminada razonable.
Sin embargo, ordenar es de mucha utilidad cuando el usuario puede determinar el
orden de ordenacin. Un mtodo comnes convertir los encabezados de tabla th de
columnas que se pueden ordenar en vnculos. Estos vnculos pueden ir a la pgina actual,
pero con una cadena de consulta anexada indicado la columna por la que ordenar:
11

ctbody>

El servidor puede reaccionar al parmetro de cadena de consulta al devolver los contenidos de la base de datos en un orden diferente.

Resaltar filas

e t ab l,e id= my-data

</th>
</tr>
</thead>

</tbody>
</table>

Ordenar

Ordenar

lf.iI

11

$ (document) .ready(function()
{
$ ('#my-data
th a') .click(function()
$ ('#my-data
tbody') .load($(this)
return false;

})
})

{
.attr('href'));

Ahora cuando se hace clie en los anclas, jQuery enva una peticin AJAX al servidor
para la misma pgina. Cuando se utiliza jQuery para realizar una peticin de pgina utilizando AJAX, establece el encabezado HTTPx-Requested-WithenXMLHttpRequest
de modo que elservidor puede determinar que se est realizando una peticin AJAX.
El cdigo de servidor se puede escribir para que devuelva solamente el contenido del
propio elemento t.bcdy, y no la pgina de alrededor, cuando este parmetro est
presente. De esta forma podemos tomar la respuesta e insertarla en lugar del elemento
t body existente.
ste es un ejemplo de mejora progresiva. La pgina funciona perfectamente bien sin
ningn JavaScript, ya que los vnculos para ordenacin del lado del servidor siguen estando presentes. Cuando JavaScript est disponible, sin embargo, AJAX secuestra la peticin de pgina y permite que la ordenacin ocurra sin una carga de pgina completa.

Ordenacin JavaScript

>

cthead>
ctr>
cth class=lIname

-/

>

ll

<a href="index.php?sort=name >Name</a>


</th>
cth class="date">
ea href="index.php?sort=date">Date</a>
ll

Sin embargo, existen momentos, cuando o bien no queremos esperar respuestas del
servidor cuando ordenamos, o no tenemos un lenguaje de script del lado del servidor
disponible. Una alternativa viable en este caso es llevar a cabo la ordenacin por completo en el navegador utilizando programacin JavaScript del lado del cliente.
Por ejemplo, suponga que tenemos una tabla que lista libros, nombres de los autores,
fechas de publicacin y precios, como se ve en la figura 7.1.

IDDI

7. Manipulacin

Aprende jQuery 1.3

de tabla

TIUo

Aulho,(s)

Building Websltes wllh


Joom1a11.5Bata 1

Hagen Graf

Nos gustara convertir los encabezados de tabla en botones que ordenen los datos
por sus columnas respectivas. Exploremos algunas formas de hacer esto.
.

_;m:mmlF.'I(;1I11m1
Feb2007

lfD

$oW.49

Etiquetas' de agrupacin de filas

Learnlng Mambo: A
SIep.by-Step l\JlOrial
lo Building You,
Webs~.

Douglas Paterson

MoodIe E-I..earnlng
Course Oevelopmenl

WllUam Rice

May2006

$35.99

AJA)( 3M PHP:
Building Rasponslve
Web Applloatlons

Cr1sllanDerte, MlhaJBuclca, flllp


Che~
T0$8, Bogdan
Brtnzarea

Mar 2006

531.49

OpenVPN: Building
Bnd Integrallng Virtual
Prtvata Networ1<s

Mar1<usFellner

May2006

0002006

$oW.49

Observe nuestro uso de las etiquetas t.he ad y t body para segmentar los datos
en agrupaciones de fila. Muchos autores HTML omiten estas etiquetas, pero pueden
resultar de utilidad al proporcionamos selectores CSS ms convenientes a utilizar. Por
ejemplo, suponga que deseamos aplicar una distribucin tpica de fila par /frnpar a esta
tabla, pero solamente al cuerpo de la tabla:
$ (document) .ready(function()
$('table.sortable
tbody
$('table.sortable
tbody

n.

553.99

.'

Figura 7.1. Tabla inicial con datos.

{
tr:odd') .addClass('odd');
tr:even') .addClass('even');

Esto aadir colores alternas a la tabla, como se ve en la figura 7.2, pero deja el encabezado sin tocar.

ctable claS9=t'sortable">
c::thead>
TIUe

c::tr>

Autho,(s)

I~.'C].2!@i'.m,.a~
,~,;'

."
, ..;'\1::-:< ':~ ;f,;j-;;;~~"

<th></th>
<th>Title</th>
<th>Author(s) </th>
<th>Publish&nbsp;Date</th>
<th>Price</th>
</tr>
</thead>
<tbody>
c::tr>

c t do e i.mq src=" ../images/covers/small/184


7192386 .png"
width="49" height="61
alt="Building Websites with
Joornla! 1.5 Beta 1 />
</td>
<td>Building
Websites
with Joomla!
1.5 Beta l</td>
<td>Hagen
Graf</td>
<td>Feb 2007</td>
<td>$40.49</td>
</tr>
11

11

c::tr>

<td><img
src" ../images/covers/small/1904811620
.png"
width=tl49"
height=1I61" alt="Learning
Mambo: A
Step-by-Step
Tutorial
to Building
Your Website"
/>
</td>
<td>Learning
Mambo: A Step-by-Step
Tutorial
to Building
</td>
<td>Douglas
Paterson</td>
<td>Dec 2006</td>
<td>$40.49</td>
</tr>
</tbody>
</table>

Figura 7.2. Aadir colores alternas a la tabla.

Your

Website

Utilizando estas etiquetas de agrupacin de fila, seremos capaces de seleccionar y


manipular fcilmente las filas de datos sin afectar al encabezado.

Ordenacin

alfabtica bsica

Ahora llevemos a cabo una ordenacin sobre la columna Title (ttulo) de la tabla.
Necesitaremos una clase en la celda del encabezado de tabla de modo que podamos seleccionarlo adecuadamente:

\;":""''''

lIiI

7. Manipulacin

de tabla

Aprende jQuery 1.3

cthead:::.
<tr>

if

cth></th>

cth class="sort-alpha">Titlec/th>
<th>Author(s) </th>
<th>Publish&nbsp,Date</th>
cth>Pricec/th>
</tr>
</thead>

Utilizar JavaScript para ordenar tablas


Para llevar a cabo la ordenacin, podemos utilizar el mtodo incorporado de JavaScript
. sort ( ) . Realiza una ordenacin sobre una tabla, y puede tomar una funcin comparador como argumento. Esta funcin compara dos elementos en la tabla y debera devolver
un nmero positivo o negativo dependiendo de qu elemento debera venir primero en
la tabla ordenada. Por ejemplo, tome una sencilla tabla de nmeros:
var

arr = [52,

97,

3,

62,

10,

63,

64,

1,

9,

3,

10,

3,

3,

4,

52,

62,

63,

64,

9,

})

( ) . Despus de esto, Ios elementos

97}

Por defecto, como vemos aqu, los elementos se ordenan lexicogrficamente (en orden
alfabtico). En este caso podra tener ms sentido ordenar los elementos numricamente.
Para hacer esto, podemos proporcionar una funcin comparador al mtodo . sort ( ) :
arr.sort(function(a,b)
if (a < b)
return -1;
if (a > b)
return 1;
return O;

}),

Esta funcin devuelve un nmero negativo si a debera venir pririiero en la tabla


ordenada, un nmero positivo si b debera venir primero, y cero si el orden de los elementos no importa. Con esa informacin a mano, el mtodo. sort () puede secuenciar
los elementos de forma apropiada:
[1,

3,

3,

4,

9,

10,

52,

62,

63,

64,

97}

Utilizar un comparador para ordenar filas de tabla


Nuestra rutina de ordenacin inicial se parece a esto:
$ (document) .ready(function()
(
$('table.sortable')
.each(function()
{
var $table = $(this),
$('th', $table) .each(function(column)
var $header = $(this),

.text()
.text()

4},

Podemos ordenar esta tabla al invocar arr . sort


estn en orden:
[1,

($header.is(' .sort-alpha'))
(
~header.addClass('clickable')
.hover(function()
$header.addClass('hover')
,
function () {
$header. removeClass (,~hover' ) i
}) .click(function()
(
var rows = $table.find('tbody
> tr') .get(),
rows. sort (function(a,
b) (
var keyA = Sta) .children('td')
.eq(column)
.toUpperCase()
,
var keyB = $(b) .children('td')
.eq(column)
.toUpperCase()
,
if (keyA < keyB) return -1,
if (keyA > keyB) return 1,
return O;

lIfiI

})

, .

$.each(rows,
function(index,
$table.children('tbody')
})

row) (
.append(row)

}),

Lo primero a destacar es nuestro uso del mtodo . each () para crear la iteracin explcita. Aunque podramos vincular un manejador click a todos los encabezados que
tienen la clase sort-alpha
al invocar $ ( table. sortable
th. sort -alpha ') .
click (), esto no nos permitira capturar fcilmente una parte crucial de informacin:
la columna ndice del encabezado que se hace clic. Puesto que . each () pasa el ndice
de iteracin a su funcin de rellamada, podemos utilizarlo para encontrar la celda relevante en cada fila de los datos ms adelante.
Una vez que hemos encontrado la celda encabezado, recuperamos una tabla de todas
las filas de datos. Esto es un estupendo ejemplo de cmo. get () es de utilidad al transformar un objeto jQuery en una tabla de nadas DOM; aunque los objetos jQuery actan
como tablas en muchos aspectos, no tienen ninguno de los mtodos de tabla nativos
disponibles, como . sort ( ) .
Ahora que tenemos una tabla de nadas DOM, podemos ordenarlos, pero para hacer
esto necesitamos escribir una funcin comparador apropiada. Deseamos ordenar las filas
de acuerdo a los contenidos textuales de las celdas de tabla relevantes, por lo que sta
ser la informacin que la funcin comparador examinar. Sabemos qu celda examinar
porque capturamos el ndice de columna en la llamada . each ( ) .
Convertimos el texto en mayscula porque las comparaciones de cadena en JavaScript
son sensibles a mayscula y minscula y queremos que nuestra ordenacin no sea sensible a mayscula y minscula. Almacenamos los valores clave en variables para evitar
clculos redundantes, compararlos, y devolver un nmero positivo o negativo como se
ha tratado antes.
Por ltimo, con la tabla almacenada, pasamos en bucle por las filas y las insertamos
en la tabla. Puesto que . append () no clona nadas, esto las mueve en lugar de copiarlas. Nuestra tabla est ahora ordenada.
I

7. Manipulacin

de labia
Aprende jQuery 1.3

Esto es un ejemplo del equivalente de mejora progresiva, es decir, degradacin elegante. A diferencia de la solucin AJAX tratada anteriormente, esta tcnica no puede
funcionar sin JavaScript asumimos que el servidor no dispone de lenguaje de script
disponible para este ejemplo. Puesto que se necesita JavaScript para el tipo de trabajo,
estamos aadiendo la clase clickable por medio del cdigo solamente, asegurndonos as que la interfaz indica que la ordenacin es posible (con una imagen de fondo)
solamente si el script se puede ejecutar. La pgina se degrada en una que sigue siendo
funcional, aunque sin ordenacin disponible.
Hemos movido las filas, de ah que nuestros colores alternos de fila estn ahora descontrolados, como muestra la figura 7.3.

$header.removeClass('hover')
i
l,) .click(function()
(
var rows = $table.find('tbody
> tr') .get();
rows.sort(function(a,
b) (
var keyA = $(a) .c~ldren('td')
.eq(column)
.toUpperCase()
;
var keyB = $(b) .children('td')
.eq(column)
.toUpperCasel);
if (keyA < keyB) return -1;
if IkeyA > keyB) return 1;
return O;

1&1

.text()
.text()

l) ;

$.each(rows, function(index,
row) {
$table.children('tbody')
.append(row);

l) ;
alternateRowCo1ors($table);

l) ;
l) ;

l) ;
l) ;
Esto corrige el color de la fila, solucionando el problema, como se muestra en la figura 7.4.

Figura 7.3. Se ha perdido la alternancia de color.

Necesitamos volver a aplicar los colores de fila despus de llevar a cabo la ordenacin. Podemos hacer esto al situar el cdigo de color en una funcin que podemos invocar cuando sea necesario:
$ (document)

.ready(function()

var alternateRowColors
= function($table)
$('tbody
tr:odd',
$table)
.removeClass('even') .addClass('odd');
$ ('tbody tr:even',
$table)
.removeClass{'odd').addClass('even')

Figura 7.4. Solucionar el problema de color de fila.

};
$('table.sortable')
.each(function()
var $table = $(this);
alternateRowColors($table);
$('th', $table) .each(function(column)
var $header = $(this);
if ($header.is(' .sort-alpha'
(
$header.addClass('clickable')
$header.addClass('hover');
l, functionl) (

El poder de los plug-ins


.hover(function()

La funcin al ternateRowColors () que escribimos es un perfecto candidato para


convertirse en un plug-in jQuery. De hecho, cualquier operacin que deseemos aplicar
a un conjunto de elementos DOM se puede expresar fcilmente como un plug-in. Para
conseguir esto, necesitamos modificar nuestra funcin existente solamente un poco:

mi

7. Manipulacin

Aprende jQuery 1.3

de tabla

jQuery.fn.alternateRowColors
= function() {
$('tbody
tr:odd',
this)
.removeClass('even') .addClass('odd');
$('tbody
tr:even',
this)
.removeClass(lodd
,addClass('even') i

.toUpperCase();
if (keyA < XeyB) return
if (keyA > keyB) return
return O;

-1;
1;

j);

1)

return

mil

"

this

Podemos extraer la computacin clave y realizar esto en un bucle aparte:

};

Hemos realizado tres cambios importantes a la funcin.

$.each(rows,
function(index,
row) (
row.sortKey
= $(row) .children('td')
.text() .toUpperCase();
}) ;
,. rows.sort(function(a,
b) {

Se define como una nueva propiedad de j Query . fn en lugar de como una


funcin independiente. Esto registra la funcin como un mtodo plug-in.

Utilizamos la palabra clave this como un sustituto de nuestro parmetro $table.


Dentro de un plug-in de mtodo, this hace referencia al objeto jQuery sobre el
que se acta.

})

Por ltimo, devolvemos thi s al final de la funcin. Proporcionar el objeto jQuery


como el valor de retorno hace que nuestro nuevo mtodo se pueda encadenar.

$.each(rows,
function(index,
$table.children('tbody')
row.sortKey = null

if (a. sortKey
if (a.sortKey
return Di

})

.text()

.toUpperCase()
;
keyB = $(b) .children('td')

.eq(column)

.text()

var

return
return

-1;
1;

row) (
.append(row)

(),

Nuestro cdigo funciona, pero es bastante lento. El culpable es la funcin comparador, que est llevando a cabo una gran cantidad de trabajo. Este comparador se invocar muchas veces durante el transcurso de una ordenacin, lo que significa que cada
momento adicional que pasa procesando se magnificar.
El algoritmo de ordenacin utilizado por JavaScript no se define por el estndar.
2
Puede ser una sencilla ordenacin como una ordenacin burbuja (el mejor caso de 0(n )
en trminos de complejidad computacional) o un enfoque ms sofisticado como ordenacin rpida (que es 0(n log n)). Sin embargo, es seguro decir que duplicar el nmero
de elementos en una tabla ser ms del doble el nmero de veces que se invoca la funcin comparador.
El remedio para nuestro comparador lento es precalcular para la comparacin.
Empezamos con nuestra funcin de ordenacin actual y lenta:
.eq(column)

b. sor t xey)
b.sortKey)

Problemas de rendimiento

rows.sort(function(a,
b) (
var keyA = $(a) .children('td')

>

En el nuevo bucle, estamos realizando todo el trabajo y almacenando el resultado en


una nueva propiedad. sortKey. Este tipo de propiedad, anexada a un elemento DOM
pero no un atributo DOM normal, se denomina un expando. Se trata del lugar adecuado
para almacenar la clave, ya que necesitamos una por elemento de fila de tabla. Ahora,
podemos examinar este atributo dentro de la funcin comparador, y nuestra ordenacin
es considerablemente ms rpida.

Ms adelante en el libro puede encontrar informacin sobre escribir plug-ins jQuery.


Ah tratamos de poner disponible un plug-in para consumo pblico frente al pequeo
ejemplo aqu que solamente se va a utilizar por nuestro propio cdigo.
Con nuestro plug-in definido, podemos invocar $table . al ternateRowColors
una sentencia ms natural jQuery, en lugar de al ternateRowColors
($table)

<

.eq(column)

Establecemos la propiedad expanda en null despus de haber terminado con ella


para limpiar. Esto no es estrictamente necesario en este caso, pero es un buen hbito
establecerlo porque las propiedades expanda que se van dejando atrs pueden ser la
causa de prdidas de memoria. Para ms informacin, vase el Apndice C.
En lugar de utilizar propiedades expando,
almacenaje de datos alternativo que podramos
o recupera informacin arbitraria asociada con
moveData () se libra de cualquier informacin

jQuery proporciona un mecanismo de


utilizar. El mtodo. data () establece
elementos de pgina, y el mtodo . realmacenada:

$.each(rows,
function(index,
row) {
$(row).data('sortKey',
$ (row) .children('td')
.eq(column) .text() .toUpperCase(;
) ;
rows.sort(function(a,
b) (
if ($(a) .data('sortKey')
return -1;
if ($(a) .data('sortKey')
return 1;

<

$(b) .data('sortKey'

>

$(b) .data('sortKey'

lID

AprendejQuery

7. ManipuLacin de tabla

return O;
}) ;
$.eaeh(rows, funetion(index,
row) (
$table.ehildren('tbody')
.append(row);
$ (row) .removeData{'sortKey');
}) ;

Utilizar. data () en lugar de propiedades expanda puede ser, a veces, ms conveniente, ya que a menudo estamos trabajando con objetos jQuery en lugar de directamente con nadas DOM. Tambin evita problemas potenciales con prdidas de memoria de
Internet Explorer. Sin embargo, para el resto de este ejemplo, nos ceiremos a las propiedades expanda para practicar el alternar entre operaciones en nadas DOM y operaciones en objetos jQuery.

1.3

$.eaeh(rows, funetion(index,
row) (
var $eell ~ $(row) .ehildren('td') .eq(eolumn);
row.sortKey = $eell.find(' .sort-key') .text() .toUpperCase()
+ ' , ~ $eell.text() .toUpperCase();

-',

});

Ordenar por la columna Author(s) ahora utiliza la clave proporcionada, ordenando.


as por el apellido, corno muestra la figura 7.5.

Tltl.

Autllor(s)

d:rrl:lIm:W

Ftttlllill!l

:1.1

Manipular las teclas de ordenar


Ahora, queremos aplicar el mismo tipo de comportamiento de ordenacin a la columna Author(s) de nuestra tabla. Al aadir la clase sort- alpha a su celda encabezado, la
columna Author(s) se puede ordenar con nuestro cdigo existente. De forma ideal los autores se deberan ordenar por el apellido, no por el nombre. Puesto que los libros tienen
mltiples autores, y algunos autores tienen varios nombres o iniciales, necesitamos ayuda
para determinar qu parte del texto utilizar corno nuestra clave de ordenacin. Podemos
proporcionar esta ayuda al situar la parte relevante de la celda en una etiqueta:
<tr>

<td><img sre=" ../images/eovers/small/1847192386.png"


width="49
height=H61" alt=I1Building
Websites with
Joomla! 1.5 Beta 1 1>
</td>
<td>Building Websites with Joomla! 1.5 Beta l</td>
<td>Hagen
<span class=tlsort-keylr>Graf</span></td>
<td>Feb 2007</td>
<td>$40.49</td>
</tr>

Figura 7.5. Tabla ordenada por el apellido.

11

11

<tr>

c t d sci mq src " ../images/eovers/small/1904811620


.png"
width="49It
height="6111
alt=IILearning
Mambo: A
Step-by-Step Tutorial to Building Your Website" />
</td>
<td>Learning Mambo: A Step-by-Step Tutorial to Building
Your Website
</td>
<td:>Douglas <span class="sort-keyl1>paterson<!span></td>
<td>Dee 2006</td>
<td>$40.49</td>
</tr>

Ahora, tenemos que modificar nuestro cdigo de ordenacin para tener en cuenta
esta etiqueta sin molestar el comportamiento existente para la columna Title, que ya funciona bien. Al anexar la clave de ordenacin marcada a la clave que hemos calculado
previamente, podemos ordenar primero por el apellido si se invoca, pero sobre toda la
cadena corno seguridad:

Si dos apellidos son idnticos, la ordenacin utiliza toda la cadena para decidir la
posicin.

Ordenar otros tipos de datos


Nuestro usuario debera poder ordenar no slo por las columnas Title y Author(s),
sino por las columnas Publish Date y Price tambin. Puesto que hemos agilizado nuestra
funcin comparador, puede gestionar todos los tipos de datos, pero primero las claves
calculadas se tendrn que ajustar para otros tipos de datos. Por ejemplo, en el caso de
precios a los que necesitamos quitar el carcter $ inicial y analizar el resto de modo que
podamos compararlos numricamente:
var key = parseFloat($eell.text()
.replaee(/A(A\d.J*/,
row.sortKey = isNaN(key) ? o : key;

"));

La expresin regular utilizada aqu elimina cualquier carcter distinto de los nmeros
y puntos decimales, pasando el resultado a parseFloat (). El resultado de parseFloat () luego se tiene que comprobar, porque si no se puede extraer ningn nmero
del texto, se devuelve NaN(not a number). Esto puede causar estragos en . sort () .
Para las celdas de fecha, podemos utilizar el objeto JavaScript Date:
row.sortKey

= Date.parse('l

' + $eell.text());

El

7. Manipulacin

Aprende jQuery 1.3

de tabla

Las fechas en esta tabla contienen un mes y ao solamente; Date. parse () requiere
una fecha especificada completamente, por lo que precedemos la cadena con 1. Esto proporciona un da para complementar el mes y ao, y la combinacin luego se convierte en
una marca de tiempo, que se puede ordenar utilizando nuestro comparador normal.
Podemos repartir estas expresiones entre funciones aparte, e invocar la apropiada
basndonos en la clase aplicada al encabezado de tabla:

return

})

o;

$.each(rows,
function(index,
$table.children('tbody')
row. sortKey = nul,~i

})

row) (
.append(row)

$table.alternateRowColors()
})

jQuery.fn.alternateRowColors
= function() (
$('tbody
tr:odd', this)
.removeClass('even')
.addClass('odd')
/
$('tbody
tr:even',
this)
.removeClass('odd') .addClass(reven') i
return this

})

})/

})

La variable f indSort:Key se duplica como la funcin para calcular la clave, y existe


una indicacin para indicar si el encabezado de columna se marca con una clase permitiendo que se pueda ord-enar. Ahora podemos ordenar por fecha o precio, como mues, tran las figuras 7.6 y 7.7, respectivamente.

}/
$ (document) .ready(function()
(
$('table.sortable')
.each(function()
var $table = $(this)/
$table.alternateRowColors()
/
$('th', $table) .each(function(column)
var $header = $(this) /
var findSortKey;
if ($header.is('.sort-alpha')
{
findSortKey
function($cell)
{
return $cell.find('.sort-key')
.text() .toUpperCase()
+ ' , + $cell.text() .toUpperCase()

.'
o',

"

};
el se if ($header. is ( ,.sort-numeric' l I {
findSortKey
= function($cell)
{
var key = $cell.text() .replace(/A[A\d.l*/.
key.
parseFloat(key);
return isNaN(key)
? o : key;
}

");

}
Figura 7.6. Ordenar por fecha.

else if ($header.is('.sort-date'
{
findSortKey
= function($cell)
{
return Date.paree('l
+ $cell.text(

=:.

ntlo

I-::

Author(s}

};

if

(findSortKey)
{
$header.addClass('clickable')
.hover (function ()
$header.addClass('hover')/
}. function () (
$header.removeClass('hover')
/
}) .click (function () (
var rows = $table.find('tbody
> tr') .get() /
$.each(rows,
function(index,
row) (
var $cell = $ (row) .children('td')
.eq(column)
row.sortKey
= findSortKey($cell);

})

rows.8ort(function(a.
b) (
if (a.90rtKey
< b.sortKey)
if (a.8ortKey
> b.sortKey)

lID

return
return

-1/
1/

Figura 7.7. Ordenar por precio.

IEI

7. Manipulacin

r'"

de tabla

Resaltar columna
Puede ser una buena mejora de interfaz de usuario recordar visualmente al usuario
lo que se ha hecho en el pasado. Al resaltar la columna que se ha utilizado recientemente
para ordenar, podemos centrar la atencin del usuario en la parte de la tabla que es ms
probable que sea relevante. Afortunadamente, puesto que ya hemos determinado cmo
seleccionar las celdas de tabla en la columna, aplicar una clase a esas celdas es sencillo:
$table.find('td')
.removeClass('sorted')
.filter(' :nth-child('
+ (column
+ 1) + ') ')
.addClass('sorted')
;

Auttlor(s)

jQuery.fn.alternateRowColors
= function()
$('tbody
tr:odd',
this)
,removeClass('even') .addClass('odd')
$('tbody
tr:even',
this)
.removeClass{'odd')
.addClass{'even')
return this

$ (document) .ready(function()
(
$('table.sortable')
.each(function()
var $table = $(this);
$table.alternateRowColors()
;
$('th', $table) .each(function(column)
var $header = $(this);
var findSortKeYi
if ($header.is(' .sort-alpha'))
(
findSortKey
= function($cell)
(
return $cell.find('
.sort-key') .text() .toUpperCase()
+ ' , + $cell.text()
.toUpperCase()
;

};

SteveA1wa1

Or. Ma/1( A_e,

else if ($header.is(' .sort-numeric'))


(
findSortKey
= function($cell)
(
var key = $cell.text()
.replace(/'['\d.l*/,
key = parseFloat(key);
return isNaN(key)
? o : key;

K SOOttAlIen

");

};

aaln

elsa if ($header.is(' .sort-date'))


(
findSortKey
= function($cell)
(
return Date.parse('l
' + $cell.text());

};
PhUlppe aaurnann, Henriette
aaumann, Pa1l1ck Grassle

Figura

7.8. Resaltar una columna.

Alternar la direccin de la ordenacin

if

(findSortKey)
(
$header.addClass('clickab1e')
.hover(function()
$header.addClass('hover')
;
}. function () (
$header.removeC1ass('hover')
;
}) .c1ick(function()
{
var sortDirection = 1;
if ($header. is ( , . sorted-asc' ) )
sortDirection = -1;

Nuestra ltima mejora de ordenacin es permitir ordenacin ascendente y descendente. Cuando el usuario hace clic en una columna que ya est ordenada, queremos invertir el orden actual de ordenacin.
Para invertirlo, todo lo que tenemos que hacer es invertir los valores devueltos por
nuestro comparador. Podemos hacer esto con una sencilla variable:

var rows = $table.find('tbody


> tr') .get();
$.each(rows,
function(index,
row) (
var $ce11 = $(row) .chi1dren('td')
.eq(co1umn);
row.sortKey
= findSortKey($ce11);

if

rows.sort(function(a,
b) {
if (a.sortKey < b.sortKey)
if (a.sortKey
> b.sortKey)

(a.sortKey

if (a.sortKey

<
>

b.sortKey)
b.sortKey)

return
return

-sortDirection;
sortDirection

lID

Si sortDirection es igual a 1, entonces la ordenacin ser la misma que ant~s. Si


es igual a -1, la ordenacin se invertir. Podemos utilizar clases para mantener registro
del orden actual de una columna:

};

Este fragmento primero elimina la clase sorted de todas las celdas, luego la aade a
las celdas que estn en la misma columna que hemos utilizado para nuestra ordenacin.
Observe que tenemos que aadir 1 al ndice de columna que hemos encontrado anteriormente, ya que el selector : nth-child {)es en base uno en lugar de en base cero. Con
este cdigo en su lugar, recibimos una columna resaltada despus de cada operacin de
ordenacin, como muestra la figura 7.8.
"
e

Aprende jQuery 1.3

})

return
return

-sortDirection
sortDirection;

r~"

ID

7. Manipulacin

de tabla

return

})

O;

}
e1se {
$header.addClass('sorted-desc');

Ordenar y paginar van juntos

$table.findl'td') .removeClass('sorted')
.filter(' :nth-child(' + (column + 1) + ')')
.addClass('sorted') ;
$table.alternateRowColors();
;

}
})

.'

]l;

})

Como un beneficio secundario, puesto que utilizamos clases para almacenar la direccin de ordenacin, podemos aplicar estilo a los encabezados de columna para indicar
el orden actual tambin, como se ve en la figura 7.9.

Los datos que se benefician de la ordenacin es probable que tambin sean un candidato para la paginacin. No es raro desear combinar estas dos tcnicas para la presentacin
de datos. Puesto que ambos afectan al conjunto de datos que est presente en una pgina,
sin embargo, es importante considerar sus interacciones mientras se implementan.
Tanto ordenar como paginar se pueden realizar tanto en el servidor, o en el navegador Web. Sin embargo, debemos mantener las estrategias para las dos tareas en sincrona; de lo contrario, podemos acabar con un comportamiento confuso. Suponga, por
ejemplo, que tenemos una tabla con ocho filas y dos columnas, ordenada inicialmente
por la primera columna.
Si los datos se vuelven a ordenar por la segunda columna, muchas filas pueden cambiar de lugar, como se ve en la figura 7.10.

1
2

H
Antes
Figura 7.9. Aplicar estilo a los encabezados

lID

Como con ordenar, la paginacin a menudo se realiza en el servidor. Si los datos a


mostrar se almacenan en una base de datos, es fcil extraer un bloque de informacin de
cada vez utilizando la clusula LIMIT de MySQL, ROWNUM en Oracle, o mtodos equivalentes en otros motores de base dedatos.
Como con nuestro ejemplo de ordenacin inicial, la paginacin se puede activar al
enviar informacin al servidor en una cadena de consulta, como index . php ?page= 52 ..
y nuevamente, como antes, podemos llevar a cabo esta tarea con una carga completa de
pgina o al utilizar AJAX para recuperar slo una parte de la tabla. Esta estrategia depende del navega dar, y puede gestionar amplios conjuntos de datos muy bien.

$.each(rows, function(index,
row) {
$table.children('tbody')
.append(row);
row.sortKey = null
}) ;
$table.find('th') .removeClass('sorted-asc')
.removeClass('sorted-desc')
if (sortDirection _. 1) {
$header.addClaas('sorted-asc');

})

Aprende jQuery 1.3

8
Despus

de columna.
Figura 7.10. Ordenar por la primera y segunda columna.

Paginacin del lado del servidor


Ordenar es una forma estupenda de pasar por una amplia cantidad de datos para
encontrar informacin. Tambin podemos ayudar al usuario a centrarse en una parte
del amplio conjunto de datos al paginarlos.

Ahora consideremos lo que sucede cuando se aade paginacin a la mezcla. Suponga


solamente que las cuatro primeras filas se facilitan por el servidor y el navegador intenta
ordenar los datos.
Si la paginacin se realiza por el servidor y la ordenacin por el navegador, todo el
conjunto de datos no se encuentra disponible para la rutina de ordenacin, haciendo
que los resultados sean incorrectos, como muestra la figura 7.11.

lImI

7. Manipulacin

II

de tabla

---

.--

Despus

Antes

Figura 7.11. Resultado de aadir paqlnacin,

Solamente los datos ya presentes en la pgina se pueden manipular por JavaScript.


Para impedir que esto sea un problema, debemos llevar a cabo ambas tareas en el servidar (preguntando al servidor el conjunto de datos correcto en cada pgina u operacin
de ordenacin), o ambas en el navegador (con todos los posibles datos disponibles para
JavaScript en todo momento), de modo que los primeros resultados mostrados son en
realidad las primeras filas en el conjunto de datos, como muestra la figura 7.12.

Antes

Despus

Figura 7.12. Resultado correcto.

Paginacin JavaScript

I~

Aprende jQuery 1.3

no queremos que los encabezados o pies de pgina desaparezcan cuando nos movemos
a la segunda pgina. Para seleccionar las filas que contienen datos, ocultamos todas las
filas primero)uego seleccionamos las filas en la pgina actual, mostrando las filas seleccionadas. El mtodo. slice () mostrado aqu funciona como el mtodo de tabla del
mismo nombre; reduce la seleccin a los elementos entre las dos posiciones dadas.
La tarea ms propensa a error al escribir este cdigo es formular las expresiones a
utilizar en el filtro. sl ice () . Necesitamos encontrar los ndices de las filas al principio
y final de la pgina actual. Para la fila inicial, simplemente multiplicamos el nmero de
la pgina actual por el nmero de filas en cada pgina. Multiplicar el nmero de filas
por uno ms que el nmero de pgina actual nos da la fila inicial de la siguiente pgina;
el mtodo. slice () va a buscar las filas hasta y no incluido este segundo parmetro.

Mostrar el paginador
Para aadir interaccin de usuario a la mezcla, necesitamos situar un pagina dar
junto a la tabla: un conjunto de vnculos para navegar a diferentes pginas de datos.
Podramos hacer esto al insertar simplemente vnculos para las pginas en el cdigo
HTML, pero esto violara el principio de mejora progresiva que hemos estado adoptando. En su lugar, deberamos aadir los vnculos utilizando JavaScript, por lo que los
usuarios sin posibilidades de script disponibles no sean inducidos a error por vnculos
que no pueden funcionar.
Para mostrar los vnculos, necesitamos calcular el nmero de pginas y crear un nmero correspondiente de elementos DOM:
var nurnRows
var numpages

$table.find('tbody

tr') .length;
/ numPerPage)

= Math.ceil{nurnRows

$ (document) .ready(function()
{
$('table.paginated')
.each(function()
var currentPage = o;
var numPerpage = 10;
var $table = $(this);
$table.find('tbody
tr') .hide()
.slice(currentPage
* numPerpage,
(currentPage
+ 1) * numPerpage)
.show() ;

})
})

var $pager = $('<div class=Upager ></div>')


for (var page = o; page < numPages;
page++)
{
$('<span class=lIpage-number > , + (page + 1) +
.appendTo($pager)
.addClass('clickable');
l1

1t

Por lo tanto, examinemos cmo aadiremos paginacin JavaScript a la tabla que ya


hemos hecho que se pueda ordenar en el navegador. En primer lugar, nos centraremos
en mostrar una determinada pgina de datos, sin tener en cuenta la;interaccin de usuario por ahora.

'</span>')

}
$pager. insertBefore

($table) ;

El nmero de pginas se puede encontrar al dividir el nmero de filas de datos por


el nmero de elementos que deseamos mostrar en cada pgina. Puesto que la divisin
puede no mostrar un entero, debemos redondear el resultado utilizando Math.cei 1 ( )
para aseguramos de que la ltima pgina parcial estar accesible. Luego, con este nmero a mano, creamos botones para cada pgina y posicionamos el nuevo paginador
sobre la tabla, como muestra la figura 7.13.
1112113114115116117
e Author(s)

Este cdigo muestra la primera pgina, diez filas de datos. Una vez ms nos basamos en la presencia de un elemento t.body para separar datos de los encabezados;

lmII

Figura 7.13. El paginador en la tabla.

lliEI

7. Manipulacin de tabla

Habilitar los botones del paginador


Para hacer que estos nuevos botones funcionen en realidad, necesitamos actualizar la
variable currentPage
y luego ejecutar nuestra rutina de paginacin. A primera vista,
parece que deberamos poder hacer esto al establecer currentPage
en page, que es el
valor actual del iterador que crea los botones:
$Idocument) .readylfunctionl)
(
$I'table.paginated')
.eachlfunctionl)
var currentPage = Di
var numPerpage = la;
var $table = S(this);
var repaginate
= functionl) (
$table.find('tbody
tr') .hide()
,slice(currentPage
* numPerpage,
(currentPage + 1) * numPerPage)
.show();

1m

Para corregir este problema, aprovecharemos una de las caractersticas ms avanzadas de los mtodos de vinculacin de eventos de jQuery. Podemos aadir un conjunto
de datos de eyento personalizado al manejador cuando lo vinculamos que seguir estando disponible cuando se invoque el,manejador. Con esta posibilidad de uso a nuestra
disposicin, podemos escribir:
$(I<:span class="page-numberll></span>r)
.text(page
+ 1)
.bind('click',
{newpage:
page} , function(event)
(
currentPage = event.data['newPage');
repaginate()
;
}) .appendTo($pager)
.addClass('clickable');

El nuevo nmero de pgina se pasa al manejador por medio de la propiedad data


del evento. De esta forma el nmero de pgina escapa a los peligros del cierre y se congela en el tiempo en el valor que contena cuando el manejador se vincul. Ahora los
, vnculos de nuestro paginador pueden llevamos de forma correcta a diferentes pginas,
como muestra la figura 7.15.

};
var numRows = $table.findl'tbody
tr') .length;
var numpages
= Math.ceillnumRows
/ numperpage);
var $pager = $('<div class="pager"></div>') i
for (var page = O; page < numPages;
page++)
{
$(I<span
clas9=lIpage-number"></span>') .text(page
.clicklfunctionl)
(
currentpage = page;
repaginate()
;
}) .appendTol$pager)
.addClass('clickable');

Aprende jQuery 1.3

.'
+

1)

}
Spager.insertBefore($table);

})

n.
;

Esto funciona, porque la nueva funcin repaginate


() se invoca cuando se carga
la pgina y cuando se hace clie en cualquiera de los vnculos de pgina. Todos los vnculos nos presentan una tabla que, sin embargo, no tiene filas de datos, como se ve en
la figura 7.14.
- ,.

Figura 7.15. Desplazarse a diferentes pginas.

Marcar la pgina actual

!"!t!!1ItlIQ4MIfflHillml

Figura 7.14. Preparar los botones del paginador.

El problema es que al definir nuestro manejador click, hemos creado un cierre. El


manejador click hace referencia a la variable page, que se define fuera de la funcin.
Cuando la variable cambia la siguiente vez que se pasa por el bucle, esto tambin afecta
a los manejadores click que ya hemos establecido para los botones anteriores. El efecto es que, para un paginador con 7 pginas, cada botn nos dirige a la pgina 8 (el valor
final de pgina cuando se completa el bucle). Ms informacin sobre cmo funcionan
los cierres se puede encontrar en el Apndice C.

Nuestro paginador se puede hacer ms amigable al resaltar el nmero de la pgina


actual. Solamente necesitamos actualizar las clases en los botones cada vez que se hace
clic en uno:
$Idocument
) .ready(function()
(
$('table.paginated')
.each(function()
var currentPage = o;
var numPerpage = 10;
var $table = $Ithis);
var repaginate
= function() (
$table.find('tbody
tr') .hide()
.slice(currentPage
* numPerpage,

mi

7. Manipulacin

de labia

(currentPage
.show() ;

Aprende jQuery 1.3


+

1) * numPerpage)

};
var numRows = $table.find('tbody
tr') .length;
var numpages = Math.ceil(numRows
/ numPerpage} i
var $pager
= $ ('c:::div class=lIpagertl></div>');
foro (var page = O; page < numpages;
page++)
{
$('c:::span class="page-numbertl></span>')
.text(page
.bind('click',
{newPage,
page} , function(event)
currentPage = event.data(tnewPage
i
repaginate() ;
$(this) .addClass('active')
.siblings() .removeClass('active');
}) .appendTo($pager)
.addClass('clickable');

1)

t]

11m

porque se encuentra contenido dentro de un manejador $ (document) . ready (! diferente. Podramos simplemente consolidar las dos piezas de cdigo, pero en su lugar
hagamos algo diferente. Podemos desacoplar los comportamientos, de modo que una
ordenacin in';ocael comportamiento ,repaginate
si existe, pero lo ignora de lo contrario. Para conseguir esto, utilizaremos un manejador para un evento personalizado.
En nuestra explicacin de gestin de evento anterior, nos limitamos a nombres de
evento que se activaban por el navegador Web, corno click y mouseup. Los mtodos
.bind () y . trigger
() no se limitan a estos eventos, sin embargo; podemos utilizar
cualquier cadena corno un nombre de evento. Utilizando esta posibilidad de uso, po/ demos definir un nuevo evento denominado repaginate
corno un sustituto para la
funcin que hemos estado invocando:

}
$pager. insertBefore
($table)
.find('span.page-number:first').addClass('active')

})

Ahora tenemos un indicador del estado actual del pagnador, corno muestra la figura 7.16.

$table.bind('repaginate',
function()
{
$table.find('tbody
t r v.) .hide()
.slice(currentPage
* numPerpage,
(currentPage
+ 1) * numPerpage)
.show() ;
}) ;

Ahora en los lugares donde estbamos invocando repaginate


$table.trigger('repaginate')

(), podemos invocar:

Podemos lanzar esta llamada en nuestro cdigo de ordenacin tambin. No har nada
si la tabla no tiene un paginador, por lo que podemos mezclar las dos posibilidades de
uso de la forma deseada.

El cdigo

terminado

El cdigo completo para ordenar y paginar en su totalidad se incluye a continuacin:


jQuery.fn.alternateRowColors
= function()
{
$('tbody
tr,odd',
this)
.removeClass('even') .addClass('oddr)
i
$('tbody
tr,even',
this)
.rernoveClass(lodd
.addClass('even') i
return this
l)

Figura 7.16.

Indicadorde la pginadel paginador.

Paginacin con ordenacin


Comenzamos este debate indicando que los controles de ordenacin y paginacin
tenan que ser conscientes unos de otros para evitar resultados confusos. Ahora que tenemos un paginador que funciona, tenemos que hacer que las operaciones de ordenacin
respeten la seleccin de pgina actual.
Hacer esto es tan sencillo corno invocar nuestra funcin repaginate
() siempre
que se lleva a cabo una ordenacin. El mbito de la funcin, sin embargo, hace que sea
problemtico. No podemos llegar a repaginate
() desde nuestra rutina de ordenacin

};
$ (document) .ready(function()
{
$('table.sortable')
.each(function()
var $table = $(this);
$table.alternateRowColors();
$('th', $table) .each(function(column)
var $header = $(this);
var findSortKey;
if ($header.is(' .sort-alpha'))
(
findSortKey
= function($cell)
{
return $cell.find('.sort-key')
.text() .toUpperCase()
+ ' , + $cell.text()
.toUpperCase()
;

r.

mi

7. Manipulacin

de tabla

else if ($header.is(' .Bort-numeric


{
findSortKey = function($cell)
(
var key = $cell.text() .replace(/A[A\d.J*/,
key = parseFloat(key);
return isNaN(key) ? o , key;

Aprende jQuery 1.3

"

lliiI

$('table.paginated') .each(function()
var currentPage = O;
var numPerpage = 10i
var $~able = $(this);
$table.bind('repaginate',
fun~tion()
$table.find('tbody
tr') .hide()
.slice(currentpage
* numPerPage,
(currentPage + 1) * numPerpage)
.show ();
}) ;
var numRows = $table.find('tbody
tr') .length;
var numpages = Math.ceil(nurnRows
/ numPerPage);
var $pager = $('<div class="pager ></div>');
for (var page = o; page < numPages; page++) {
$('<span class="page-number"></span>')
.text(page + 1)
.bind('click', {newPage, pagel, function(event)
(
currentPage = event.data{'newPage'];
$table.trigger('repaginate')
;
$(this) .addClass('active')
.siblings() .removeClass('active')
i
}) .appendTo($pager) .addClass('clickable');

");

};
else if ($header.is(' .sort-date')) (
findSortKey = function($cell)
(
return Date.parse('l
' + $cell.text());
};
r'

l1

if

(findSortKey) (
$header.addClass('clickable')
.hover(function()
$header.addClass('hover')
;
}, function () (
$header.removeClass{'hover')
;
}) .click(function()
{
var sortDirection
= 1;
if ($header.is(' .sorted-asc'))
sortDirection
= -1;

"

}
var rows = $table.find('tbody
, tr') .get();
$.each(rows, function(index,
row) (
var $cell = $ (row) .children('td') .eq(column);
row.sortKey = findSortKey($cell);

})

}
else (
$header.addClass('sorted-desc')

}
$table.find('td') .removeClass('sorted')
.filter (',nth-child (' + (column + 1) + ')')
.addClass('sorted') ;
$table.alternateRowColors();
$table.trigger('repaginate');

})

.addClass('active')

Modificar la apariencia de la tabla


Hemos examinado algunas formas de ordenar las filas de datos en una tabla para
proporcionar ayuda al usuario a la hora de encontrar la informacin deseada. Sin embargo, a menudo es el caso que hay muchos datos que buscar despus de llevar a cabo
cualquier ordenacin o paginacin. Podemos ayudar al usuario al manipular no slo el
orden y cantidad de filas mostradas, sino la apariencia de aqullas que se muestran.

Resaltar filas
Una forma prctica de dirigir la vista del usuario a las filas resaltadas es proporcionar una indicacin visual sobre los datos que son importantes. Para examinar algunas
estrategias de resaltado, necesitamos una tabla con la que trabajar. Esta vez, empezaremos con una tabla de elementos de noticias. La tabla ser un poco ms complicada que
la ltima; incluir algunas filas utilizadas como subencabezados, adems de una fila de
encabezado principal. La estructura HTML es como sigue:

}
});

})

})

rows.sort(function(a,
b) {
if (a.sortKey < b.sortKey) return -sortDirection;
if (a.sortKey > b.sortKey) return sortDirection;
return O;
}I;
$.each(rows, function(index,
row) (
$table.children('tbody')
.append(row);
row.sortKey = null
}) ;
$table.find('th') .removeClass('sorted-asc')
.removeClass('sorted-desc')
;
if (sortDirection == 1) (
$header.addClass('sorted-asc')
;

})

$pager.insertBefore($table)
.find(rspan.page-number:first')

}I;
$ (document) .ready(function()

<table>
<thead>
<tr>
<th,Date</th,
<th,Headline</th,

lmI

7. Manipulacin

de tabla

Aprende jQuery 1.3

lmiI

<th,Author<!th,
<th,Topic<!th,
</tr>

<!thead,
<tbody'

JQuery, MIcrosoft, and NokIa

John Reslg

1I11rd.party

JQuery Conferenoo 2008 Agend\l

ReyBango

oonference

JohnReslg

announcement
conferenoe

ctr>

JQuery.comStte Red.slgn

cth colspan="4">2008c/th>
<!tr,
ctr>
<td,Sep 28<!td,
<td,jQuery,
Microsoft,
<td,John
Resig<!td,
<td,third-party<!td,
<!tr,

Reglstratlon Open for JQuety Conrerence 2008

Kan Swedberg

jQuery VI 1.5.2

Paul Bakaus

!elease

Jun 26

JQuery UI 1.5.1

Paul8akaus

rele

Jun 26

JQuery carne 2008 Announced

Rey Bango

conference

Jun 9

JQueryUI v1.5 Roleased, Foous on Conslstent API and E1Iects

Paul Bakaus

rol

Jun 4

JQuery 1.2.6: Evon'" 100% faster

John Reslg

release
oonference

and Nokia<!td,

ctr>
<td,Jan 15<!td,
<td,jQuery
1.2.2: 2nd Birthday
<td,John Resig<!td,
ctd>releasec/td>
<!tr,
<!tbody,
et.body

Present<!td,

Mar 7

JQueryVI Wor1dwideSprinl: Man:ll14-15

Rlchartl Worth

Feb8

JQuery 1.2.3: AlR, Namespaclng, and UI Alptta

John Reslg

!el

Jan 23

jQuery VI and bayo"": The JQuetyUeray par1nershlp

Paul Bakaus

announcement

Jan 15

jQuery 12.2: 2nd Blrthday Present

John ResIg

roIease

JQuery Pluglns sHeupdated

Mlke HosteUer

announcement

2007
Dec8

Doc6

FIot, a now pIottlng plugln

Nov2

Google Uslng JQuery

ror JQuery

Figura 7.17.

Bmdley Sapos

plug.-ln

Roy Bango

Ihlrd-parly

Resaltar friasen la tabla.

<tr>

cth
<!tr,

colspan="4":;.2007</th>

Como hemos visto, aplicar un diseo de franjas a las filas puede ser tan sencillo como
un par de lneas para aadir clases a las filas pares e impares:

ctr:>

<td,Dec 8<!td,
<td,jQuery
Plugins site
<td,Mike
Hostetler<!td,
ctd>announcement</td>
<!tr,

updated<!td,

ctr>
<td,Jan ll<!td,
<td,Selector
Speeds<!td,
<td,John
Resig<!td,
ctd>sourcec/td>
<!tr,
<!tbody,

$ (document)

.ready(function()

$('table.striped
$('table.striped

})

tr:odd) .addClass('odd');
tr:even) .addClass('even');

Aunque este cdigo funciona bien para estructuras sencillas de tabla, si introducimos
filas adicionales que no queremos que se le apliquen las franjas alternas de color (como
las filas subencabezado que estamos utilizando para los aos en nuestra tabla), el patrn
bsico par-impar no es suficiente. Si, por ejemplo, la fila 2006 se clasificara como even,
las filas antes y despus de ella seran odd, lo que probablemente no es deseable, como
muestra la figura 7.18.

<!table,

Observe el uso de mltiples secciones e t.body. Esto es cdigo HTML vlido para
agrupar conjuntos de filas juntas. Hemos situado los subencabezados de seccin dentro
de estas agrupaciones, utilizando elementos t.h. Con CSS bsico aadido, esta tabla
se muestra como se ve en la figura 7.17.

Alternar color de filas


Ya hemos visto un sencillo ejemplo de resaltar fila anteriormente en este captulo, y
en un captulo anterior. Marcar las filas de un color diferente es una forma comn de
dirigir la vista del usuario entre mltiples columnas de forma precisa.

Figura 7.18.

Patrn a franjas aplicado a filasubencabezado.

Podemos garantizar que nuestro patrn de alternar fila empieza de nuevo con cada
ao al utilizar la pseudo-clase : nth -child () que hemos aprendido en un captulo anterior, como se ve en la figura 7.19.

l'

ElI!I

7. Manipulacin

de tabla

,r

Aprende jQuery 1.3

II!II

Como eje~plo, modificaremos el diseo a franjas de nuestra tabla de noticias 'para colorear sus filas de tres en tres.

Figura 7.19.

Patrn a franjas comienza de nuevo con cada ao.

$ (document) .ready(function()
{
$('table.striped
tr:nth-child(odd)
$('table.striped
tr:nth-child(even)

})

') .addClass('odd');
') .addClass('even');

Figura 7.21.

Cada grupo de filas ahora empieza con una fila odd, pero las filas subencabezado se
incluyen en este clculo. Por lo tanto, podramos no considerar las filas subencabezado
con la pseudo-clase :has () como muestra la figura 7.20.

Mejorarla presentacin de filas a franjas.

En un captulo anterior presentamos el mtodo. f il ter () para seleccionar elementos de pgina de una forma muy flexible. Recuerde que. filter
() puede tomar no
solamente una expresin selector, sino tambin una funcin filtro, y podemos escribir:
$ (document) .ready(function()
{
$ ('table.striped
tbody') .each(function()
{
$ (this) .find ('tr: not ( :has (th) ) ,) .filter (function
return
(index % 6) < 3;
}) .addClass ( "odd ') ;
}) ;

})
Figura 7.20.
$ (document) .ready(function()
{
$('table.striped
tr:not(:has(th))
$('table.striped
tr:not(:has(th))
}I;

Excluirlas filassubencabezado.
:odd') .addClass('odd');
:even') .addClass('even');

Ahora los encabezados se excluyen, pero las agrupaciones empezarn con una fila odd
o even dependiendo de la clasificacin aplicada a la fila de datos anterior. Reconciliar
estos dos comportamientos puede ser complicado; una opcin sencilla es incorporar algo
de iteracin explcita utilizando el mtodo . each ( ) .
$( document) .ready(function()
{
$('table.striped
tbody') .each(function()
{
$(this) .find('tr:not(:has(th))
:odd') .addClass('odd');
$(this) .find('tr:not(:has(th))
:even') .addClass('even');
}) ;
});

Ahora cada agrupacin se alterna en franjas de forma independiente, y las filas subencabezado se excluyen de los clculos, como se ve en la figura 7.21.

Alternar colores de fila avanzado


Estas manipulaciones de filas par e impar nos han preparado para tcnicas ms complicadas. En tablas particularmente densas, incluso los colores de filas alternos pueden
ser confusos para la vista, y puede ser beneficioso alternar colores en un intervalo mayor.

(index)

Este cdigo realiza mucho en muy poco espacio, por lo que lo dividiremos en pequeas piezas. Primero, utilizamos el mtodo. each () como antes para segmentar nuestra
tarea al agrupar filas. Queremos que nuestras franjas de tres filas empiecen de nuevo despus de cada subencabezado, por lo que esta tcnica nos permite trabajar en una seccin
de cada vez. Luego, utilizamos. f ind () como en nuestro ltimo ejemplo para localizar
todas las filas que no tienen elementos -c t h (y por lo tanto, no son subencabezados).
Ahora, necesitamos seleccionar los tres primeros elementos de este conjunto, saltarse tres elementos, etc. Aqu es donde entra en juego. f i 1ter ( ) . La funcin filtro toma
un argumento que contiene el ndice del elemento dentro del conjunto coincidente, es
decir, el nmero de fila en el apartado de la tabla que estamos examinando. Si, y slo si,
nuestra funcin filtro devuelve true, el elemento permanecer en el conjunto.
El operador mdulo (%) nos proporciona la informacin que necesitamos. La expresin
index % 6 evala en el resto del nmero de fila cuando se divide entre 6; si este resto es
O,1, o 2, entonces marcaremos la fila como odd; si es 3, 4 5, la fila ser even.
El cdigo, segn se ha presentado, solamente marca los conjuntos odd de filas. Para
aplicar tambin la clase even, podramos escribir otro filtro que aplique el filtro contrario, o podramos ser un poco ms creativos:
$ (document) .ready(function()
{
$('table.striped
tbody') .each(function()
{
$(this) .find('tr:not(:has(th))
') .addClass('even')
.filter(function(index)
{
return
(index % 6) < 3;
}) .removeClass('even')
.addClass('Odd');
});

})

Aprende jQuery

Aqu aplicamos la clase even a todos las filas, y la eliminamos si aadimos la clase
odd. Nuestra tabla ahora tiene aplicado estilo alternando agrupaciones de fila, lo que
empieza de nuevo con cada nueva seccin de la tabla, como se ve en la figura 7.22.
HaadUn 8 ~ "
r

.<'

"',"

~t;':-:::i1;~,
...,... ~':.Y
. ;~'

})

seo 28 '

ti;;:

.'JOh~:~~{g',;il~t1~(

Aug31

:'R-eY-8;~'g'O'(?\::~\~:~~~~ferti~fe

~;r,"

Aug29

: Jahn Reslg

"ennooncement

Aug 15

Kan Swedberg

Jul14

Paut Bakaus

ralease

Jun 26

Paul Bakaus

release

. ..

Jun '26

"

';,;

:1'

f;;

conference

R~y"8anQ~':,>?:k;,: 'i;nf~r~~,ca
E.'"

'-"':;',.-

Jun 9

Observe que utilizamos la pseudo-clase : nth- child (n) como parte de la expresin
selector que apunta a la tercera columna donde est la informacin de autor, En caso de
que la estructura de tabla fuera a cambiar ms adelante, querramos que esta constante 3 estuviera solamente en un lugar en el cdigo, de modo que se pudiera actualizar
fcilmente. Por esta razn, almacenamos el resultado de nuestro selector en la variable
$authorCells
en lugar de repetir el selector cada vez que se necesita,
'f:
r.;.;'

.r

~~,..~{~}~f~~~~~~~~
~
~i~-party

ElD

$authorcells.clicklfunctionl)
// Resaltar
filas aqu,
})

li3III

1.3

.: -"".," ....'.,x\:

:.:1):. .. ;

~;.:Pa~18aka~s ...;~.;: reease

Jun 4

Recuerde que a diferencia de los ndices JavaScript, la pseudo-clase : nth- child (n}
basada en CSSempieza a numerar en 1, no en o.

"John Reslg

Mar7

Rlchard Wonh

conrerenoe

Feb B

John Reslg

release

Jan 23

Paul Bakaus

Dee6

Cuando el usuario hace clie en una celda en la tercera columna, qltr~mos que el texto
de la celda se compare con el de la celda de la misma columna en cualquier otra fila, Si
coincide, la clase highl ight se alternar. Es decir, la clase se aadir si no est ya ah, y
se eliminar si lo est. De esta forma, podemos hacer clic en una celda de autor para eliminar el resaltado de la fila si ya se ha hecho clic en esa celda o una con el mismo autor.

"plu~ln

Nov2

Ihiril,party

Sep 17

ennouncement

Sep 10

John Reslg

release

Sep 6

John Reslg

conference

Aug24

Jchn Resig

release

Figura

7.22. Estiloaplicadoa aqrupacionesde fila.

l'

$Idocument)
.readyIfunction1)
(
var $authorCells
= $ l' t ab l.e.striped
t d .nth-child
$authorCells.clicklfunctionl)
(
var authorName
= $Ithis) ,textl);
$authorCells,eachlfunctionlindex)
(
if lauthorName
== $ (t.h.s l. text ()) (
$Ithis)

,parentl)

(3) ') ;

"l

,toggleClassl'highlight');

Resaltar filas basado en interaccin

del usuario

;~

Otra mejora visual que podemos aplicar a nuestra tabla de artculos de noticias es resaltar la fila basndose en la interaccin del usuario, Aqu responderemos a hacer clic en
el nombre de un autor al resaltar todas las filas que tienen el mismo nombre en su celda
Author. Podemos modificar la apariencia de 'estas filas resaltadas al aadir una ,clase:

I :i

.
~ :1

~1

})
})

#content
tr.highlight
background,
#ff6;

Es importante que asignemos a esta nueva clase highl ight especificidad adecuada,
de modo que el color de fondo anular el de las clases even y odd.
Ahora necesitamos seleccionar la celda apropiada y anexarle comportamiento utilizando el mtodo. click ():
$Idocument)
var

.readylfunctionl)

$authorCells

$I'table.striped

})

t-

El cdigo funciona bien en este punto, excepto cuando un usuario hace clie en dos
nombres de autor en sucesin. En lugar de cambiar las filas resaltadas de un autor al siguiente como podramos esperar, acabamos con la clase highlight
en ambos grupos
de filas. Para evitar este comportamiento, podemos aadir una sentencia else al cdigo, eliminado la clase highlight
para cualquier fila que no tiene el mismo nombre de
autor que en el que se ha hecho clie:
$Idocument)
.readylfunctionl)
(
var $authorCells
= $I'table.striped
td,nth-child(3)
$authorCells.clicklfunctionl)
(
var authorName
= $Ithis) ,textl);
$authorCells.eachlfunctionlindex)
(
if (aut.horNarne == s Lth i.s) .textl))
(
$Ithis)

td,nth-child(3)

.parentl)

');

.toggleclassl'highlight');

');

:'. irr

u11'"

iIilL.:J!"J':;

-, I

mi

7. Manipulacin

de labia

Aprende jQuery 1.3

else {
$(this).parent().removeClass('highlight');
}

if

})

(authorName
== $(this) .text(
(
$(this) .parent() .toggleClass('highlight');

}I ;
})

BiD

~lse (
$(this) .parent()

.remqveClass('highlight'l;

Ahora cuando hacemos clic en Rey 8ango, por ejemplo, podemos ver todos sus artculos mucho ms fcilmente, como aparece en la figura 7.23.

Headllne

.~11'I1Ua

IJ!FlI

11;

18<

!le1l28

'-:-:f:::\~ReyBlngo

conference

})
})
})

La clase c1ickab1e es un paso en la direccin correcta, pero todava no le dice al


usuario qu suceder cuando se hace clic en la celda. Por lo que conoce el usuario de la
pgina, ese clic podra fcilmente activar otro comportamiento, como enviar el usuario
a otra pgina. Alguna otra indicacin de lo que va a pasar al hacer clic est en orden.
Las descripciones emergentes son una caracterstica familiar de muchas aplicaciones
de software, incluidos los navegadores Web. Podemos abordar este desafo de usabilidad al mostrar una descripcin emergente cuando el ratn pasa por encima de una de
las celdas Author. El texto de la descripcin emergente puede describir a los usuarios
el efecto que tendr su accin, con un mensaje como Highlightall articles by Rey 8ango
(Resaltar todos los artculos de Rey Bango). Este texto se encontrar en un <di V>, que
podemos anexar a -e body . La variable $tooltip
se utilizar en todo el script para
hacer referencia a este elemento recin creado:
var

$tooltip

$(!<div

id=UtooltiplI></div>t)

.append'ro t ibody

t )

Existen tres operaciones bsicas que tendremos que llevar a cabo de forma repetida
en nuestra descripcin emergente:
Nov2

Google Uslng JQuery

ReyBango
,,..--.~'t,

1hIrd-party

1. Mostrar la descripcin emergente cuando el ratn est sobre el elemento interac-

tivo, .

Figura 7.23. Resultados para un autor determinado.

2. Ocultarlo cuando el ratn abandona el rea.

Si luego hacemos clic en John Resig en cualquiera de las celdas, se eliminar el resaltado de las filas de Rey Bango y se aadir a las de [ohn.

Descripciones emergentes
Aunque el resaltado de una fila podra ser una caracterstica de utilidad, hasta el
momento no es aparente para el usuario que la caracterstica exista. Podemos empezar
a remediar esta situacin al asignar a todas las celdas de autor una clase c1ickab1e,
a las que hemos aplicado estilo para cambiar el cursor del ratn a un puntero cuando
est dentro de la celda:
$ (documentl .ready(function()
{
var $authorCells
= $('table.striped
td:nth-child(3)
$authorCells
.addClass('clickable')
.click(function()
(
var authorName
= $(this) .text();
$authorCells.each(function(index)

');

3. Volver a posicionar la descripcin emergente cuando el ratn se mueve.


Escribiremos funciones para cada una de estas tareas primero, luego las uniremos a
eventos de navegador utilizando jQuery.
Empecemos con positionToo1
tip, al que haremos referencia cuando el ratn se
mueve sobre cualquiera de las celdas Author:
var

positionTooltip
= function (event)
var tPosX = event.pageX
var tPosY = event.pageY + 20;
$tooltip.css({top:
tPosY, left: tposX});

};

Aqu utilizamos las propiedades pageX y pageY del objeto event para establecer las
posiciones top y 1eft de la descripcin emergente. Cuando se invoca esta funcin en
respuesta a un evento de ratn, como mousemove, event .pageX y event. pageY nos
dar las coordenadas del cursor del ratn, por lo que tPosX y tPosY harn referencia
a una ubicacin de pantalla 20 pxeles por debajo del cursor del ratn.

BiIiI

7. Manipulacin

de tabla

Aprende jQuery 1.3

A continuacin necesitamos escribir nuestra funcin showTool t ip ( ) r para situar


la descripcin emergente en la pantalla.
var

showTooltip
= function(event)
(
var authorName
= $(this) .text();
$tooltip
.text('Highlight
all articles
by
.show() ;
positionTooltip(event)
;

.addClass('clickable')
.hover~showTooltip,
hideTooltip)
.mousemove(positionTooltip)
.click{function(event)
(
var authorName
= $(this) .t~t();
$authorCells.each(function(index)
{
if (authorName
== $(this) .text(
(
$(this) .parent() .toggleClass('highlight');

, + authorName)

};

La funcin showTool t ip () es bastante sencilla. Completamos los contenidos de la


descripcin emergente utilizando una cadena creada desde los contenidos de la celda
(que ser el nombre del autor) y lo mostrar.
Luego lo situamos en la ubicacin apropiada en la pgina con la funcin pos i t ionTooltip (). Puesto que la descripcin emergente se ha anexado al elemento body, necesitaremos algo de CSS para hacer que flote sobre la pgina en la ubicacin correcta:
#tooltip
(
position: absolute;
z-index: 2;
background:
#efd;
border: lpx solid #ccc;
padding:
3px;

Por ltimo, escribimos una sencilla funcin hideTooltip


var

lIiiI

el se (
$(this) .parent() .removeClass('highlight');
}

})

})

Observe que los argumentos para los mtodos . hover () y . mousemove () estn
haciendo referencia a funciones que estn definidas en alguna otra parte. Como tal, ornitimos los parntesis que seguiran a llamadas a las funciones. La descripcin emergente
ahora aparece cuando pasamos por encima de una celda autor, como muestra la figura
7.24, se mueve con el movimiento del ratn y desaparece cuando movemos el cursar
del ratn fuera de la celda.

():

hideTooltip
= function()
$tooltip.hide()
;

Figura

};

y ahora que tenemos funciones para mostrar, ocultar, y posicionar la descripcin


emergente, podemos hacerles referencia en los lugares apropiados en nuestro cdigo:

7.24. Descripcinemergente al pasar sobre celda de autor.

Un problema con nuestra implementacin actual es que la descripcin emergente


contina para sugerir hacer clic en una celda para resaltar los artculos incluso despus
de que esos artculos se han resaltado, como muestra la figura 7.25.

$ (document) .ready(function()
{
var $authorCells
= $('table.striped
td:nthchild(3)
');
var $tooltip
= $('<div id="tooltip"></div>')
.appendTo('body');
J\Jn 4

var positionTooltip
= function(event)
var tPosX = event.pageX
var tPosY = event.pageY + 20;
$tooltip.css({top:
tPosY, left: tPOSX});

Fab8

Wort(M1d.(~ntMarch

JQuery 12.3: AIR, Namespaclng,

Figura

};
var

jQuery 1.2.6: Events 100% rnster

~~rt.. jQlerrYI

showTooltip
= function(event)
(
var authorName
= $(this) .text();
$tooltip
.text('Highlight
all articles
by
.show () ;
positionTooltip(event)
;

};
var hideTooltip
= function()
$tooltip.hide()
;

};
$authorCells

, + authorName)

Jo~ Reslg
14.1~.,
800 UI Alpha

reIease

Rl~J'ftia~~~

'''~IHlghlight.

a.rticlu

by John Resig

Johi~eleiSStI'-_.J

7.25. La descripcinemergente sigue en pantalla.

Necesitamos una forma de cambiar el texto de la descripcin emergente si la fila tiene


la clase highlight.
Podemos realizar esto al situar una prueba condicional en la funcin showTool tip () para comprobar la presencia de la clase. Si el t r padre de la
celda actual tiene la clase highlight,
queremos utilizar la palabra Unhighlight en lugar
de Highlight cuando creamos la descripcin emergente:
var action = Highlight i
if ($(this) .parent() .is(' .highlight')
action = 'Unhighlight';
I

lElI

7. Manipulacin

}
$tooltip
.text(action
.show() ;

de tabla

all articles

Aprende jQuery 1.3

by

authorName)

Ahora la descripcin emergente ofrece una sugerencia ms inteligente cuando el puntero pasa por 'encima de una fila que ya est resaltada, como se ve en la figura 7.26.
28

Esto elige de forma correcta el texto de la descripcin emergente cuando el ratn entra
en una celda, pero tambin necesitamos volver a calcular la etiqueta en el momento en
que se hace clic en el ratn. Para ello, necesitamos invocar la funcin showTooltip ()
dentro del manejador de evento click:
$ (document) .ready(function()
{
var $authorCells
= $('table.striped
td:nth-child(3)
');
var $tooltip
= $('<div id=lItooltip"></div>')
.appendTo('body');
var positionTooltip
= function(event)
(
var tPosX = event.pageX;
var tPosY = event.pageY + 20;
$tooltip.css({top:
tPosY, left: tPOSX});
};
var

showTooltip
= function(event)
(
var authorName
= $(this) .text();
var action.=
'Highlight';
if ($(this) .parent() .is(' .highlight'))
action = 'Unhighlight' i

}
$tooltip
,text(action + ' all articles
.show () ;
positionTooltip(event)
;
};
var

by , + authorName)

hideTooltip
= function()
$tooltip. hide () ;

};
$authorCells
.addClass('clickable')
.hover(showTooltip,
hideTooltip)
.mousemove(positionTooltip)
.click(function(event)
(
var authorName
= $(this) .text();
$authorCells.each(function(index)
{
if (authorName
== $(this) .text()) (
$(this) .parent() .toggleClass('highlight');

}
el se (
$(this) .parent()

Aug31

jQuery

Ml~;;""3~!',l!~
Contera""" 2008 Agenda

~;~n~W;.~;
.~~~)5, R~l.k .!l.i!';c:ip,'!Q for)d~~,9'J'hf~'~~
j~114' ''J.ri~~~.y,
i5,'2
''''~7':\i>~:'_
;~'.

~:r

Ju'n 26,

jCiuery UI1.5, 1

Figura 7.26. Mejorar la descripcin emergente.

Contraer

expandir secciones

Cuando un amplio conjunto de datos se divide en secciones, puede resultar de utilidad ocultar informacin en la que no estamos interesados en el momento. En nuestra
tabla de artculos de noticias, las filas se agrupan por ao contraer, u ocultar, un ao
de artculos puede ser una forma conveniente de obtener un visin global de todos los
datos de la tabla sin tener que desplazarse demasiado.
Para que se puedan contraer las secciones de la tabla de artculos de noticias, primero
necesitamos crear un elemento de pgina que se utilizar para activar el comportamiento. Una interfaz estndar para elementos que se pueden contraer es un signo menos, con
un correspondiente signo ms para elementos que se pueden ampliar. Insertaremos el
icono con JavaScript, siguiendo las tcnicas de mejora progresiva.
$ (document) .ready(function()
{
var collapselcon = r../images/bullet_toggle_minus.pngr
var collapseText = rCollapse this section'
var expandlcon
= '.. /images/bullet_toggle-plus.png';
var expandText = rExpand this section' i
$('table.collapsible
tbody') .each(function()
var $section
= $(this);
$('<img />') .attr('srcr
collapselcon)
.attr('alt',
collapseText)
.prependTo($section.find('th'))
;
}) ;
I

});

.removeClass('highlight');

}
}) ;
ahowTooltip.call(thia,

EiD

event);

}l;
}l;

Al utilizarla funcin JavaScript call (), podemos invocar showTooltip () como si


se estuviera ejecutando dentro del mbito del manejador el ick de la celda con el nombre
del autor. Necesitamos hacer esto de modo que la palabra clave this haga referencia al
objeto correcto (esta celda de tabla) durante la ejecucin de showTooltip () .

Hemos almacenado las ubicaciones de los conos, as como sus representaciones


textuales alternativas, en variables al principio de la funcin. Esto nos permite hacerles
referencia fcilmente, y proporciona una forma sencilla de realizar cambios si fuera necesario. Hemos realizado la incorporacin de imagen en un bucle . each () , lo que demostrar ser adecuado ms adelante cuando necesitemos hacer referencia al elemento
t body de nuevo lo tendremos disponible por medio de la variable $section que
hemos definido aqu.
A continuacin, haremos que los iconos activen el contraer y expandir las filas. La
incorporacin de una clase clickable proporciona el feedback de usuario necesario,

lJIlI

7. Manipulacin

de tabla

y una clase en el elemento


en realidad visibles o no.

Aprende jQuery 1.3

t body

nos ayuda a mantener registro de si las filas estn

$ (document) .ready(function()
{
var collapselcon
= ' .. fimagesfbullet_toggle_minus.png';
var collapseText
= 'Collapse this section'
var expandlcon
= ' .. fimagesfbullet_toggle-plus.png';
var expandText
= tExpand this section'
$ ('table. collapsible
t body") .each (function ()
var $section
= $(this);
$('<img f,') .attr('src',
collapselcon)
.attr('alt',
collapseText)
.prependTo($section.find('th'))
.addClass('clickable')
.click(function()
{
if ($section.is(' .collapsed'))
$section.removeClass('col1apsed')
.find('tr:not(:has(th))
') .fadeln('fast');
$(this) .attr('src',
collapselcon)
.attr('alt',
collapseText);

}
else {
$section.addClass('collapsed')
.find('tr:not(:has(th))
') .fadeOut('fast');
$(this) .attr('src',
expandlcon)
.attr('alt',
expandText);

})

})

Cuando ocurre un clic, realizamos lo siguiente:


1. Aadir o eliminar la clase collapsed en el elemento e t.body, para mantener
registro del estado actual de la seccin de tabla.
2. Localizar todas las filas en el apartado que no contiene encabezados, y mostrar
u ocultadas utilizando una transicin de desvanecer.

Los artculos del 2007 no se han eliminado; simplemente se han ocultado hasta que
hacemos clic en el icono para expandir el apartado que ahora aparece en esa fila.

Las filas de tabla presentan ciertos obstculos a la animacin, ya que los navegadores
utilizan valores diferentes (t ab 1e - row y block) para su propiedad di sp 1ay visible,
Los mtodos . hide () y . show (), sin animacin, se pueden utilizar siempre con
filas de tabla. Si se desea animacin, . fadeln () y . fadeOut () se pueden utilizan
tambin .

Filtrado
Anteriormente hemos examinado ordenar y paginar como tcnicas para ayudar a los
usuarios a centrarse en partes relevantes de los datos de una tabla. Vemos que ambos
se pueden implementar con tecnologa del lado del servidor, o con JavaScript. El filtrado completa este arsenal de estrategias de organizacin de datos. Al mostrar al usuario
solamente las filas de tabla que coinciden con un criterio dado, podemos eliminar distracciones innecesarias.
Ya hemos visto cmo realizar un tipo de filtro: resaltar un conjunto de filas. Ahora
ampliaremos esta idea para ocultar filas que no coinciden con el filtro.
Podemos empezar creando un lugar donde situar nuestros vnculos de filtrado. En una
estrategia tpica de mejora progresiva, insertamos estos controles utilizando JavaScript
de modo que las personas sin programacin disponible no ven las opciones:
$ (document) .ready(function()
{
$('table.filterable')
.each(function()
var $table = $(this);
$table.find('th')
.each(function(column)
if ($ (this) .is (' .filter-column'))
{
var $filters
= $('cdiv
class="filters"></div>');
$ ('<h3,<fh3,')

3. Alternar el estado actual del icono, cambiando sus atributos src y al t para que
refleje la accin que se activar ahora cuando se hace clie.

.text('Filter
by , + $(this) .text()
.appendTo($filters)
;
$filters. insertBefore
($table) ;

Con este cdigo en su lugar, hacer clic en el icono para contraer este apartado junto
a 2007 hace que la tabla se parezca a la figura 7.27.
})
})
})

Figura

7.27. Contraer una seccin.

BII

+ ': ')

Obtenemos la etiqueta para el cuadro de filtro de la columna encabezados de


modo que este cdigo se puede volver a utilizar para otras tablas bastante fcilmente.
Ahora tenemos un encabezado a la espera de algunos botones, como se muestra en la
figura 7.28.

lIfI

7. Manipulacin

de tabla

Aprende jQuery 1.3

lID

accidentales debido a las propiedades de los cierres. Luego, en el manejador click,


comparamos los contenidos de cada celda contra la palabra clave y ocultamos la fila si
no hay coincidencia. Puesto que nuestro selector de fila excluye filas que contienen un
elemento t.h , no tenemos que preo:uparnos por que se oculten subencabezados.
Ambos vnculos ahora funcionan segn lo anunciado, como se ve en la figura 7.29.

Hoadllno

Headllne

Figura

Fllter

7.28. Preparar un filtro.

by Top.lc:

release

Opciones de filtro
Ahora podemos pasar a implementar un filtro. Para empezar, aadiremos filtros
para un par de temas conocidos. El cdigo para esto es bastante similar al ejemplo de
resaltar autor anterior:
Figura 7.29.

Incorporarfiltrospara temas conocidos.

$ (document) .ready(function()
(
$('table.filterable')
.each(function()
var $table = $(this);

Recopilar opciones de filtro del contenido


$table.find('th')
.each(function(column)
if ($(this).is('.filter-column'))
{
var $filters
= $('cdiv class=l'filters"></div>');
$ (, <h3></h3>')
.text ( ,Fil ter by , + $ (thi s) .text () + ':')
.appendTo($filters)
;

Ahora necesitamos ampliar las opciones de filtro para abordar el rango de temas
disponibles en la tabla. En lugar de incorporar en el cdigo todos los temas, podemos
recopilarlos del texto que se ha incorporado en la tabla. Podemos cambiar la definicin
de keywords para que sea:

var keywords
= ['conference',
'release'] i
$.each(keywords,
function(index,
keyword)
{
$('<div class=tlfilter"></div>')
,text(keyword)
.bind('click',
{key: keyword},
function(event)
(
$('tr:not(:has(th))',
$table) .each(function()
{
var value = $('td', this) .eq(column) .text();
if (value == event.data['key'])
{
$ (thi s) .show () ;

}
;

$(this) .addClass('active')
.siblings() .removeClass(lactive');
}) .addClass('clickable')
.appendTo($filters)

keywords[$(this)

+ (column
.text()]

+ 1) + ') ')

$(this) .text();

});

Este cdigo se basa en dos trucos:


1. Al utilizar un mapa en lugar de una tabla para albergar las palabras clave a medida
que se encuentran, eliminamos duplicados automticamente; cada clave puede
tener solamente un valor, y las claves son siempre nicas.

else (
$ (this) .hide () ;

})

var keywords
= {};
$table.find('td:nth-child('
.each(function()
(

2. La funcin $ . each () de jQuery nos permite trabajar sobre tablas y mapas de


forma idntica, por lo que el cdigo siguiente no tiene que cambiar .
;

});

$filters.insertBefore($table);

Ahora tenemos un complemento completo de opciones de filtro, como muestra la


figura 7.30.

}
})

}l;
})

Empezando con una tabla esttica de palabras clave por las que filtrar, pasamos en
bucle por ellas y creamos un vnculo de filtrado para cada una. Como con en el ejemplo
de paginado, necesitamos utilizar el parmetro data de . bind () para evitar problemas

Invertir los filtros


Para un mayor nivel de detalle, necesitamos una forma de regresar a la lista completa despus de haberla filtrado. Aadir una opcin para todos los temas es bastante
sencillo:

mi

l'
,,

7. Manipulacin de tabla

$('<div class=lIfilter">all</div>')
.click(function()
$table.find('tbody
tr') .show();
$(this) .addClass('active')
.siblings() .removeClass('active');
}) .addClass('clickable
active') .appendTo($filters);

Aprende jQuery 1.3

lID

Alternar color de fila

Filler by Tople:

oonference
announoement
reieeee

plug-ln
standanls
documenlalion
MOIIal

El aplicar, color de fila alterno avanzado que hemos incorporado anteriormente se


confunde por nuestros nuevos filtroszl'uesto que no se vuelve a aplicar el color alterno
de fila despus de llevar a cabo un filtro, las filas mantienen su color como si las filas
filtradas siguieran presentes.
Para tener en cuenta las filas filtradas, el cdigo de filas de colores alternos necesita
poder encontrarlas. La pseudo-clase jQuery : visible puede ayudamos al recopilar el
conjunto correcto de filas a aplicar color alterno.
Mientras realizamos este cambio, podemos preparar nuestro cdigo de filas alternas que se va invocar desde otros lugares al crear un tipo de evento personalizado para
ello, como hicimos cuando hicimos que ordenacin y paginacin funcionaran conjuntamente.

mlscellaneous
souroe

Figura 7.30. Ampliar las opciones de filtro.

Esto nos proporciona un vnculo ali que simplemente muestra todas las filas de la
tabla, como se ve en la figura 7.31. Este nuevo vnculo se marca como act i ve para em-.
pezar.

$ (document) .ready(function()
(
$('table.striped')
.bind('stripe',
function()
$('tbody',
this) .each(function()
(
$(this) .find('tr:visible:not(:has(th
.removeClass('odd')
.addClass('even')
.filter(function(index)
{
return
(index % 6) < 3;
}) .removeClass('even')
.addClass('odd');

{
')

}) .trigger('stripe');

}),
Headllne

Filler by Tople:

En nuestro cdigo de filtrado, ahora podemos invocar $table .trigger ( stripe' )


cada vez que .ocurre una operacin de filtrado. Con el nuevo manejador de evento y sus
activadores en su lugar, la operacin de filtrado respecta el color alterno de fila, como
se ve en la figura 7.32.
I

thlrd-party
oonference
announoement

nlleasa
plug~n
standards
documentstl,on
tutotial

Headllne

ea

Filler by Tople:

11; 2008
all

mlscenaneous

thlrd-party

source

conference
announcement
M

Figura 7.31. Posibilidad de regresar a la lista completa.

',Jn~4

Interactuar con otro cdigo

&:;:;::.:;:~_>

~~il
F~8

pI~n
,l

~.~

standards.

documentaBon
Morlal
mlscellaneous

Hemos aprendido con nuestro cdigo de ordenar y paginar que no podemos tratar
las diferentes caractersticas que escribimos como islas. Los comportamientos que creamos pueden interactuar en formas algunas veces sorprendentes; por esta razn, merece
la pena volver a visitar nuestros esfuerzos anteriores para examinar cmo coexisten con
las nuevas posibilidades de filtrado que hemos aadido.

sourca

Figura 7.32. Tener en cuenta el color de fila alterno.

EDil

7. Manipulacin

~-

de tabla

Aprende jQuery 1.3

r.

Expandir y contraer

var

El comportamiento de expandir y contraer aadido anteriormente tambin entra en


conflictocon nuestros filtros. Si una seccin se contrae y se elige un nuevo filtro, entonces
los elementos coincidentes se muestran, incluso si estn en la seccin contrada. Por el
contrario, si la tabla se filtra y se expande una seccin, entonces todos los elementos en
la seccin expandida se muestran con independencia de si coinciden o no con el filtro.
Una forma de abordar la ltima situacin es cambiar la forma en que mostramos y
ocultamos filas. Si utilizamos una clase para indicar que se debera ocultar una fila, no
necesitamos invocar explcitamente. hide () y . show ( ) . Al reemplazar. hide () con
.addClass (' filtered')
y. show() con. removeClass ( ' f i Lt.er-ad ' ) .junto con
una regla CSSpara la clase, podemos llevar a cabo el ocultar y mostrar, pero trabajamos
mejor con el cdigo que se contrae. Si se elimina la clase y la fila se contrae, la fila no se
mostrar sin darse cuenta.
Introducir esta nueva clase filtered
tambin nos ayuda con el problema contrario. Podemos comprobar la presencia de filtered
cuando llevamos a cabo una ampliacin de seccin, saltando estas filas en lugar de mostrndolas. Comp.robar esta clase
es una sencilla cuestin de aadir: not ( . filtered)
a la expresin selector utilizada
durante la expansin.
Ahora nuestras caractersticas funcionan bien, cada una pudiendo ocultar y mostrar
las filas independientemente.

showTooltip
= function(event)
{
var aut'horName = $ (this) .text () ,
var ac~ion = 'Highlight' i
if ($ (this).parent () .is (, .hi9lVight'
action = lUnhighlight';

}
$tooltip
.text(action + ' all articles
.show() ,
positionTooltip(event)
,

$authorCells
.addClass('clickable')
.hover(showTooltip,
hideTooltip)
.mousemove(positionTooltip)
.click(function(event)
(
var authorName
= $(this) .text(),
$authorCells.each(function(index)
{
if (authorName
== $(this) .text(
(
$(this) .parent() .toggleclass('highlight'),

}
(

showTooltip.call(this,

$ (document) .ready(function()
(
$('table.striped')
.bind('stripe',
function()
{
$('tbody',
this) .each(function()
(
$(this) .find('tr:visible:not(:has(th
')
.removeClass(rodd')
.addClass('even')
.filter(function(index)
{
return
(index % 6) < 3,
}) .removeClass ('even' l addClass ('odd' ) ,

j),
}) .trigger('stripe'),

$ (document) .ready(function()
{
var $authorCells
= $('table.striped
td:nth-child(3)
'),
var $tooltip
= $('<div id="tooltip"></div>')
.appendTo('body'),
var positionTooltip
= function(event)
var tPosX = event.pageX

event

$tooltip.css({top:

,pageY

tPosY,

.removeClass('highlight'),

}
}),

Nuestra segundo ejemplo ha demostrado alternar color de fila, resaltar, descripciones emergentes, contraer/expandir, y filtrado. Tomadas juntas, el cdigo JavaScript
para esta pgina es:

tPosY,

authorName)

hideTooltip
= function()
$tooltip.hide()
,

El cdigo terminado

var

};

$(this) .parent()

},
var

else

})

by

20

left:

tPosX}),

event),

}),
}),
$ (document)

.ready(function()

var collapselcon
= '../images/bullet_toggle_minus.png',
var collapseText = 'Collapse this section' i
var expandlcon
= '../images/bullet_toggle-plus.png',
var expandText = 'Expand this section'
$('table.collapsible
tbody') .each(function()
var $section
= $(this),
$('<img />') .attr('src',
collapselcon)
.attr('alt',
collapseText)
.prependTo($section.find('th'
.addClass('clickable')
.click(function()
{
if ($section.is('
.collapsed'
(
$section.removeClass('collapsed')
.find('tr:not(:has(th
:not(.filtered)
.fadeln('fast')
,
$(this) .attr('src',
collapselcon)
.attr('alt',
collapseText),
el se (
$section.addClass('collapsed')
.find('tr:not(:has(th

')

')

BfI

mi

7. Manipulacin

de tabla

.fadeOut('fast',
function()
(
$(this).css('display',
"norie
}) ;

L,

En este captulo, hemos explorado ,illgunas de las formas de descomponer y analizar


tablas en nuestros sitios, reconfigurnClolas en contenedores funcionales para nuestros
datos. Hemos tra tado ordenar datos en tablas, utilizando diferentes tipos de datos (palabras, nmeros, fechas) junto con paginar tablas en bloques que se vean fcilmente. Hemos
aprendido sofisticadas tcnicas de alternar el color de filas y descripciones emergentes
gracias a JavaScript. Tambin hemos examinado cmo expandir y contraer contenido al
.igual que filtrar y resaltar filas que coinciden con los criterios facilitados.
,r
Hemos incluso tratado brevemente algunos temas bastante avanzados, como ordenar y paginar con cdigo del lado del servidor y tcnicas AJAX, calcular dinrnicamente
coordenadas de pgina para elementos, y escribir un plug-in jQuery.
Como hemos visto, lastablas HTML engloban una gran cantidad de sutilizas y complejidad en un pequeo paquete. Afortunadamente, jQuery puede ayudamos a domar
fcilmente a estas criaturas, permitiendo que salga a la superficie el verdadero potencial
de los datos tabulares.

}
})
})
})

.trigger('stripe');

$ (document) .ready(function()
(
$('table.filterable')
.each(function()
var $table = $(this);
$table.find('th')
.each(function(column)
if ($(this).is('.filter-column'))
var $filters
$ (, <h3></h3>')

$('cdiv

class="filterslI></div>')

.text ('Filter by , + $ (this) .text () + ':')


.appendTo($filters);
$('cdiv class="filter">allc/div>')
,click(function()
$table. find ('tbody t r
removeClass ('filtered')
$(this) .addClass('active')
.siblings() .removeClass('active')
i
$table.trigger('stripe')
;
i

}) .addClass('clickable
var keywords

active')

.appendTo($filters);

{};

$table.find('td:nth-child('
.each(function()
(
keywords

(column

1) + ') ')

[$ (this) .text ()1 = $ (this) .text () ;

});

$.each(keywords,
function(index,
$('cdiv
class="filterrr></div>')

keyword)
{
.text(keyword)

.bind('click',
{key: keyword},
function(event)
(
$('tr:not(:has(th))',
$table) .each(function()
{
var value = $('td', this) .eq(column) .text();
if (value == event.data['key'l)
(
$(this) .removeClass('filtered');
}
else (
$(this)

.addClass('filtered');

$(this) .addClass('active')
.siblings() .removeClass{'active') i
$table.trigger(/stripe')
;
}) .addClass ('clickable')
.appendTo ($filters)
}) ;
$filters.insertBefore($table)
}

})
})
})

lJJlI

Resumen

$(this) .attr('src',
expandlcon)
.attr('alt', expandText);
$section.parent()

Aprende jQuery 1.3

..

8
Formularios
con funciones
-

"

.'\

Casi todo sitio Web que requiera informacin por parte del usuario emplear un
formulario en una forma u otra. A lo largo de la vida de Internet, los formularios han
desempeado el rol de mula de carga, llevando informacin desde el usuario final de
vuelta al editor del sitio Web, de forma fiable, pero con muy poca gracia o estilo. Quiz
esta ausencia de estilo ha sido causada por el repetido y arduo viaje al servidor y vuelta; o quiz tena que ver con los elementos inflexibles con los que el formulario tena
que trabajar y su falta de deseo de seguir la ltima moda. Cualquiera que sea la razn,
no ha sido hasta recientemente, con el resurgimiento de la programacin del lado del
cliente, que los formularios han encontrado nuevo vigor, propsito y estilo. En este captulo, examinaremos formas en las que podemos infundir nueva vida a los formularios.
Mejoraremos su estilo, crearemos rutinas de validacin, los utilizaremos para clculos,
y enviaremos sus resultados al servidor mientras nadie mira.

Mejorar un formulario bsico


Igual que aplicamos jQuery a sitios Web, siempre debemos preguntamos cmo se
vern y funcionarn las pginas cuando JavaScript no se encuentra disponible para
nuestros visitantes (a menos, por supuesto, que sepamos exactamente quines sern los
visitantes y cmo estarn configurados sus navegadores). Sin embargo, esto no quiere
decir que no podamos crear un sitio ms atractivo y ms completo para visitantes con
JavaScript activado. El principio de mejora progresiva es popular entre los desarrolladores JavaScript porque respeta las necesidades de todos los usuarios mientras proporciona

ED

Aprende jQuery 1.3

8. Formularios con funciones

mi

c::/li>

algo adicional a la mayora de ellos. Para demostrar mejora progresiva con respecto a
formularios, crearemos un formulario de contacto que podemos mejorar tanto en apariencia como comportamiento utilizando jQuery.

c::li>

<label for=1I1ast-namell>Last
Namec::/label>
< in~ut
clase=," required
type= text" name= IIlast
.
~d="la9t-namel~ ..,/>
<span> (required) c::/span>
ti

ti

-name 11

</li>

Estilo de formulario mejorado de forma progresiva

c::li>How would

you

like

to be contacted?

(choose at least one methodl

En primer lugar, realicemos algunas modificaciones estticas a nuestro formulario.


Sin JavaScript activado, el primer conjunto de campos del formulario se muestra como
se ve en la figura 8.1.
PenIonalln
Fln51Neme

Laal Neme

I(requlnld)

19 by Phcne
9byFex

I
I

I(requlnld
_J (requlnld

for=l1by-emaill1>

<input type=l1checkbox"
name=l1by-contact-typell
value=I1E-maill1
id=l1by-emaill1 />

by E-Mail
</label>

j(raqulnld)

<input

class=l1conditional"
type=lItext"
name=lIemail"
id=l1email"
/>
<span>(required
when corresponding
checkbox

How would you Ilke lo be oontacted'l (choose 81lees! one meIhod)

9 by E.Mell

,.'

<ul>
<li>
<label

when correspondlng checl<box checked)


when co"""pondlng

(requlnld when correspondlng

checl<box checked) "

checkedl</span>
</lb

checkboX checkea)

<li>
<label

for=lIby-phonell>

<input

Figura 8.1. Conjunto de campos de formulario.

Aunque ciertamente parece funcional y contiene numerosa informacin para guiar


al usuario por cada uno de los campos, definitivamente podra aceptar cierta mejora.
Mejoraremos progresivamente este grupo de tres formas:
1. Modificar el DOM para permitir aplicar estilo flexible a' degend>.
2. Cambiar el mensaje de campo obligatorio (required) por un asterisco (") y el
mensaje de campo especial (required only when the corresponding checkbox is
checked, u obligatorio slo cuando la casilla de verificacin correspondiente est
seleccionada) a un asterisco doble ("").Poner en negrita la etiqueta para cada campo
obligatorio y situar una clave en la parte superior del formulario que explique lo
que significa el asterisco sencillo y doble.
3. Ocultar la entrada de texto correspondiente de cada casilla de verificacin al cargarse la pgina, y luego alternarlo, visible y oculto, cuando el usuario selecciona
o deselecciona las casillas.
Empezamos con el HTML de <fieldset>:
<fieldset>

<legend>personal

Info</legend>

<01>

<li>
c::label for="first-nametl>First
Namec::/label>
<input c Las s e vr'equd r'ed" type=lItext"
name="first-name

11

id=lIfirst-name"

<span> (required) </span>

/>

type="checkbox"

name="by-contact-type"
/>

value= 11 Phone" id=lIby-phone"


by Phone
</label>
<input

class="conditional"

type="text

id="phone" />
<span> (required when corresponding
checkedl</span>
</lb

lt

name=lIphone"

checkbox

<-li>
<label

for="by-fax">

<input
type="checkboxlI
name=lIby-contact-type"
value=IIFax"
id="by-fax"
/>

by Fax
</label>
<input

class="conditional"
type=lItext"
name="fax"
id=lIfaxlI />
<span>(required
when corresponding
checkbox

checkedl</span>
</li>
</ul>
</li>
</01>
</fieldset>

Una cosa a destacar aqu es que cada elemento de pares de elementos se considera
un elemento de lista (db).
Todos los elementos se sitan dentro de una lista ordenada 01, y las casillas de verificacin (junto con sus campos de texto) se sitan dentro de una lista sin ordenar anidada (eu l ), Adems, utilizamos el elemento Labe I.
para indicar el nombre de cada campo. Para los campos de texto, Labe L precede a
<input>; para casillas de verificacin, engloba <input>. Aunque no existe estructura

mil

8. Formularios con funciones

Aprende jQuery 1.3

de elemento "estndar" para elementos dentro de un conjunto de campos, la lista ordenada parece ser lo ms parecido a cualquier cosa que represente el significado semntico
de los elementos en un formulario de contacto.
Con nuestro HTML en su lugar, estamos listos para utilizar jQuery para la mejora
progresiva.

Un enfoque alternativo que mantiene los elementos <1eqerid intactos implica situar
sus contenidos en una etiqueta e span:
$ (document) :!ready(function () (
$('legend') .wraplnner(l<span></s~an>');
}) ;

Situar un <span> dentro de <legend> tiene al menos dos ventajas frente a reemplazar <Le qerid con un <h3 >: mantiene el significado semntico de <legend> para
lectores de pantalla con soporte ]avaScript y requiere menos trabajo en la parte del script.
La desventaja es que hace que el estilo del encabezado sea un poco ms difcil de lograr.
Al menos, tenemos que establecer la propiedad position
de <fieldset>
y e spans.,
as como el padding-top
del f e Lds et; y el width de <span>:

La leyenda
La leyenda del formulario es un elemento muy difcil de aplicar estilo con CSS.
Las inconsistencias de navegador y las limitaciones de posicionamiento hacen que trabajar con ello sea un ejercicio de frustracin. An as, si nos preocupa utilizar elementos de pgina significativos, y bien estructurados, la leyenda es una eleccin atractiva,
si no visualmente llamativa, para mostrar un ttulo en el <fieldset
> de nuestro formulario.
Solos con HTML y CSS, estamos obligados a comprometer la eleccin de cdigo semntico o diseo flexible. Sin embargo, podemos cambiar el HTML cuando se carga la
pgina, convirtiendo cada <Leqerid en un <h3> para las personas qllevisualizan la
pgina, aunque las mquinas que leen la pgina, y aquellos con ]avaScript disponible,
siguen viendo <legend>. Esto se puede realizar de forma sencilla utilizando el mtodo
. replacewi th () de jQuery:
$ (document) .ready(function()
(
$('legend')
.each(function(index)
$(this) .replaceWith('<h3>'

(
+ $(this)

.text()

fieldset
{
position: relative
padding-top:
1.5em;

legend span (
position: absolute
width:
100%;

Si elegimos reemplazar los elementos <Leqerid del formulario o insertar un <span s


en ellos, tienen suficiente estilo para nuestros fines, es el momento de limpiar los mensajes de campo obligatorio.

'</h3>');

}l;

Observe aqu que no podemos basamos en la iteracin implcita de jQuery. Con cada
elemento que reemplazamos, necesitamos insertar los contenidos de texto nicos de ese
elemento. Para esto nos basamos en el mtodo. each ( ) , que nos permite dirigimos al
texto determinado con $ (thi s) .
Ahora, cuando aplicamos un fondo azul y color de texto blanco a <h3> en la hoja
de estilo, el primer conjunto de campos del formulario se parece lo'que muestra la figura 8.2.
Personal Info
FlmI Name [
Las! Name

(mqulred)

Haw would yoo IIko lo be con1Dclec!? (oooose SI laest ene method)

El by Phone

!!I by

Fax

:::J
::J
.__ ::J

(mqulred when correspondlng 00_

En nuestro formulario de contacto, los campos obligatorios tienen class=" required"


para permitir aplicar estilo al igual que respuesta a la entrada del usuario; los campos de
entrada de datos para cada tipo de contacto tienen aplicado class=" condi t ona l''.
Vamos a utilizar estas clases para cambiar las instrucciones impresas dentro del parntesis a la derecha de cada entrada de datos.
Empezamos por establecer variables para requiredFlag
y conditionalFlag,
y
luego completamos el elemento span s junto a cada campo obligatorio y condicional
con el texto almacenado en esas variables:

$ (document) .ready(function()
{
var requiredFlag = ' * ';
var conditionalFlag
=
**

I(mqulred)

El by E-MaIl

Mensajes de campo obligatorio

OOeeked)

$ ( 'form

l.

:input' )

.filter('.required')
.next('span')
.text(requiredFlag)
.end ()

(requlred when correspondlng cheekbox OOeeked)


(mqulred when correspondlng chocldlox cheeked)

.filter('.conditional')

Figura 8.2. Aplicar estilo al primer conjunto de campos de formulario.

.next('span')
})

.text(conditionalFlag);

.end()

DI

Aprende jQuery 1.3

8. Formularios con funciones

Utilizar . end () nos permite ampliar la cadena de mtodos de modo que continuamos
trabajando con el mismo conjunto de elementos y mantenemos la creacin de objetos al
mnimo. Todo mtodo . end () devuelve la seleccin un paso hacia atrs, volviendo el
conjunto coincidente de elementos a lo que era antes del ltimo mtodo transversal Aqu
utilizamos dos en una fila: el primer . end () revierte el conjunto coincidente a . f i 1ter ( , . required'
) y el segundo lo revierte a $ ( , form : input' ) . De esta forma, cuando . fi1ter
( , . conditiona1'
) selecciona elementos con c l as s "condi tiona1",
se aplica a todas las entradas de datos dentro del formulario. Ahora, puesto que un solo
asterisco (*) puede no captar inmediatamente la atencin del usuario, tambin aadiremos c1ass=" req-1abe1"
a Labe l para cada campo obligatorio y aplicaremos
font -weight :bo1d a esa clase. Para ello, podemos ampliar an ms la cadena.

$ (document) .ready(function()
var requiredFlag = ' * ';
var conditlonalFlag
= ' .*

'i

var requiledKey = $('input.required:first')


.next('span
.text(); ~,
var conditlonalKey
= $ ('input.conditional:first')
.next(lspanl) .text{)
l)

requiredKey = requiredFlag +
requiredKey.replace(/'\(.+)\)$/,
'$1');
conditionalKey
= conditionalFlag
+
conditionalKey.replace(/'\((.+}\)$/,
'$1');
//

$ (document) .ready(function()
var requiredFlag =
* ,.
var conditionalFlag

mi

cdigo

contina

j);

$ ( 'form :input' )
.filter(' .required')
.next('span') .text(requiredFlag)
.end()
.prev('label').addClass('req-label').end()
.end ()
.filter(' .conditional')
.next('span') .text(conditionalFlag);

"

Una cadena tan larga de mtodos puede ser difcil de seguir, por lo que un salto de
lnea consistente y un patrn de sangrando es esencial. El conjunto de campos con el
texto modificado y la clase aadida ahora se parece a la figura 8.3.
Personal

Info

FI t Horno

c=------n-

_n-=.J
o

:::oJo

LatNlIML

How would yoo Ilke ID be ccn1acIDd7 (clloose al leas! one mothod)


by E-Mail

1-

El byPhono

1-

El by Fax

1-

E!I

Figura

8.3. Conjuntode campos mejorado.

No del todo mal. Los mensajes de campo obligatorio y condicional no eran en realidad tan malos despus de todo; simplemente eran demasiado repetitivos. Tomemos la
primera instancia de cada mensaje y mostrmoslo por encima del formulario junto a la
indicacin que estamos utilizando para simbolizarlo.
Antes de completar los elementos < span que albergan los mensajes con sus indicaciones respectivas, necesitamos almacenar los mensajes iniciales en un par de variables.
Luego podemos quitar los parntesis al utilizar una expresin regular:

Las dos primeras lneas adicionales declaran variables (requiredKey


y conditiona1Key) para almacenar el texto de cada tipo de campo. Las segundas dos lneas
modifican el texto en esas variables, concatenando cada indicador, y su texto respectivo,
menos el parntesis. Quiz la expresin regular, junto con su mtodo . rep1ace () ,
merece una explicacin ms detallada .
Un parntesis sobre la expresin regular
La expresin regular se encuentra dentro de dos barras inclinadas y se parece a esto:
+) \) $ /. El primer carcter,
indica que lo que sigue necesita aparecer al principio de la cadena. Est seguido por dos caracteres, \ {,que buscan un parntesis de inicio.
La barra invertida escapa el carcter que sigue, dicindole al analizador de la expresin
regular que lo trate literalmente. Esto es necesario porque los parntesis estn entre los
caracteres que tienen significado especial en expresiones regulares, como veremos a
continuacin. Los siguientes cuatro caracteres, (. + ) , buscan uno o ms caracteres (representado por +) de cualquier tipo dentro de la misma lnea (representado por.) y los
sitan en un grupo por el uso de los parntesis. Los ltimos tres caracteres, \) s, buscan
un parntesis de cierre al final de la cadena. Por lo tanto, todo junto, la expresin regular
est seleccionado un parntesis de inicio, seguido por un grupo de caracteres, y termina
con un parntesis de cierre. El mtodo. rep1ace () busca dentro de un contexto determinado una cadena representada por una expresin regular y lo reemplaza con otra
cadena. La sintaxis se parece a esto:
/

A \

A,

'context'.replace(/regular-expression/,

'replacement')

Las cadenas de contexto de nuestros dos mtodos. replace () son las variables requiredKey y condi tiona1Key. Ya hemos examinado la parte de expresin regular de
esto, contenida dentro de dos barras inclinadas. Una coma separa la expresin regular
y la cadena de sustitucin, que en nuestros dos casos es '$1 El marcador de posicin
$1 representa el primer grupo en la expresin regular. Nuevamente, puesto que nuestra expresin regular tiene un grupo de uno o ms caracteres, con un parntesis en cada
lado, la cadena de sustitucin estar todo dentro de, y no incluidos, los parntesis.
I

T_
,

mil

8. Formularios con funciones

Aprende jQuery 1.3

Insertar la leyenda del mensaje del campo

mi

ocultarlas, junto con sus indicaciones correspondientes, cuando el documento se carga


inicialmente:.
.

Ahora que hemos recuperado los mensajes del campo sin los parntesis, podemos
insertarlos, junto con sus indicaciones correspondientes, por encima del formulario:

$ (document) .ready(function()
(
$ (,input: condi tional ') .next (,spa'l') .andSelf ().hide ();

})

$ (document) .ready(function()
(
var requiredFlag =
* ';
var conditionalFlag
= ' ** '

var requiredKey = $('input.required:first')


.next (,span ') .text ();
var conditionalKey = $('input.conditional:first')
.next(lspan') .text() i
requiredKey = requiredFlag +
requiredKey.replace(/A\.+)\)$/,
'$1');
conditionalKey
= conditionalFlag +
conditionalKey.replace(/A\.+)\)$/,
'$1');
$('<p></p>')
.addClass('field-keys')
.append(requiredKey
+ '<br />')
.append(conditionalKey)
.insertBefore('#contact'l;

})

P.rsonallnfo
flrstNama
L.aI1Namo

r.=.:::

1-

1-

How wouid you IIke lo be oonIBcIed'I (choose alleast one molhod)

I!J by E-Mail

.'

[_n_

-- HJ"

J"

I!i! by Phone

lB by Fax

L__

==:::J"

Figura 8.4. Mejorar la leyenda de los campos .

Las cinco nuevas lneas le deberan ser relativamente familiares ahora. Aqu tiene lo
que hacen:
1. Crear un nuevo elemento de prrafo.
2. Asignar al prrafo una clase de field-keys.
3. Anexar requiredKey

y un salto de lnea al prrafo.

4. Anexar condi tionalKey

al prrafo.

5. Insertar el prrafo y todo lo que hemos anexado dentro de l delante del formulario
de contacto.
Cuando se utiliza. append () con una cadena HTML, como hacemos aqu, tenemos
que tener cuidado que cualquier carcter HTML especial se escape adecuadamente. En
este caso, el mtodo . text () que hemos utilizado cuando declaramos las variables ha
hecho esto por nosotros. Cuando definimos algunos estilos para. field-keys
en la
hoja de estilo, el resultado se parece a lo que aparece en la figura 8.4.
Nuestro trabajo jQuery para el primer conjunto de campos est casi completo.

Campos mostrados condicionalmente


Mejoremos an ms el grupo de campos que piden a los visitantes cmo les gustara que se les contactara. Puesto que las entradas de texto se tienen que incorporar solamente si sus casillas de verificacin correspondientes estn seleccionadas, podemos

El conjunto de campos ahora tiene su interfaz modernizada, como muestra la siguiente figura:
- ------------_._----

Personal Info
fl .1
L.aI1

N.",. [-----------JN.",. I
1-

How wouId you IIke lo be conIacIed'I (choooe al leas! one melhod)

!!! by

E-Mail

8byPhone
8byFax

Figura 8.5. Interfaz modernizada.

Para hacer que aparezcan los campos de entrada de texto y las indicaciones, anexamos el mtodo. click () a cada casilla de verificacin. Haremos esto dentro del contexto de cada entrada de texto condicional de modo que podamos establecer un par de
variables para reutilizacin:
$ (document) .ready(function()
(
$('input.conditional') .next('span') .andSelf() .hide()
.end() .end()
.each(function()
{
var $thisInput = $(this);
var $thisFlag = $thisInput.next('span');
$thisInput.prev('label').find(':checkbox')

&IiI

Aprende jQuery 1.3

8. Formularios con funciones

$thislnput.show()
;
$~hisFlag.show()
;
$(this) .parent('label')

.click(function()
{
// cdigo contina
}) ;
})
})

.,

Aqu nuevamente hacemos uso de dos mtodos . end ( ) , esta vez de modo que podamos anexar el mtodo. each () al selector $ ( , input. condi tional ' ) original.
Ahora tenemos una variable para la entrada de texto actual y el indicador actual.
Cuando el usuario hace clic en la casilla de verificacin, vemos si est seleccionada;
si es as, mostramos la entrada de texto, mostramos la indicacin, y aadimos la clase
req-label
al elemento Labe L padre:
$ (document) .ready(function()
(
$('input.conditional')
.next('span')
.andSelf() .hide()
.end () .end ()
.each(function()
(
var $thislnput
= $(this);
var $thisFlag
= $thislnput.next('span');
$thislnput. prev ('label ') .find (, .checkbox ')
.click(function()
{
if (thia.checked)
{
$thislnput.ahow();
$thisFlag.show();
$(this) .parent('label')
.addClass('req-labe1');

"

Para comprobar si hay una casilla seleccionada aqu, se prefiere thi s . checked porque tenemos acceso directo al nodo DOM va la palabra clave this. Cuando el nodo
DOM no est accesible, podemos utilizar $ ( , selector'
) . is ( , : checked ") en su
lugar, ya que. is () devuelve un booleano (true o false).
Nos quedan por hacer dos cosas:
1. Aseguramos de que las casillas de verificacin no estn seleccionadas cuando la
pgina se carga inicialmente, ya que algunos navegadores mantendrn el estado
de elementos de formulario al refrescarse la pgina.
2. Aadir una condicin else que oculta los elementos condicionales y elimina la
clase req-label
cuando la casilla de verificacin no est seleccionada.
$ (document) .ready(function()
(
$ ('input.conditiona1')
.next('span')
.andSelf() .hide()
.end() .end()
.each(function()
(
var $thislnput
= $(this);
var $thisF1ag
= $thislnput.next('span');
$thislnput. prev (,label' ) .find (,,checkbox' )
.attr('checked',
falae)
.click(function()
{
if (this.checked)
(

})
})

y esto concluye la parte de estilo de esta transformacin de formulario. A continuacin, aadiremos algo de validacin del lado del cliente.

- Validacin de formulario

})
})

.addClass('req-label');

e11'e {
$thislnput. hide () ; .
$thisFlag.hide();
$(this) .parent('labe1')
,removeClass('req-label');

&11

Antes de aadir validacin a cualquier formulario con jQuery, necesitamos recordar


una regla importante: la validacin del lado del cliente no es sustituto para validacin
del lado del servidor.
Nuevamente, no podemos basamos en que los usuarios tengan JavaScript activado.
Si realmente necesitamos que se incorporen ciertos campos, o que se incorporen en un
formato determinado, JavaScript slo no puede garantizar el resultado que demandamos.
Algunos usuarios prefieren no activar JavaScript, algunos dispositivos simplemente no
lo soportan, y algunos usuarios pueden de manera intencionada enviar datos maliciosos
al eludir las restricciones JavaScript.
Por qu entonces preocuparse por implementar validacin con jQuery? La validacin
de formulario del lado del cliente utilizando jQuery puede ofrecer una ventaja frente
a la validacin del lado del servidor: feedback inmediato. El cdigo del lado del servidor, tanto si es ASP, PHP, o cualquier otro acrnimo, necesita que la pgina se vuelva
a cargar para surtir efecto (a menos que se acceda asncronamente, por supuesto, que
en cualquier caso requiere JavaScript). Con jQuery, podemos sacar provecho de la rpida respuesta del lado del cliente al aplicar validacin a cada campo obligatorio cuando
pierde foco (en blur), o cuando se pulsa una tecla (en keyup).

Campos obligatorios
Para nuestro formulario de contacto, comprobaremos la presencia de la clase required en cada entrada de datos cuando el usuario entra o sale de cada entrada de datos.
Antes de empezar con este cdigo, sin embargo, deberamos regresar a nuestros campos
de texto condicionales. Para simplificar nuestra rutina de validacin, podemos aadir la
clase required
al <input> cuando se muestra, y eliminar la clase cuando el <input>
posteriormente se oculta. Esta parte del cdigo ahora se parece a esto:
$thislnput.prev('label')
.find(' ,checkbox')
.attr('checked',
false)
.click(function()
{
if (this.checked)
{

&!I

8. Formularios con funciones

Aprende jQuery 1.3

$thislnput.show()
.addClass('required');
$thisFlag.show()
,
$(this) .parent('label')
.addClass('req-label'),
else (
$thislnput.hide()
.removaClass('required');
$thisFlag.hidel)
,
$(this) .parentl'label')
.removeClassl'req-label'),

&El

$('<span></span>')
.addClass('error-message')
.text(errorMessage}
r . appendTo($listltem)
;
$listltem.addClass('war~ng')'
}

})

j),

})

Con las clases required en su lugar, estamos listos para responder cuando el usuario deja uno de estos campos vacos. Se situar un mensaje detrs del indicador obligatorio, y el elemento <1i > del campo recibir estilos para alertar al usuario por medio
de class="warning":

Nuestro cdigo funciona bien la primera vez que el usuario deja un campo en blanco;
.' sin embargo, dos problemas con el cdigo son evidentes cuando el usuario entra y deja
( ms tarde el campo, como se muestra en la figura 8.6.
Personallnfo

$ (document) .ready(function()
{
$('form
:input') .blur(function()
(
if ($(this) .hasClass('required'
(
var $listltem
= $(this) .parents('li:first'),
if Ithis. value == ,,) (
var errorMessage = 'This is a required
$ l'<span></span>')
.addClass('error-message')
.textlerrorMessage)
.appendTo($listltem)
,
$listltem.addClass('warning')
;

Flrst Nama
Lost Nom.

---J .

Mar"
I
Tum.,

J-I

How wouId )'<lOIIke lo be oon1BCI8d? (choose alleast CM melllod)

field'

"

b)'E U

=::J -

ThI.1s a raqulred IIeId, when Its lBIated ehed<box Is chedcec1ThI


l. a requlred IIeId, whon Ito mlated ehed<box Is _

I!!! byPhcna
I!!! by Fax
Figura 8.6. Dejar un campo en blanco.

}
j),
}) ;

El cdigo tiene dos sentencias if para cada entrada de formulario en bl ur: la primera comprueba la clase required, y la segunda comprueba la presencia de una cadena
vaca. Si ambas condiciones se cumplen, construimos un mensaje de error, lo situamos
en c s'pari c Las s "error-message"
, y lo anexamos al <li> padre.
Queremos proporcionar un mensaje algo diferente si el campQ es uno de los campos de texto condicionales only required when its corresponding checkbox is checked
(slo obligatorio cuando su casilla de verificacin correspondiente est seleccionada).
Concatenaremos un mensaje modificador al mensaje de error estndar. Para hacer esto,
podemos anidar una sentencia i f ms que comprueba la clase condi t ional solamente
despus de que se hayan cumplido las dos primeras condiciones if:
$Idocument) .ready(function()
{
$('form
:input') .blur(function()
(
if ($(this) .hasClass('required'
(
var $listltem
= $(this) .parentsl'li:first');
if

(this.value
== ") (
var errorMessage = 'This is a required field'
if ($(this) .hasClass('conditional'
{
errorMessage += " when its related
+
'checkbox ia checked';
I

Si el campo permanece en blanco, el mensaje de error se repite tantas veces como el


usuario abandone el campo. Si se incorpora texto en el campo, c Las s e "warning" no
se elimina. .
Obviamente, solamente queremos un mensaje por campo, y queremos que el mensaje se elimine si el usuario soluciona el error. Podemos solucionar ambos problemas
al eliminar c Las s e "warning" del <li> padre del campo actual y cualquier apan
c l as s "error-message"
> dentro del mismo c l s cada vez que el campo pierde el
foco, antes de pasar por las comprobaciones de validacin:

$ (document)
$('form

.ready(function()
{
:input') .blur(function()

$(this).parents('li:first').removaClass('warning')
.find('span.error-message'}.remove()
if ($(this) .hasClass('required'
(
var $listltem
= $(this) .parents('li:first');
if (this.value
== ") {
var errorMessage = 'This is a required
if ($ Ithis) .hasClass ( 'conditional '
(
errorMessage += " when its related
i s checked' j
$ ('<span></span>')
.addClass('error-message')
.text(errorMessage)

field'
checkbox

mi

8. Formularios con funciones

Aprende jQuery 1.3

.appendTo($listltem)
;
$listItem.addClass(
'warning');

campos de correo electrnico, telfono y tarjeta de crdito. Para nuestra demostracin,


situaremos 'en su lugar una sencilla comprobacin de expresin regular para el campo
de correo electrnico, Echemos un vistazo al cdigo completo para la validacin de correo electrnico antes de adentrarnos en la propia expresin regular:

j);

Por ltimo, tenemos un script de validacin en funcionamiento para campos obligatorios y condicionalmente obligatorios. Incluso despus de incorporar y salir de campos
obligatorios repetidamente, nuestros mensajes de error ahora se muestran de forma correcta, como se ve en la figura 8.7.

$ (document) .ready(function()
{
// ...
cdigo contina
..
if (this.id == 'email')
{
var $listltem
= $(this) .parents('li:first');
if ($(this).is(':hidden'))
{
this.value =
}
if (this.value 1= II &&
11;

Personal Inlo
Flrat Nama

[MMk

lID

!/.+@.+\.[a-zA-Z){2.4}$/.test(this.value))
{
var errorMessage = 'Please use proper e-mail
+
(e.g. joe@example.com) Ii
$(I<span></span>l)
.addClass('error-message')
.text(errorMessage)
.appendTo($listltem);
$listltem.addClass('warning')
;

'--~.

format'

1"

. byE 11

c--__~-=---~
~

. byPhono

Thl818 requlred 1IeId. wlien lis mlatad cho<:IcboX Is checkad

1~

T11I810. requlred fIeId, wIien lis mlatad cho<:IcboXIs checked

I!!l by Fax

//
})

cdigo

contina

. . .

Figura 8.7, Script de validacin en funcionamiento.

El cdigo realiza las siguientes tareas:


Pero, espere. Queremos eliminar la clase warning del elemento < 1i > Ysus elementos e span class="error-message">
cuando el usuario quita la seleccin de una
casilla de verificacin tambin. Podemos hacer esto al visitar nuestro cdigo de casilla
de verificacin anterior una vez ms y hacer que active blur en el campo de texto correspondiente cuando su casilla de verificacin no est seleccionada:
if

Comprobaciones para el id del campo de correo electrnico; si la comprobacin


tiene xito:

(this.checked)
{
$thislnput.show()
.addClass('required');
$thisFlag.show()
;
$ (this) .parent('label')
.addClass('req-label');
el se {
$thislnput.hide()
.removeClass('required').blur();
$thisFlag.hide()
;
$(this) .parent('label')
.removeClass('req-label');

Ahora cuando una casilla de verificacin no est seleccionada, los estilos de aviso
relacionados, y los mensajes de error estn fuera de la vista y de la mente.

Establece una variable para el elemento de lista padre.


Comprueba el estado oculto del campo de correo electrnico. Si est oculto
(que sucede cuando su casilla de verificacin correspondiente no est seleccionada), su valor se establece en una cadena vaca. Esto permite que nuestra
eliminacin del mensaje de error anterior funcione correctamente para los
campos de correo electrnico tambin.
Comprueba que el valor del campo no es una cadena vaca y que el valor del
campo no coincide con la expresin regular. Si las dos comprobaciones tienen
xito, el script:

Crea un mensaje de error.

Inserta el mensaje en

Anexa el elemento e span c l as s "error-message"


al elemento de lista padre.

Aade la clase warning

Formatos obligatorios
Existe un tipo ms de validacin a implementar en nuestro formulario de contacto:
formatos de entrada de datos correctos. Algunas veces puede ser de utilidad proporcionar un aviso si el texto se incorpora en un campo de forma incorrecta (en lugar de
simplemente dejado en blanco). Los principales candidatos para este tipo de aviso son

spar;

c La s s e "error-message"

al elemento de lista padre.

Ahora echemos un vistazo a la expresin regular en solitario:


!/ .+@.+\. [a-zA-Z) {2.4}$/ .test(this.value)

>.
>y suscontenidos

EIiI

8. Formularios con funciones

Aunque esta expresin regular es similar a la que hemos creado anteriormente en el


captulo, utiliza el mtodo. test () en lugar del mtodo. replace (), ya que solamente
necesitamos que devuelva true o falseo Como antes, la expresin regular va entre las
dos barras inclinadas. Luego se comprueba contra una cadena que se sita dentro de los
parntesis de . test (), en este caso el valor del campo del correo electrnico.
En esta expresin regular, buscamos un grupo de uno o ms caracteres no de nueva
lnea (.+), seguido por un smbolo e, y luego seguido por otro grupo de uno o ms caracteres no de nueva lnea. Hasta el momento, una cadena como lucia@example pasara
la prueba, como lo haran millones de otras permutaciones, aunque no es una direccin
de correo electrnico vlida.
Podemos hacer que la comprobacin sea ms precisa al buscar un carcter . seguido
de dos a cuatro letras entre a y z al final de la cadena. Eso es exactamente lo que hace el
resto de la expresin regular. Primero busca un carcter entre a y z o A Y Z ( [a - zA - Z 1 ).
Luego dice que una letra en ese rango puede aparecer de dos a cuatro veces solamente
({ 2,4}). Por ltimo, insiste que esas dos a cuatro letras aparecen al final de la cadena: $.
Ahora una cadena como 1ucia@example . com devolvera true, mientras que 1ucia@
example,01ucia@example.2fnolucia@example.exampleoluci~-example.
com, devolvera falseo Pero queremos que nos devuelva true (y el mensaje de error,
etc., creado) solamente si el formato de direccin de correo electrnico adecuado no se
incorpora. sa es la razn por la que precedemos la expresin de comprobacin con el
signo de exclamacin (no operador):
!/ .+@.+\.

El cdigo de validacin est ahora casi completo para el formulario de contacto.


Podemos validar los campos del formulario una vez ms cuando el usuario trata de enviarlo, esta vez todo a la vez. Al utilizar el manejador de evento . submi t () en el formulario (no el botn Send), activamos blur en todos los campos obligatorios:
$ (document) .ready(function()
(
$('form') .submit(function()
(
$('#submit-message')
.remove();
$(' :input.required')
.trigger('blur');

})

$ (document) .ready(function()
(
$('form') .submit(function()
(
$('#submit-message') ,remove();
$(' :input.required')
.trigger('blur');
var nmwarnings :1:1 $ (1 .warning,~, this)
if (numWarnings)
{
$ ('<div></div>')
.attr({
lid':
'submit-message',
'clasa':
.warning ,

Observe ahora que hemos colado una lnea para eliminar un elemento que todava
no existe: <di v id=" submi t -message" >. Aadiremos este elemento en el siguiente
paso, Simplemente estamos eliminndolo como medio de prevencin aqu porque ya
sabemos que necesitaremos hacerlo basndonos en los problemas que hemos encontrado al crear mltiples mensajes de error anteriormente en el captulo.
Despus de activar bl ur, recibimos el nmero total de clases warning en el formulario actual. Si no hay ninguna, crearemos un nuevo <di v id=" submi t -message" >
y lo insertaremos delante del botn Send donde es ms probable que lo vea el usuario.
Tambin impediremos que el formulario realmente se enve:

&iI

,length

})
.append('Please correct errara with
numWarnings +
fields')
.insertBefore('#send');
return falss

})
})

Adems de proporcionar una peticin genrica para solucionar errores, el mensaje


indica el nmero de campos que se tienen que solucionar, como se ve en la figura 8.8.
l~axredenonM

3 ~d.

Figura 8.8. Informacin para el usuario.

[a-zA-Z] (2,4}$/.test(this.value)

Una ltima comprobacin

Aprende jQuery 1.3

Sin embargo, podemos hacer algo mejor que simplemente mostrar el nmero de errores, podemos listar los nombres de los campos que contienen errores:
$ (document) .ready(function()
(
$('form') .submit(function()
(
$('#submit-message')
.remove();
$(' :input.required')
.trigger('blur');
var numWarnings = $(1 .warning', this) .length
if (numWarnings)
{
var list = [l;
$('.warning
label').each(function()
list.push($(this).text());
}) ;
$ (' <div></div>
1)
.attr ((
'id': 'submit-message',
'class': 'warning'

.append('Please

correct error s with the following


numWarnings +
fields:<br />')
.append('&bull;
, + list.join('<br
/>&bull;
'))
.insertBefore{'#send')
return false
1

};
}) ;

})

ltr-'r.',

&El

Aprende jQuery 1.3

8. Formularios con funciones

Elprimer cambio en el cdigo es la variable list establecida en una tabla vaca. Luego,
obtenemos cada etiqueta que es un descendiente de un elemento con la clase warning
y empujamos su texto en la tabla list (con la funcin nativa JavaScript push). Ahora,
el texto de cada una de estas etiquetas constituye un elemento aparte en la tabla listo
Modificamos nuestra primera versin del contenido <di v id=" submi t -message" >
un poco y le anexamos nuestra tabla listo Utilizando la funcin JavaScriptnativa j oin ()
para convertir la tabla en una cadena, unimos cada uno de los elementos de tabla con
un salto de lnea y un boliche, como se ve en la figura 8.9.
Ploase oonect """'"
-F1rs1Name
-wtName

&ni

especialmente si el usuario desea hacer clic en la mayora de ellas. Una opcin p"!raseleccionar, o deseleccionar, todas las casillas de verificacin es de utilidad en este tipo de
situacin. Po? lo tanto, creemos una.
Para empezar, creamos un nuevo.elemento <1i , lo completamos con un <1abe 1 ,
dentro del cual situamos <input t.ype "checkbox" id= "discover-all"
> y algo
de texto, y lo anexamos al elemento -e u L dentro de -e L class="discover"
>:
e

$ (document) .ready(function()
$ ('<1i></li>')

.html('<label><input
type="checkbox"
id="discover-allll
<em>check
all</em></label>')
.prependTo('li.discover
:> ul')

wtth 1he fo!owIng 3I1e1d.:

/>'

- by E-MaIl

})

I~
Figura 8.9. Unir los elementos de la labia con salto de lnea y boliche.

Ciertamente, el HTML para la lista de campos es de presentacin en lugar de semntico. Sin embargo, para una lista efmera, una que se genera por JavaScript como un ltimo paso y pensada para eliminarla lo ms pronto posible, perdonaremos este cdigo
rpido en aras de la sencillez y brevedad.

Ahora tenemos una nueva casilla de verificacin con una etiqueta que dice check
all (seleccionar todas). Pero todava no hace nada. Necesitamos anexarle el mtodo
. click

():

$ (document) .ready(function()
$ ('<1i></li>')
.htrnl('<label><input
type= checkbox" id=lIdiscover-all
<em>check
all</em></label>')
.prependTo('li.discover
:> ul');
$('#discover-all').click(function()
{
var $checkboxes
= $(this).parents('ul:first')
.find(':checkbox')
if (this.checked)
{
$checkboxea.attr('checked',
true};
el se {
$checkboxea.attr('checkedl,
11);
}
}) ;
}) ;

11

/>'

Manipulacin de casilla de verificacin


Nuestro formulario de contacto tambin tiene una seccin de varios, que contiene
una lista de casillas de verificacin, como se muestra en la figura 8.10.
MIsceltaneous
How dId you di""""

. us1 (Check all thaI apply)

!!!I Magaztne

8w_

Dentro de este manejador de evento, primero establecemos la variable $checkboxes,


que consta de un objetojQuery que contiene toda casilla de verificacin dentro de la lista
actual. Con la variable establecida, manipular las casillas de verificacin se convierte en
una cuestin de seleccionarlas si la casilla de verificacin check all est seleccionada, y
deseleccionarlas si check all no lo est.
Un ltimo toque se puede aplicar a esta caracterstica de casilla de verificacin al
aadir una clase checkall a la etiqueta de la casilla de verificacin check all, y cambiar su texto a un-check all (deseleccionar todas) despus de que se ha seleccionado por
el usuario:

El Talevlslo"
ElMoYle

13 SchooI
!!!IMom

13 Blltboartl
13 Gramtl
El Detrttus
El HateMaIl

$ (document) .ready(function()
{
$ ('di></li>')
.htrnl('<label><input
type="checkbox
id="discover-all"
, <ern>check all</ern></label>')
.prependTo('li.discover
> ul');
$('#discover-a11')
.click(function()
(
var $checkboxes
= $(this) .parents('u1:first')
.find(' :checkbox');
lI

Figura 8.10. Lista de casillas de verificacin.

Para redondear nuestras mejoras en el formulario de contacto, ayudaremos al usuario a gestionar esta lista. Un grupo de la casillas de verificacin puede ser desalentador,

/>' +

mi

Jwr
8. Formularios con funciones
if

Aprende jQuery 1.3

(this.checked)
{
$ (thia) .next O .text (' un-check
a11');
$checkboxes.attr('checked',
true) I
else (
$(thia) .next() .text(' check a11');
$checkboxes. attr ('checked',
") I

El cdigo terminado
Aqu est-el cdigo terminado para el formulario de contacto:
.,
$ (document) .ready(function()
(
// Mejorar estilo de elementos de formulario.
$('legend')
.each(function(index)
(
$(this) .replaceWith('<h3>'
+ $(this) .text()

l.
})
.parent('labe1')

.addClass('checka11');

+ '</h3>') I

}) I
}) I

El grupo de casillas de verificacin, junto con el cuadro check all, ahora se parece a
la figura 8.11.
Mlscellaneous
How dld you <IIscover us? (Check all !ha! apply)

o"

13 check

13 Magazine
"

I3webs1t8

8 Televlslon
S MovIe

var requiredFlag = ' * ';


var conditionalFlag
=
**
i
var requiredKey = $('input.required:first')
.next('span')
.text() I
var conditionalKey
= ~('input.conditional:first')
.next('span')
.text() I
requiredKey
= requiredFlag
+
requiredKey.replace(/'\.+)\)$/,
'$1') I
conditionalKey
= conditionalFlag
+
conditionalKey.replace(/'\.+)\)$/,
'$1') I
$('<p></p>')
.addClass('field-keys')
.append(requiredKey
+ '<br />')
.append(conditionalKey)
.insertBefore('#contact')
;
I

El School
$ ('form :input' )
.filter(' .requiredr)
.next('span')
.text(requiredFlag)
.end()
.prev (' Labe l
addClass ('req-label') .end O
.end O
.filter(' ,conditional')
.next('span') .text(conditionalFlag);

SMom

B BUlboord

SGratIIII

13 Detritus

El HeteMall
Figura

// Alternar

casilla

de verificacin:

entradas

condicionales

8.11. Permitirseleccionar todas las casillas de verificacin.

y con check all seleccionada, el grupo se parece a la figura 8.12.


Miscellaneous
How <lid you dlscover us7 (Check all that apply)

un-check 0/1

I!f

Magazine

I!fW&b1llte
1f1l>levlslon

I!I Movle

$('input.conditional')
.next('span')
.andSelf() .hide()
.erid t ) .end()
.each(function()
(
var $thislnput
= $(this) I
var $thisFlag
= $thislnput.next('span')I
$thislnput.prev('label')
.find(' :checkbox')
.attr('checked',
false)
.click(function()
{
if (this.checked)
(
$thislnput.show()
.addClass('required')
I
$thisFlag.show()
I
$(this) .parent('label')
.addClass('req-label')
I
el se (
$thislnput.hide()
.removeClass('required')
.blur() I
$thisFlag.hide()
I
$ (this) .parent('label')
.removeClass('req-label')
I

I!f School

}),
Figura

8.12. Todas seleccionadas.

}) I

de texto.

ea

BfI

8. Formularios con funciones

Aprende jQuery 1.3

// Validar
campos al perder foco.
$('form
:input') .blur(function()
(
$(this)

.parents('li:first')

.append('&bull;
, + fieldList.join('<br
.ansertBefore('#send');
return false

.removeClass('warning')
.remove()

.find('span.error-message')

/>&bull;

ea

'))

};
});

if

($(this) .hasClass('required'))
(
var $listltem
= $(this) .parents('li:first');
if (this. value == ")
{
var

if

errorMessage

'This

is

a required

// Casillas
$('form

($ (this) .is (, .conditional'))


{
errorMessage
+= "
when its related
checked' i

checkbox

// Casillas
de verificacin
$ ('<li></li>')

is

(un)check

all.
/>'

.addClass('error-message')
.text(errorMessage)
.appendTo($listltem);
$listltem.addClass('warning')

(this.id == 'email')
(
var $listltem
= $(this) .parents('li:first');
if ($ (this) .is(' :hidden'))
{
this .val ue

$checkboxes.attr('checked',

.parent('label')
!=

errorMessage

+ ' (e.g.

1')

})

"

&&
!/ .+@.+\. [a-zA-Z] {2,4}$/ .test(this.value))
(this.value

};

var

con

.htrnl('<:label><input
type=ucheckbox"
id="discover-allu
<em>check
all</em></label>')
.prependTo('li.discover
> ul');
$('#discover-all')
.click(function()
{
var $checkboxes
= .$(this) .parents ('ul: first')
. find ( checkbox' ) ;
if (this.checked)
(
$(this) .next() .text(' un-check
all');
$checkboxes.attr('checked',
true) i
el se (
$(this) .next() .text(' check all');

('

$('<span></span>')

if

.removeAttr('checked')

field';

if

de verificacin

:checkbox')

})

"

'Please

use

proper

e-mail

format'

Aunque hemos realizado mejoras significativas en el formulario de contacto, todava


queda mucho por hacer. La validacin, por ejemplo, se presenta de varias formas. Para
un plug-in de validacin flexible, visite http://plugins
. jquery. com/proj ect/
validate/
.

joe@example.com)';

$('<span></span>')
.addClass(rerror-message')

.text(errorMessage)
.appendTo($listltem)
;
$listltem.addClass('warning')

.addClass('checkall');

Formularios compactos

}
}l;

Algunos formularios son mucho ms sencillos que los formularios de contacto. De


hecho, muchos sitios incorporan un formulario de un solo campo en cada pgina: una
funcin de bsqueda para el sitio. Los elementos habituales de un formulario, como etiquetas de campo, botones de envo y el texto, son incmodos para una parte tan pequea
de la pgina. Podemos utilizar jQuery para ayudar a simplificar el formulario mientras
mantiene sus funcionalidades, e incluso mejorar su comportamiento para que sea ms
til que un equivalente de pgina completa.

// Validar
formulario
al enviar.
$('form') .submit(function()
(
$('#submit-message')
.remove() ;
$(' :input.required')
.trigger('blur');
var

numWarnings

if

$(' .warning',

this)

.length

(numWarnings)
(
var fieldList
=
[);
$(' .warning
label') .each(function()
fieldList.push($(this)
.text());
}l;
$('<div></div>')
.attr({
'id':

Texto como marcador de posicin para campos

'submit-message',

'class':

'warning'

.append('Please

correct

numwarnings

errors
'

with

fields:<br

the following
/>')

, +

El elemento e Labe L para un campo de formulario es un componente esencial de


sitios Web accesibles. Todo campo se debera etiquetar de modo que los lectores de pantalla y otros dispositivos de ayuda puedan identificar qu campo se utiliza, y para qu
propsito. Incluso en la fuente HTML, la etiqueta ayuda a describir el campo:

B!II

8. Formularios con funciones

Aprende jQuery 1.3

c:::form id=lIsearch
action=lIsearch/index.phpll
method=lIget >
c:::label for=lIsearch-text">search
the sitec:::/label>
<input type="text
name="search-text"
id=lIsearch-text
</form>
l1

ea

ll

ll

ll

II-!he .no

/>

Figura 8.15.

Para evitar el primer problema, ri'ecesitamos ocultar el texto de la etiqueta cuando


el campo recibe foco, y mostrarlo de nuevo cuando se pierde foco, siempre y cuando.
no haya texto incorporado por el usuario en el campo. Ocultar el texto de la etiqueta en
foco es sencillo:

Sin estilo, vemos la etiqueta delante del campo, como se muestra en la figura 8.13.

8e.~h~.tte

Figura

8.13. Etiquetasin estilo.


l'

Aunque esto no ocupa mucho espacio, en algunos diseos de sitio incluso esta lnea
de texto podra ser demasiado. Podramos ocultar el texto con CSS, pero luego esto no
proporciona al usuario forma de saber para qu es el campo. En su lugar, utilizaremos
CSS para posicionar la etiqueta sobre el campo, solamente si JavaScript est disponible,
al aadir una clase al formulario de bsqueda:
$ (docurnent) .ready(function()
var $search = $('#search')
)) ;

$ (docurnent) .ready(function()
(
var $search = $('#search') .addClass('overlabel');
var $searchlnput
= $search.find('input');
var $searchLabel
= $search.find('label');
$searchlnput
.focus(function()
(
$searchLabel.hide();
)l
.blur(function()
{
if (this.value
== ")
$searchLabel.show()
)
)) ;

(
.addClass('overlabel');

En una sola lnea estamos aadiendo una clase al formulario de bsqueda y almacenando el selector en una variable de modo que podemos hacerle referencia ms adelante.
La hoja de estilo utiliza la clase overlabel
para aplicar estilo a la etiqueta:
.overlabel
(
position: relative
)
.overlabel
label (
position: absolute
top: 6px;
left: 3px;
color: #999;
cursar: text

'1

No se puede hacer clicen la etiqueta.

))

(
;

La etiqueta ahora est oculta cuando el usuario escribe texto en el campo, como se
ve en la figura 8.16.

Ilt<..
Figura 8.16.

Ocultarla etiqueta cuando se escribe.

El segundo problema ahora es bastante sencillo de solucionar tambin. Podemos


ocultar el texto de la etiqueta y proporcionar al usuario acceso a la entrada de datos al
permitir que un clic en la etiqueta active el evento focus para la entrada de datos:
$ (docurnent) .ready(function()
var
var
var

No solamente la clase aadida posiciona la etiqueta adecuadamente, sino que tambin deshabilita el texto para distinguirlo como un marcador de posicin, como muestra
la figura 8.14.

Ilsesn:Ii Ihe stte


Figura 8.14.

$searchlnput
.focus(function()
(
$searchLabel.hide();
))

II

Aplicarestilo a la etiqueta.

.blur(function()
{
if (this.value==

ste es un buen efecto, pero tiene un par de problemas:

,,) (

$searchLabel.show()

1. El texto de la etiqueta oscurece cualquier texto que el usuario incorpora en el


campo de texto.
2. Ahora solamente se puede acceder a la entrada de texto al utilizar la tabulacin.
Puesto que la etiqueta cubre la entrada de datos, al usuario se le impide hacer
clie en l, como se ve en la figura 8.15.

$search = $('#search') .addClass('overlabel');


$searchlnput
= $search.find('input');
$searchLabel
= $search.find('label');

))

$searchLabel.click(function()
$searchlnput.trigger('focuB');
}) ;
))

BliI

8. Formularios con funciones

Aprende jQuery 1.3

Por ltimo, necesitamos gestionar el caso en el que el texto permanece en el campo de


entrada de datos cuando la pgina se refresca, similar a lo que tenamos que hacer con
las entradas condicionales en el apartado de validacin de formulario anteriormente en
este captulo. Si la entrada de datos tiene un valor, la etiqueta se oculta:
$ (document) .ready(function()
(
var $search := $('#search') .addClass('overlabel');
var $searchlnput = $search.find('input') i
var $searchLabel = $search.find('label') i

Necesitamos algn cdigo del lado del servidor para gestionar peticiones. Aunque
una implementacin del mundo real se basar normalmente en una base de datos para
/ producir una lista de terminaciones posibles, para este ejemplo podemos utilizar un
sencillo script PHP con los resultados incorporados:
<?php
if (strlen($_REQUESTC'search-text'])
print '[]';
exit

(
;

"

});

$searchLabel.click(function()
(
$searchlnput.trigger('focus')
;

})
})

La idea bsica detrs de la rutina autocompletar es reaccionar a una tecla, y enviar


una peticin AJAX al servidor que contiene los contenidos del campo en la peticin. Los
resultados contendrn una lista de posibles terminaciones para el campo. El script entonces presenta esta lista como un desplegable por debajo del campo.

En el servidor

if ($searchlnput.val())
$searchLabel.hide();

$searchlnput
.focus(function()
(
$searchLabel.hide() ;
})
.blur(function()
{
if (this.value == ")
$searchLabel.show()
}

eDI

I,

$possibilities = array();
foreach ($terms as $term) {
if (strpos($term, strtolower($_REQUEST['search-text']))

===
$possibilities

print

Podemos realzar an ms nuestro campo de bsqueda al ofrecer autocompletar sus


contenidos. Esta caracterstica permitir a los usuarios escribir el principio de un trmino de bsqueda y que se le presenten todos los posibles trminos que comienzan con la
cadena escrita. Puesto que la lista de trminos se.puede extraer de una base de datos que
dirige el sitio, el usuario puede saber que los resultados de bsqueda estn disponibles si
se utiliza el trmino facilitado. Tambin, si la base de datos proporciona los trminos en
orden de popularidad o nmero de resultados, se puede guiar al usuario hacia bsquedas
ms apropiadas. Autocompletar es un tema muy complicado con sutilezas introducidas
por diferentes tipos de interaccin de usuario. Disearemos un ejemplo operativo aqu,
pero no podemos, en este espacio, explorar todos los conceptos avanzados como limitar
el ndice de peticiones o completar mltiples trminos. Se recomienda el componente
autocompletar en la coleccin plug-ins de interfaz de usuario jQuery para implementaciones sencillas y del mundo real, como un punto de partida para otras ms complejas.
Se puede encontrar en http://ui.jquery
. com/.

1) {

$terms = array(
access
action'
/1 Lista contina ...
'xarnl' ,
'xoops "

Una ventaja de utilizar la etiqueta en lugar de insertar un valor predeterminado directamente en la entrada de texto es que esta tcnica se puede adaptar a cualquier campo de
texto sin tener que preocuparse por un conflicto potencial con un script de validacin.

Autocompletar AJAX

<

O)

[] =

(' ['. implode(',

{
rr r

11.

str_replace

$possibilities).

(11

11 \

111,

$term)

'] ');

La pgina compara la cadena proporcionada contra el principio de cada trmino, y


compone una tabla JSON de coincidencias. Las operaciones de manipulacin de cadena
aqu (como str _replace () e implode () ) se aseguran de que el resultado del script
sea JSON con formato adecuado, para evitar errores JavaScript durante el anlisis.

En el navegador
Ahora podemos realizar una peticin de este script PHP desde nuestro cdigo
JavaScript:
$ (document) .ready(function()
{
var $autocomplete = $('<ul class=lIautocompletetr></ul>')
.hide()
.insertAfter('#search-text');
$('#search-text')
$.ajax<{

.keyup (function ()

BllI

Aprende jQuery 1.3

8. Formularios conJunciones

'url': '../search/autocomplete.php',
'data ': {' search-text':
$ (, #search-text r) . val () },
'dataType': 'json',
'type':
'GET',
'success': function(data)
if (data.1ength)
{
$autocomp1ete.empty(),
$.each(data,
function(index,
term) {
$('<li></li>')
.text(term) .appendTo($autocomp1ete)
}),
$autocomp1ete.show()
,

.
}) ,
})

-t

Id.1

de,ellct
deftnltlVe
d lgn .
d lgnlng
dOYOlopers

o.,

development

Figura 8.18. Mecanismo autocompletar

incorporado del navegador.

Completar el campo de bsqueda

Necesitamos utilizar keyup, no keydown o keypress, como el evento que activa la


peticin AJAX. Los dos ltimos eventos ocurren durante el proceso de pulsar la tecla,
antes de que los caracteres se hayan incorporado realmente en el campo. Si intentamos
actuar sobre estos eventos y lanzamos la peticin, la lista de sugerencia i por detrs
del texto de bsqueda. Cuando se incorpora el tercer carcter, por ejemplo, la peticin
AJAX se realizar utilizando simplemente los dos primeros caracteres. Al actuar sobre
keyup, evitamos este problema. En nuestra hoja de estilo, posicionamos esta lista de
sugerencias de forma absoluta, de modo que solapa el texto por debajo. Ahora cuando
escribimos el campo de bsqueda, vemos nuestros trminos posibles presentados, como
se ve en la figura 8.17.

Nuestra lista de sugerencias no nos hace mucho bien si no podemos situadas en el


cuadro de bsqueda. Para empezar, permitiremos que un clic del ratn confirme una
.sugerencia:
'success': function(data)
if (data.1ength)
{
$autocomp1ete.empty()
;
$.each(data,
function(index,
term) {
$('<li></li>')
.text(term)
.appendTo($autocomp1ete)
.click(function()
{
$ ('#search- text' ) .val (term) ,
$autocomplete.hide();
}) ;

}),
$autocomplete.show()

'deep
deftnltlVe
d lgn
deslgnlng
developers
dOYOlopment

Figura 8.17. Trminos de bsqueda posibles.

Para mostrar adecuadamente nuestra lista de sugerencias, tenemos que tener en


cuenta el mecanismo incorporado de autocompletar de algunos navegadores Web. Los
navegadores a menudo recordarn lo que los usuarios han incorporado en un campo de
formulario, y sugieren estas entradas la siguiente vez que se utiliza el formulario. Esto
puede parecer confuso cuando se utiliza junto con nuestras sugerencias personalizadas
de auto completar, como muestra la figura 8.18. Afortunadamente, esto se puede deshabilitar en los navegadores que realizan autocompletar al establecer el atributo autocomplete del campo de formulario en off. Podramos hacer esto en el HTML, pero
esto no estara en consonancia con el principio de mejora progresiva porque estaramos
deshabilitando la funcin autocompletar del navegador sin ofrecer la nuestra. En su
lugar, podemos aadir este atributo desde nuestro script:
.attr('autocomplete',

I~.m

$('#search-text')

eg

'off')

Esta modificacin establece el texto del cuadro de bsqueda en cualquiera que sea
el elemento de lista sobre el que se haya hecho clic. Tambin ocultamos las sugerencias
despus de esto.

Navegacin por medio de teclado


Puesto que el usuario est ya en el teclado, y escribiendo el trmino de bsqueda, es
muy conveniente permitir que el teclado controle la seleccin desde la lista de sugerencia
tambin. Necesitaremos mantener un registro del elemento actualmente seleccionado
para activado. Primero, podemos aadir una funcin de ayuda que almacenar el ndice
del elemento y llevar a cabo los efectos visuales necesarios para revelar qu elemento
est seleccionado actualmente:
var selectedltem = null
var setSelectedltem
= function(item)
selectedltem = item
if (selectedltem
=== null)
$autocomplete.hide(),
return

DiI

8. Formularios con funciones

if

(selectedltem
selectedltem

< O)
O;

(selectedltem
selectedltem

>= $autocomplete.find('li')
= $autocomplete.find('li')

.length)
(
.length - 1;

jde~eps

$autocomplete.find('li')
.removeClass('selected')
.eq(selectedltem)
.addClass('selected');
$autocomplete.show()
;

detlnl1lve
deslgn
developeno
development

La variable selectedItern
se establecer en null siempre que no haya un elemento seleccionado. Al invocar siempre setSelectedItern
() para cambiar el valor de la
variable, podemos estar seguros de que la lista de sugerencias solamente est visible
cuando existe un elemento seleccionado.
Las dos pruebas para el valor numrico de selectedItern
estn presentes para asegurar los resultados en el rango apropiado. Sin estas pruebas, selectedItern
terminara
con cualquier valor, incluso negativo. Esta funcin se asegura de que el valor actual de
selectedItern
siempre es un ndice vlido en la lista de sugerencias ..
Ahora podemos revisar nuestro cdigo existente para utilizar la nueva funcin:
$('#search-text')
.attr('autocomplete',
'off') .keyup(function()
$.ajax({
'url':
/search/autocomplete.php',
'data': ('search-text':
$ ('#search-text')
.val() l,
'dataType': 'json',
'type': 'GET',
'success': function(data)
if (data.length)
(
$autocomplete.empty()
;
$.each(data,
function(index,
term) (
$('<li></li>')
.text(term)
.appendTo($autocomplete)
.mouseover(function()
{
setSelectedltem(index);
..

})
.click(function()
(
$('#search-text')
.val(term);
$autocomplete.hide()
;

})
})

q'
'g

Ahora necesitamos permitir que las teclas del teclado cambien qu elemento est actualmente activo en la lista.

Gestionar

las teclas del cursor

Podemos utilizar el atributo keyCode del objeto evento para determinar qu tecla se
ha pulsado. Esto nos permitir ver los cdigos 38 Y 4 O,correspondientes a las flechas
arriba y abajo, y reaccionar en consecuencia:
$('#search-text')
.attr('autocomplete',
'off') .keyup(function(event)
if (event.keyCode
> 40 I I event.keyCode
== 8) {
// Teclas con cdigos 40 e inferior
son especiales
// (lntro, teclas del cursor, escape, etc.).
// Cdigo de tecla 8 es retroceso.
$.ajax({
'url': r /search/autocomplete.php',
'data': ('search-text':
$('#search-text')
.val()},
'dataType':
'json',
'type':
'GET'
'success': function(data)
if (data.length)
(
$autocomplete.empty()
;
$.each(data,
function(index,
term) {
$ (,<1i></li>') .text (term)
.appendTo($autocomplete)
.mouseover(function()
(
setSelectedltem(index)
;
I

.click

setSelectedltem(O);

(function () (
$('#search-text')
.val(term);
$autocomplete.hide()
;

else (
setSelectedltem(null);

})
})

setSelectedltem(O);

});

Esta revisin tiene varios beneficios inmediatos. Primero, la lista de sugerencias se


oculta cuando no existen resultados para una bsqueda dada. En segundo lugar, podemos aadir un manejador rnouseover que resalte el elemento bajo el cursor del ratn.

Figura 8.19. Efecto del manejador mouseover.

})

doalgnlng

l;

mi

En tercer lugar, el primer elemento se resalta inmediatamente cuando se muestra la lista


de sugerencias, como se ve en la figura 8.19.

l
if

Aprende jQuery 1.3

else (
setSelectedltem(null);

}
})

1m

8. Formularios con funciones

Aprende jQuery 1.3

mil

Eliminar la lista de sugerencias

else if

(event.keyCode 38 &&
selectedltem 1== null) (
// Usuario pulsa la Flecha arriba.
setSelectedltem(selectedltem
- 1);
event.preventDefault()

Existe una ltima modificacin que haremos a nuestro comportamiento autocompletar. Deberamds ocultar la lista de sugerencias cuando el usuario decide hacer alguna
otra cosa en la pgina. En primer lugar, podemos reaccionar a la tecla Ese en nuestro
manejador keyup, y dejar que el usuario descarte la lista de esa forma:

}
(event.keyCode == 40 &&
selectedltem 1== null) (
// Usuario pulsa la Flecha abajo.
setSelectedltem(selectedltem
+ 1);
event.preventDefault();

else if

el se if (event.keyCode == 27 && selectedltem


// Usuario ha pulsado la tecla Esc.
setSelectedltem(null) ;

1==

null)

})

Nuestro manejador keyup ahora comprueba el keyCode que se ha enviado, y lleva


a cabo la accin correspondiente. Las peticiones AJAX se saltan si la tecla pulsada era
especial, corno una tecla del cursor o la tecla Ese. Si se detecta una tecla del cursor y la
lista de sugerencia se muestra, el manejador cambia el elemento seleccionado en 1 en la
direccin apropiada. Puesto que escribimos setSelectedItem
() para asegurar los
valores en el rango de ndices posibles para la lista, no tenemos que preocupamos por
que el usuario se aleje en cualquier extremo de la lista.

Insertar sugerencias en el campo


A continuacin, necesitamos gestiona! la tecla Intro. Cuando se muestra la lista de
sugerencias, pulsa! la tecla Intro debera completa! el campo con el elemento actualmente
seleccionado. Puesto que ahora vamos a hacer esto en dos lugares, deberamos separar
la rutina de completa! campo (que hemos codificado anteriormente para el botndel
ratn) en una funcin aparte:

An ms importante, deberamos oculta! la lista cuando el campo de bsqueda pierde foco. El primer intento en esto es bastante sencillo:
'$('#search-text') .blur (function (event)
setSelectedltem(null);

})

Sin embargo, esto provoca un efecto secundario no deseado. Puesto que un clic de
ratn en la lista elimina foco del campo, este manejador se invoca y la lista se oculta.
Esto significa que nuestro manejador el i ck definido anteriormente nunca se invoca, y
resulta imposible interactuar con la lista utilizando el ratn.
Existe una solucin sencilla a este problema. El manejador bl ur siempre se invocar
antes del manejador el i ck. Una solucin alternativa es oculta! la lista cuando se pierde
el foco, pero esperar una fraccin de segundo primero:
$I'#search-text') .blur(function(event)
setTimeout(function()
(
setSelectedltem(null) ;
},

var populateSearchField
= function() (
$('#search-text') .vall$autocomplete
.findl'li') .eqlselectedltem) .text(;
setSelectedItem(null) ;

250);

}I;

};

Esto nos proporciona una oportunidad para que se active el evento click
mento de lista antes de que el elemento de lista se oculte.

Ahora nuestro manejador click puede ser una sencilla llamada a esta funcin.
Podemos invocar esta funcin cuando gestionamos la tecla Intro tambin:

Autocompletar

$('#search-text') .keypress (function (event) {


if (event.keyCode == 13 && selectedltem
1== null)
// Usuario pulsa tecla Intro.
populateSearchFieldl) ;
event.preventDefault() ;

}
}) ;

Este manejador est anexado al evento keypress en lugar de keyup corno antes.
Tenemos que hacer esta alteracin de modo que podamos impedir que la pulsacin de
tecla enve el formulario. Si esperamos hasta que se activa el evento keyup, la presentacin estar ya en marcha.

frente a live

en el ele-

search

El ejemplo anterior se ha centrado en autocompletar el campo de texto, ya que es una


tcnica que se aplica a muchos formularios. Sin embargo, pala bsquedas en particular,
se prefiere una alternativa denominada live search. Esta caracterstica lleva a cabo las
bsquedas de contenido a medida que el usuario escribe.
Funcionalmente, autocompletar y live search son muy similares. En ambos casos,
pulsar una tecla inicia un envo AJAX al servidor, pasando los contenidos del campo
actual junto con la peticin. Los resultados luego se sitan en un cuadro desplegable por
debajo del campo. En el caso de autocompletar, corno hemos visto, los resultados son
posibles trminos de bsqueda a utilizar. Con live search, los resultados son las pginas
que contienen los trminos de bsqueda que se han escrito.

mi

8. Formularios con funciones

Aprende jQuery 1.3

En el extremo JavaScript, el cdigo para crear estas dos caractersticas es casi idntico, por lo que no entraremos en detalle aqu. Decidir cul utilizar es una cuestin de
equilibrio; live search proporciona ms informacin al usuario con menos esfuerzo, pero
tpicamente requiere ms recursos.

var populateSearchField
= function()
(
$('#sea!ch-text')
.val($autocomplete
.find('li') .eq(selectedltem)
.text());
setSel~ctedltem(null)
;

};

",

$ ('#search-text')

El cdigo terminado

$ (document) .ready(function()
(
var $search = $('#search') .addClass('overlabel');
var $searchlnput
= $search.find('input');
var $searchLabel
= $search.find('label');
($searchlnput.val())
$searchLabel.hide()

.'

$searchlnput
.focus(function()
(
$searchLabel.hide();

})
.blur(function()
(
if (this.value
== ")
$searchLabel.show()

r:

'

(
;

(
;

else

var

$autocomplete

$('<ul

selectedltem

(selectedltem
selectedltem

(selectedltem
selectedltem

>= $autocomplete.find('li')
= $autocomplete.find('li')

= null;

(event.keyCode
== 38 &&
selectedltem
!== null)
// Usuario ha pulsado Flecha arriba.
setSelectedltem(selectedltem
- 1);
event.preventDefault() i

else

setSelectedltem
= function(item)
selectedltem
= item;
if (selectedltem
=== null)
$autocomplete.hide()
;
return

if

fl

class=lIautocomplete ></ul>')

})

.insertAfter('#search-text')

var

setSelectedltem(null)

.hide ()
var

setSelectedltem(O);

$searchLabel.click(function()
$searchlnput.trigger('focus')

})

.val()},

}
})

/search/autocomplete.php',

'data', ('search-text',
$('#search-text')
r dataType ' : . r j son'
,
"t ype ", 'GET',
'success': function(data)
if (data.length)
(
$autocomplete.empty()
;
$.each(data,
function(index,
term)
$('<li></li>')
.text(term)
.appendTo($autocomplete)
.mouseover(function()
(
setSelectedltem(index)
;
}) .click(populateSearchField);

(event.keyCode
> 40 II event.keyCode
== 8) (
// Teclas con cdigos 40 e inferior
son especiales
// (Intro, teclas del cursor, Esc, etc.).
// Cdigo de tecla 8 es Retroceso.
$.ajax

if

Nuestro cdigo completo para la presentacin del campo de bsqueda y comportamientos autocompletar es de la siguiente forma:

if

'offl)

.attr(rautocomplete',

.keyup(function(event)

if

}
else

(event.keyCode
== 40 &&
selectedltem
!== null) (
// Usuario ha pulsado
Flecha abajo.
setSelectedltem(selectedltem
+ 1);
event.preventDefault()
;

< O)

o;

if

}
if

.length) (
.length - 1;

}
$autocomplete.find('li')
.removeClass('selected')
.eq(selectedltem)
.addClass('selected');
$autocomplete.show()
;

i.

else if (event.keyCode
== 27 && selectedltem
// Usuario ha pulsado
tecla Ese.
setSelectedltem(null)
;

!== null)

}
}) .keypress(function(event)
if

(event.keyCode

== 13 && selectedltem

!== null)

1m

t.mI

8. Formularios con funciones

Aprende jQuery 1.3

/1 Usuario ha pulsado tecla


populateSearchField() ;
event.preventDefault() ;

Intro.

}
}) .blur(function(event)
(
setTimeout (function () (
setSelectedltem(null) ;
},

})

250);

j);

Trabajar con datos de formulario numricos


Ahora hemos examinado varias caractersticas de formulario que se aplican a entradas
textuales del usuario. Sin embargo, a menudo nuestros formularios son numricos en
contenido. Existen varias mejoras de formulario que podemos realizar cuando estamos
tratando con nmeros como valores de formulario.
En nuestro sitio de librera, un principal candidato para un formulario numrico es
el carrito de la compra. Necesitamos permitir que el usuario actualice cantidades de artculos que se compran, y tambin necesitamos presentar datos numricos de vuelta al
usuario para precios y totales.

Estructura de tabla de carro de la compra


El HTML para el carro de la compra describir una de las estructuras de tabla ms
relacionadas que hemos visto hasta el momento:

</tr>
ctr plass="shipping">
<td class="itemtl>Shippingc/td>
<ftd class=lIquantity">S</td>
'ctd class="price">$2
pe r, Lt.ernc y t.d s
<td class="cost">$lO.OOc/td>
</tr>
<tr class="total">
<td class="item">Total</td>
<td class="quantity"></td>
ctd class="price"></td>
<td class="cost">$172.13</td>
</tr>
<tr class="actions">
<td></td>
ctd>
<input type="button"
value=IIRecalculate11
</td>
<td></td>
ctd>

name="recalculate"
id="recalculatell

<input type=lIsubmit" name="submit"


value="Place
Order" id="submit"
</td>
</tr>
</tfoot>
<tbody>
<tr>

cform action=Ucheckout.php"
ctable id=lIcart">
cthead>

ctr>
cth
cth
cth
cth
</tr>
</thead>

class=llitem11>Iteme/th>
class=lIquantityl1>Quantity</th>
class="price'I>Pricec/th>
class="cost >Totalc/th>
11

Building Telephony
</td>
<td class="quantityll>
<input

Systems

With Asterisk

type="text"
name="quantity-2"
id="quantity-2
maxlength="3"

class=l1subtotalll>
ctd class="itemll>Subtotalc/td>
ctd class="quantityll></td>
ctd class=llprice"></td>
ctd class="cost">$152.9Sc/td>
</tr>
ctr class=lItaxl1>
ctr

ctd
ctd
ctd
ctd

class=llitem1'>Taxc/td>
class=l1quantity"></td>
class="price">6%c/td>
class="cost">$9.18c/td>

value="l"
/>

</td>
<td class="price">$26.99c/td>
<td class="cost">$26.99</td>
</tr>
<tr>
<td class="item">
Smarty PHP Template
</td>
<td class=lIquantity">
cinput

ctfoot>

/>

<td class="item">

11

methoct="postll>

/>

Prograrnming

and Applications

type=tltext" name="quantity-l"
id=lIquantity-l"
maxlength="3"

value="2"
/>

</td>
<td class="price">$35.99</td>
<td class="cost">$71.98</td>
</tr>
<tr>
<td class="item">
Creating your MySQL Database
</td><td class="quantity">
<input

type="text"
name="quantity_3"
id="quantity-3"
maxlength="3"

value="1"
/>

mi

&lI

r"

p"

8. Formularios con funciones

Aprende jQuery 1.3

</td>
ctd

class="price">$17.99c/td>

ctd

class="cost">$17.99</td>

mi

Antes de pasar a manipular los campos de formulario, aplicaremos una lnea estndar
de cdigo de.fila de diferente color para mejorar la apariencia de la tabla:

</tr>
$ (docurnent) .~eady(function()
{
$ ('#cart "t body tr: nth-child (everO.,') .addClass
}) ;

ctr>

class="item">
Drupal: Creating 810g5, Forums,
Community Websites
</td>
ctd class="quantity">

ctd

<input

type="text

ll

Portals,

value=1I111

11

11

('alt' ) ;

Una vez ms, nos aseguramos de seleccionar solamente filas a colorear si estn en el
cuerpo de la tabla, como se ve en la figura 8.21.

name="quantity-4

id="quantity-4

and

maxlength="3

11

/>

</td>
ctd

class="pricer'>$35.99</td>

ctd

class="cost">$35.99</td>

</tr>
</tbody>
</table>
c/form>

Esta tabla presenta otro elemento pocas veces visto, -ct f oot;. Como -;:thead>, este
elemento agrupa un conjunto de filas de tabla. Observe que aunque el elemento viene
delante del cuerpo de la tabla, se presenta detrs del cuerpo cuando se muestra la pgina, como se ve en la figura 8.20.

Shlpplng

S2perttem

Tocal

Ut'ildlli

@i.~

Figura 8.21. Coloreas filas a bandas.


nem

QuanUty

Building Telephony Syalems WIIh_


Smar1y PHP Templata Prograrnmlng and Appllcatlons
eraeUng your MySQL Dombase
Drupa!: CraaUngBIogs, Forums. PorIBls, 800 COmmunlly
Websltes

Prlce

Total

$26.99

$26.99

D
D
D

$35.99

571.99

$17.99

$17.99

$35.99

$35.99

SubtolBl

$152.95

Tax

6%
$2 perltem

Shlpplng
Tocal

$9.18
$10.00
$1n.13

o 'i!lKi'i0i'd~

Figura 8.20. Uso de <tfoot> y <thead>.

El orden de este cdigo fuente, aunque no intuitivo para los diseadores que piensan
visualmente sobre cmo se muestra la tabla, es de utilidad para aquellos con problemas
visuales. Cuando la tabla se lee en alto por dispositivos de ayuda para usuarios con necesidades especiales, el pie de pgina se lee antes que el contenido potencialmente extenso, permitiendo al usuario recibir un resumen de lo que va a venir.
Tambin hemos situado una clase en cada celda de la tabla, identificando qu columna de la tabla contiene esa celda. En el captulo anterior, hemos demostrado algunas formas de encontrar celdas en una columna al examinar el ndice de la celda dentro de su
fila. Aqu permitiremos que el cdigo ]avaScript sea ms sencillo al hacer que la fuente
HTML sea un poco ms compleja. Con una clase identificando la columna de cada celda,
nuestros selectores se pueden hacer ms sencillos.

Rechazar entrada no numrica


Cuando hemos mejorado el formulario de contacto, hemos tratado algunas tcnicas
de validacin de entrada de datos. Con ]avaScript, verificamos que lo que ha escrito el
usuario coincide con lo que esperbamos de modo que pudiramos proporcionar feedback
antes incluso de que se enviara el formulario al servidor. Ahora, examinaremos el equivalente a validacin de entrada de datos denominada enmascarar entrada de datos.
La validacin de entrada de datos comprueba lo que el usuario ha escrito segn ciertos criterios para entradas vlidas. Enmascarar entrada de datos aplica criterios a las
entradas mientras se estn escribiendo en primer lugar, y simplemente desestima pulsaciones de teclado no vlidas. En nuestro formulario de carro de la compra, por ejemplo,
los campos de entrada de datos deben contener slo nmeros. El cdigo de enmascarar
entrada de datos puede hacer que cualquier tecla que no sea un nmero no haga nada
cuando uno de estos campos recibe el foco:
$('td.quantity
input') .keypress(function(event)
if (event.which
&& (event.which
< 48 II
event.which
> 57)) (
event.preventDefault()
;

}
})

Cuando capturamos pulsaciones de teclado para la funcin autocompletar de nuestro campo de bsqueda, observamos el evento keyup. Esto nos permite examinar la

mi

8. Formularios con funciones

propiedad . keyCode del evento que nos ha dicho qu tecla se ha pulsado en el teclado.
Aqu, observamos el evento keypress en su lugar. Este evento no tiene una propiedad
. keyCode, pero en su lugar ofrece la propiedad. which. Esta propiedad informa del
carcter ASCII que est representado por la pulsacin de teclado que acaba de ocurrir.
Si la pulsacin de teclado resulta en un carcter (es decir, no es una tecla del cursor,
Supr, o alguna otra funcin de edicin) y ese carcter no est en el rango de cdigos
ASCII que representan numerales, entonces invocamos. preventDefaul
t () en el
evento. Como hemos visto antes, esto impide que el navegador acta sobre el evento; en
este caso, eso significa que el carcter nunca se inserta en el campo. Ahora, los campos
de cantidad pueden aceptar solamente nmeros.

Aprende jQuery 1.3

mi

mismo smbolo. Por el contrario, necesitamos una cadena a pasar al mtodo. t extt ) de
jQuery cuando mostramos el resultado del clculo, de modo que utilizamos la funcin
String () para crear una nueva utilizando nuestra cantidad total calculada.
Cambiar una cantidad ahora actualiza el total automticamente, como se ve en la
figura 8.22.
.>

Clculos numricos
6%

Ahora, pasaremos a cierta manipulacin de los nmeros que el usuario incorporar


en el formulario de carro de la compra. Tenemos un botn Recalculate (Volver a calcular) en el formulario, que har que el formulario se enve al servidor, donde se pueden
calcular nuevos totales y el formulario se puede presentar de nuevo al usuario. Esto requiere un recorrido completo que no es necesario, sin embargo; todo el trabajo se puede
realizar en el lado del navegador utilizando jQuery.
El clculo ms sencillo en este formulario es para la celda en la fila Shipping (EnVO)
que muestra la cantidad total de elementos solicitados. Cuando el usuario modifica una
cantidad en una de las filas, queremos aadir todos los valores incorporados para producir un nuevo total y mostrar este total en la celda:
Var $quantities
= $('td.quantity
input');
$quantities.change(Eunction()
(
var totalQuantity = O;
$quantities.each(Eunction()
(
var quantity
= parselnt(this.value);
totalQuantity
+= quantity;

})
})

td.quantity')

$2 por Item

(_0Iifi~

~Ki0I~

Figura 8.22. Actualizar la cantidad total automticamente.

Analizar y aplicar formato a moneda


Ahora, podemos pasar a los totales en la columna derecha. El coste total de cada fila
se debera calcular al multiplicar la cantidad facilitada por el precio de ese elemento.
Puesto que estamos llevando a cabo varias tareas para cada fila, podemos empezar por
volver a estructurar los clculos de cantidad un poco para que se basen en fila en lugar
de en campos:
$('#cart
tbody tr') .each(Eunction()
(
var quantity
= parselnt($('td.quantity
totalQuantity
+= quantity;

})

$('tr.shipping

15

input',

this) .val());

.text(String(totalQuantity));

Tenemos varias opciones respecto al evento a seguir para esta operacin de volver
a calcular. Observaremos el evento keypress, y activaremos el volver a calcular con
cada pulsacin del teclado. Podramos tambin observar el evento blur, que se activa
cada vez que el usuario abandona el campo. Aqu, podemos ser algo ms conservadores
con el uso de CPU, sin embargo, y solamente llevar a cabo nuestros clculos cuando se
activa el evento change. De esta forma, volvemos a calcular los totales solamente si el
usuario abandona el campo con un valor diferente de lo que tena antes.
La cantidad total se calcula utilizando un sencillo bucle . each ( ) . La propiedad
. value de un campo informar de la representacin de cadena del valor del campo,
de modo que utilizamos la funcin parselnt
() incorporada para convertir esto en un
entero para nuestro clculo. Esta prctica puede evitar situaciones extraas en las que la
suma se interpreta como concatenacin de cadena, ya que las dos operaciones utilizan el

Esto produce el mismo resultado que antes, pero nosotros ahora tenemos un lugar
adecuado para insertar nuestro clculo de coste total para cada fila:
$('td.quantity
input') .change (Eunction ()
var totalQuantity = O;
$('#cart
tbody tr') .each(function()
(
var price = parseFloat($('td.price',
.replace(rA\d.J*/,
"));
price = isNaN{price) ? O : price
var quantity =
parselnt ($ ('td.quantity
input',
var cost = quantity * price
$('td.cost',
this).text('$'
+ cost);
totalQuantity
+= quantity;

this) .text()

this) .val());

j);
$('tr.shipping

})

td.quantity')

.text(String(totalQuantity));

EifI

8. Formularios con funciones

Aprende jQuery 1.3

Vamos a buscar el precio de cada elemento de la tabla utilizando la misma tcnica


que necesitamos cuando ordenbamos tablas por precio anteriormente. La expresin regular primero quita los smbolos de moneda de delante del valor, y la cadena resultante
luego se enva a parseFloa
t ( ) , que interpreta el valor como un nmero en coma flotante. Puesto que realizaremos clculos con el resultado, necesitamos comprobar que se
ha encontrado un nmero, y establecer el precio en O de lo contrario. Por ltimo, multiplicamos el coste por la cantidad, y luego situamos el resultado en la columna total
con un $ precedindolo. Ahora podemos ver nuestros clculos totales en accin como
muestra la figura 8.23.

mi

Como vemos aqu, el total que debera ser $1079.70 se muestra como $1079.7. Incluso
peor, los lmites de precisin de JavaScript algunas veces pueden conducir a errores de
redondeo. Estos pueden hacer que los clculos aparezcan completamente rotos.
f

Tax

6%

Shlpplng

$2 perttem

52

Total

@iJCritet

@'t_gj~f~

Figura 8.25. Errores de redondeo.

Afortunadamente,
la solucin para ambos problemas es sencilla. La clase Number de
JavaScript tiene varios mtodos para tratar con este tipo de problema, y . toFixed
()
ajusta la cuenta aqu. Este mtodo toma un nmero de lugares decimales como parmetro, y devuelve una cadena que representa el nmero en coma flotante redondeado
a esos muchos lugares decimales:

6%
16

$2 perltem

~lliliiil~

Figura 8.23. Clculos totales.

Tratar con decimales


Aunque hemos situado signos de dlar delante de nuestros totales, JavaScript no es
consciente de que estamos tratando con valores monetarios. Por lo que se refiere al ordenador, son smplemente nmeros, y se deberan mostrar con tal. Esto significa que
si el total termina en un cero detrs del punto decimal, se eliminar, como se ve en la
figura 8.24.

SUbtlllal

Ahora nuestros totales todos se muestran

como valores monetarios

$152.95

Tal<
Shlpplng

$('#cart tbody tr') .each(function()


(
var price ~ parseFloat($('td.price',
this) .text()
.replace(j"["'d.J*j,
"));
price = isNaN(price) ? o : price;
var quantity ~ parselnt($('td.quantity
input', this) .val());
var cost = quantity * price
$('td.cost', this) .text('$' + cost.toFixed(2));
totalQuantity +~ quantity;
}) ;

43

6%

$9.18

$2 per Item

$10.00

Total

$1T2.13
t1<iiiilC_~

Figura 8.24. Trabajar con decimales.

~~

Tax
Shlpplng

6%
52

S2peritem

Total
@t'8Iil~

Figura 8.26. Mejorar los valores monetarios con decimales.

normales.

mi

8. Formularios con funciones

Aprende jQuery 1.3

ED

Redondear valores
Despus de una larga serie de operaciones aritmticas, el redondeo de nmeros en coma
flotante podria causar suficiente error acumulado que incluso . toFixed () no pueda
enmascararlo. Laforma ms segura de gestionar manipulaciones de moneda en grandes
aplicaciones es almacenar y manipular todos los valores en cntimos, como enteros; los
puntos decimales se pueden aadir para visualizacin solamente.

Para calcular impuestos, necesitamos dividir la cifra facilitada entre 100 y luego
multiplicar taxRate por el subtotal. Como el impuesto siempre se redondea, debemos
asegurarnos de que el valor correcto se utiliza tanto para la visualizacin como para clculos posteriores. La funcin Math. ee il () de JavaScript puede redondear un nmero
hacia arriba hasta el entero ms prximo, pero puesto que estamos tratando con dlares
y cntimos tenemos que ser un poco ms complicados:
var taxRate = parseFloat($('tr.tax
td.price') .text(
j
var tax = Math.ceil(totalCost
* taxRate * 100) j 100;
$('tr.tax
td.cost') .text('$' + tax.toFixed(2;
totalCost
+= taxi

Otros clculos
El resto de los clculos en la pgina siguen un patrn similar. Para el subtotal, podemos sumar nuestros totales para cada fila segn se calculan, y mostrar el resultado utilizando el mismo formato de moneda que antes, como se ve en la figura 8.27.
$('td.quantity
input') .change(function()
var totalQuantity = Di
var totalCost a O;
$('#cart
tbody tr') .each(function()
{
var price = parseFloat($('td.price',
this) .text()
.replace(jA(A\d.*/,
";
price = isNaN(price)
? O : price;
var quantity =
parselnt($('td.quantity
input', this) .val(;
var cost = quantity * price
$('td.cost',
this) .text('$' + cost.toFixed(2;
totalQuantity
+= quantity;
totalCost += cost;
j);
$ ('tr.shipping
td.quantity')
.text (String(totalQuantit
$('tr.subtotal
td.cost') .text('$'
+
totalCost.toFixed(2;

100;

El impuesto se multiplica por 100 primero de modo que se convierte en un valor en


cntimos, no dlares. Esto luego se puede redondear de forma segura por Math . ee i 1 ( )
y luego dividirse por 100para convertirlo de nuevo en dlares. Por ltimo, . toFixed ()
se invoca como antes para producir el resultado correcto.

"

6%
$2 por ltBm

Shlpplng

T_
~ttiKaJaliiO,

y;

~~l

Figura 8.28. Calcular el impuesto.

j);

Toques finales
El clculo de envo es ms sencillo que el impuesto ya que no implica ningn redondeo en nuestro ejemplo. El transporte se multiplica por el nmero de artculos para
determinar el total:
$('tr.shipping
td.quantity')
.text(String(totalQuantity;
var shippingRate
= parseFloat($('tr.shipping
td.price')
.text().replace(r(A\d.l*j,
";
var shipping
= totalQuantity
* shippingRate;
$('tr.shipping
td.cost') .text('$' + shipping.toFixed(2;
totalCost
+= shipping;

6%
23

,Rii:II~

$2 perttem

@'i!<i!<d~

Hemos estado siguiendo el importe total a medida que hemos ido avanzando, por
lo que todo lo que nos queda por hacer para esta ltima celda es formatear totalCost
de forma apropiada:

Figura 8.27. Gestionar totales.


$('tr.total

td.cost')

.text('$'

+ totalCost.toFixed(2;

mi

8. Formularios con funciones

Aprende jQuery 1.3

.insertAfter($('td:nth-Child(2)',
.append($deleteButton)
;

Ahora, hemos replicado por completo cualquier clculo del lado del servidor que ocurrira, por lo que podemos ocultar el botn Recalculate, como muestra la figura 8.29.
$('#recalculate')

) ;
$ ('<td>&bsp;</td>')
.insertAfter ('#cart

.hide();

tfoot

this

t,f:'>nth-child(2) ,) ;

Necesitamos crear celdas vacas en las filas cabecera y pie de pgina como marcadores
de posicin de modo que las columnas de la tabla se alineen correctamente. Los botones
se crean y aaden en las filas del cuerpo solamente, como muestra la figura 8.30.

Tax

6%

Shlpplng

$2 perltem

Total

@~~~
Figura 8.29. Eliminar el botn Recalculate.

.'
Shipplng

Si los comprobadores en nuestro sitio cambian de parecer acerca de los elementos


que han aadido a sus carros, pueden cambiar el campo Quantity (Cantidad) para esos
elementos a O.Podemos proporcionar un comportamiento ms alentador, sin embargo,
al aadir botones Delete (Suprimir) explcitos para cada elemento. El efecto actual del
botn puede ser el mismo que cambiar el campo Quantity, pero el feedback visual puede
reforzar el hecho de que el artculo no se comprar.
.; ,.
En primer lugar, necesitamos aadir los nuevos botones. Puesto que no funcionar
sin JavaScript, no los pondremos en el HTML. En su lugar, dejaremos que jQuery los
aada a cada fila:

Figura 8.30. Permitir eliminar elementos.

~-~

Ahora necesitamos hacer que los botones hagan algo. Podemos cambiar la definicin
del botn para aadir un manejador click:

Eliminar elementos

$('<th>&nbsp;</th>')
.insertAfter('#cart
thead th:nth-child(2)
$('#cart tbody tr') .each(function()
{
$deleteButton
~ $('<irng />') .attr({
'width':
'16',
height ':
16 '
'src':
/imag8s/cross.png',
'alt': 'remove from cart',
'title': 'remove from cart',
'class': 'clickable'
) ;
$ ( "<t.do c y t do ' )

$2 perltem

Total

Este cambio una vez ms se hace eco de nuestro principio de mejora progresiva: en
primer lugar, asegrese de que la pgina funciona correctamente sin JavaScript. Luego,
utilice jQuery para llevar a cabo la misma tarea de forma ms elegante cuando sea posible.

');

$deleteButton
width
height
I

~ $('<irng />') .attr({


'16

1:

1161,

1:

'src':
/images/cross.png',
'alt': 'remove from cart',
'title': 'remove from cart',
'class': 'clickable'
}) .click(functionn
{
l

..

$(this).parents('tr')
.val (O);

.find('td.quantity

input')

El manejador encuentra el campo quanti ty en la misma fila que el botn, y establece el valor en 0, como muestra la figura 8.31. Ahora, el campo se actualiza, pero los
clculos no estn en sincrona.
Necesitamos activar el clculo como si el usuario hubiera cambiado manualmente
el valor del campo:

$deleteButton
~ $('<irng />') .attr({
'width':
'16',
'height':
'16',
'sre': '../images/eross.png',
'alt': 'remove fraro cart',
'title
'remove froro cart',
1:

i~~"

8, Formularios con funciones

Aprende jQuery U

class
'clickable'
}I.click(function()
{
$(thisl .parents('tr'l
.find('td.quantity
.val(O) .trigger('change');
I

BD

1:

input'l

}I ;

6%
$2pe<ltem

Tax

Shlpplng

__
....

"_1

Total

~
Figura 8.33. Ocultar la fila en la tabla.
Tax

6%
$2perHem

Shlpplng

YoIal

{I!I-.w-.,
Figura 8.31. Aadir un manejador al baln.

.:

Ahora los totales se actualizan cuando se hace clic en el botn.

Cuando la fila se oculta,el campo sigue presente en el formulario. Esto significa que
se enviar con el resto del formulario, y el elemento se eliminar en el lado del servidor
en ese momento.
Nuestro diseo de filas de lneas alternas se ha visto alterado al eliminar esta fila.
Para corregir esto, movemos nuestro cdigo de filas alternas existentes a una funcin
de modo que podemos invocarla de nuevo ms adelante. Al mismo tiempo, necesitamos modificar el cdigo para asegurarnos de que nuestra seleccin de fila alterna ignora
cualquier fila oculta.
Desafortunadamente, incluso si filtramos todas las filas ocultas, seguimos sin poder
utilizar el selector : nth-child (even), porque aplicar la clase al t a todas las filas visibles que son hijo par de su padre. Veamos lo que sucede cuando aplicamos el siguiente
cdigo modificado a cuatro filas de tabla cuando la segunda est oculta:
$('#cart
tbody tr'l .removeClass('alt')
.filter(' ,visible,nth-child(even)

') .addClass('alt');

Recibimos el siguiente cdigo [resumido]:


i'i_di'~
Figura 8.32. Actualizar totales.

Ahora el feedback visual. Ocultaremos la fila en la que se ha hecho clic, de modo que
el elemento se elimina claramente de la cesta, como muestra la figura 8.33.
$deleteButton
= $('<img
/>') .attr({
'width':
'16',
'height':
'16',
'sre': ' ../images/cross.png',
'alt': tremove from cart'
'title':
'remove from cart'
'class':
'clickable'
)) .click(function()
(
$(this) .parents('tr')
.find('td.quantity
.val(O) .trigger('change')
.end () .hide () ;
));
I

<tr> . . . </tr>
e t r- s t.y Lee "display:
none 11:>
e t r s . . . </tr>
<tr class="alt">
. . . </tr>

</tr>

Son visibles tres filas; slo la cuarta tiene aplicada la clase al t. Lo que necesitamos
es la expresin selector : visible: odd, ya que elegir cada dos filas despus de eliminar las ocultas de la seleccin (y justifica el cambio de un selector de ndice uno a otro
de ndice cero). Como se vio en el captulo2, utilizar: odd o : even podra producir resultados inesperados si tuviramos ms de un elemento -c t body. pero en este caso,
estamos en buena forma. Con el cambio de selector en su lugar, nuestra nueva funcin
se parece a esto:
var

input')

stripe = function()
{
$('#cart
tbody tr') .removeClass('alt')
.filter(' ,visible,odd')
.addClass('alt');

};
stripe()

&llI

8. Formularios con funciones

Aprende jQuery 1.3

Ahora podemos invocar esta funcin de nuevo despus de eliminar una fila:
=

$deleteButton
I

width

1:

16

$('<img
I

1>'1

.attr({

height ": 116


'sre':
/images/cross.png',
lalt': Iremove from cart',
'title': 'remove from cart',
'class': 'clickable'
}1.click(function(1
(
$(this) .parents('tr'l
.find('td.quantity
.val(O) .trigger('change')
.end () .hide () ;
stripe ();
}) ;
I

Pero con JavaScript disponible, y con el potencial de jQuery a nuestra disposicin,


podemos convertir este pequeo vnculo en un formulario completo. Realizaremos esto
al solicitar el formulario desde una pgina PHP. Tpicamente los datos que completan
el formulario se almacenarn en una.base de datos de algn tipo, pero para los fines de
esta demostracin, mantendremos algunos datos estticos en una tabla PHP.
Para recuperar el formulario y hacer que aparezca dentro del cuadro Shipping to
(Enviar a), utilizamos el mtodo $ . get () dentro del manejador de evento. el iek () :
$ (document) .ready(function()
(
$('#shipping-name')
.click(function()
(
$.get('shipping.php',
function(data)
$('#shipping-name')
.remove();
$ (data) .hide() .appendTo('#shipping')

input'l

mi

})

La fila eliminada ahora ha desaparecido, como muestra la figura 8.34.


})

.slideDown();

return

false

Al comprobar la ausencia de la variable de servidor $_SERVER l ' HTTP_X_


REQUESTED
_WITH 1 antes de imprimir la mayor parte de la pgina, la pgina PHP
(shipping .php) devuelve solamente un fragmento de toda la pgina, el formulario,
cuando se solicita con el mtodo $. get () .
En la rellamada del mtodo $ . get ( ) eliminamos el nombre en el que se ha hecho
clicy en su lugar anexamos el formulario y sus datos desde shipping .php. Luego aadimos return false de modo que el evento predeterminado para el vnculo en el que
se hace clic (cargar la pgina indicada en el atributo href) no ocurre. Ahora el cuadro
Shipping to es un formulario editable, como muestra la figura 8.36.
I

~i&-~

Figura 8.34. Eliminar la fila.


Shipplng lo:

Esto completa otra mejora utilizando jQuery que es completamente transparente


para el cdigo en el servidor. Por lo que se refiere al servidor, el usuario simplemente
ha escrito un Oen el campo de entrada, pero para el usuario se trata de una operacin
de eliminacin diferente de cambiar una cantidad.

Flrstname:

Las! name:

__

Addmss:ooeo

Drl""

CIIy: ~~.

l?
ZlP: C

Stale:

Editar informacin de envo


La pgina del carro de la compra tiene tambin un formulario para informacin de
envo. En realidad, no se trata de un formulario cuando se carga la pgina, y sin JavaScript
habilitado, se muestra como un cuadro escondido a la derecha del rea de contenido,
que contiene un vnculo a una pgina donde el usuario puede editar la informacin de
envo, como se ve en la figura 8.35.

4staveScll

Figura 8,35. Acceso a la informacin de envo.

==:::J

Schoon

=::J

I
I

I
J

GttImessage: !:jOY thEtB8 grs8,t. books-r


the cliff-han,9'eral

You' 11 leva

~
Figura 8,36. Cuadro de envo como formulario editable.

El usuario ahora puede editar la informacin de envo sin dejar la pgina.


El siguiente paso es secuestrar el envo del formulario y publicar los datos editados
de vuelta al servidor con jQuery. Empezamos al serializar los datos en el formulario y
almacenarlos en una variable postData. Luego publicamos los datos de vuelta al servidor utilizando shipping. php una vez ms:

&iI

8. Formularios con funciones

Aprende jQuery 1.3

$ (document) .ready(function()
{
$('shipping
form') .submit(function()
(
var postData = $(this) .serialize();
$.post('shipping.php',
postData);
return false
};
j);

var

mi

saveShipping
= function() {
var postData
= $('#shipping
,input') .serialize();
$.post("shipping.php',
postData,
function(data)
{
$('~shipping
form') .remove();
$ (data) .appendTo('#shippin~');
$('#shipping-name')
.click(editShipping),
}) ;
return false

};
$ ('#shipping-name')

.click(editShipping),

}) ;

Elplug-injQuery Form ofrece un mtodo . serialize


() ms robusto. El plug-in, que
se puede encontrar en http://www.malsup.com/j
query/form/,
se recomienda
para la mayora de escenarios de envo de formularios AJAX.
Tiene sentido que se elimine el formulario en este punto y que el cuadro Shipping
to regrese a su estado original. Podemos conseguir esto en la rellamada del mtodo
$ . post () que acabamos de utilizar:
$ (document) .ready(function()
{
$('#shipping
form') .submit(function()
(
var postData
= $(this) .serialize();
$.post('shipping.php',
postData,
function(data)
$ ('#shipping
form') .remove(),
$ (data) .appendTo('#shipping'),

})

.'

return

false

};

})

Pero, esto no funcionar. La forma en la que lo tenemos configurado ahora, el manejador de evento . submi t () se vincula al formulario Shipping to tan pronto como se
carga el DOM, pero el formulario no est en el DOM hasta que el usuario hace clic en el
nombre Shipping to. El evento no se puede vincular a algo que no existe.
Para solucionar este problema, podemos situar el cdigo de creacin de formulario
en una funcin denominada edi tShipping
() y el cdigo de envo del formulario o
eliminacin del formulario en una funcin denominada saveShipping
() . Luego podemos vincular la funcin saveShipping
() en la rellamada de $ . get (), despus de
que se haya creado el formulario. De igual forma, podemos vincular la funcin edi tShi pping () tanto cuando el DOM est listo y cuando el vnculo Edit shipping se vuelve
a crear en la rellamada de s . post () :
$ (document) .ready(function()
(
var editShipping
= function()
{
$.get('shipping.php',
function(data)
$('#shipping-name')
.remove();
$ (data) .hide() .appendTo('#shipping')
.slideDown();
$('#shipping
form') .submit(saveShipping),

})

return

i.

false

El cdigo ha formado un patrn circular de cierto tipo, en el que una funcin permite
la otra al volver a vincular sus respectivos manejadores de evento.

El cdigo terminado
Tomados juntos, el cdigo para la pgina de carrito de la compra son meramente 80
lneas, bastante pequeo considerando la funcionalidad que realiza, pero especialmente
cuando tenemos en cuenta el estilo dinmico que ha adquirido el cdigo para legibilidad
ptima. Muchas de las lneas en jQuery se podran haber combinado, si hubiramos estado particularmente preocupados con el nmero de lneas, debido a la posibilidad de
encadenar de jQuery. En cualquier caso, aqu tiene el cdigo terminado para la pgina
de carrito de compra, que concluye este captulo sobre formularios:
$ (document) .ready(function()
(
var stripe = function()
{
$('#cart
tbody tr') .removeClass('alt')
.filter(' :visible:odd') .addClass('alt')

};
stripe()
$('#recalculate')

.hide();

$(' .quantity input') .keypress(function(event)


if (event.which
<< (event.which
< 48 II
event.which>
57))
event.preventDefault();

}) .change(function()
var totalQuantity
= O;
var totalCost
= O;
$('#cart
tbody tr') .each(function()
(
var price = parseFloat($(' .price', this)
.text () .replace
['\d.] * /,
";
price = isNaN(price)
? O , price;
var quantity =
parselnt($('
.quantity input', this) .val(), 10);
var cost = quantity * price
$ (,.cost " this). text (,$' + cost. toFixed (2 ;
totalQuantity
+= quantity;

(r

~"!n'

&DI

8. Formularios con funciones


totalCost

Aprende jQuery 1.3

cost

+=

}) ;
return. false

});

IJD

};
$(' .subtotal .cost') .text('$' + totalCost.toFixed(2));
var taxRate = parseFloat($(' .tax .price') .text()) / 100;
var tax = Math.ceil(totalCost
* taxRate * 100) / 100;
$('.tax .cost').text('$' + tax.toFixed(2));
totalCost += taxi
$(' .shipping .quantity') .text(String(totalQuantity));
var shippingRate = parseFloat($('.shipping
.price')
.text() .replace(r'\d.]*/,
"));
var shipping = totalQuantity
* shippingRate;
$(' .shipping .cost') .text('$' + shipping.toFixed(2));
totalCost += shipping;
$(' .total .cost') .text('$' + totalCost.toFixed(2));

})

$('<th>&nbsp;</th>')
.insertAfter('#cart
thead th:nth-child(2) ');
$('#cart tbody tr') .each(function()
{
$deleteButton = $('<img />') .attr({
'width 1: '16',
'height': '16',
'src
/images/cross.png'
'alt': 'remove from cart
'title': 'remove from cart
c La s s ":
clickable
}) .click (function () {
$(this) .parents('tr') .find('td.quantity
.val (O) .trigger ('change' )
.end ().hide ();
stripe ();
l:

'

l,

$('#shipping-name')
})

.click(editShipping);

-',

Resumen
En este captulo hemos investigado formas de mejorar la apariencia y comportamento
de elementos de formulario HTML comunes. Hemos aprendido cmo mejorar el estilo
de formularios, ocultar y mostrar campos condicionalmente basndose en otros valores de campo, y validar contenidos de campos antes del envo y durante la entrada de
datos. Hemos tratado caractersticas como autocompletar AJAX para campos de texto,
permitiendo incorporar slo caracteres especficos en un campo, y llevar a cabo clculos
sobre valores numricos en campos. Tambin hemos aprendido a enviar formularios
utilizando AJAX en lugar de refrescar una pgina.
El elemento formulario es a menudo el pegamento que mantiene un sitio interactivo
junto. Con jQuery, podemos fcilmente mejorar la experiencia del usuario al completar
formularios mientras se preserva su utilidad y flexibilidad.

input')

});

$ (' c t.do e y t.d> ")


.insertAfter($('td:nth-child(2)',
.append($deleteButton) ;
});
$ (,<td>&nbsp; </td>' )
.insertAfter('#cart
tfoot

})

this))

td:nth-child(2)

');

$ (document) .ready(function()
{
var editShipping = function() {
$.get('shipping.php',
function(data)
$('#shipping-name') .remove();
$(data) .hide() .appendTo('#shipping') .slideDown();
$('#shipping form') .9ubmit(saveShipping);

})

return

false
};
var saveShipping = function() {
var postData = $(this) .serialize();
$.post('shipping.php',
postData, function(data)
$('#shipping form') .remove();
$(data) .appendTo('#shipping');
$('#shipping-name') .click(editShipping);

____________________________

.'

9
Rotativos

Hemos visto algunas formas de ocultar informacin cuando no se necesita y revelarla


bajo demanda. Algunas veces, sin embargo, queremos mover contenido en y fuera de la
vista con incluso ms estilo. Estos tipos de animaciones se conocen tambin como carruseles o rotativos. Lo que tienen en comn es una habilidad para girar rpidamente entre
mltiples datos en una forma llamativa e impresionante. En este captulo exploraremos
estas animaciones avanzadas, combinndolas con tcnicas AJAX y sutilezas CSSpara realmente causar impresin. Pasaremos por dos grandes ejemplos en este captulo: un ttulo
rotativo y un carrusel de imgenes. Estos ejemplos nos permitirn aprender cmo:

Animar la posicin de un elemento.

Analizar documentos XML.

Preparar efectos de estilo avanzados utilizando opacidad parcial.


Recuperar informacin de dominios diferentes.
Crear un elemento de interfaz de usuario para desplazamiento horizontal.
Componer capas para etiquetas y superposiciones.

Titular rotativo
Para nuestro primer ejemplo de rotativo, tomaremos un feed de noticias y desplazaremos los titulares, junto con extracto del artculo, a la vista uno de cada vez. Las historias fluirn hasta quedarse a la vista, se detendrn para leerse, y luego se desplazarn

mi

9. Rotativos

Aprende jQuery 1.3

fuera de la vista como si fueran una cinta infinita de informacin dando vueltas continamente por la pgina.

Configurar la pgina
En su nivel ms bsico, esta caracterstica no es muy dificil de implementar. Pero como
pronto veremos, hacer que est lista para produccin requiere un poco de sutileza.
Empezamos, como siempre, con un bloque de HTML. Situaremos el feed de noticias
en la barra lateral de la pgina:
<:h3>Recent News</h3>
<:div id="news-feedU>
<a href="news/index,htmlll>News
</div>

Releases</a>

Hasta el momento, el rea de contenido de nuestro feed de noticias contiene solamente


un solo vnculo a la pgina de noticias principal, como se ve en la figu5a 9.1.
Recent N_s
NowsRe!

Observe ql!-eaqu la altura de los elementos de noticias individuales (representados


por la clase headl ine) y su contenedor es de 2 OOpx.Igualmente, puesto que los elementos headl Lrie estn posicionados de forma absoluta relativos a #news - feed, podemos
alinear la parte superior de los elementos de noticias con la parte inferior de su contenedor. De esta forma, cuando establecemos la propiedad overflow de #news-feed
en hidden,los titulares no se muestran inicialmente. Establecer la posi tion de los ti- .
tulares en absolute
es necesario por otra razn tambin: para que cualquier elemento
tenga su ubicacin animada en la pgina, debe tener posicin absolute
o relati ve,
en lugar del posicionamiento static
predeterminado.
Ahora que tenemos el HTML y CSS en su lugar, podemos aplicar los elementos de
noticias desde un feed RSS. Para empezar, situaremos el cdigo en un mtodo. each ( ) ,
que actuar como una sentencia i f Ycontendr el cdigo dentro de un espacio de nombre privado:
$ (document) .ready(function()
(
$('#news-feed')
.each(function()
var $container
= $(this);
$container.empty()
;
}) ;
)) ;

S8~

Figura 9.1. rea de contenido inicial.

ste es nuestro apreciado escenario de degradacin, en caso de que el usuario no


tenga habilitado JavaScript. El contenido con el que trabajaremos proceder de un feed
RSS en su lugar.

Normalmente cuando utilizamos el mtodo . each ( ) , estamos iterando sobre un


conjunto de elementos posiblemente extenso. Sin embargo, aqu nuestro selector #newsfeed est buscando un ID, por lo que solamente existen dos resultados potenciales. La
funcin factory podra hacer que un objeto jQuery coincidiera con un nico elemento con
el ID news - f eed, o podra no encontrar elementos en la pgina con ese ID y producir
un objeto jQuery vaco. La llamada . each () se ocupa de ejecutar el cdigo contenido
si, y slo si, el objeto jQuery no est vaco.
Al principio de nuestro bucle . each ( ) , el contenedor del feed de noticias se vaca
para dejado listo para su nuevo contenido, como se ve en la figura 9.2.
RecentNews

El CSS para este <di v es importante ya que determinar no solamente cunto de


cada noticia se mostrar cada vez, sino tambin dnde en la pgina aparecern los elementos de noticias. Junto con la regla de estilo para los elementos de noticias individuales, el CSS se parece a esto:
#news-feed

position: relative
height: 200px;
width: 17em;
overflow:
hidden;

Figura 9.2. Vaciar el contenedor.

}
.headline

mi

position:
absolute;
height: 200px;
top: 210px;
overflow:
hidden;

Recuperar el feed
Para recuperar el feed, utilizaremos el mtodo $ . get ( ) , una de las muchas funciones
AJAX de jQuery para comunicarse con el servidor. Este mtodo, como hemos visto antes,
nos permite operar sobre contenido desde una fuente remota al utilizar un manejador de

lIlIlII

Aprende jQuery 1.3

9. Rotativos

xito. El contenido del feed se pasa a este manejador como una estructura XML. Luego
podemos utilizar el motor selector de jQuery para trabajar con estos datos.

mil

RecentNew8
IQuory. M!croto!!. and Nolda

$ (document) .ready(function()
(
$('#news-feed') .each(function()
var $container = $(this);
$container.empty();
$.get('news/feed.xml'.
function(data)
{
$ ('rss item'. data) .each(functionO
{
II Trabajar con los titulares aqu.
}) ;
}) ;

})
})

touery

UI18n:2

JOotry Confarenca 2008 Agenda


O.al!! lo JayaScr!pt Rock Sta,,1
IQuery Sita Red !an II!t
Communltv

,Speakl

IQuery.comSII!! Red go
Raglatratlan Optn tgr !QueN
ConferaDa, 2008
IQuerI UI1.5.2
/'

Figura 9.3. Todava no se ha aplicado la clase headline.

Adems de los titulares, deseamos mostrar un poco de informacin de soporte sobre


- cada artculo. Capturaremos la fecha de publicacin y resumen del artculo, y mostraremos esto tambin.
Para ms informacin sobre $. get () y otros mtodos AJAX, consulte enun captulo
anterior.

Ahora, necesitamos combinar las partes de cada elemento en un bloque de cdigo


HTML que se pueda utilizar. Podemos utilizar . each () de nuevo para pasar por los
elementos en el feed y crear los vnculos de los titulares:
$ (document) .ready(function()
(
$('#news-feed') .each(function()
var $container = $(this);
$container.empty();
$.get('news/feed.xml',
function(data)
{
$('rss item', data) .each(function()
{
var $link = $('<a></a>')
.attr('href'. $('link'. this) .text(
.text ($ (,title'. this). text O);
ver $headline = $('<h4></h4>').append($link);

$ (document) .ready(function()
(
$('#news-feed') .each(function()
var $container = $(this);
$container.empty() ;
$.get('news/feed.xml'.
function(data)
{
$('rss item', data) .each(function()
{
var $link = $ ('<a></a>')
.attr('href', $('link', this) .textO)
.text($('title', this) .text(;
var $headline = $('<h4></h4>') .append($link);
var pubDate = new Date(
$('pubDate'. this).text(;
var pubMonth ~ pubDate.getMonth()
+ 1;
var pubDay = pubDate.getDate();
var pubYear = pubDate.getFul1Year();
var $publication = $('<div></div>')
.addClass('publication-date')
.text(pubMonth + '1' + pubDay + '1'
+ pubYear);
var $summary = $('<div></div>')
.addC1ass('summary')
html ($ ('description'. this). text O) ;

$ ('<div></div>')
.append($headline)
.appendTo($container);

})
})
})
})

$ (' <div></div>')
.append($head1ine.

$publication.

.appendTo($container)

$summary)

});

Obtenemos el texto de los elementos <ti t Le s y <link> de cada elemento, y construimos el elemento <a> a partir de ellos. Este vnculo luego se sita en un elemento
<h4 >. Situamos cada elemento de noticias en <di v id= "news - feed" , pero por ahora
estamos omitiendo la clase headl ine en el <di v contenedor de cada noticia, de
modo que podemos ver ms fcilmente nuestro trabajo en progreso, como muestra la
figura 9.3.

}) ;
}) ;

})

La informacin de fecha en un feed RSS se codifica en formato RFC 822, que incluye
informacin de fecha, hora y zona horaria (por ejemplo, sun , 28 Sep 2 OO8 18 : 01 : 55
+ O O O O). Este formato no es particualrmente agradable a la vista, por lo que utilizamos el

Ea

9. Rotativos

Aprende jQuery 1.3

objeto Date incorpordo de JavaScript para producir una representacin ms compacta


de la fecha (como 9/28/2008).
La informacin de resumen es ms fcil de recuperar y aplicar formato. Sin embargo,
merece la pena destacar que en nuestro feed de ejemplo, algunas entidades HTML pueden existir en la descripcin. Para asegurarnos de que no se escapan automticamene
por jQuery, necesitamos utilizar el mtodo. htrnl () para insertar la descripcin en la
pgina, en lugar del mtodo. text ().
Con estos nuevos elementos creados, los insertamos en el documento utilizando el
mtodo . append ( ) . Observe aqu que estamos utilizando una nueva caracterstica del
mtodo; si se proporciona ms de un argumento, todos ellos se anexan en secuencia,
como muestra la figura 9.4.

lID

Tambin queremos que el primer titular sea visible inmediatamente al cargarse la


pgina. Para conseguir esto, podemos establecer su propiedad top en O.
$('div.headli~')

.eq(currentHeadline) .css('top', 01;

El rea del rotativo de la pgina est ahora en el estado inicial correcto.


Recent Newa
IQl!lry. Mlcro!oll
9/2812008

and NOIIIa

Wa llaVe twa pleces of fanlas1lc, albeH


Berendlpltous, news today: BoIh
Mlcroson and NoIda arelaklng 1Ile
majar slap 01 adolUng jQuery as par!
o/1heIr oIIIoIai appllcatlon
daVelopment plalfonn.

Recent Newa
IQueo( MIc!'QIoll and NaJIla
9/211I2008
We llaVe twa pleces of fanIasUc, albeIt
sernndlpltous, news tDday: 60th
MlcroBOft and Nakla are Ialclng 1Ile
maJarstep of adolUng jQuelY as par!
011llelr 011I0101
applloatlon
development plaiform.

Figura 9.5. Primer titular visible .

'

Por ltimo, almacenamos el nmero total de titulares para uso posterior y definimos
una variable de tiempo de espera a utilizar para el mecanismo de pausa entre cada rotacin.

IQueo( UJ 1.6rc2
9/1912008
Hev evervone.

j'm oled 10 announce

var headlineCount = $('div.headline'l .length,

Figura 9.4. Anexar los elementos en secuencia.

var pause

Como podemos ver, el ttulo, fecha, vnculo y resumen de cada noticia ahora estn en
su lugar. Todo lo que queda es aadir la clase headl ine con. addClass ( headl ine
(que ocultaremos a la vista debido al CSS definido anteriormente), y estamos listos para
continuar con nuestra animacin.
I

I )

Configurar el rotativo

la funcin rotar titular

Puesto que el elemento de noticias visible cambiar con el tiempo, necesitamos una
forma de mantener fcilmente registro de qu elementos son visibles y dnde estn. En
primer lugar, estableceremos dos variables, una para el titular actualmente visible, y otra
para el titular que acaba de no estar a la vista. Inicialmene, ambos valores sern O.
var currentHeadline = o, oldHeadline = o;

A continuacin, nos ocuparemos del posicionamiento inicial de los titulares. Recuerde


que en la hoja de estilo acabamos de establecer la propiedad top de los titulares en la
pxeles ms grande que la height de su contenedor; puesto que el contenedor tiene una
propiedad de overflow de hidden, los titulares no se muestran inicialmente. Ser de
utilidad ms adelante si almacenamos esa propiedad en una variable, de modo que podamos mover titulares a esta posicin cuando sea necesario.
var hiddenPosition = $container.height(1

No hay necesidad todava de asignar a pause un valor en este momento; se establecer cada vez que ocurre la rotacin. Sin embargo, siempre debemos declarar variables locales utilizando var para evitar el riesgo de colisiones con variables globales del
mismo nombre.

10;

Ahora estamos listos para rotar los titulares, fechas y resmenes. Definiremos una
funcin para esta tarea de modo que podamos repetir fcilmente la accin cada vez
que lo necesitamos. En primer lugar, ocupmonos de actualizar las variables que estn
registrando qu titular est activo. El operador mdulo (%) nos permitir fcilmente pasar
en ciclo por los nmeros de titulares. Podemos aadir 1 al valor currentHeadline
cada vez que nuestra funcin se invoca, y hacer que este valor mdulo tome el valor
headlineCount
para limitar la variable a nmeros de titular vlidos.

Recuerde que hemos utilizado esta misma tcnica para pasar en ciclo por los colores
de fila cuando aplicbamos color alterno a filas de tabla.

mi

Aprende jQuery 1.3

9. Rotativos

f1D

Tambin deberamos actualizar el valor oldHeadl ine de modo que podamos fcilmente manipular el titular que se est moviendo fuera de la vista.

segundos despus de que se haya recuperado el feed RSS.Ahora tenemos un rotativo


de titulares totalmente operativo.

var headlineRotate
= function() {
currentHeadline
= (oldHeadline + 1) % headlineCount
// Animar las posiciones de titular aqu.
oldHeadline = currentHeadline
};

$ (document) .rrady(function()
(
$('#news-feed') .each(function()
var $container = $(this);
$container.empty() ;
$.get('news/feed.xml',
function(data)
{
$('rss item', data) .each(function()
{
var $link = $(Ica></a>')
.attr('href', $('link', this).text())
.text($('title', this) .text());
var $headline = $('<h4></h4>') .append($link) ;

Ahora tenemos que llenar el vaco con el cdigo que mueve los titulares. En primer
lugar, aadiremos una animacin que mueve el titular antiguo fuera de la vista. Luego,
insertaremos otra animacin que pasa el nuevo titular a la vista.
var headlineRotate
= function() {
currentHeadline
=
(oldHeadline + 1) % headlineCount
$('div.headline') .eq(oldHeadline) .animate(
{topo -hiddenPosition},
'slow', function()
$(this) .css('top', hiddenPosition);
}) ;
$(rdiv,headline')
.eq(currentHeadline) ,anmate (
{top: aL'
slow', function () (
pause = setTimeout(headlineRotate,
5000);

})

var
var
var
var
var

.'

var $summary = $('cdiv></div>')


.addClass(lsurnmary')
.html($('description',
this) .text());

oldHeadline

pubDate = new Date($('pubDate',


this) .text());
pubMonth = pubDate.getMonth()
+ 1;
pubDay = pubDate.getDate();
pubYear = pubDate.getFullYear();
$publication = $('cdiv></div>')
.addClass('publication-date')
.text(pubMonth + '1' + pubDay + '1' + pubYear);

currentHeadline

};

$('cdiv></div>')

.addClass('headline')
.append ($headline, $publication,
.appendTo($container) ;

En ambos casos, estamos animando la propiedad top del elemento de noticias.


Recuerde que los elementos estn ocultos porque tienen un valor top de hiddenPosition (que es un nmero mayor que la altura del contenedor). Animar esta propiedad en O pone el elemento a la vista; animarlo a - hiddenPos i t ion lo mueve fuera de
la vista de nuevo.

})

var currentHeadline
= o, oldHeadline
= o;
var hiddenPosition
= $container.height()
+ 10;
$('div.headline') .eq(currentHeadline) .css('top',
var headlineCount
= $(rdiv.headliner)
.length
var pause

O);

var headlineRotate
= function() {
currentHeadline
=
(oldHeadline + 1) % headlineCount;
$('div.headline') .eq(oldHeadline) .animate (
{topo -hiddenPosition},
'slow', function()
$(this) .css('top', hiddenPosition);

Recuerdede un captuloanterior que top es una propiedad de posicionamientoCSS,y


solamente tiene efectosi la posi tion del elemento es absolute b r"lati ve.

})

En ambos casos, tambin tenemos una funcin de rellamada especificada para actuar
cuando se completa la animacin. Cuando el titular antiguo ha salido completamente
de la vista, hace que su propiedad top se restablezca en hiddenPosi tion de modo
que est listo para regresar ms tarde. Cuando el titular de noticias ha terminado con
su animacin, queremos que ponga en cola la siguiente transicin; esto se realiza con
una llamada a lafuncin}avaScript setTimeout (), que registra una funcin a invocar
despus de un perodo especificado. En este caso, estamos haciendo que headl ineRotate () se lance de nuevo en cinco segundos (5000milisegundos).
Ahora tenemos un ciclo de actividad; una vez que se completa una animacin, la
siguiente est lista para activarse. Queda invocar la funcin la primera vez; haremos
esto con otra llamada a setTimeout (), haciendo que la primera transicin ocurra 5

$summary)

$('div.headline') .eq(currentHeadlinet.animate(
(top: o), 'slow', function () (
pause = setTimeout(headlineRotate,
5000);

})

oldHeadline
};
pause

})

= currentHeadline;

setTimeout(headlineRotate,

5000)

}l;

})

A mitad de la animacin, podemos ver un titular cortado en la parte superior, y el siguiente que aparece a la vista cortado en la parte inferior, como muestra la figura 9.6.

Ea

9. Rotativos

Aprende jQuery 1.3

la variable en true y luego en la rellamada del segundo mtodo. animate


blecemos en falseo

Rac:ent News
IlaYo

.-c"'V<VQ'QIU

."tu

lItO'v.lUDuaaa

15growln 11'IOI9stabIe every day. The


full changaln Is avallable hera WYO"
want lo Ilnd out n (...]

Ull.S.l
6/2712008

Soon IIfIer the mleass 01jQUOI)' UI


1.5, we were gettfng many useful
feedback and fssues entered In our
bug!md<er. Todey, we're happy lo

cortados.

Detenerse al pasar por encima


Aunque el rotativo de titulares est operativo completamente, existe un significativo
problema de usabilidad que deberamos abordar: un titular podra desplazarse fuera de
la vista antes de que un usuario pueda hacer clic en uno de sus vnculos. Esto obliga al
usuario a esperar hasta que el rotativo ha pasado en ciclopor todo el conjunto de titulares
de nuevo antes de tener una segunda oportunidad. Podemos reducir la posibilidad de
este problema al hacer que el rotativo se detenga cuando el cursar del ratn del usuario
pasa por encima de cualquier parte dentro del titular.

};
Rac:entNewa
_
on :sun!ISY. :septelt1llW 26,
IAtlllMW.a,se1!two tracks of
~

setTimeout(headlineRotate,

250)

(beginner and

-...atI~_".
~ced

bugfIx relsase lo our Google Codo


aoccunl. Whlle there's, sgain, no new
APllntroduced, more !han 30 Issues
llaVe been deared and the':odebese
l. growlng morstable evaty day. The
full changelog IsavaIlable he", K YO"
want lo Ilnd out K (.]

$container.hover(function()
clearTimeout(pause) i
}, function() (
pause

(), lo esta-

var headlineRqtate
= function()
if (Irotat'elnProgress) {
rotatelnProgress
= true;
currentHeadline
=
(oldHeadline + 1)
% headlineCount
$('div.headline') .eq(oldHeadline) .animate(
{top, -hiddenPosition},
'slow', function()
$(this) .CSS(ltop',
hiddenPosition) i
}) ;
$('div.headline') .eq(currentHeadline) .animate(
[Eop , o).
'slow', function () (
rotatelnProgress
= false
pause = setTimeout(headlineRotate,
5000);
)) ;
oldHeadline = currentHeadline;

lQuary

Figura 9.6. Titulares parcialmente

BiI

});

Cuando el ratn entra en el rea del titular, el primer manejador . hover () invoca
la funcin JavaScript clearTimeout
() . Esto cancela el cronmetro en progreso, impidiendo que se invoque headlineRotate
(). Cuando el ratn se aleja, el segundo manejador . hover () reinicia el cronmetro, invocando as headl ineRota te () despus
de 250 milisegundos de retraso.
Este sencillo cdigo funciona bien la mayor parte del tiempo. Sin embargo, si el usuario mueve el ratn por encima y fuera de <di v rpidamente y de forma repetida, puede
ocurrir un efecto poco deseado. Mltiples titulares estarn en movmiento a la vez, posicionndose uno encima de otro en el rea visible, como muestra la figura 9.7.
Desafortunadamente, necesitamos llevar a cabo cierta ciruga para extirpar este cncer. Antes de la funcin headlineRotate
(), introduciremos una variable ms:
>-

var rotateInProgress

= false

Ahora, en la primera lnea de nuestra funcin, podemos comprobar si una rotacin


estactualmente en progreso. Solamente si el valor de rotatelnProgress
es false
queremos que el cdigo se ejecute de nuevo. Por lo tanto, situamos todo dentro de la
funcin en una sentencia if. Inmediatamente dentro de este condicional, establecemos

Figura 9.7. Unos titulares encima de otros.

Estas lneas adicionales mejoran nuestro rotativo de titulares sustancialmente. Pasar


por encima de forma rpida y repetida ya no hace que los titulares se apilen uno encima
de otro. Sin embargo, este comportamiento de usuario todava nos deja con un problema molesto: el ritmo del rotativo se pierde con dos o tres animaciones inmediatamente
una detrs de otra, en lugar de todas ellas espaciadas de forma uniforme en intervalos
de cinco segundos.
El problema es que ms de un contador se puede activar de forma concurrente si un
usuario retira su ratn del <di v antes de que el contador existente se complete. Por lo
tanto necesitamos poner ms de una salvaguardia en su lugar, utilizando nuestra variable
pause como un indicador de si otra animacin es inminente. Para hacer esto, establecemos la variable en false cuando el tiempo de espera se pasa o cuando se completa.
Ahora podemos comprobar el valor de la varaible para aseguramos de que no existe
tiempo de espera activo antes de situar uno nuevo en su lugar.
var headlineRotate
= function()
if (! rotatelnProgress)
{
rotatelnProgress
= true

BB

9. Rotativos

Aprende jQuery 1.3

pausa . falsa;
currentHeadline
= (oldHeadline + 1)
% headlineCount;
$('div.headline')
.eq(oldHeadline)
.animate(
{top: -hiddenPosition}.
'slow', function()
$(this) .css('top',
hiddenPosition);

})

mil

Dentro del archivo f eed. php, recuperamos el contenido de nuestro feed de noticias
del sitio remoto, luego imprimimos el contenido como el resultado del script.
'
<?php
!
header ('Con t errt v'I'ype : text/xml');
",
print file_get_contents('http://jquery.com/blog/feed');

?>

$('div.headline')
.eq(currentHeadline)
{top: O},
'slow', function()
(
rotatelnProgress
= false
if (Ipause) {
pause

.animate(

setTimeout(headlineRotate,

Observe aqu que necesitamos establecer explcitamente el tipo de contenido de la


pgina en text/xml
de modo que jQuerypuede ir a buscarloy analizarlo como si fuera
un documento XML normal, esttico.

5000);

});

oldHeadline

= currentHeadline

};
if

(Ipause)
pause = setTimeout(headlineRotate,

5000);

}
$container.hover(function()
clearTimeout(pause)
;
pausa = falsa;
}, funct ion () {
if (1 pausa) {
pause = setTimeout(headlineRotate,
}

})

.'

Algunos proveedores de hospedaje Web pueden no permitir el uso de la funcin PHP


file_get_contents
() para ir a buscar archivos remotos debido a problemas de
seguridad. En estos casos, soluciones alternativas, como utilizar la librera eURL,pueden
estar disponibles. Ms informacin sobre esta librera se puede encontrar en ht t P : / /
wiki.dreamhost.com/CURL.

250);

Aadir un indicador de carga

Por fin, nuestro rotativo de titulares puede soportar todo tipo de intentos del usuario para desbaratarle.

Recuperar un feed de un dominio diferente

Recuperar un archivo remoto como ste podra llevar algo de tiempo, dependiendo
de un nmero de factores, por lo que deberamos informar al usuario de que la carga
est en progreso.
Para hacer esto, aadiremos una imagen de indicador de carga a la pgina antes de
, lanzar nuestra peticin AJAX.
var

El feed de noticias que hemos estado utilizando para nuestro ejemplo es un archivo
local, pero podramos querer recuperar un feed de otro sitio. Como.:hemos visto en un captulo anterior, las peticiones AJAXno se pueden, como regla, realizar a un sitio diferente
que el que alberga la pgina que se visualiza. All, tratamos el formato de datos JSONP
como un mtodo para eludir esta limitacin. Aqu, sin embargo, asumiremos que no podemos modificar la fuente de datos, por lo que necesitamos una solucin diferente.
Para permitir que AJAX vaya a buscar ese archivo, utilizaremos cdigo del lado del
servidor como un proxy para la peticin, para que JavaScript crea que el archivo XML
est en nuestro servidor aunque reside en uno diferente. Escribiremos un pequeo script
PHP para extraer el contenido del feed de noticias a nuestro servidor, y pasar esos datos
al script jQuery solicitante. Este script, que denominaremos feed. php, se puede invocar
de la misma forma que se fue a buscar feed. xml previamente:
$.get('news/feed.php',

//
})

...
;

function(data)

$loadinglndicator
= $('<img/>')
.attr({
'sre': 'images/loading.gif',
'alt':
Loading.
Please wait.
I

.addClass('news-wait')
.appendTo($container)

Luego, como primera lnea de la rellamada de xito de nuestra funcin $ . get ( ) ,


podemos eliminar la imagen de la pgina con un sencillo comando:
$loadinglndicator.remove()

Ahora, cuando la pgina se carga por primera vez, si hay un retraso al recuperar el
contenido del titular, veremos una imagen de carga en lugar de un rea vaca, como
muestra la figura 9.8.
Esta imagen es un GIF animado, y en un navegador Web girar para significar que
se est llevando a cabo cierta actividad.

mi

Aprende jQuery 1.3

9. Rotativos

&111

$ (document) .ready(function()
(
$('#news-f~ed')
.each(function()
var $container
= $(this);
$contai~er.empty()
;

RacentNews

var fadeHeight
= $container.height()
for (var yPos = O; yPos < fadeHeight;
$('<div></div>')
.addClass('fade-slice')
.appendTo($container)
;

\1

"";'1\'

/ 4;
yPos

+=

2)

}
});

})

Figura 9.8. Mostrar una imagen de carga.

Podemos fcilmente crear nuevas imgenes GIF animadas para utilizarse como indicadores de carga AJAX al utilizar el servicio en http: / / aj axload. info/.

Efecto degradado
Antes de dejar nuestro ejemplo de titular rotativo, dmosle un toque final, al hacer
que el texto del titular parezca que aparece progresivamente desde la parte inferior de
su contenedor. El efecto ser un degradado, apareciendo como si el texto fuera opaco en
la parte superior del efecto y transparente en la parte inferior.
Un solo elemento de texto no puede tener mltiples opacidades simultneamene,
sin embargo. Para simular esto, cubriremos el rea de efecto con una serie de elementos, cada uno de los cules tiene una opacidad diferente. Estos cortes sern elementos
<di v con algunas propiedades de estilo en comn, que podemos declarar en nuestra
hoja de estilo:
.fade-slice
(
position:
absolute;
width: 20ern
height: 2px;
background:
#efd;
z-index: 3

Todos tienen las mismas propiedades width y background - color que su elemento
contenedor, <di v id= "news- feed" >. Esto engaar el ojo del usuario al pensar que el
texto se est desvaneciendo, en lugar de cubrirse por otro elemento.
Ahora podemos crear los elementos ed i.v c Las s "fade-slice"
>. Para estar seguros de que tenemos el nmero correcto, primero determinaremos una altura en pxeles para toda el rea de efecto. En este caso, estamos eligiendo 25 por ciento de la altura
<di v Ld " news - f eed" >. Utilizaremos un bucle f or para iterar por la altura del rea,
creando un nuevo elemento de corte para cada segmento de 2 pxeles del degradado:

Ahora tenemos 25 cortes (uno para cada segmento de 2 pxeles del area de degradado de 50 pxeles), pero estn todos apilados en la parte superior del contenedor. Para
- que nuestro truco funcione, necesitamos que cada uno tenga una posicin y opacidad
diferente. Podemos utilizar la variable de iteracin yPos para determinar de manera
matemtica las propiedades opaci ty y top de cada elemento:
$ (document) .ready(function()
(
$('#news-feed')
.each(function()
var $container
= $(this);
$container.empty()
;
var
for

fadeHeight
= $container.height()
/ 4;
(var yPos = O; yPos < fadeHeight;
yPos '+= 2) (
$('<div></div>')
.css({
opacity:
yPos / fadeHeight.
top: $container.height()
- fadeHeight
+ yPos
}) .addClass('fade-slice')
.appendTo($container);

}
})

j);

Estos clculos pueden ser difciles de visualizar, por lo que situaremos los nmeros
en una tabla. Los valores de opacidad suben incrementalmente de transparente a opaco,
ya que los valores superiores empiezan en la parte superior del rea de degradado (150)
y crecen a la altura del contenedor:

150

0.04

152

0.08

154

0.12

156

0.16

158

ti

&DI

9. Rotativos

Aprende jQuery 1.3


var $loadinglndicator
= $('<irng/>')
.attr 1{
's"rc':
images/loading. gif t ,
'~lt': Loading. Please wait.'
})
I

40

0.80

190

42

0.84

192

44

0.88

194

46

0.92

196

48

0.96

198

.addClass('news-wait')
.appendTo($container)
;

('

Recuerde que puesto la posicin superior del ltimo <di v clas s = " f ade - s 1 i ce " >
es 198,su altura de 2 pxeles claramente superpondr los dos pxeles inferiores del <div
contenedor de 200 pxeles de alto. Con nuestro cdigo en su lugar, el texto en el rea de
titular de la pgina ahora se funde desde transparente a opaco, a medida que solapa la
parte inferior del contenedor, como muestra la figura 9.9.

$.get('news/feed.php',
function(data)
$loadingIndicator.rernove()
;
$ ( 'rss itern', data). each (function () {
var $link = $('<a></a>')
.attr('href',
$('link',
this) .textll)
.text($('title',
this).textll);
var $headline
= $('<h4></h4>') .append($link);
var
var
var
var
var

RecentNewa

pubDate
= new Date($('pubDate',
this) .text());
pubMonth
= pubDate.getMonth()
+ 1;
pubDay
= pubDate.getDate();
pubYear
= pubDate.getFullYear();
$publication = $('<div></div>')
.addClass('publication-date')
.text(pubMonth
+ '1' + pubDay + ,/,
+ pubYear);

'
n .
" ..
""'

another earty verston of 1.6, a


upgmde lo 1.6m2 lo hlghly
recommended. ThIs lo also (]

$surnmary = $('<div></div>')
.addClass('sumrnaryl)
.htrnl($('description',
this) .text());
$('<div></div>')
.addClass('headline')
.append ($headline,
$publication,
$surnrnary)
.appendTo($container)
;
}) ;

var

1Que!y COnfll 2008 Agencia


8/3112008
The soId-ootlQuery Conference 2008.
betng held In BosIon a11he MIT S!ata
Center 00 5etemb<lr 281!1.18 nelH1y
upon USo WIth 13seoslons b<llng
l",,,,_,,~ ." th""

Ir<;

,,,"'.

h,"' . ..,.,. ,.,~",,1I

Figura 9.9. Efecto de transparente

a opaco.

El cdigo terminado
Nuestro primer rotativo est ahora completo. Los elementos de noticias se van ahora
a buscar desde un servidor remoto, se formatean, yse animan segn lo planificado, y
cuentan con un bonito estilo:
$ (docurnent) .ready(function()
(
$('#news-feed')
.each(function()
var $container
= $(this);
$container.ernpty()
;
var
for

fadeHeight
= $container.height()
/ 4;
(var yPos = O; yPos < fadeHeight;
yPos += 2) (
$('<div></div>')
.css({
opacity:
yPos I fadeHeight,
top: $container.height()
- fadeHeight
+ yPos
}) .addClass('fade-slice')
.appendTo($container);

var currentHeadline
= O, oldHeadline = O;
var hiddenPosition
= $container.height{) + 10;
$('div.headline')
.eq(currentHeadline)
.css('top',
var headlineCount
= $('div.headline')
.length
var pause
var rotateInProgress
= false;
var

O);

headlineRotate
= function()
if (!rotateInProgress)
{
rotateInProgress
= true
pause = false
currentHeadline
= (oldHeadline + 1)
% headlineCount
$('div.headline')
.eq(oldHeadline)
.anirnate(
{top: -hiddenPosition},
'slow', function()
$(this) .css('top',
hiddenPosition);

}l;
$('div.headline')
.eq(currentHeadline)
{top: O}, "a Low! , function Il (

.animate(

rotateInProgress
= false
if (!pause)
(
pause = setTimeout(headlineRotate,

5000)

&D

mi

9. Rotativos

Aprende jQuery 1.3


});
oldHeadline

};
if

cimg

currentHeadline

src="images/covers/medium/1847190871.jpgll

width="120"
alt=IICommunity
<sp,h

(!pause)
pause

= setTimeout(headlineRotate,

cimg

$eontainer.hover(funetion()
elearTimeout(pause)
;

pause

false;

cspan

The

Cookbook">

height="148

1t

Inside

osCommerce:

The

Cookbook"

/>

class="price">$44.99c/span>

c/a>

= setTimeout(headlineRotate.

<a href="images/covers/large/1847190979.jpg"
250) ;

title="Learn

OpenOffice.org

Programming:

});

})

7190901. jpg"

osCornmerce:

src=lIimages/covers/mediurn/1847190901.jpgll

alt="Deep

})

Inside

width="120"

}. funet ion () (
if (!pause) (

/>

clas9="price">$3S.99c/span>

title="Deep

pause

height="148"
Server Quickly"

<la>
<a href=" images/eovers/large/184

5000);

&a

OOoBasic

Spreadsheet
and

Calc

Macro

automation">

<img sre="images/covers/medium/1847190979.jpg"
width="120"
height="148"

alt="Learn

OpenOffice.org

Programming:

Un carrusel de imgenes

.'

cspan

Calc

Macro

automation"

/>

c/a>

<a href="images/eovers/large/1847190987.jpg"
title="Mierosoft
AJAX C# Essentials:
cimg

ASP.NET

2.0

Building

Applications">

src=lIimages/covera/medium/1847190987.jpg"
height='t148It

width="120"

AJAX C# Essentials:
Building
ASP.NET
2.0 Applieations"
/>

alt="Microsoft

Responsive
capan

class="price">$3l.99c/span>

c/a>

<a href=" images/eovers/large/184


title="Google

dmg

Un mecanismo alternativo para desplazarse porun conjunto de imgenes se implementa


por el plug-injCarousel parajQuery. Adems, el plug-in altamente flexible SerialScroll
permite desplazar cualquier tipo de contenido. Aunque no idntico al resultado que
conseguiremos aqu, estos plug-ins pueden producir efectos de deplazamiento de alta
calidad con muy poco cdigo.

and

class="price">$3s.99c/span>

Responsive

Como otro ejemplo de desplazar contenido por la pgina, implementaremos una


galera de imgenes para la pgina principal del sitio de librera. La galera presentar
algunos libros destacados para la venta, con vnculos a la portada ampliada para cada
uno. A diferencia del ejemplo anterior, donde los titulares se movan segn una planificacin establecida, aqu utilizaremos jQuery para desplazar las imgenes por la pantalla
en respuesta a la interaccin del usuario.

Spreadsheet

OOoBasic

Web

Toolkit

7191002. jpg"
GWT

Java

src "images/eovers/medium/184
width=1I120"

height="148"

alt="Google

Web

cspan

Toolkit

GWT

AJAX

Prograrnming">

7191002. jpg"
Java

AJAX

Programming"

/>

class=rtprice">$40.49c/span>

<la>
<a href="images/eovers/large/1847192386.jpg"
title=tlBuilding

<img

width="120"
alt="Building
capan

Websites

with

Joomla!

1.5

Beta

1">

src="images/eovers/medium/1847192386.jpg"
height="148"
Websites

with

Joomla!

1.5

Beta

1"

/>

class="price">$40.49c/span>

c/a>

Configurar la pgina

</div>
</div>

Como siempre, empezamos diseando el HTML y CSS de modo que los usuarios
sin JavaScript disponible reciban una representacin llamativa y funcional de la informacin:

Cada imagen se encuentra contenida dentro de una etiqueta de ancla, apuntando a


la versin ms grande de la portada. Tambin tenemos precios para cada portada; se
ocultarn por ahora, y utilizaremos JavaScript para mostrados ms adelante en un momento apropiado.
Para ahorrar espacio en la pgina principal, queremos mostrar solamente tres portadas a la vez. Sin JavaScript, podemos realizar esto al establecer la propiedad overf low
del contenedor en scroll,
y ajustar la anchura de forma apropiada:

<:div id=Ufeatured-bookslI>
<:div class=lIcoversll>
<a href=" images/eovers/large/184
title="Community

Server

7190871. jpg"

Quickly">

,,,.--

&!I

9. Rotativos

#featured-books
{
position: relative
background,
#ddd;
width, 440px;
height,
186px;
overflow: scroll
margin: 1em auto;
padding,
O;
text-align: center;
z-index: 2;
}
#featured-books
.CQvers
position: relative
width, 840px;
z-index: 1;

BiI

el camino del posicionamiento que deseamos realizar para animar las portadas. Por lo
tanto, nuestra primera prioridad ser anular algunos estilos:
r
$ (document) .ready(function()
var spacing = 140;
$('#featured-books')
.css({
'widthr:
spacing * 3,
r height':
166px
roverflow':
hidden
} ) .f ind (,.covers a'). css ({
"f Loa t t : 'none',
'position': 'absolute',
,left " 1000
));
I

1 I

}
#featured-books
a
f Loa t : left;
margin: lOpx
height,
146px;
}
#featured-books
.price
display: none;

var

$covers

$covers.eq(O)
$covers.eq(l)
$covers.eq(2)

})

Estos estilos provocan un poco de discusin. El elemento ms exterior necesita


tener una propiedad z - index mayor que el que est dentro; esto permite que Internet
Explorer oculte la parte del elemento interior que se extiende ms all de su contenedor. Establecemos la anchura del elemento exterior en 44 Opx, que acomoda tres imgenes, el margen de 1 Opx alrededor de cada una, y un 2 Opx adicional para la barra de
desplazamiento.
Con estos estilos en su lugar, las imgenes se pueden ver utilizando una barra de
desplazamiento estndar, como muestra la figura 9.10.

Figura 9.10. Desplazarse por las imgenes con barra de desplazamiento

Aprende jQuery 1.3

$('#featured-books
.css('left',
.css('left',
.css('left',

.covers

O);
spacing);
spacing

a');

2);

La variable spac ing va a ser de utilidad en muchos clculos. Representa la anchura


de una de las imgenes de portada, ms el relleno a cada lado. La width del elemento
contedor ahora se puede establecer en exactamente lo que es necesario para contener
tres de las imgenes de portada, ya que no necesitamos espacio para la barra de desplazamiento. En su lugar, cambiamos la propiedad overflow a hidden, y adis barra de
desplazamiento. Las imgenes de portada se posicionan todas de forma absoluta, y empiezan con una coordenada izquierda de 10 OO.Esto las sita fuera del rea visible. Luego
movemos las tres primeras portadas en posicin, una de cada vez. La variable $covers
que alberga todos los elementos de anda tambin ser de utilidad ms adelante.
Ahora las tres primeras portadas son visibles, sin ningn mecanismo de desplazamiento disponible, como muestra la figura 9.11.

estndar.
Figura 9.11. Slo tres portadas sin desplazamiento.

Revisar los estilos con JavaScript


Ahora que hemos pasado a hacer que la galera de imgenes sea de utilidad sin
JavaScript, necesitamos deshacer algunas de las sutilezas. La barra de desplazamiento
ser redundante cuando implementemos nuestro propio mecanismo de desplazamiento, y el diseo automtico de la portada utilizando la propiedad float se pondr en

Mover las imgenes cuando se hace dic


Ahora, necesitamos aadir cdigo para responder a un clicen alguna de las imgenes
finales, y reordenar las portadas segn sea necesario. Cuando se hace clic en la portada
izquierda, esto significa que el usuario quiere ver ms imgenes a la izquierda, que a su

&El

9. Rotativos

Aprende jQuery 1.3

vez significa que necesitamos mover las portadas a la derecha. De forma similar, cuando se hace die en la portada derecha tendremos que mover las portadas a la izquierda.
Queremos que el carrusel gire, de modo que cuando las imgenes se van por el lado izquierdo, se anexan a la derecha. Para empezar, simplemente cambiaremos las posiciones
de las imgenes sin animacin.
(document) .ready(function()
var spacing = 140;
$('#featured-books')
.css({
'width': spacing * 3,
'height': '166px',
'overflow':
'hidden'
j) . f ind (,.covers a') .css ({
'float':
'none',
'position':
'absolute',
,left': 1000
j);
var

setUpCovers
var $covers

functian()

= $('#featured-hooks

event.preventDefault()

// Imagen derecha;
// desplazarse
hacia la izquierda
(para ver las
$covers.eq(2)
.css('left', spacing * 2)
.click(function(event)
(
$covers.eq(O)
.css('left',
1000);
$covers. eq (O)
.appendTo('#featured-books
.cavers');
setUpCovers();
event.preventDefault()

})

};
setUpCovers()
;

imgenes

a:la derecha).

Figura 9.12. Reorganizar las portadas.

Hacer die en la imagen #2 lleva a cabo el proceso a la inversa. Esta vez, es #0 el que
se oculta a la vista, y luego se mueve al final de la cola. Esto cambia #1 al puesto #0, #2
al #1, y #3 al #2.
Existen un par de detalles que tenemos que tener en cuenta para evitar anomalas de
interaccin de usuario:
1. Necesitamos invocar .preventDe f aul t () dentro de nuestro manejador el ick,
ya que nosotros hemos convertido todas las portadas en vnculos a la versin ms
grande. Sin esta llamada, el vnculo se seguir y nunca veremos nuestro efecto
de movimiento.
2. Necesitamos quitar el vnculo de todos los manejadores click al principio de
la funcin setUpCovers
(), o podremos acabar con mltiples manejadores
vinculados a la misma imagen a medida que el carrusel rota.

// Imagen central.
$covers.eq(l)
.css('left',
spacing);

})

La nueva funcin setUpCovers () incorpora el cdigo de posicionamiento de imagen que escribimos anteriormente. Al encapsular esto en una funcin, podemos repetir
el poscionamiento de la imagen despus de que se hayan reordenado los elementos;
esto ser importante, como pronto veremos.
En nuestro ejemplo, hay seis imgenes en total (que JavaScript har referencia con
los nmeros a 5), y los nmeros 0, 1, Y 2 son visibles. Cuando se hace clic en imagen
#0, queremos mover todas las imgenes a la derecha en una posicin. Primero movemos imagen #2 fuera del rea visible (con . e s s ( , 1e f t ' , 10 O O ) ), ya que no queremos
que est visible despus del movimiento. Luego, movemos la imagen al final de la lnea
,.. (#5) al principio de la cola (utilizando .prependTo ( ) ). Esto reordena todas las imgenes de modo que cuando se invoca setUpCovers
() de nuevo, el #5 anterior es ahora
#O,#Ose ha convertido en #1, y #1 se ha convertido en #2. El cdigo de posicionamiento
existente en esta funcin es por lo tanto suficiente para mover las portadas a sus nuevas
ubicaciones, como muestra la figura 9.12.

"

.covers a');

$covers.unbind('click') i
// Imagen izquierda;
// desplazarse
a la derecha
(para ver imgenes
a la izquierda).
$covers.eq(O)
.css (,left " O)
.click(function(event)
(
$covers.eq(2)
.css('left',
1000);
$covers.eq($covers.length
- 1)
.prependTo('#featured-books
.covers');
setUpCovers() ;

})

mi

Aadir animacin deslizable


Puede ser difcil entender lo que ha sucedido cuando se ha hecho die en una imagen; puesto que las portadas se mueven instantneamente, es posible que haya parecido que simplemente se han cambiado en lugar de movido. Para mitigar este problema,

mi

Aprende jQuery 1.3

9. Rotativos

podemos aadir una animacin que hace que las portadas se deslicen en lugar de simplemente aparecer en sus nuevas posiciones. Esto requiere una revisin de la funcin
setUpCovers ( ) :
var setUpCovers = function() {
var $covers = $ ('#featured-books
$covers.unbind(lclick
i

.covers a')

1)

/1 Imagen izquierda;

desplazarse a la derecha (para ver imgenes


$covers. eq (O)
.css('left', O)
.click(function(event)
(
$covers.eq(O) .animate({'left':
spacing}, 'fast');
spacing * 2}
fast
i
$covers.eq(l) .animate({'left':
spacing * 3}
fast r ) i
$covers.eq(2) .animate({'left':
$covers.eq($covers.length
- 1)
.css('left
-spacing)
animate ({ ,left ': O}, 'fast', function () (
$(this) .prependTo('#featured-books
.covers');
setUpCovers() ;
}) ;
event.preventDefault() ;
I

a la izquierda).

lIiII

de portada, debemos aplazar la llamada hasta que la animacin se completa, por lo que
situamos la llamada en la rellamada de la animacin.
Un clic en.la imagen ms a la derecha lleva a cabo un conjunto similar de animaciones, pero al contrario. Esta vez, es la.imagen ms a la izquierda la que se mueva fuera
de la vista, y se debe mover al final de la cola antes de activar setUpCovers () cuando
se completa la animacin. La nueva imagen, ms a la derecha, por el contrario, se debe'
posicionar (spacing * 3) antes de que su animacin pueda empezar.

t,

})

// Imagen derecha; desplazarse a la izquierda (para ver imgenes


$covers.eq(2)
.css('left', spacing * 2)
.click(function(event)' (
$covers.eq(O)
animate ({ ,left': -spacing), 'fast', function ()
$(this) .appendTo('#featured-books
.covers');
setUpCovers() ;
}) ;
$covers. eq (1) .animate ({ 'left': O). 'fast');
$covers.eq(2) .animate({ 'left': spacing}, 'fast');
$covers. eq (3)
.css(11eft', spacing * 3)
animate ({ 1eft
spacing * 2}
fast ') i
event.preventDefault();
1

})

1:

a la derecha).

Mostrar

conos

de accin

Nuestro carrusel de imgenes ahora rota sin problemas, pero no hemos proporcionado
ninguna indicacin al usuario de que haciendo clicen las portadas har que se desplacen.
Podemos ayudar al usuario al mostrar los iconos apropiados cuando el ratn pasa por
encima de las imgenes, como muestran las imgenes 9.14 a 9.16. En este caso, situaremos los iconos sobre las imgenes existentes. Al utilizar la propiedad opacity, podemos continuar para ver la portada por debajo cuando se muestra el icono. Utilizaremos
sencillos iconos monocromos para que la portada no sea demasiado obscura.

// Imagen central.
$covers. eq (1)
.css('left', spacing);
};

Cuando se hace die en la imagen izquierda, podemos mover las tres imgenes visibles a la derecha en el ancho de una imagen (reutilizando la variable spacing que
hemos definido anteriormente). Esta parte es sencilla, pero nosotros tambin tenemos
que hacer que la nueva imagen se desplace para situarse a la vista. Para hacer esto, tomamos la imagen del final de la cola, y primero establecemos que su posicin de pantalla
est fuera de la pantalla en el lado izquierdo (- spacing). Luego, lo pasamos a la vista
junto con los otros elementos, como muestra la figura 9.13.
Aunque la animacin se ocupa del movimiento inicial, todava necesitamos cambiar el
orden de la portada al invocar setUpCovers () de nuevo. Sino lo hacemos, el siguiente
clic no funcionar correctamente. Puesto que setUpCovers () cambia las posiciones

_________________________________

Figura 9.13. Hacer que una nueva imagen aparezca a la vista.

.'

~
Figura 9.14. Icono para desplazarse

I
Il

a la izquierda.

Figura 9.15. Icono para ampliar portada.

Figura 9.16. Icono para desplazarse

a la derecha.

Necesitaremos tres conos, uno para las portadas izquierda y derecha, que el usuario
decidir hacia qu lado desplazarse, y uno para la portada del centro, en el que el usua-

mi

Aprende jQuery 1.3

9. Rotativos

lIiD

rio puede hacer clic para una versin ampliada. Podemos crear elementos HTML que
hagan referencia a los conos y almacenarlos en variables para uso posterior:

Ahora, todo lo que tenemos que hacer en nuestros manejadores hover es situar las
imgenes en la ubcacin DOM correcta y mostrarlas.

$leftRollover
= $('<img/>')
.attr('src,
'images/left.gif')
.addClass('control')
.css('opacity',
0.6)
. ess ( 'display I
I none 1) i
var $rightRollover
= $('<img/>')
.attr('src', 'images/right.gif')
.addClass('control')
.css('opacity',0.6)
.css('display',
'none')
var $enlargeRollover
= $('<irng/>')
.attr('src', 'images/enlarge.gif')
.addClass('control')
.css('opacity',
0.6)
.c ss ('display',
"norie t L,

var

var

.,.

})

Puede haber notado una gran cantidad de repeticin aqu. Para miniqUzar este cdigo adicional, podemos situar esto en una funcin que podemos invocar para cada icono
que se necesita crear:

{
$('#featured-books

.CQvers a )
l

.show();

// Imagen derecha;
desplazarse
a la izquierda
$covers.eq(2)
.css(11eft', spacing * 2)
.click(function(event)
(
$covers.eq(O)
.animate({'left':
-spacing},
'fast',
$(this) .appendTo('#featured-books
setUpCovers();

var $leftRollover
= createControl('images/left.gif');
var $rightRollover
= createControl('images/right.gif');
var $enlargeRollover
= createControl('irnagesJenlarge.gif');

})

(para ver

function()
.covers');

$covers. eq (1) .animate ({ ,left ': O), 'fast');


$covers.eq(2)
.animate(('left':
spacing},
'fast');
$covers.eq(3)
.css(Ileft', spacing * 3)
.animate (( 'left': spacing * 2), 'fast');
event.preventDefault()
;
}).hover(function()
{
$rightRollover.appendTo(this).show();
}, function()
{
$rightRollover.hide();
}) ;

En el CSS para la pgina, establecemos que el z - index de estos controles sea mayor
que el de las imgenes, y luego los posicionamos de forma absoluta de modo que puedan solapar las portadas:
#featured-books
.control
position: absolute;
z-index: 3
left: o;
topo o;

// Imagen central
$covers.eq(l)
.css('left',
spacing)
.hover(function()
{
$enlargeRollover.appendTo(this)
}, function () {
$enlargeRollover.hide();
}) ;

};

a la izquierda).

event.preventDefault()
;
}) .hover(function()
{
$leftRo11over.appendTo(this)
}, func tion () {
$leftRollover.hide();
}) ;

function
createControl(src)
return $ (, <img/> 1)
,attr(
"s r c
are)
.addClass('control')
.css('opacity',O.6)
.css('display',
"norie t L:

Los conos rollover comparten todos la misma clase control,


de modo que uno
podra estar tentado a situar el estilo opaci ty en la hoja de estilo CSS. Sin embargo, la
opacidad no se gestiona de forma consistente entre navegadores; en Internet Explorer,
la sintaxis para 60 por ciento opacidad es filter:
alpha (opacity=60)
. En lugar
de lidiar con estas distinciones, establecemos el estilo opacidad utilizando el mtodo
. css () de jQuery, lo que elimina estas inconsistencias de navegador.

$covers.unbind('click
mouseenter mouseleave')
// Imagen izquierda; desplazarse a la derecha (para ver imgenes
$covers.eq(O)
.css('left',
O)
.click(function(event)
(
$covers.eq(O)
.animate({'left':
spacing},
'fast');
$covers. eq (1) .animate ({ 'left': spacing * 2), 'fast');
$covers. eq (2) .animate ({ 'left': spacing * 3), 'fast');
$covers.eq($covers.length
- 1)
.css( 'left', -spacing)
.animate ({ 'left ': O), 'fast', function () (
$(this) .prependTo('#featured-books
.covers');
setUpCovers()
;

= function()

setUpCovers
var $covers

.show();

imgenes

a la derecha)

DI

Aprende jQuery 1.3

9. Rotativos

Igual que hicimos anteriormente con el iek, desvinculamos los manejadores mouseenter y mouseleave al principio de setUpcovers () de modo que los comportamientos de pasar por encima no se acumulen. Aqu, utilizamos otra caracterstica del mtodo
. unb ind ( ) :manejadores para mltiples tipos de evento se pueden desvincular a la vez
al separar los nombres de tipos de evento con espacios.
Por qu mouseenter y mouseleave? Cuando invocamos el mtodo. hover (),
internamente jQuery traduce esto en dos vinculaciones de evento separadas. La primera
funcin que proporcionamos se vincula como un manejador para el evento mouseenter,
y la segunda se vincula a mouseleave. Por lo tanto, para eliminar los manejadores vinculados utilizando. hover (), necesitamos desvincular mouseenter y mouseleave.
Ahora cuando el cursor del ratn est sobre una portada, la imagen rollover apropiada
est superpuesta sobre la parte superior de la portada, como muestra la figura 9.17.

Aplicaremos un conjunto de reglas de estilo a esta nueva das e que son similares a
las que hemos-visto antes:
'
irng.enlarged ~
position: 'absc Lut e ,
z-index: Si
cursar: pointer

Este posicionamiento absoluto permitir que la portada flote sobre las otras imgenes
que hemos posicionado, porque el z - index es mayor que los que ya hemos utilizado.
Ahora necesitamos posicionar la imagen ampliada cuando se hace clic en la imagen del
centro en el carrusel:
/1 Imagen central; ampliar portada.
$eovers.eq(l)
.css('left', spacing)
.eliek(funetion(event)
(
$enlargedCover.attr('sre'.

"

Figura 9.17.

Efectodel cursorsobre una portada.

Ampliar imagen
Ahora, nuestra galera de imgenes es totalmente funcional, con un carrusel que permite al usuario navegar hasta la imagen deseada. Un clic en la imagen central lleva a
una vista ampliada de la portada en cuestin. Pero, podemos hacer mucho ms con esta
funcionalidad de ampliacin de imagen.
En lugar de llevar al usuario a una URL diferente cuando se hace die en la imagen
del centro, podemos superponer la portada del libro ampliado sobre la propia pgina.

Una serie de variacionessobre eltema de mostrar informacinsuperpuesta en la pgina


se encuentran disponiblescomoplug-insjQuery.Algunosde los ms popularesincluyen
FancyBox,ShadowBox,Thickbox,SimpleModal,yjqModal.
Esta imagen de portada ampliada requerir un nuevo elemento de imagen, que podemos crear al mismo tiempo que se instancian las imgenes de pasar por encima:
var $enlargedCover ~ $('<irng/>')
.addClass('enlarged')
.hide()
.appendTo('body') ;

lImI

$(this) .attr('href'))

.ess({
'left', ($('body') .width() - 360) / 2,
'top' , 100,
'width', 360,
'height', 444
}) .show ();
event.preventDefault()
;
})
.hover(function()
(
$enlargeRollover.appendTo(this)

.show();

}, funetion() (
$enlargeRollover.hide();
}l;

Podemos aprovechamos de los vnculos ya presentes en la fuente HTML para saber


dnde reside el archivo de imagen de la portada ms grande en el servidor. Tomamos
esto del atributo href del vnculo, y lo establecemos como el atributo sre de la imagen
de portada ampliada.
Ahora, debemos posicionar la imagen. top, width, y height se han incorporado en
el cdigo de momento, pero left requiere un poco de clculo. Queremos que la imagen
ampliada se centre en la pgina, pero no podemos saber por adelantado cul es la coordenada apropiada para conseguir este posicionamiento. Podemos encontrar la marca a
mitad de camino en la pgina al medir el width del elemento body y dividirlo entre
dos. La mitad de nuestra imagen ampliada estar en ambos lados de este punto, por lo
que la coordenada izquierda de la imagen ser ($ ( body
width () - 360) / 2, ya
que 360 es el width de la portada ampliada. La portada est posicionada ahora de forma
apropiada, centrada horizontalmente en la pgina, como muestra la figura 9.18.
I

I )

Ocultar la portada ampliada


Necesitamos un mecanismo para descartar la portada una vez que se ha ampliado .
La forma ms sencilla de hacer esto es hacer que un evento eliek en la portada haga
que desaparezca paulatinamente:

!'~"';'

lIlII

9. Rotativos

Aprende jQuery 1.3

// Imagen central; ampliar portada.


$eovers.eq(l)
.css('left', spacing}
.eliek(funetion(event)
(
$enlargedCover.attr('src',
$(this) .attr('href'))
.ess ({
'left': ($('body') .width()
'top'
: 100,
'width':
360,
'height': 444

de nuevo para cada ampliacin. Si no hacemos nada para desvincular el manejador, se


apilarn con el'tiempo. Utilizar. one () se asegura de que los manejadores se eliminan
una vez utilizados.

Mostrar un botn cerrar

- 360) /2,

Este comportamiento es suficiente para eliminar la portada grande, pero no estamos


proporcionando ninguna indicacin al usuario de que hacer clic en la portada har que
desaparezca. Podemos proporcionar esta ayuda al etiquetar la imagen ampliada con un
,; botn Cerrar. Crear el botn es similar a definir los otros elementos de instancia nica
que hemos utilizado, los elementos que se garantizan que aparecen solamente una vez,
y podemos invocar la funcin de utilidad que hemos creado anteriormente:

})
.show()
.one('click', function() {
$enlargedCover.fadeOut();

event.preventDefault()

})
.hover(function()
(
$enlargeRollover.appendTo(this)
}, function () (
$enlargeRollover.hide() ;

})

var $closeButton = createControl('images/close.gif')


.addClass('enlarged-control')
.appendTo('body') ;

.show();

Cuando se hace clic en la portada central, y se muestra la portada ampliada, necesitamos posicionar y mostrar el botn:

.'

$closeButton.css({
'left': ($('body') .width()
"t.op ' : 100
}) .show() ;

Learning JQuery
!!Ol>lII_l1ollIIcI

--

_.""

.~!~~L_ ....
<S.We1

Smarty fltip Templete

lOu!rt.com alC!Btdnkln

""'pal:<>oatIng-,
Forums. PortaIa, and
CommunJtyWebsltes

We'Ve just puahed out a bl'Bnd new


sIte redesign (fct jQuery.com 8IId aU
It!saub-&nea). Thls has b8an a long
lime yomlng 8tId 11.feele: great 10 get It
OIJI the door. New Homopeoe E8IIIy
tbemosloontentiouspartollhe
tMeslgrt l but absolutely the moet

locem ipsum dolor lit amet.


ccnsectetur adIpISJclng ent,
sed do elusmod tempor
Inckflduol lit labore et doIore
m9\V18 aBqua. ut enlm ad
mlnIm venlam, qu/s noatrud
exeroItetlonullatnoolaborls
nl81 ut allquIp WI B8 convnodo
oonsequa1.OultautelnJre
dolor In ntpmhendorit In
voIuptateveHt88SeclllUn
dolara eu 1uQlaI nuIIa pariaU.

""""""" ""'oa:oocot

__
._
...
_.J

Rocont_

Cr9atI~yourMySQI..
0Btsbase: PractIcal DesIgn
T1ps and TechnlQUeS

wpldatal non prokSent, stnt


tl wIpa quI otnola deserunl
moIIlt anlm Id _1 Iaborum.

I!!-~.

- 360) / 2,

Las coordenadas del botn Cerrar son idnticas a las de la portada ampliada, por lo que
sus esquinas superior-izquierda estn alineadas, como se muestra en la figura 9.19.

YourCUt
Bulcllng TeIephony
Systems Wlth Ast8l1sk

lIiiI

."....1d1Ing. JQuer Iong baen


-by

"""---"""(

<

..

l.oremlpst.rnOOloteHa:
dofota magna BIIqua. lit enIm lid rnInIm venlam; q.M nostrucI tOOiIdbibUtuaamco
/8bOiIsnlilutalqulp ex
ea oommodo conseqUlI. DulI sute ln.Ite dolor In repn;Ihendertt ti vaIuptate veHt esse IIum dOOre eu
l'uglat nUlIa partatur. EXceptour aInt oooaocet cupldatat non ptOIdent, sunt In CUlpa quI o1'fIcta deserunt
moIItan/mldestl8borum.

Figura 9.18. Portada ampliada y centrada.

Utilizamos el mtodo. one () para vincular este manejador el iek, que elude un
par de problemas potenciales. Con un . bind () regular del manejador, el usuario podra hacer clic en la imagen de nuevo a medida que se desvanece. Esto podra hacer
que el manejador se activara de nuevo. Tambin, puesto que estamos reutilizando el
mismo elemento de imagen cada vez que se ampla la portada, la vinculacin ocurrir

Figura 9.19. Botn Cerrar.

lI!IlI

9. Rotativos

,,

Ya tenemos un comportamiento vinculado a la imagen que la oculta cuando se hace


clic en la imagen. Tpicamente en esta situacin podramos basamos en el burbujeo de
evento para hacer que un clic en el botn Cerrar cause el mismo efecto. Sin embargo, en
este caso, el botn Cerrar no es un elemento descendiente de la portada, a pesar de las
apariencias. Hemos posicionado de forma absoluta el botn Cerrar sobre la portada, lo
que significa que clics en el botn no se pasan a la imagen ampliada. En su lugar, debemos gestionar clics en el botn Cerrar:
// Imagen central, ampliar portada.
$covers.eq(l)
.css('left', spacing)
.click(function(event)
(
$enlargedCover.attr('src',
.css ({

- 360) / 2,

})
show ()
one ('click', function () (
$closeButton.unbind('click')
$enlargedCover.fadeOut()
,
]l;
$closeButton
css ({
'left', ($('body') .width()
'top' , 100

lI!IiI

contenido textual en lugar de una imagen. Una vez ms, creamos un elemento de instancia nica al principio de nuestro cdigo JavaScript:
I

var $priceBaage = $('<div/,')


.addClass('enlarged-price')
.css('opacity',0.6)
. ess (' display'
"norie ")
.appendTo('body') ,
I

Puesto que el precio ser parcialmente transparente, un contraste alto entre el color
de fuente y el fondo funcionar mejor:

$(this) .attr('href'

"Lef t t : ($('body') .width()


'top' : 100,
'width':
360,
t height':
444

Aprende jQuery 1.3

.hide();

- 360) / 2,

})
show ()
.click(function()
{
$enlargedCover.click();
}) ;

.enlarged-price
(
background-color,
#373c40,
color, #fff,
width, 80px,
padding, Spx,
font-size: 18px;
font-weight, bold,
text-align, right,
position: absolute;
z-index: 6;

Antes de poder mostrar la etiqueta del precio, necesitamos completarlo con la informacin de precio real del HTML. Dentro del manejador eliek de la portada del centro,
la palabra clave this hace referencia al elemento de vnculo. Puesto que el precio est
en un elemento apan dentro del vnculo, obtener el texto es sencillo:
var price

$(this) .find(' .price') .text();

Ahora podemos mostrar la etiqueta cuando se ampla la portada:

event.preventDefault(),

)
.hover(function()

$enlargeRollover.appendTo(this)
}, function() (

$enlargeRollover

.show(),

hide(),

Cuando mostramos el botn Cerrar, vinculamos un manejador de evento el i ck para


ello. Todo lo que este manejador necesita hacer, sin embargo, es activar el manejador
el i ck que ya hemos vinculado a la portada ampliada. Necesitamos modificar ese manejador, sin embargo, y ocultar el botn Cerrar all. Mientras estamos en ello, desvinculamos
el manejador c Li ck para impedir que los manejadores se acumulen en el tiempo.

Ms diversin con el etiquetado


Puesto que tenemos los precios para los libros disponibles en la fuente HTML, podemos mostrar esto como informacin adicional cuando se ampla la portada del libro.
Esta vez aplicaremos la tcnica que acabamos de desarrollar para el botn Cerrar para

$priceBadge.css({
,right " ($ ("body ') .width () - 360) / 2,
'top' , 100
) .text (price) .show ();

Esto ajustar el precio en la esquina superior derecha de la imagen ampliada, como


muestra la figura 9.20. Una vez que situamos un $prieeBadge. hide () ; dentro del
manejador eliek de la portada, hemos terminado.

Animar la ampliacin de la portada


Cuando el usuario hace clic en la portada del centro, la versin ampliada aparece
actualmente en el centro de la pgina. Para mejorar esto, podemos utilizar las posibilidades de animacin incorporadas de jQuery para pasar suavemente entre la vista en
miniatura de la portada y la versin a tamao completo.
Para hacer esto, necesitamos saber las coordenadas iniciales de la animacin; por
ejemplo, la posicin de la portada central en la pgina. Calcular esta posicin requiere
algo de DOM transversal utilizando JavaScript sencillo, pero jQuery nos proporciona

lIl!I

Aprende jQuery 1.3

9. Rotativos

un mtodo abreviado. El mtodo. offset () devuelve un objeto que contiene las coordenadas 1eft y top de un elemento relativo a la pgina. Luego podemos insertar el
width y height de la imagen en este objeto, y tener la informacin de posicin contenida en un paquete.
var startPos
startPos.width
startPos.height

$closeButton.unbind('click')
$prkeBadge.hide()
;
$enlargedCover.fadeOut()
;
}l;
r
$closeButton
.css ({
'1eft': endPoB.left,
'top' : endPos.top

$(this) .offset();
$(this) .width();
= $(this) .height();

IDI

.hide();

})
show ()
.click(function()
$enlargedCover.click()
}) ;
$priceBadge
css ({
'right': endPoB.left,
'top' : endPos.top

,..

})
.text(price)
show() ;

"

})

Observe que el botn Cerrar y la etiqueta de precio no se pueden situar hasta que la
animacin se completa, por lo que hemos movido su cdigo a una rellamada del mtodo
.an imat.e () . Tambin hemos aprovechado esta oportunidad para simplificar las llamadas . css () para estos elementos al reutilizar la informacin de posicin que hemos
calculado para la portada ampliada. Ahora tenemos una transicin suavizada de portada
pequea a grande, como muestra la serie de imgenes en las figuras 9.21 a 9.24:

Query Fake Bookstore


Figura 9.20. Ajustar el precio en la portada.

. FeeI free ID broWselllrough

lile sita and pretend ID buy books.

Nuestras coordenadas de destino ahora se pueden calcular a partir de stas bastante


fcilmente. Recopilaremos stas en un objeto similar.
o
var endPos = {};
endPos.width
= startPos.width
endPos.height
= startPos.height
endPos.top
= 100;
endPos.left

($('body')

* 3;
* 3;

.width()

- endPos.width)

/ 2;

Ahora podemos utilizar estos dos objetos como mapas de atributos CSS, que se pueden pasar a mtodos como. css () y . animate () .
$enlargedcover.attr('src',
.caa(atartPoa)
.show ()
,animate(endPoB,
$enlargedCover

$(this) .attr('href'))

'normal',

.one('click',

function()

function()

,1,OOI1sectetur adlplslclng all~ sed do alusmod tempor Incidid un! ut la


It enlm ad mlnlm vooNim, quls nostnJd exercttatlon uAamoo taborts nlsl
;1.Oul. aute lrure dolor In rsprehendom In voIuptale veI~ ess a cIIlum
r slnt oocaecal cupldalBl non proldanl, sunt In culpa qul ofllcla daserunt

.met, con ctotur adlplslclng all~ sed do alusmod lampor Incldldun! ut la


entm ad mlnlm venlam, quls nostrud exercttaUon ulJamco laborts nlsi

Figura 9.21. Transicin.

Paso 1.

IJEI

AprendejQuery

9. Rotativos

1.3

ED

Query Fake Bookstore

,/

met, consectetur adlplslclng ell1, sed do elusmod tempor lneldldunt ut la


I enlm ad mlnlm ventam. quls nostrud exercllatlon uUamco !abono nlsl

utl
Figura 9.24. Transicin.

Figura 9.22. Transicin. Paso 2.

Aplazar las animaciones

Paso 4.

hasta que la imagen se carga

Nuestra animacin funciona bien, pero depende de una conexin rpida al sitio. Si la
portada ampliada tarda algo de tiempo en cargarse, entonces los primeros momentos de
la animacin podran mostrar la X roja indicando una imagen rota, o seguir mostrando
la imagen anterior. Podemos hacer la transicin un poco ms elegante al esperar hasta
que la imagen se ha cargado por completo antes de iniciar la animacin:
$enlargedCover.attr('src'.
.css(startPos)
.show ();

$(this) .attr('href'))

var perfor.mAnimation = function()


$enlargedCover.animate(endPos,
'normal', function()
$enlargedCover.one('click',
function() (
$closeButton.unbind('click')
.hide();
$priceBadge.hide() ;
$enlargedCover.fadeOut()
;

})

$closeButton
.css({
'left': endPos.left,
'top' : endPos.top
met, consectetur adlplslclng ell1,sed do elusmod tempor InoIdldunt ut la
t enlm ad mlnlm venlam, quls nostrud exercllatlon uUamco !abono nlsl

utl

Figura 9.23. Transicin. Paso 3.

}l
.show()
.click(function()

mi

Aprende jQuery 1.3

9. Rotativos

$enlargedCover.click()
}) ;
$priceBadge
.css ((
right ,: endPos.left,
'tap' : endPos.top

})
.text(price)
.show ();

&11

los titulares de noticias, deberamos proporcionar una indicacin al usuario de que est
ocurriendo cierta actividad al mostrar un indicador de carga entre tando.
El indicador ser otra imagen de instancia nica que se mostrar cuando sea apropiado:
r
var $waitThrobber = $('<irng/>')
.attr('src', timages/wait.gif')
.addClass('control')
.css('z-index',
4)
.hide o .
Para esta imagen, estamos utilizando un GIF animado, porque el movimiento reforzar
". al usuario de que la actividad se est llevando a cabo, como muestran la figura 9.25.

}) ;

};
if ($enlargedCover[O] .complete)
performAnimation();

}
else {
$enlargedCover.bind(lload',

performAnimation);

Hay dos casos que tenemos que considerar: la imagen est disponible casi instantneamente (quiz debido a guardado en cach), o necesita tiempo para cargarse. En la
primera situacin, el atributo complete de la imagen ser true, por lo que podemos
invocar nuestra funcin performAnimation
() inmediatamente. En el segundo caso,
tenemos que esperar a que se complete la carga de la imagen antes de llamar a performAnimation (). ste es un caso extrao en el que el evento load DOM estndar es de
ms utilidad para nosotros que el evento ready personalizado de jQuery. Puesto que"
load se activa en una ventana, imagen, o marco cuando todos sus contenidos se han
cargado por completo, podemos observar el evento para aseguramos de que la imagen
se muestra correctamente. Solamente entonces se ejecuta el manejador, y se lleva a cabo
la animacin.

Paso 3

Paso 2

Paso 1
Figura

Solamente llevar dos lneas situar nuestro indicador de carga en su lugar, ahora
que tenemos el elemento definido. Al principio de nuestro manejador de click para
la imagen central, antes de empezar a hacer cualquier trabajo, necesitamos mostrar el
indicador:
$waitThrobber.appendTo(this)

.show();

$waitThrobber.hide()

(), cuando sabemos que la imagen

Esto es todo lo que se necesita para marcar la portada que se ampla con el indicador
de carga. La animacin aprece superpuesta en la esquina superior izquierda de la portada, como muestra la figura 9.26.

Internet Explorer y Firefox tienen diferentes interpretaciones de lo que hacer si la


imagen est ya en la cach del navegador. En este caso, Firefox enviar inmediatamente
el evento load a }avaScript, pero Internet Explorer nunca enviar el evento porque no
ha ocurrido ninguna carga. Nuestra comprobacin del atributo complete compensa
esta diferencia en implementaciones.

,. ""O . lile

w.w' (.~.
o>

([)

"'\iii

Aadir un indicador de carga


Pero ahora, podemos tener una situacin extraa en conexiones de red lentas cuando una imagen tarda unos cuantos momentos en cargarse. Nuestra pgina parece no
hacer nada mientras esta descarga est en progreso. Como hicimos cuando cargamos

Paso 4

9.25. Indicadorde carga progresivo.

Yal principio de la funcin performAnimation


se ha cargado, eliminamos el indicador de la vista:
Estamos utilizando la sintaxis. bind ( , Load ' ) en lugar del mtodo abreviado .load ()
aqu por claridad ya que . load () es tambin un mtodo AJAX; las dos sintaxis son
intercambiables.

tre.

!'

,
~?

tK1;IN?,\ ,;; . ., -.. M;~". 4w~Y..L;


Figura

9.26. Indicadorde carga.

mil

Aprende jQuery 1.3

9. Rotativos

El cdigo terminado

.css('left', -spacing)
animate ({ ,left ': o}, 'fast', function
$(this) .prependTo('#featured-books

Este cdigo representa solamente una pequea fraccin de lo que se puede hacer en
la Web con imagen animada y rotativos de texto. Todo junto, el cdigo es:
$ (document) . ready(function()
var spacing = 140

function createControl(src)
return $ (' <irng/>')
.attr{'src',
src)
.addClass('control')
.css('opacity',
0.6)
.ess ('display',
'nane')

})

$leftRollover
= createControl('images/left.gif');
$rightRollover
= createControl('images/right.gif');
$enlargeRollover
= createControl('images/enlarge.gif');
$enlargedCover
= $('<img/>')
.addClass('enlarged')
.hide()
appendTo (,body ') ;
var $closeButton
= createControl('images/close.gif')
.addClass('enlarged-control')
appendTo (,body ') ;
var $priceBadge
= $('<div/>')
.addClass('enlarged-price')
.css('opacity',O.6)
ess ( 'display',
'none
.appendTo('body')
;
var $waitThrobber
= $('<img/>')
.attr('src', 'images/wait.gif')
.addClass('control')
.css('z-index',
4)
.hide() ;
$ ('#featured-books')
.css({
'width': spacing * 3,
'height':
'166px',
'overflow':
'hidden'
find (,.covers a') .css ((
'float':
'none',
'position':
'absolute',
'left': 1000

derecha;

desplazarse

a izquierda

(para ver

imgenes

function ()
.covers');

});
$covers. eq (1) .animate ({ ,left ': O}, 'fast');
$covers.eq(2)
.animate({ 'left': spacing},
'fast');
$covers.eq(3)
.css('left', spacing * 3)
animate ({ ,left': spacing 2},

'fast');

event.preventDefault()
;
}) .hover(function()
(
$rightRollover.
appendTo (this) .show() ;
}, function()
(
$rightRollover.hide()

setUpCovers
= function() {
var $covers = $('#featured-books
.CQvera a') i
$covers.unbind('click
mouseenter
mouseleave') ;
// Imagen izquierda;
desplazarse
a derecha
(para ver imgenes
$covers.eq(O)
.css (,left', O)
.click(function(event)
(
$covers.eq(O)
.animate({'left':
spacing} , fast ');
$covers. eq (1) .animate ({ 'left' : spacing * 2}, 'fast');
$covers.eq(2)
.animate({'left':
spacing * 3}, 'fast');
$covers.eq($covers.length
- 1)

.show();

setUpCovers();

});
// Imagen

central;

ampliar

;
portada

$covers.eq(l)
.css('left',
spacing)
.click(function(event)
(
$waitThrobber.
appendTo (this) .show() ;
var price = $(this) .find(' .price') .text();
var startPos
= $(this) .offset();
startPos.width
= $(this) .width();
startPos.height
= $(this) .height();
var endPos = {};
endPos.width
= startPos.width
endPos.height
= startPos.height
endPos.top
= 100;
endPos.left
= ($('body')
$enlargedCover.attr('src',

var

C>,

$covers.eq(2)
.css('left', spacing * 2)
.click(function(event)
(
$covers. eq (O)
animate ({ 'left': -spacing},
'fast',
$(this) .appendTo('#featured-books

})

();

// Imagen

() (
.covers');

}) .hover (function () (
$leftRollover.appendTo(this)
}, function()
(
$leftRollover.hide()
;

var
var
var
var

setUpCovers()
});
event.preventDefault

a la izquierda).

lIfI

.css(startPos)
.show() ;
var performAnimation
$waitThrobber.hide()

3;
3;

.width()
- endPos.width)
$(this) .attr('href'))

function()
;

$enlargedCover ,animate (endPos, 'normal,


function () (
$enlargedCover.one('click',
$closeButton.unbind('click')
$priceBadge.hide()
;
$enlargedCover.fadeOut();

function()
(
.hide();

/ 2;

a la derecha)

~~~l'"

BIlI

9. Rotativos
/

}) ;
$closeButton
.css ({
'left': endPos.left,
'top' : endPos.top

.show ()

.click(function()
(
$enlargedCover.click()
j);
$priceBadge
.css ({
1 right ,: endPos.left,
Itop' : endPos.top
j)

})

.text(price)
.show () ;

},
if ($enlargedCover[O]
performAnimation()

.complete)
,

}
else (
$enlargedCover.bind('load',

performAnimation);

}
event.preventDefault()

j)
.hover(function()
(
$enlargeRollover
appendTo(this)
l, function() (
$enlargeRollover.hide()
,
})

.show(),

},
})

setUpCovers()

Resumen
En este captulo, hemos examinado los elementos de pgina que cambian en el tiempo, por s mismos o en respuesta a una intervencin del usuario. Estos rotativos pueden
diferenciar una presencia Web moderna de sitios diseados de forma tradicional. Hemos
tratado la presentacin de un feed XML de informacin en una pgina, al igual que rotar
elementos en y fuera de la vista en intervalos de tiempo. Adems de mostrar un conjunto de imgenes en una galera al estilo de un carrusel por la que se puede desplazar,
tambin hemos tratado ampliar una imagen para un primer plano con una animacin
suavizada y presentar controles de interfaz de usuario de una forma discreta.
Estas tcnicas se 'pueden combinar de muchas formas para dar vida a pginas que
de otra forma seran aburridas, a la vez que mejorar simultneamente la usabilidad de
nuestras aplicaciones basadas en Web. Las animaciones y efectos que seran tediosos de
conseguir de otra forma se podran realizar sin esfuerzo gracias al potencial de jQuery.

,,

~~"

'~.

\.":.:1

,.,

..' . /.-"'"

.~"

tr: .
<>
~
~
,

,&,.

'{:-."

.. ~--

....

10? "
'l;;f'"

~...-.,

.~

.'0, ~
\. ,6

~'"

,......

'C'
..."...\. _. '"

.....,'0 ..\

'd13""

___

, r.;
'. "'.

~).
.-'--.
. . ........
>$l'
----:-~ (' (9)"

'..

\./

._."
\

~f.. '

15"

.' \

_...
(J'

__

@'

1')

'0"

~
@ \\

"1'f.,""@'

IJ!.

o ~...
"

j<"' ":!.I

r@

<-,

,---~'

@1@-

"SI

~,.~....;',

~.

-,;,:.'~
,~, O"I!!J .,..,
. -r-,
"

.-....

,.'',,"'

r>~l

-.~

f~~'

,~ ..~.

~..,

~<>

//@
/<....,
@

-l

..

.~.-.:

~'V~._'

"\

'

.. _

(@J

O \ ~,--

"

10
Utilizar plug-ins

A lo largo de este libro, hemos examinado muchas de las formas en que se puede utilizar la librera jQuery para realizar una amplia variedad de tareas. An as, un aspecto
que ha quedado relativamente sin explorar es la ampliabilidad de jQuery. Tan potente
como su librera base, su elegante arquitectura de plug-in ha permitido a desarrol1adores
ampliar jQuery, haciendo que sea una librera an ms rica en caractersticas.
La creciente comunidad jQuery ha creado cientos de plug-ins, desde pequeos selectores de ayuda a widgets de interfaz de usuario a gran escala. Ya hemos tratado el
potencial de plug-ns y creado uno sencillo en un captulo anterior. En este captulo, examinamos cmo encontrar plug-ins desarrollados por otros e incorporarlos en nuestras
pginas Web. Exploraremos el popular plug-n Form y la librera oficial de plug-ins de
interfaz de usuario jQuery, y luego listaremos y describiremos brevemente una serie de
otros plug-ins populares "recomendados por el autor".

Encontrar plug-ins y ayuda


El sitio Web jQuery proporciona un amplio repositorio de plug-ins disponibles en
http://plugins
. j query. com/, con caractersticas como valoraciones de usuario,
versiones, e informes de errores. Este repositorio de plug-ins es tambin un estupendo
lugar para empezar cuando se busca documentacin. Cada plug-in listado en el repositorio
se puede descargar como un archivo. z ip, y muchos de ellos tambin tienen vnculos a
demos, cdigo de ejemplo y tutoriales para ayudamos a empezar.

lEfI

10. Utilizar plug-ins

Aprende jQuery 1.3

Incluso se pueden encontrar ms plug-ins en repositorios de cdigo general como


http://github
. com/ y en los weblogs de los desarrolladores de plug-ins.
Si no puede encontrar las respuestas a todas nuestras preguntas en el repositorio de
plug-ins, el sitio Web del autor, y los comentarios del plug-in, siempre podemos recurrir al jQuery Google Group enhttp://groups
. google. com/group/j query-en/.
Muchos de los autores de plug-ins son colaboradores frecuentes de la lista, y siempre
estn deseosos de ayudar con cualquier problema que puedan encontrar los nuevos
usuarios.

El plug-in Forrn
El plug-in Form es un extraordinario ejemplo de un script que convierte una tarea difcil Ycompleja en algo terriblemente sencillo. El archivo plug-in, junto con la documentacin detallada, se encuentra disponible en http://malsup/com/jquery/form/.
Como base del plug-in se encuentra el mtodo. aj axForm () . Convertir un formulario convencional en un formulario AJAX requiere una sencilla lnea de cdigo:
r'

Cmo utilizar un plug-in


Utilizar un plug-in jQuery es muy sencillo. El primer paso es incluirlo en el head del
documento, asegurndose de que aparece detrs del archivo fuente jQuery principal:

1m

$ (document) .ready(function()
$ (/ #myForm/) .ajaxForm ();
});

Este ejemplo preparar < form id=" myForm" > para enviarse sin tener que refrescar
la pgina actuaL Esta caracterstica es en s misma bastante atractiva, pero el verdadero
- potencial viene con el mapa de opciones que pasamos al mtodo. Por ejemplo, el siguiente
cdigo invoca. aj axForm () con las opciones target, beforeSubmi t, y success:

<head>
<meta

http-equiv="Content-Typel!

content=lItext/html

charset=utf-Sn/>
type=l1text/javascriptll><!script>

<script

src="jquery.js"

<script

src="jquery.plugin.jsll

$ (document) .ready(function()
{
function va1idateForm()
{
// el cdigo de validacin
//

</head>

beforeSubmit:

$ (document) .ready(function()
$ (/#myID/) .someP1ugin();
;

Muchos plug-ins tienen flexibilidad incorporada tambin, proporcionando una serie


de parmetros opcionales que podemos establecer para modificar su comportamiento.
Podemos personalizar su operacin tanto como se necesite, tpicamente al incluir un
mapa como el argumento del mtodo:
$ (document) .ready(function()
$ (/#myID/) .someP1ugin ({
send:

true

message:

})

/This p1ugin

});

La sintaxis de los plug-ins jQuery es, tpicamente, bastante similar a la sintaxis de los
mtodos dentro del propio jQuery. Ahora que hemos visto cmo incluir un plug-in en
una pgina Web, echemos un vistazo a algunos de los ms populares.

de formulario
para

abortar

el

ira aqu
envo

validateForrn,

success: function() {
a1ert(/Thanks
for your commenti/);

})

La opcin target indica el elemento, en este caso, un elemento con Ld " log", que
se actualizar por la respuesta del servidor.
La opcin beforeSubmit
lleva a cabo tareas antes de enviar el formulario. Aqu,
hace referencia a la funcin validateForm
() . Si la funcin devuelve false, el formulario no se enviar.
La opcin success lleva a cabo tareas despus de que el formulario se enva con xito.
En este ejemplo simplemente proporciona un mensaje de alerta para permitir al usuario
saber que el formulario se ha enviado. Otras opciones disponibles con. aj axForm () y
el similar. aj axSubmi t () incluyen:

url: La URL al que se enviarn los datos de formulario, si es diferente del atributo
action del formulario.

type: El mtodo utilizado para enviar el formulario, GETo POST.El predeterminado es el atributo method del formulario, o si no se facilita ninguno, GET.

dataType: El tipo de datos esperado de respuesta del servidor. Los valores


posibles son null, xml, script, o j son. El valor predeterminado es null (una
respuesta HTML).

is greati/

false

$ (/#test-form/) .ajaxForm({
target: /#log/,

<title>Example<!title>

Despus de ello, es cuestin de incluir un archivo JavaScript personalizado en el que


utilizamos los mtodos que el plug-in crea o ampla. A menudo, podemos aadir una
sola lnea dentro del mtodo $ (documen t) . ready () de nuestro archivo personalizado para invocar cierta accin:

devolver

};

type=lItext/javascriptll></script>
<script
src=!tcustorn.jsll type=lltext/javascript"></script>

})

podemos

mil

Aprende jQuery 1.3

10. Utilizar plug-ins

resetForm: Booleano;predeterminado es falseo Si se establece en true, todos


los valores del campo del formulario se restablecern en sus predeterminados
cuando el envo tiene xito.

clearForm: Booleano;predeterminado es falseo Si se establece en true, todos


los valores del campo del formulario se borrarn cuando el envo tiene xito.

IPD

Cuando se requiere menos personalizacin, se puede pasar a losmtodos . a j axForm ()


y . a j axSubmi t () una funcin en lugar de un mapa de opciones. Puesto que la 'funcin se trata como el manejador de xito, podemos obtener el texto de la respuesta del
servidor, de es'taforma:
$ (document) .ready(function()
(
$ (#myForm) .ajaxForm (function (responseText)

El plug-in Form proporciona una serie de otros mtodos para ayudar a gestionar
formularios y sus datos. Para un anlisis ms detallado de estos mtodos, as como ms
demos y ejemplos, visite http://www.malsup.com/jquery/form/.

alert(responseText)

j):
j);
,1

Consejos

trucos

la librera de plug-ins jQuery UI

El mtodo. aj axForm () es a menudo ms apropiado que el mtodo . aj axSubmit ( ) , a expensas de poca flexibilidad. Cuando queremos que el plug-in gestione todas
las vinculaciones de evento por nosotros, as como invocar el mtodo. aj axSubmi t ( )
por nosotros en el momento apropiado, deberamos utilizar. aj axFOl;m() . Cuando
deseamos control ms detallado sobre la gestin del evento submi t, ~e recomienda,
. ajaxSubmit ().
Tanto. aj axForm () como. aj axSubmi t () por defecto pasan a utilizar los valores action y method en el cdigo del formulario. Siempre y cuando utilicemos cdigo
apropiado para el formulario, el plug-in funcionar exactamente como esperamos sin
ninguna necesidad de modificacin. Como beneficio aadido, automticamente adquirimos las ventajas de mejora progresiva; el formulario es totalmente funcional sin
JavaScript habilitado.
.
Normalmente cuando se enva un formulario, si el elemento utilizado para enviar el
formulario tiene un nombre, sus atributos name y val ue se envan junto con el resto de
los datos de formulario. El mtodo. aj axForm () es proactivo en este sentido, aadiendo manejadores click a todos los elementos <input t ype " submit" > de modo que
sabe cul envi el formulario. Elmtodo . a j axSubmi t ( ) r por otro lado, es reactivo y no
tiene forma de determinar esta informacin. No captura el elemento que enva. La misma
distincin se aplica a elementos <input t.ype " image" > tambin: .-aj axForm () los
gestiona, mientras que . a j axSubmi t () los ignora.
A menos que se suba un archivo como parte del envo del formulario, los mtodos
. a j axForm () y . a j axSubmi t () pasan su argumento opt ions al mtodo $ . a j ax ( )
que es parte de jQuery. Por lo tanto, cualquier opcin vlida para $ . aj ax () se puede
pasar por medio del plug-in Form. Con esta caracterstica en mente, podemos hacer que
las respuestas de nuestro formulario AJAXsean an ms robustas, de esta forma:
$ (document) .ready(function()
$ (#myForm) .ajaxForm({
timeout: 2000,
error: function
(xml, status,
alert(e.message)
:

}
}) :
}):

Aunque el plug-in Form realiza una cosa, y lo realiza bien, jQuery UI realiza una
amplia variedad de cosas (y las hace bien). De hecho, jQuery UI no es tanto un plug-in,
sino una biblioteca completa de plug-ins.
Dirigido por Paul Bakaus, el equipo jQuery DI ha creado una serie de componentes
bsicos de interaccin y widgets completos para ayudar a que la experiencia Web sea
ms como la de una aplicacin de escritorio. Los componentes de interaccin incluyen
mtodos para arrastrar, soltar, ordenar y cambiar elementos de tamao. El conjunto actual de widgets incluye un men con efecto acorden, un selector de fecha, un cuadro
de dilogo, un deslizador, y pestaas, con algunos ms en desarrollo. Adems, jQuery
UI proporciona un amplio conjunto de efectos avanzados para complementar las animaciones principales jQuery.
Puesto que la librera UI completa es demasiado extensa para tratarla adecuadamente
en este captulo, limitaremos nuestra exploracin a efectos UI, el componente de interaccin Sortable (para ordenar lista de elementos), y el widget Dialog (para cuadro de
dilogo). Las descargas, documentacin y demos de todos los mdulos jQuery se encuentran disponibles en http://ui.jquery
. com/.

Efectos
El mdulo Efectos de jQuery DI viene con un archivo y un conjunto de archivos de
efectos individuales. El archivo principal proporciona animaciones para colores y clases,
as como aceleracin y desaceleracin avanzada.

Animaciones
e)

de color

Con el archivo de efectos principal referenciado en el documento, el mtodo. animate () se ampla para aceptar propiedades de estilo adicionales, como borderTopColor,
backgroundColor,
y color. Por ejemplo, ahora podemos cambiar gradualmente un
elemento de texto negro sobre fondo blanco a texto blanco sobre fondo negro:

IEI

10. Utilizar plug-ins

',lO,

,)"",

,,'\"

Aprende jQuery 1.3

"'r' '.

o bien, se puede

$ (document) .ready(function()
$ (/#mydiv/) .animate({
color, I#fff/.
backgroundColor,
1#0001
}./slow/);
j);

ID

realizar con una opcin aadida a un segundo mapa de opci~nes:

$ (document) .ready(function()
{
$ (/#mydiv/) .animate({
color, .1#fff/.
backgroundColor,
1#0001

}. {
duration: /slow/,
easing: /easelnQuart/

A un poco ms de la mitad de la animacin, el <di v se parece a lo que muestra la


figura 10.1.

}) ;

})

Figura 10.1. Animacin en progreso.

El elemento se muestra exactamente como debera, con el texto en su camino a convertirse en blanco y el color de fondo acercndose a negro.

Animaciones

Demostraciones del conjunto completo de funciones se encuentran disponibles en


http://gsgd.co.uk/sandbox/jquery/easing/.

Efectos adicionales
Los archivos de efectos individuales aaden varias transiciones, que se pueden implementar con el mtodo. effect () y algunas de las cules amplan la funcionalidad
de los mtodos de jQuery . show (), . hide (), y . toggle () tambin. Por ejemplo, el
efecto explode, que oculta elementos al ampliarlos en un nmero dado de piezas, se
puede conseguir con el mtodo. effect () :
$ (document) .ready(function()
(
$U#explode/)
.effectUexplode/.
}) ;

de clase

Los tres mtodos de clase con los que hemos trabajado en captulos anteriores
(. addClass (), . removeClass (), y . toggleClass
()) ahora toman un segundo argumento opcional para la duracin de la animacin. Podemos escribirlos como
.addClass {/highlight/,
/fast/}
o .removeClass {/highlight/,
/slow/}
o . toggleClass
{/highlight,
1000}.

{pieces:

16}.

800);

o bien, se puede conseguir con el mtodo . hide ( ) :


$ (document) .ready(function()
{
$ (/#explode/) .hide(/explode/.
})

{pieces:

16}.

800);

De cualquier forma, el efecto oculta un cuadrado que empieza as:

Aceleracin

desaceleracin

avanzada

Las funciones avanzadas de aceleracin y desaceleracin varan l,avelocidad y distancia a las que ocurren las transiciones en varios puntos en el transcurso. Por ejemplo,
la funcin easelnQuart
termina una animacin a cuatro veces la velocidad a la que
empez. Podemos especificar una funcin personalizada de aceleracin y desaceleracin
en cualquiera de los mtodos principales de animacin jQuery o los mtodos de efecto jQuery VI. Esto se puede realizar al aadir un argumento o aadir una opcin a un
mapa de opciones, dependiendo de la sintaxis que se utiliza. Por ejemplo, especificar la
funcin easelnQuart
para nuestra animacin de color anterior se puede realizar con
un argumento adicional:
$ (document) .ready(function()
$ (/#mydiv/) .animate({
color, I#fff/.
backgroundColor:
1#0001
}, Islow/,
leaselnQuart/);

})

[J
Figura 10.2. Ocultar un elemento.

En la mitad de la animacin, se parece a lo que muestra la figura 10.3.Y al final de la


animacin, el cuadrado se oculta.

Componentes de interaccin
Entre los componentes de interaccin de jQuery VI est Sortable (para ordenar lista
de elementos), que puede transformar casi cualquier grupo de elementos en una lista de
arrastrar y soltar. En la figura 10.4, tenemos una lista no ordenada con algunos estilos
CSS aplicados a cada elemento.

,rr-r,oi"!

mil

10. Utilizar plug-ins

Aprende jQuery 1.3

ID

Figura 10.3. Animacin en progreso.

Figura 10.5. Arrastrar y soltar elementos.

"

Podemos mejorar la interaccin de usuario al aadir opciones al mtodo. sortable () . Aunque este mtodo tiene cerca de treinta opciones disponibles, utilizaremos
unas pocas para nuestro ejemplo:
$ (document) .ready(function()
(
$ (/#sort-container!)
.sortable
opacity:
. s,
cursar: /move/,
axis, !y!

({

});

Figura 10.4. Lista no ordenada.

El HIML es bastante sencillo:


<ul id="sort-container">
<li>John<!li>
<li>Paul</li>
<li>George<!li>
c::li>Ringoc::/li>
c::li>Petec::/li>
c Ld sSt.uc y Ld >
<fuI>

})

Las dos primeras opciones, opaci ty y cursor, se explican por s mismas. La tercera, axis, limita el movimiento del elemento a un eje determinado (en este caso, el eje y)
mientras que se ordena, como muestra la figura 10.6.

Ahora, para que la lista se pueda ordenar, simplemente escribimos el siguiente cdigo:
$ (document) .ready(function()
(
$ (!#sort-container!)
.sortable();

})

Esta sencilla lnea dentro de $ (document)


. ready () nos permite arrastrar
cada elemento y soltarlo en una posicin diferente dentro de la lista, como muestra la
figura 10.5.

Figura 10.6. Aadir opciones al mtodo

.sortablei),

ElI

Aprende jQuery 1.3

10. Utilizar plug-ins

mi

Como es evidente por el color de fondo ms claro del elemento ordenado, tambin
nos hemos aprovechado de una clase que se le aplica automticamente, ui - sortablehelper, al aplicar estilos a la clase en nuestra hoja de estilo.
Para ms informacin sobre todos los componentes de interaccin jQuery UT, visite
http://docs.jquery.com/UI#Interaction.

MyDlalog

Widgets
Adems de los componentes de construccin, jQuery DI incluye un conjunto de robustos widgets de interfaz de usuario que funcionan como los elementos que estamos
acostumbrados a ver en aplicaciones de escritorio. El widget Dialog, por ejemplo, utiliza
los componentes de arrastrar y cambiar de tamao para producir un cuadro de dilogo,
de modo que no tenemos que crear el nuestro.
Como con otros widgets de interfaz de usuario, Dialog acepta un gran nmero de
opciones. Su mtodo denominado. dialog () tambin puede tomar argumentos de
cadena que alteran lo que hace el cuadro de dilogo. En su nivel ms bsico, el mtodo . dialog () convierte un elemento existente en un cuadro de dilogo y lo muestra,
junto con los contenidos del elemento. Por ejemplo, podemos empezar con una sencilla
estructura <di v ,
<div id="dlg">My

Dialog</div>

Como era de esperar, este <di v parece bastante sencillo;un sencillobloque de texto,
como muestra la figura 10.7.

My rnalog

Figura 10.7. Un sencillo bloque de texto.

Podemos invocar el cuadro de dilogo bsico en nuestro archivo J avaScript tan pronto como el DOM est listo.
- ,.
$ (document) .ready(function()
$(/#dlg/) .dialog();
j);

El texto ahora se encuentra en un cuadro de dilogo, como muestra la figura 10.8.


Este cuadro de dilogo se puede cambiar de tamao al hacer clic en uno de su bordes
y arrastrar. Se puede mover al hacer clic en cualquier lado dentro del rea superior del
cuadro de dilogo, por debajo del borde superior. Y, se puede cerrar al hacer clic en el
vnculo X en la esquina superior derecha.
Podemos obviamente hacerlo mejor aplicando estilo, sin embargo. Aunque jQuery
DI proporciona un conjunto mnimo de estilos para asegurarse de que los widgets son
funcionales, nos deja a nosotros las decisiones sobre la apariencia y comportamiento. En
la figura 10.9 tiene un cuadro de dilogo con un tema predeterminado aplicado.

Figura 10.8. Texto en un cuadro de dilogo.

My Dialog

,f.

Figura 10.9. Cuadro de dilogo con estilo.

Ahora, las diferentes reas estn claramente indicadas, y el cursor del ratn cambia
para proporcionar incluso ms feedback visual en las partes del cuadro de dilogo habilitadas para arrastrar y cambiar de tamao. Como con los otros mtodos jQuery DI,
. dialog () viene con un nmero de opciones. Algunas de las opciones afectan la apariencia del cuadro de dilogo mientras que otras permiten que los eventos se activen:
$ (document) .ready(function()
var $dlg = $ (/#dlg/) ;
var dlgText
= $dlg.text();
$dlg.dialog({
autoOpen: false
title: dlgText,
open: function()
$dlg.empty()
;

).
buttons:
(
/add message/:
function()
$dlg.append(/<p>Inserted

).
/erase messages/:
function()
$(/p/, $dlg) .remove();

)
})

$ (/#do-dialog/)
.click(function()
$dlg.dialog(/open/)
;
j);
})

(
message</p>/)

lIi!I

Aprende jQuery 1.3

10. Utilizar plug-ins

Hemos configurado el cuadro de dilogo para que est oculto inicialmente y se abra
cuando el usuario haga clic en un botn con id= "do-dialog".
Tambin hemos movido
el contenido de texto inicial del cuadro de dilogo al rea de ttulo y aadido dos botones,
uno con add message (aadir mensaje) como su texto y otro con erase messages (eliminar
mensajes) como su texto. Cada botn tiene una funcin asociada para anexar o eliminar
prrafos cuando se hace die. Despus de hacer clic en el botn de aadir mensaje tres
veces, el cuadro de dilogo con estas opciones se parece a la figura 10.10.

IDI

SUdor

!&C=

Oatepick.er

;~~~:;~~
Su

No

Tu

w.

Th

Fr

$a

Inserted message
[nsertecf

message

Inserted

message

..~;;-~~']~

~r~~~~~~~~
Icrem Ipsum dolor sit: .met, consedlllur odipisidng elit. sed do
eiu.mod tempof' Inddldunt ut labore et dolore magna afiqua. ut
enim ad mlntm venlam, qull nostrvd exercltation ull.mea
laborla ni" ut allqulp ex ee c:ommodo COt1sequat.

,a

Figura 10.10. Modificar la apariencia del cuadro de dilogo.

.'

P1ogreosbar

H;ghtightl Em>'

o H.yl

Las otras opciones para configurar la visualizacin y comportamiento de los cuadros de dilogo se puede encontrar en http://does.j
query. com/UI/Dialog/
dialog#options.

Framewol'i<

loon8

(content

color

Sampkt ut-state-highlight

ayle.

praview)

1l~J ITli @:,1] E~~ ;;;~r<:l!K:~~~ ~~:

[ A

AJe"1 Sample

ut-stetilH!lTor

styIe.

Figura 10.11. Herramienta ThemeRoller.

ThemeRoller
Una reciente incorporacin a la librera jQuery VI es ThemeRoller, un motor temtico
interactivo basado en Web para widgets VI (vase figura 10.11). ThemeRoller facilita la
creacin de elementos altamente personalizables, de aspecto profesional. Como hemos
indicado, el cuadro de dilogo que acabamos de crear tiene aplicado el tema predeterminado; este tema se mostrar desde ThemeRoller si no se proporcionan parmetros
personalizados.
,.
Generar un conjunto completamente diferente de estilos es cuestin de visitar ht tp : / /
ui . j query . com/ themeroller
/, modificar las varias opciones segn se desee, y pulsar
el botn Download This Theme (Descargar esta temtica). Un archivo. z ip de hojas de
estilo e imgenes luego se puede situar en el directorio apropiado. Por ejemplo, al elegir
algunos colores y texturas diferentes, podemos cambiar en unos minutos nuestro cuadro
de dilogo anterior para que se parezca a lo que muestra la figura 10.12.

Figura 10.12. Mejorar nuestro cuadro de dilogo anterior.

Formularios
Hemos investigado algunas formas de manipular formularios en un captulo anterior.
Estos plug-ins pueden realizar tareas relacionadas con facilidad.

Otros plug-ins recomendados


Autocomplete
Adems de los plug-ins descritos en este captulo, los plug-ins listados ms adelante se recomiendan por los autores no slo por su popularidad, sino tambin por tener
cdigo slido.

http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete
http://plugins.jquery.com/projeet/autoeompletex

mil

10. Utilizar plug-ins

Aprende jQuery 1.3

Escrito por el desarrollador jQuery [orn Zaefferer, el plug-in Autocomplete proporciona una lista de coincidencias posibles a medida que el usuario escribe en una entrada
de texto, como muestra la figura 10.13.

El plug-in Jeditable (vase figura 10.15) convierte elementos no de formulario en


entrada de datos editable cuando un usuario lleva a cabo alguna accin, como Un clie
o doble dic. El contenido cambiado se enva automtieamente
para almacenarse en el
servidor.
'
""-

Single City (local):

Month (local):
Danvllle

dolor si! amel, oonsectetuer adipiscing eli!, sed diam nonummy nibh

Hidden input
Single City (contana):

Ed~pl

magt'la aliquam eral volulp

E-Mail (local):
Single Bird (remate):

De Graff

dolor sit amel, oonsectetusr adipiscing elil, sed diam


'\~gna aliquam erat volulp

/'

,oolor

Multiple Cities ~ocal):

Deflanee

SI'

XJUZij",J&&lL

Deerfteld

.;

Lorem ipsum dolor sil amel, oonsecteluer adipiscing slil, sed diam nonumm

Figura 10.15. Plug-in Jeditable.

.'

Validation

http://bassistance.de/jquery-plugins/jquery-plugin-validation
http://plugins.jquery_com/project/validate
Otro plug-in de J6m Zaefferer, Validation es una herramienta enormemente flexible para validar entrada de datos de formulario basado en un amplio rango de criterios
(vase figura 10.14).
a complete

fonn

Firstname

i Please'entr your fimname

Lastname

:1

i Plea,seenter }'Our lastname

Username

Password

i Please provide a passworc!

i Pleas prov/de a password

' Please enter a va/id email address

Masked input
http://digitalbush.com/projects/masked-input-plugin/
http://plugins.jquery.com/project/maskedinput
El plug-in Masked Input (vase la figura 10.16) ofrece una forma para que los usuarios incorporen datos de forma ms fcil, como fechas, nmeros de telfono, o nmeros
de la seguridad social, en un determinado formato. Sita automtieamente
ciertos caracteres (como una barra inclinada para las fechas) en el campo mientras permite que
se incorpore solamente un determinado conjunto de caracteres, segn se determina en
las opciones del plug-in.
The following example is a dernonstratlon from the usage tab.

Plls en.ter a usemame


Date

Confirm

Phone

"

Tax ID

passwotd
Email
!!Iease agree to

SSN

muerer

dolars mgna aliquam eral volulp

Figura 10.13. Plug-inAutocomplete.

Validating

lSiI

Pleil$e ,!(;(:ept our policy

C!ur policy

W04-----1

L_. .
I

c=

99199/9999

J (999) 999-9999
] 99-9999999
I 999-99-9999

Product Key

L.....m_=:=J a'-999-a999

Eye Script

::::J

-9.99 -9.99 999

Figura 10.16. Plug-in Masked input.


Figura 10.14. Plug-in Validation.

Tablas
jeditable
http://www.appelsiini.net/projects/jeditable
http://plugins. jquery. com/proj ect/j edi table

En un captulo anterior, hemos tratado tcnicas para organizar y mejorar datos tabulares. Muchos desarrolladores de plug-in han agrupado rutinas para ayudamos en
estas tareas.

~F'i

ID

Aprende jQuery 1.3

10. Utilizar plug-ins

Tablesorter

Flexigrid
http://code.google.com/p/flexigrid/
http://ptugins
. jquery. com/project/flexigrid
'~
Como jqGrid, Flexigrid es un plug-in de cuadrcula con todas las caractersticas.
Algunos de stas incluyen soporte JSON,paginacin, bsqueda rpida, mostrar y ocultar y cambiar el tamao de columnas, y ordenar filas (vase la figura 10.19).

http://tablesorter.com/
http://plugins.jquery.com/project/tablesorter
El plug-in Tablesorter (vase la figura 10.17)puede convertir cualquier tabla con elementos < t.he ad y < t body en una tabla que se puede ordenar sin refrescar la pgina.
Lascaractersticas especialesincluyen ordenar por mltiples columnas, analizadores para
ordenar muchos formatos diferentes (por ejemplo, fecha, hora, moneda, URL), ordenacin secundaria "oculta",y ampliabilidad por medio de un sistema de widgets.
Liiot

tIam
'c';"-~-'[_[~;;;'-"'''~-~'''I:--''''i<;['~I!DIIIi;<;:t
1lI~;"-,"-~",_......
-.!ih~~
)1:
..
/;:.r.l~.;~~~'1>~...I~~w~~,:..'~1.'\'(
A..- ..
~:

Bruce

Evans

22

~ i*~'t-$~'~i'
Clarlt

46

Kanl

..

$13.19

11%

-100.9

$15.89

Ii'

44%

26

20.9%

-12.1

~~._

..
"..,:,;.;'' '..:..;6..''"' ..,,~

Jan 18,20079:12NA

"$1~at9 ,,:/:< : '~.7," ,!;1;~~.f\


:ttt~ii~;{.'~lil!2:il
9.=12.A!.t .....

18

~~~*K''~\!
:Hcibd"""::,,,.;t as
Pr
28

lB

.,'tf~.i<.:

Jan 12,200311:14AM

~:111.21l92,5'1~1~:'&~:-%M'O'';i~;

,......

$9.99

JuI6. 20068:14M\'"

Figura 10.17. Plug-in Tablesorter.


Figura 10.19. Plug-in Flexigrid.

jqGrid

Imgenes

http://www.trirand.com/blog/
http://plugins.jquery.com/project/jqGrids
Un control ]avaScript compatible con AJAX,jqGrid (vase la figura 10.18)permite a
los desarrolladores representar dinmicamente y manipular datos tabulares en la Web.
Proporciona opciones para edicin en lnea, edicin de celda, navegacin de pagnador,
seleccin de mltiples elementos, sub-cuadrculas y cuadrculas en rbol. El plug-in
viene con una amplia documentacin en http://www.secondpersonplural.ca/
jqgriddocs/.
8 OJqG~d Examples
re &. loadlng Data
m I Manlpulatlng
8

Selec' Theme: oo'j,'rbli

La manipulacin de imagen es una tarea que a menudo requiere procesado intensivo


del lado del servidor. Sin embargo, algunos autores de plug-in han desarrollado formas
de realizar gestin sencilla de imagen en JavaScript utilizando jQuery como vehculo.

Icrop
http://deepliquid.com/content/Jcrop.html
http://plugins.jquery.com/project/Jcrop
[crop (vase la figura 10.20)ofrece una forma rpida y sencilla de aadir recorte de
imagen a aplicaciones Web. Las caractersticas incluyen bloquear relacin de aspecto,
tamao mnimo y mximo, vnculos de interaccin y estilo personalizado.

Advanced

CJ Multl Selea
c:aMaster Detall

~~rr4

Magnify

t::JCrld as Subgrid
(?aReslzlng
Q;jSearch BI9 Sets
lB a+New stnce beta 3.0
I!l

CY:fi1r.~*'

a+ Row Edlting

m 1+ Data Mapplng

m 1+lntegratlons
ti! rUve Data Manlpulatlon
ID ,a+New In verslon 3.1
fB a+New In verslon 3.2
te a+New In verstcn 3.3

1-

i '!"
1:4

t:~::" .

lltem"4

..

.."..~[:~...:~Z:~~.".f}~~b~O ..
.

'LOO ........... !2O.O ........ioo.ri .-~

http://www.jnathanson.com/index.cfm?page=pages/jquery/magnify/
magnify
http://plugins.jquery.com/project/magnify

~!;,~:r~~~~!~~:~~~~~~;~:~~=='"==
Figura 10.18. Pluq-in jqGrid.

Cuando se proporciona con una imagen proporcionalmente pequea y grande, el


plug-in Magnify (vase la figura 10.21)generar una "lupa" como las que se utilizan comnmente para el detalle del producto e imgenes de primer plano.

Ea

Aprende jQuery 1.3

10. Utilizar plug-ins

Jcrop

mi

Thumbnail Demo

"

Vcry fancy

captlon

te

thls Image

Figura 10.22. Plug-in FancyBox.

"

Thickbox
http://jquery.com/demo/thickbox/

Thickbox es un verstil plug-in lightbox que puede mostrar un sola imagen, mltiples
imgenes, contenido en lnea, contenido e f r ame, o contenido servido por medio de
AJAX en un cuadro de dilogo modal hbrido (vase la figura 10.23).

Figura 10.21. Plug-in Magnify.

jQuery lightbox y cuadros de dilogo modales


Uno de nuestros ejemplos en el captulo anterior mostraba cmo superponer informacin detallada sobre una pgina sin el uso de una ventana emergente, una caracterstica
a menudo denominada Lightbox.
Los siguientes plug-ins ayudan en la creacin de esas superposiciones.

FancyBox
http://fancy.klade.lv/

Este clon de Lightbox enfatiza el estilo, con su apariencia al estilo Mac y un elegante
efecto de sombra. Adems de mostrar automticamente imgenes escaladas, el plug-in
FancyBox (vase la figura 10.22) puede mostrar contenido en lnea o e .f r ame.

Figura 10.23. Plug-in Thickbox.

l!IiI

T"

Aprende jQuery 1.3

10. Utilizar plug-ins

BlockUI

http://malsup.com/jquery/block/
http://plugins.jquery.com/project/blockUI
El plug-n BlockUI simula comportamiento sncrono, sin bloquear el navegador.
Cuando se activa, impedir la interaccin de usuario con la pgina (o parte de la pgina)
hasta que se desactive (vase la figura 10.24).

I
I
I

BIII

Flot
http://cqde.google.com/p/flot/
http://plugins
. j query. com/proj ect/flot
El plug-in Flot utiliza el elemento c anve s > para producir grficos de conjuntos de
datos y opcionalmente modificar esos grficos basndose en la interaccin de usuario
(vase la figura 10.26).Con la inclusin del script de traduccin Excanvas, Flot puede
mostrar grficos en Internet Explorer tambin, porque las instrucciones Canvas se con('vierten al formato VML propietario de Internet Explorer .
20

_ _ ._-'- I

-+--'
I

15

___

l'

.___

~.

1---

Jriited Stales

11I1
11I1

UnHed Kingdom
Denmark
No
_rway

Russla

11I1 Germ any.,


11I1 Sweden

Figura 10.24. Plug-in BlockUI.

jqModal

sL=:;r:~1< i=b:~ ~t

http://dev.iceburg.net/jquery/jqModal/
http://plugins.jquery.com/project/jqModal
El plug-in jqModal es una solucin ligera de cuadro de dilogo modal que tambin
es potente y flexible.Con un nfasis en ampliabilidad, deja mucha de la interaccin a los
desarrolladores Web que lo implementan (vase la figura 10.25).

01
1990

1992

1994

1996

I
1996

2000

2002

2004

Figura 10.26. Plug-in Flot.

view

Ci

~ i'iM%ffi5
(alert), View (<otloe)

ase in which :. "n'!';.~r,~fev~r,


'(.1/'~rc~~~~ffd~"!!11
Ml ;.~cssis
bllows a desi nC!"\l,:"p!~~!\a.r!>~)~~'f'hwj
C.l> m overfays,
,edoI hope lo lVi'l>urotng)Or:~IMkitl!r.t""lIfI<t,hMm~ul:fM",.bg li'~ s. Interesf<
.tJ<>tt~Il1.of,l>
.lli lUins t. +he food. only h.dwoods should be
used for ...,king <D:Idgrilling. sueh <0$ook. peccn,

a (dialog)

iS'rM;.y-:~~.~~.'l\'Jfr./W~?i~me.squit

Sparklines
http://omnipotent.net/jquery.sparkline/
http://plugins.jquery.com/project/sparklines

e,

b (alert) aj ~ rtrlit!fing on t'" type of mea! b&ingcooked.


Al

e (alert) onShow. onHide callbacks.


Figura 10.25. Plug-in jqModal.

Grficas
Como con la manipulacin de imagen, las grficas han sido tradicionalmente una
actividad del lado del servidor que requera gran cantidad de procesado. Los programadores creativos han desarrollado variasformas de crear grficas en el navegador, y
han agrupado estas tcnicas en los plug-ns que se muestran aqu.

Nombrado as por un concepto popularizado por el experto de visualizacin de datos


Edward Tufte, el plug-in Sparklines (vase la figura 10.27)genera grficas en lnea pequeas y sencillas. Como Flot, Sparklines utiliza el elemento <canvas> para mostrar
las grficas, pero la conversin para Internet Explorer se realiza dentro del plug-in en
lugar de basarse en Excanvas.

Eventos
Como hemos visto una y otra vez, jQuery proporciona una gran cantidad de herramientas para interceptar y reaccionar a eventos de usuario como clics del ratn y pulsaciones de teclado. Sin embargo, muchas opciones se ponen disponibles en la librera

&El

Aprende jQuery 1.3

10. Utilizar plug-ins

principal aunque siempre habr ms tcnicas avanzadas que explorar. Estos plug-ins
facilitan la implementacin de algunos escenarios de evento menos comunes.

Resumen
En este captulo hemos examinadoformas en las que podemos incorporar plug-ins
de terceros en nuestras pginas Web. Hemos examinado el plug-in Form y jQuery DI
y hemos listado algunos otros. En el siguiente captulo, nos aprovecharemos de la arquitectura plug-n de jQuery para desarrollar algunos tipos diferentes de plug-ins por
nuestra cuenta.

Mouse speed......1l..Inllne ~Ilnegr$phs

Bar Cllar1S 111_.1. negativa values: .-'-'-

CI;Imposile Inline ~

('

In~ne wtth normal range ~


CompO$iI8 bar~
Discreta 111111111111111,11
Discreta with thrashold

1!IIIIUI

Customlze slzeand cpIOUt$~


Triste. chatte .......
(Ihlnkgames won. loS! or drawn)

.'

Tri$late ch$rt tlaIng a (XlIoUrmap: _ -_


,Pis Charla

I!D

8$.

Bulle! !;haJ'IS

Figura 10.27. Plug-in Sparklines.

hoverlntent
http://cherne.net/brian/resources/jquery.hoverlntent.html
http://plugins.jquery.com/project/hoverlntent
El plug-in hoverIntent proporciona un solo mtodo para ocup~r ellugar del mtodo
. hover () cuando es importante impedir la activacin accidental de animaciones cuando
el usuario mueve el ratn sobre o fuera de un elemento. Intenta determinar la intencin
del usuario al monitorizar el cambio en velocidad del movimiento del ratn del usuario.
Este plug-in es especialmente efectivo cuando se utiliza con navegacin desplegable.

live query
http://github.com/brandonaaron/livequery/
http://plugins.jquery.com/project/livequery
Como el mtodo . 1i ve () incorporado de jQuery, el plug-in Live Query anexa dinrnicamente y mantiene vinculaciones de evento a elementos en el DOM, con independencia de cuando se creen los elementos. El plug-in proporciona una implementacin
alternativa que puede ser preferible en algunas situaciones.

r
/

"

11 Desarrollar
plug-ins

Los plug-ins de terceros disponibles proporcionan un grupo de opciones para mejorar


nuestra experiencia de codificacin, pero algunas veces necesitamos llegar un poco ms
lejos. Cuando escribimos cdigo que se podra reutilizar por otros, o incluso nosotros mismos, lo queremos poder empaquetar como un nuevo plug-in. Afortunadamente, el proceso de desarrollo de un plug-in es ms complejo que escribir el cdigo que lo utiliza.
En este captulo, tratamos cmo crear muchos tipos diferentes de plug-ins, desde
el ms sencillo al ms complejo. Empezaremos con plug-ins que simplemente ponen
disponibles nuevas funciones globales, y pasaremos a tratar mtodos del objeto jQuery
de varios tipos. Tambin trataremos de ampliar el motor de selector jQuery con nuevas
expresiones, y concluiremos con algunos consejos sobre distribuir un plug-in para que
lo utilicen otros desarrolladores.

Aadir nuevas funciones globales


Algunas de las posibilidades incorporadas de jQuery se proporcionan a travs de lo
que hemos denominado funciones globales. Como hemos visto, stos son en realidad
mtodos del objeto j Query, pero en sentido prctico, son funciones dentro de un espacio de nombres j Query. Un ejemplo de esta tcnica es la funcin $ . aj ax ( ) . Todo lo
que $ . aj ax () realiza se podra conseguir con una funcin global normal denominada
simplemente aj ax () , pero este enfoque nos dejara abiertos a conflictos de nombre de
funcin. Al situar la funcin dentro del espacio de nombre j Query, solamente nos tenemos que preocupar por conflictos con otros mtodos jQuery.

II!II

r
I

11. Desarrollar plug-ins

Para aadir una funcin al espacio de nombre j Query, podemos simplemente asignar la nueva funcin como una propiedad del objeto j Query:
jQuery.globalFunction
= function() (
alert(/This
is a test. This is only

Aprende jQuery 1.3


jQuery.myPlugin
= (
functionOne:
function()
(
alert(/This
is a test. This
},

a test./);

Ahora en cualquier cdigo que utiliza este plug-n, podemos escribir:

};

Tambin podemos utilizar el alias $ y escribir:


$.globalFunction()

a test./);

functionTwo:
function(param)
(
alert(/The
parameter
is "/ + pai:am + /"./);

};

jQuery.globalFunction()

is only

I!!I

Esto funcionar como una llamada de funcin bsica, y se mostrar la alerta.

Este patrn crea esencialmente otro espacio de nombre para nuestras funciones
globales, denominado jQuery. rnyPlugin. Aunque informalmente llamamos a estas
,...funciones "globales", ahora son mtodos del objeto rnyPlugin, una propiedad del objeto global j Query. Por lo tanto tenemos que incluir el nombre del plug-in en nuestras
llamadas de funcin:

Aadir mltiples funciones

$.myPlugin.functionOne()
$.myPlugin. functionTwo

Si nuestro plug-in necesita proporcionar ms de una funcin global, podramos declararlas independientemente:
.'

Con esta tcnica (y un nombre de plug-in suficientemente nico), estamos totalmente


protegidos de colisiones de espacio de nombres en nuestras funciones globales.

jQuery.functionOne
= function()
alert(/This
is a test. This

(
is only

a test./);

i.
jQuery.functionTwo
= function(param)
(
alert(/The
parameter
is ,,/+ param + /"./);

};

Ahora, ambos mtodos estn definidos, por lo que podemos invocarlos en el modo
normal:
$.functionOne();
$.functionTwo(/test/)

;
(/test/) ;

Qu sentido tiene?
Ahora tenemos los fundamentos bsicos del desarrollo de plug-in entre nuestros
trucos. Despus de guardar nuestras funciones en un archivo denominado j query .
rnyplugin. j s, podemos incluir este script y utilizar las funciones desde otros scripts
en la pgina. Pero en qu es esto diferente de cualquier otro archivo JavaScript que
pudiramos crear e incluir? Ya hemos tratado los beneficios del espacio de nombre de
situar nuestro cdigo dentro del objeto j Query. Sin embargo, existe otra ventaja a escribir nuestra biblioteca de funcin como una extensin jQuery: puesto que sabemos que
jQuery estar incluido, las funciones pueden utilizar jQuery.

Tambin podemos emplear otra sintaxis al definir nuestras funciones, utilizando la


funcin $ . extend ():
jQuery. extend ((
functionOne:
function()
(
alert(/This
is a test. This

r.

is only

functionTwo:
function(param)
(
alert(/The
parameter
is "/ + param

a test./);

/"./);

}
});

Esto produce los mismos resultados.


Corremos el riesgo, sin embargo, de un tipo diferente de polucin de espacio de
nombre. Aunque estamos protegidos de la mayora de nombres de variable y funcin
JavaScript al utilizar el espacio de nombre j Query, podramos todava tener un conflicto
con nombres de funcin definidos en otros plug-ins jQuery. Para evitar esto, es mejor
encapsular todas las funciones globales para un plug-in en un objeto:

Aunque se incluir jQuery, no deberamos asumir que el mtodo abreviado $ est


disponible. Recuerde que el mtodo $ . noCon fl i e t () puede abandonar el control de
este mtodo abreviado. Para tener en cuenta esto, nuestros plug-ins siempre deberan
invocar mtodos jQuery utilizando j Query o definir internamente $, como se describe
ms adelante.

Crear un mtodo de utilidad


Muchas de las funciones globales proporcionadas por la librera principal jQuery
son mtodos de utilidad; es decir, proporcionan mtodos abreviados para tareas que se
necesitan frecuentemente, pero que no son difciles de realizar a mano. Las funciones

l!liI

Aprende jQuery 1.3

11. Desarrollar plug-ins

As que ahora hemos visto la proteccin del espacio de nombre y la disponibilidad de


la librera garantizada que conceden los plug-ins jQuery. Sin embargo, stos son simplemente beneficios organizativos. Para aprovechar realmente el potencial de los plug-ins
jQuery, necesitamos aprender cmo crear nuevos mtodos en instancias individuales
de objeto jQuery.

de gestin de tabla $ . each ( ) , $ . map ( ) , y $ . grep () son buenos ejemplos de stas.


Para ilustrar la creacin de dichos mtodos, aadiremos una nueva funcin $ . sum () a
su nmero. Nuestro nuevo mtodo aceptar una tabla, sumar los valores en la tabla, y
devolver el resultado. El cdigo para nuestro plug-in es bastante breve:
jQuery.sum
= function(array)
var total = Di
jQuery. each (array, function(index,
total += value

})

value)

lID

Aadir mtodos de objeto jQuery

return

"

total

};

Observe que aqu, hemos utilizado el mtodo $ . each () para pasar por los valores
de la tabla. Podramos ciertamente utilizar un sencillo bucle for () aqu, pero puesto que
podemos estar seguros de que la librera jQuery se ha cargado antes de nuestro plug-in,
podemos utilizar la sintaxis con la que estbamos cmodos.
Para probar nuestro plug-in, crearemos una sencilla pgina para mostrar las entradas y salidas de la funcin:

La mayora de la funcionalidad incorporada de jQuery se proporciona por medio


de sus mtodos de objeto, y aqu es donde los plug-ins tambin destacan. Siempre que
escribimos una funcin que acta sobre parte del DOM, es apropiado crear un mtodo
. de objeto.
.
Hemos visto que aadir funciones globales requiere ampliar el objeto j Query con
nuevos mtodos. Aadir mtodos de instancia es similar, pero en su lugar ampliamos
el objeto j Query . fn:
jQuery.fn.myMethod
a1ert(/Nothing

= function()
happens./);

<body>

<p>Array contents:</p>
<ul id="array-contents"></ul>
<p>Array sum:</p>
<div id=lIarray-sum"></div>
</body>

Ahora escribiremos un pequeo script que anexa los valores de la tabla y la suma de
tabla a los marcadores de posicin que hemos creado.
$ (document) .ready(function()
(
var myArray
= [52, 97, 0.5, -22);
$.each(myArray,
function(index,
va1ue)
$ (/#array-contents/)
.append(/<li>/
+ va1ue

})

El objeto j Query. fn es un alias de jQuery .prototype,


sin.

proporcionado por conci-

Podemos invocar luego este nuevo mtodo desde nuestro cdigo despus de utilizar
cualquier expresin selector:
+ /</li>/);

$(/div/)

.myMethod();

$ (/#array-sum/)

.append($.sum(myArray));

}) ;

Un vistazo a nuestra pgina HTML verifica que nuestro plug-in est funcionando
correctamente, como muestra la figura 11.1.
Array contenta:
52

O,
0.5
.Z
Atraysum:

Nuestra alerta se muestra cuando invocamos el mtodo. Podramos tambin haber


escrito una funcin global, sin embargo, puesto que no hemos utilizado los nodos DOM
coincidentes en ningn sentido. Una implementacin de mtodo razonable acta sobre
su contexto.

Contexto del mtodo de objeto


Dentro de cualquier mtodo plug-in, se establece la palabra clave thi s en el objeto jQuery actual. Por lo tanto, podemos invocar cualquier mtodo jQuery incorporado
sobre this, o extraer sus nodos DOM y trabajar sobre ellos:
jQuery.fn.showA1ert
= function()
(
a1ert(/you
se1ected
/ + this.1ength

Figura 11.1. Plug-in en funcionamiento.

+ /

e1ements./);

lm1I

11. Desarrollar plug-ins

Aprende jQuery 1.3

Para examinar lo que podemos hacer con contexto de objeto, escribiremos un pequeo plug-in para manipular las clases en los elementos coincidentes. Nuestro nuevo
mtodo tomar dos nombres de clase y alternar qu clase se aplica a cada elemento
con cada invocacin.
jQuery.fn.swapClass
if (this.hasClass

function(classl,
(elassl))
(

this.removeClass(elassl)

class2)

Pero algo est mal. Cuando hacemos clie en el botn, se le aplica a todas las filas la
clase that, como muestra la figura 11.3.

Lorom

Ipsum dolor

Comectetur

.addClass(clasS2);

if

(this. hasClass

(claSs2))

this.removeClass(elass2)

OuIs no:rtrud

sIt ame'

.dlpJsJcJng

Sed do elusmod

incJdJdunf

ufl4bor8

VfJnJttm

tJxerclt1llion

LBborl5 nlsJ ut a/lqulp

.addClass(elasSl);

811t

tempor

MagnllS1lqUII
ut 8lIim ad mJnIm

else

mil

ex

ullsmco
68

oommodo

Duls Bute lruf8 dolor

(5Swap-ctasses)

};

Figura

En primer lugar, comprobamos la presencia de c Las s r en el elemento coincidente y


sustituimos class2 si se encuentra. De lo contrario, comprobamos class2 e intercambiamos classl si es necesario. Si ninguna clase est presente, no hacemos nada.
Para comprobar nuestro mtodo, necesitamos algo de HTML con el ,que jugar:

<u1>
<li>Lorem

ipsum

dolor

8it

ametc/li>

eli class="this">Consectetur
adipisicing
elite/li>
cli>Sed do eiusmod tempor incididunt
ut laborec/li>
e1i class=Uthat">Magna
aliquac::/li>
eli class="thislt>Ut
enirn ad minim veniame/li>
<:1i>Qui8 nostrud exercitation
ullarncO</li>
cli>Laboris
nisi ut aliquip ex ea cornmodoc/li>
eli class="that">Duis
aute irure dolorc/li>
<fuI>
<input

type="button"

value="Swap

classes"

id=:: 11swapll

/>

La clase this tiene estilo aplicado como texto en negrita, y la clase that como texto
en cursiva, como muestra la figura 11.2.
Lorem Ipsum d~r 1ft amet
Con . ctetur aclJpl.5clng .IIt
Sed do eiusmod
Ma{Jfl8SUque

tempor incidldunt

Ut _"1m ad mtnlm
Qula nostrud

utlabore

Necesitamos recordar que una expresin selector jQuery siempre puede coincidir
con cero, uno o mltiples elementos. Debemos permitir cualquiera de estos escenarios
cuando diseamos un mtodo plug-in.
En este caso, estamos invocando. hasClass (), que solamente examina el primer
elemento coincidente. En su lugar, necesitamos comprobar cada elemento de forma independiente y actuar sobre l.
La forma ms sencilla de garantizar un comportamiento adecuado con independencia
del nmero de elementos coincidentes es siempre invocar . each () sobre el contexto
del mtodo; esto refuerza la iteracin implcita, que es importante para mantener consistencia entre plug-in y mtodos incorporados.
Dentro de la llamada. each (), thi s hace referencia a cada elemento DOM en turno,
por lo que podemos ajustar nuestro cdigo a comprobar de forma separada y aplicar
clases a cada elemento coincidente.
jQuery.fn.swapClass
= funetion(clasBl,
this.eaeh(funetion()
(
var $element
= jQuery(this);
if ($element.hasClass(classl))
$element.removeClass(elaS9l)

Laborts nIsI ut Bllqulp 8'1: ea commodo


Duls IJuts lrura dolor

Figura 11.2.

(
.addCla9s(ela992);

uJlamco

}
})

~~

class2)

else if ($element.hasClass(class2))
(
$element.removeCla99
(ela992) .addClass(classl);

vltl1lam

8X8rcllation

11.3. Efectos de la clase that.

};

Textocon los estilos aplicados.

Ahora podemos invocar nuestro mtodo siempre que se haga clic sobre el botn:
$ (doeument)

.ready(funetion

La palabra clave thi s hace referencia a un objetojQuery dentro del cuerpo del mtodo de
objeto, pero hace referencia a un elemento DOMdentro de la invocacin . each ().

() (

$ (/#swap/) .eliek(funetion()
$ (fU/) .s.,apClass (fthis/,
return false

{
/that/);

Ahora cuando hacemos clie en el botn, las clases se intercambian sin afectar a los
elementos que no tienen aplicada ninguna clase, como muestra la figura 11.4.

'I-~~

lB

11. Desarrollar plug-ins

Aprende jQuery 1.3

Lotem

lpsum

CoMect8tur

.css(/text-decoration/,
return false;

dofor sH. emet


adlplslcJng

8lit

Sed do e1usmod tempor incidldunl

ut lIfIim

ad minlm venJINTI
n(sI

ut

ullamco

alIqulp ex ea commodo

Dula aute lrure dolor

Mtodos transversales DOM

SwaP"'IBS~
Figura 11.4.

Alternarestilos.

Encadenar mtodos
Adems de iteracin implcita, los usuarios jQuery deberan poder basarse en encadenar comportamiento. Esto significa que necesitamos devolver un objeto jQuery de todos
los mtodos plug-in, a menos que el mtodo est claramente pensado para recuperar una
informacin diferente. El objeto jQuery devuelto es normalmente el proporcionado como
this. Si utilizamos. each () para pasar por this, podemos devolvep su resultado:
jQuery.fn.swapClass
= function(classl,
return this.each(function()
{
var $element
= jQuery(this);
if ($element.hasClass(classl))
$element.removeClass(classl)

class2)

(
.addClass(class2);

}
el se if ($element.hasClass(class2))
(
$element.removeClass(class2)
.addClass(classl);

}
})

/underlineJ};

j);

Ouis nostrud exerdtation


Laborls

});

ut labore

Magn llqua

En algunos casos, podemos querer que un mtodo plug-in cambie qu elementos DOM
se hacen referencia por el objeto jQuery. Por ejemplo, suponga que quisiramos aadir un
mtodo transversal DOM que encontrara los abuelos de los elementos coincidentes:
jQuery.fn.grandparent
= function()
var grandparents
= [];
this.each(function()
(
grandparents.push(this.parentNode.parentNode);
j);
grandparents
= jQuery.unique(grandparents);
return this.setArray(grandparents);
};

Este mtodo crea una nueva tabla grandparents,


completndola al pasar por todos
los elementos actualmente referenciados por el objeto jQuery. La propiedad DOM estndar . parentNode se utiliza para encontrar los elementos abuelo, que se pasan a la
tabla grandparents.
Esta tabla se despoja de sus duplicados con una llamada a $ . unique ( ) . Luego el mtodo interno jQuery . setArray () cambia el conjunto de elementos
coincidentes en la nueva tabla. Ahora, podemos encontrar y operar sobre el abuelo de
un elemento con una sola llamada de mtodo. Para comprobar nuestro mtodo, configuraremos una estructura <di v profundamente anidada:

};

Previamente, cuando invocamos . swapClass () tuvimos que iniciar una nueva


sentencia para hacer otra cosa con los elementos. Con la sentencia ret urn en su lugar,
sin embargo, podemos encadenar libremente nuestro mtodo de plug-in con mtodos
incorporados, como muestra la figura 11.5.
l.ot!m losum dolor stt

amet

ConnqteItr 8dlpI4IcJng

.~
Sed

tN

81ft

do tlullDOd temPOl' tnddldunt

orWn IdrnJnlm

Qufs n9!!nJd

labods n-'
PUl.

tu-

lit

tabor!

wnJam

8X8ldtatlon
ul a1lgulp!IX

ultamea
e8 commodo

Inu. dolor

_ ~_.i\.

~'I5",""

Figura 11.5.
$ (document) .ready(function()
(
$ (/#swap/) .click(function()
$(/li/)
.swapClass(/this/,
/that/)

DI

Estilosubrayado.

<div>Deserunt mollit anim id est laborum</div>


<div>Ut enim ad minim veniam
<div>Quis
nostrud exercitation
<div>Ullamco
laboris nisi
<div>ut aliquip ex ea</div>
<div class="targetll>Commodo
consequat
<div>Lorem
ipsum dolor sit amet</div>
</div>
</div>
</div>
<div>Duis
aute irure dolor</div>
<div>In reprehenderit
<div>In voluptate</div>
<div>Velit
esse
<div>Cillum
dolore</div>
<div class="target">Fugiat
nulla pariatur</div>
</div>
<div>Excepteur
sint occaecat
</div>
</div>
<div>Non proident</div>
</div>
<div>Sunt
in culpa qui officia</div>

cupidatat</div>

mi

11. Desarrollar plug-ins

Aprende jQuery 1.3

Identificaremos los elementos destino di v c Las s


su texto en negrita, como muestra la figura 11.6.
o.ru.nl molSt

"

target"

al aplicar estilo a

-,

Qul. no.ttud uercitaUon


lJIlamco labom niai
UleJiquipex

})

connquat

lot&m
Ou

Sin embargo, este mtodo es destructivo. El objeto jQuery actual se modifica com~ efecto secundario; uno que es evidente si almacenamos el objeto jQuery en una variable:
$ (docu rnent) .~eady(function()
{
var $target ~ $(/.target/);
$target.grandparent()
.addClass(/highlight/);
$target.hide()
;

anim id eet J.borum

Ut enim ad minlm veniam

Commodo

1m

ipMIm

dolor

ait

Este cdigo debera resaltar los elementos abuelo, y luego ocultar los elementos des, tino. Sin embargo, el efecto actual es que los abuelos se ocultan en su lugar, como muesr tra la figura 11.8.

amet

utaiNredolor

In~,..hend.rit
Involuptata

\lo"
Deaerunl moml.,im

Cillumdolo,..

id ..tl8borum

UI: enim ad minlm wniam

Fugl.t nuJl. ~riatur

Non proident
Exc.plur

sinl OCC8ecat cupidsla.l

_~~cut~~.~_da
Non proidenl

Figura 11.6.

Estructura anidada.

Ahora podemos localizar los elementos abuelo de los elementos al utilizar nuestro
nuevo mtodo:
$ (docurnent) .ready(function()
$(/.target/)
.grandparent()

Figura 11.8.

"

Sunl n culpa qui ofrlcia

{
.addClass(/highlight/);

}l;

La clase highl ight pone en cursiva los elementos abuelo en la pgina, como muestra la figura 11.7.

Ocultarlos abuelos.

El objeto jQuery almacenado en $target ha cambiado para hacer referencia al abuelo. Para evitar esto, tenemos que hacer que el mtodo sea no destructivo. Esto es posible
por la pila interna que jQuery mantiene para cada objeto.
jQuery. fn.grandparent
~ function()
var grandparents
~ (J;
this.each(function()
{
grandparents.push(this.parentNode.parentNode)
}) ;
grandparents
~ jQuery.unique(grandparents);
return this.pushStack(grandparents);

};
Oeterunl mollit &f1im id ut laborum
UI:

en,"" Id mlnlm

ven.m

Qui. noaUud &JUHChalion


Ullamoo

"

Jabone nist

'Ut a1iquip ex ea
Conwnodo cvnaequal
lorem ipaum dotor ail amet

..,....Oui. aute inn

dolor

Involuptale

'Vela~
OUumdolore

Al invocar . pushStack () en lugar de . setArray () , creamos un nuevo objeto


jQuery, en lugar de modificar el antiguo. Ahora, el objeto $target no se modifica, y los
objetos destino originales se ocultan por nuestro cdigo, como muestra la figura 11.9.
Como beneficio secundario, . pushStack
() tambin permite que los mtodos
. end () y . andSelf () funcionen como nuestro plug-in, de modo que podemos encadenar mtodos juntos adecuadamente, como muestra la figura 11.10.
$ (docurnent) .ready(function
() {
$(/.target/)
.grandparent()
.andSelf()

})

.addClass(/highlight/);

FLllilt.tnutl.~riatur
Exceplaur

aint oc:caec:aI: cupklatat

Nonproidenl
SlJJ'Illn culpa qui ofIicia

Figura 11.7.

Localizarelementos abuelo en la estructura.

Los mtodos transversales DOM como. children () eran operaciones destructivas


en jQuery 1.0, pero han pasado a no destructivas en 1.1.

';'1'
;'

1m

Aprende jQuery 1.3

11. Desarrollar plug-ins

Oeaenmt
Ul

..t

mollil ..,im jd

que podemos seleccionar y elegir los que son de utilidad para cada proyecto y omitir
los irrelevantes.'
Cuando n01encontramos repitiendo algo en nuestro cdigo muchas veces, puede
requerir la creacin de un mtodo abreviado. Por ejemplo, suponga que animamos frecuentemente elementos utilizando una'combinacin de las tcnicas incorporadas "deslizar" y "desvanecer". Agrupar estos efectos significa animar la height y opacity de
un elemento de forma simultnea. El mtodo. animate () facilita esto:

I.borum

Q,n-..d....,....

tIfm

ad mlnlm

Y8f'1iem

Ullamco.borianiai
l.laJiquipex

lB

Ou.aulelruredotot

infWPf!~'!'_.
InvoluptaUI

~l~~~:

.animate(

Clliu~doIore

--,
I

ExceplMJr

..,1 occaacat

Cllpic!IIIat.

(height:

/hide/, opacity:

/hide/});

Podemos crear un tro de mtodos abreviados para llevar a cabo esta animacin cuando mostramos y ocultamos elementos:

Sunlinculpa.~~

11.9.Objetosdestinoocultos.

Figura
o."Nnl

room.

anim id eat r.borurn

lit enim ad mnim wniam

labori.

function()

niai

lA. aliqui) ex ea

c-modo
l.oI8m j~um doler .it amel
-..
.

jQuery.fn.slideFadeln
= function()
return this.animate({
height: /show/,
opacity: /show/

Ouiaauleirutedolor

})

In,.~rit
Involuptate

Ollum doIore
,FusI"'nulMplJ~
ExoeptMJr ainloceaecet

};

VeIit

cuptdatat

---~-;-:..;.
-~~;~':::;':=~:;;;
..~-~.~~:
Non_
Slmlln

};

Qu;.noattud~tioIt
Ullamco

jQuery.fn .slideFadeOut
return this.animate({
height: /hide/,
opacity: /hide/
}) ;

jQuery.fn.slideFadeToggle
return this.animate({
height: /toggle/,
opacity: /toggle/
}) ;

function()

};

CU'P- qu offioia

Figura 11.10.

Encadenarmtodos.

Aadir nuevos mtodos abreviados


Muchos de los mtodos incluidos en jQuery son mtodos abreviados para otros
mtodos subyacentes. Por ejemplo, la mayora de los mtodos de evento son mtodos
abreviados para llamadas a .bind () o . trigger (), y muchos mtodos AJAX internamente invocan $. aj ax () . Estos mtodos abreviados facilitan utilizar caractersticas
que de lo contrario se complican por muchas opciones.
La biblioteca jQuery debe mantener un delicado equilibrio entre conveniencia y
complejidad. Cada mtodo que se aade a la librera puede ayudar a los desarrolladores a escribir ciertas piezas de cdigo ms rpidamente, pero tambin aumenta el tamao global del cdigo base y puede reducir el rendimiento. Por esta razn, muchos
mtodos abreviados para funcionalidad incorporada se relegan a plug-ins, de modo

Ahora podemos invocar. slideFadeOut


() y activar la animacin siempre que se
necesite. Puesto que, dentro de una definicin de mtodo plug-in, this hace referencia
al objeto jQuery actual, la animacin se realizar sobre todos los elementos coincidentes a la vez.
Por exactitud, nuestros nuevos mtodos deberan soportar los mismos parmetros
que los mtodos abreviados incorporados. En particular, mtodos como. fadeln () se
pueden personalizar con velocidades y funciones de rellamada. Puesto que. animate () tambin toma estos parmetros, permitir esto es sencillo. Simplemente aceptamos
los parmetros y los pasamos a . animate () .
jQuery.fn.slideFadeOut
= function(speed,
return this.animate({
height: /hide/,
opacity: /hide/
}, speed, callback);

callback)

};
jQuery.fn.slideFadeln

function(speed,

callback)

[""'."

I'J

l!mI

11. Desarrollar plug-ins

Aprende jQuery 1.3

DI

return this.animate({
height,
!show!,
opacity,
!show!
}, speed, callback);
};
jQuery.fn.slideFadeToggle
return this.animate({
height,
!toggle!,
opacity,
!toggle!
}, speed, callback);
};

function(speed,

callback)

1ld...

d fad.UiiJ~'5lld"' d;fad~~

Figura 11.11.

Mtodos abreviados personalizados.

Ahora, tenemos mtodos abreviados personalizados que funcionan como sus


equivalentes incorporados. Para demostrar esto, necesitaremos una sencilla pgina
HTML:
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusrnod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, gue
nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit es se cillum dolore eu
fugiat nulla pariatur. Excepteur sint~occaecat
cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.</p>
cdiv class="controls">
<input type="button" value="Slide
and fade out
id= out
1>

.'

ll

11

11

<input type="button1! value="Slide and fade in id=l1 in"


<input type=nbutton" value="Togglen
id="toggle" />
<!div>
<!body>
l1

/>

Nuestro script simplemente invocar nuestros nuevos mtodos cuando se hace die
en los botones:
$ (document) .ready(function()
{
$ (/#out!) .click (function () {
$(!p!) .slideFadeOut(!slow!)
return false;
}) ;

$(!#in!) .click(function()
{
$(!p!) .slideFadeln(!slow!);
return false;

})

Ahora hemos visto varios ejemplos de mtodos de plug-n, algunos de los cules toman
parmetros explcitos, y otros no. Como hemos explorado, la palabra dave this siempre
se encuentra disponible para proporcionar contexto para el mtodo, pero tambin podemos proporcionar informacin adicional para influir en la operacin del mtodo. Hasta
el momento, los parmetros han sido pocos, pero por supuesto, esta lista puede hacerse
mayor. Existen varios trucos que podemos utilizar para gestionar nuestros parmetros
de mtodo y facilitar la vida a aquellos que utilizan nuestros plug-ins.
Como nuestro ejemplo, empezaremos con un mtodo plug-in que proporciona una
sombra en un bloque de texto. Nuestra tcnica ser similar a la utilizada para el efecto
desvanecido en el rotativo de noticias del captulo 9: utilizaremos un nmero de elementos que son parcialmente transparentes, superpuestos en diferentes posiciones en
la pgina.
jQuery.fn.shadow
= function() {
return this.each(function()
{
var $originalElement
= jQuery(this);
for (var i = o; i < 5 i i++) {
$originalElement
.clone ()
.css ({
position,
!absolute!,
left, $originalElement.offset()
top' $originalElement.offset()
margin,
0,
zIndex: -1
opac t y : 0.1
})
.appendTo(!body!)
;

.left + i,
.top + i,

));

$ (!#toggle!) .click(function()
{
$(!p!) .slideFadeToggle(!slow!)
return false;

Parmetros de mtodo

}
;

));

};

});

y la animacin ocurre segn lo esperado, como se muestra en la figura 11.11.

Para cada elemento en el que se invoca este mtodo, realizamos una serie de dones
del elemento, ajustando su opacidad. Estos dones se posicionan de forma absoluta, en
distintos desplazamientos desde el elemento original.

lID

11. Desarrollar plug-ins

Aprende jQuery 1.3

Como siempre, comprobaremos nuestro plug-in utilizando algo de HTML sencillo,


como se ve en la figura 11.12.

I The quick brown fox jumps

over the lazy dogo

Figura 11.12. Probar nuestro ejemplo.

mi

Nuestro nuevo parmetro funciona segn lo anticipado, la sombra es mayor, utilizando dos veces ms trozos que antes, pero la interfaz del mtodo es menos que ideal,
como se ve en la figura 11.14.Estos tres nmeros se confunden fcilmente, y su orden
no se puede deducir lgicamente. Seria una mejora etiquetar los parmetros, en beneficio de la persona que escribe la llamada de mtodo, y cualquiera que ms tarde desee
leer e interpretarlo.

<body>

<hl>The
<!body>

quick

brown

fox jumps

over

the

1azy

I-..
--~---, I

dog.<!hl>

Por el momento, nuestro plug-in no toma parmetros, de modo que invocar el mtodo es sencillo, como se muestra en la figura 11.13.

Il\'IA'~~~lt~tl""\ttA

Figura 11.13. Invocar el mtodo.


$Idocument) .ready(functionl)
$(!hl!) .shadow();

})

Parmetros sencillos

Ahora podemos incorporar algo de flexibilidad en el mtodo plug-in. La operacin


del mtodo se basa en varios valores numricos que el usuario podra querer modificar.
Podemos convertir stos en parmetros de modo que se pueden cambiar bajo demanda.
jQuery.fn.shadow
= function(slices,
return this.each(function()
{

opacity,

zIndex)

var $origina1E1ement
= jQuery(this);
for (var i = o; i < slices; i++) {
$origina1E1ement
.c1one()
.css({
position:
!abso1ute!,
1eft: $origina1E1ement.offset()
top: $origina1E1ement.offset()
margin: o,
zIndex: zIndex,
opacity: opacity

Figura 11.14. La sombra es mayor.

Mapas d parmetro
Hemos-visto muchos ejemplos en la API jQuery de mapas que se proporcionan corno
parmetros de mtodo. sta puede ser una forma ms amigable de exponer opciones a
un usuario de plug-ins que la sencilla lista de parmetros que hemos utilizado. Un mapa
proporciona una etiqueta visual para cada parmetro, y tambin hace que el orden de
los parmetros sea irrelevante. Adems, siempre que podamos simular la API jQuery
en nuestros plug-ins. deberamos hacerlo para aumentar consistencia y por lo tanto facilidad de uso .
jQuery.fn.shadow
= function(opts)
{
return this.eachlfunction()
{
var $origina1E1ement
= jQuery(this);
fer (var i = o; i < opts.slices; i++)
$origina1E1ement
.c1one()
.css({
position:
!absolute!,
1eft: $origina1E1ement.offset()
top: $origina1E1ement.offset()
margin: o,
zIndex: opts.zlndex,
opacity: opts.opacity

.1eft + i,
.top + i,

})

.1eft + i,
.top + i,

.appendTol!body!);

}
j) ;

};

})
.appendTo(!body!);

}
});

};

Ahora, cuando invocamos nuestro mtodo, debemos proporcionar estos tres valores:
$ (document) .ready (function 1) {
$ I!hl!) .shadow(lO,
0.1, -1);
j);

Todo lo que hemos cambiado para permitir nuestra nueva interfaz es la forma en que
se referencia cada parmetro; en lugar de tener un nombre de variable aparte, se accede
a cada valor como una propiedad del argumento opts a la funcin.
Invocar este mtodo ahora requiere un mapa de valores en lugar de tres nmeros
individuales (vase figura 11.15).
$ (document) .ready(functionl)
$(!hl!) .shadow({
slices: 5,

'ifr~fr~i'

ID

Aprende jQuery 1.3

11. Desarrollar plug-ins

Ilb~cty'~1$b..r,o~tQX.tw.n~

opac t y . 0.25,
zIndex: -1

))

q1(el1 ~Q

l~

DI

~-QQ-.I

Figura 11.16. Uso de valores predeterminados.

Seguimos invocando nuestro mtodo utilizando un mapa, pero ahora podemos especificar solamente los parmetros que queremos que difieran de sus predeterminados:

La finalidad de cada parmetro es ahora obvia por un rpido vistazo a la llamada


de mtodo.

1- .

$ (document) .ready(function()
$(/h1/) .shadow({
opac i ty . 0.05
)) ;
)) ;

. 1

Figura 11,15, Utilizar mapa de valores.

Los parmetros no especificados utilizan sus valores predeterminados. El mtodo


() acepta incluso valores null, por lo que si los parmetros predeterminados son todos aceptables, nuestro mtodo se puede invocar de forma muy sencilla sin
errores:

Valores de parmetro predeterminados

$. extend

A medida que crece el nmero de parmetros para un mtodo, se hace menos probable que siempre deseemos especificar cada uno. Un conjunto razonable de valores
predeterminados puede hacer que una interfaz de plug-in sea ms utilizable.
Afortunadamente, utilizar un mapa para nuestros parmetros ayuda con esta tarea
tambin; es sencillo omitir cualquier elemento del mapa y reemplazarlo con un predeterminado.
jQuery.fn.shadow
= function(options)
var defaults = {
s L ices : 5,
opacity:
0.1,
zIndex: -1
};
var apta = jQuery.extend(defaults,
options);
return this.each(function()
(
var $originalElement
= jQuery(this);
for (var i = O; i < opts.slices i++)
$originlElement
.clone()
.css({
position:
/absolute/,
left: $originalElement.offset()
.left + i,
topo $originalElement.offset()
.top + i,
margin: O,
zIndex: opts.zIndex,
opacity:
opts.opacity
))
.appendTo(/body/);
)
)) ;

$ (document) .ready(function()
$(/h1/) .shadow();
)) ;

Funciones de rellamada
Por supuesto, algunos parmetros de mtodo pueden ser algo ms complicados que
un sencillo valor numrico. Un tipo de parmetro comn que hemos visto frecuentemente a lo largo de la API jQuery es la funcin de rellamada. Las funciones de rellamada
pueden llevar gran cantidad de flexibilidad a un plug-in sin requerir una gran cantidad
de preparacin cuando creamos el plug-in.
Para emplear una funcin de rellamada en nuestro mtodo, necesitamos simplemente
aceptar el objeto funcin como un parmetro e invocar esa funcin donde sea apropiado en nuestra implementacin de mtodo. Como ejemplo, podemos ampliar nuestro
mtodo de sombra de texto para permitir que el usuario personalice la posicin de la
sombra relativa al texto.

. I

jQuery.fn.shadow
= function(options)
var'defaults
= {
slices: 5,
opacity:
0.1,
z fndex . -1,
sliceOffset:
function(i}
return {x: i, y: i};

);

);
var

Aqu, hemos definido un nuevo mapa, denominado defaults,


dentro de nuestra
definicin de mtodo. La funcin de utilidad $ . extend () nos permite tomar el mapa
options facilitado como un argumento y utilizarlo para anular los elementos en defaults, dejando los elementos omitidos solos, como muestra la figura 11.16.

return this.each(function()
(
var $originalElement
= jQuery(this)
;
tor (var i = Di i < opts.slices; i++)
var offset ='opts,sliceOffset(i);

opts

= jQuery. extend (defaults,

options);

mi

Aprende jQuery 1.3

11. Desarrollarplug-ins

personalizar estos predeterminados podra reducir significativamente la cantidad de


cdigo que se'tiene que escribir .
Para hacer que los predeterminados sean personalizables, necesitamos moverlos
fuera de nuestra definicin de mtodo y hacia una ubicacin que es accesible por cdigo de fuera:

$originalElement
.elone ()
.ess ({
position:
/absolute/,
left: $originalElement.offset().left
+ offset.x,
top: $originalElement.offset()
.top
+ offset.y,
margin: O,
zIndex: opts.zlndex,
opaeity: opts.opaeity

jQuery.fn.shadow
= funetion(options)
{
var opts = jQuery.extend({},
jQuery.fn.shadow.defaults,
options);

,..

})
.appendTo(/body/)

return this.eaeh(funetion()
(
var $originalElement
= jQuery(this);
for (var i = o; i < opts.slices; i++)
var offset = opts.slieeOffset(i);
$originalElement
.elone()
.ess({
position:
/absolute/,
left: $originalElement.offset()
topo $originalElement.offset()
margin: O,
zIndex: opts.zlndex,
opaeity:
opts.opaeity

}
})

};

Cada tramo de sombra tiene un desplazamiento diferente desde el texto original.


Antes, este desplazamiento ha sido simplemente igual al ndice del tramo. Ahora, sin
embargo, estamos calculando el desplazamiento utilizando la funcin s li c;eOf f s e t ( ) ,
que es un parmetro que el usuario puede anular. Por lo tanto, por ejemplo, podramos
proporcionar valores negativos para el desplazamiento en ambas dimensiones:
$ (doeum ent) .ready(funetion()
(
$(/hl/) .shadow({
slieeOffset:
funetion(i)
{
return {x: -i, y: -2*i};

lID

.left + offset.x,
.top + offset.y,

})
.appendTo(/body/);

}
})

};

});

})

Esto har que la sombra se site hacia arriba y a la izquierda, como muestra la figura
11.17, en lugar de hacia abajo y a la derecha.

Figura 11,17. Utilizar valores negativos.

La rellamada permite modificaciones sencillas en la direccin de la sombra, o posicionamiento mucho ms sofisticado si el usuario del plug-in proporciona la rellamada
apropiada. Si la rellamada no se especifica, entonces el comportamiento predeterminado
se utiliza una vez ms.

Predeterminados personalizables
Podemos mejorar la experiencia de utilizar nuestros plug-ins al proporcionar valores
predeterminados razonables para nuestros parmetros de mtodo, como hemos visto.
Sin embargo, algunas veces puede ser difcil predecir que ser un valor predeterminado
razonable. Si un script invocara nuestro plug-n mltiples veces con un conjunto diferente de parmetros que hemos establecido como predeterminados, la posibilidad de

jQuery.fn.shadow.defaults
elices: 5,
opacity: 0.1,
zIndex: -1,
sliceOffset: function(i)
return {x: i, y: i};
};

Los predeterminados estn ahora en el espacio de nombre del plug-in de sombra, y


se pueden hacer referencia directamente con $ . f n . shadow . de f a u 1t s. Nuestra llamada a $ . extend () tena que cambiar para dar cabida a esto tambin. Puesto que ahora
estamos reutilizando el mismo mapa defaul ts para cada llamada a . shadow (), no
podemos permitir que $ . extend () lo modifique. En su lugar, proporcionamos un
mapa vaco () como el primer argumento a s , extend (), y es este nuevo objeto el que
se modifica.
Ahora el cdigo que utiliza nuestro plug-in puede cambiar los predeterminados que
utilizarn todas las siguientes llamadas a . shadow (). Las opciones tambin se pueden
proporcionar al mismo tiempo que se invoca el mtodo.
$ (doeument) .ready(function()
$.fn.shadow.defaults.sliees
$(/hl/) .shadow({

10;

lmI

11. Desarrollarplug-ins

Aprende jQuery 1.3

sliceOffset:
function(i)
return {x: -i, y: i};
}

})

return
cas~ />/:
return

va1ue

>= parselnt(parts[3]);

va1ue

> parselnt(parts[3]

I;

}
})

Este script crear una sombra con 10 tramos, porque ste es el nuevo valor predeterminado, pero tambin situar sombra a la izquierda y hacia abajo, debido a la rellamada sliceOffset
que se proporciona junto con la llamada de mtodo, como se ve
en la figura 11.18.
/

I"~"""-I

Figura 11.18. Utilizar el valor predeterminado

Las partes incorporadas de jQuery se pueden ampliar tambin. En lugar de aadir


nuevos mtodos, podemos personalizar los existentes. Un deseo comn, por ejemplo, es
ampliar las expresiones de selector proporcionadas por jQuery para proporcionar ms
opciones esotricas.
El tipo ms sencillo de expresin de selector a aadir es una pseudo-clase; stas son
las expresiones que empiezan con dos puntos, como: checked o :nth - chi Id ( ) . Para
ilustrar el proceso de crear una expresin de selector, crearemos una pseudo-clase denominada : css (). Este nuevo selector nos permitir localizar elementos basndonos
en los valores numricos de sus atributos CSS.
Cuando utilizamos una expresin de selector para encontrar elementos, jQuery
busca instrucciones en un mapa interno denominado expr. Este mapa contiene cdigo
JavaScript a ejecutar sobre un elemento, haciendo que el elemento se encuentre contenido en el conjunto resultado si el cdigo evala en true. Podemos aadir nuevas expresiones a este mapa utilizando la funcin $ . extend ( ) .
."

var

va1ue

= parseF1oat(jQuery(e1ement)

switch
(parts[2])
case /</:

set)

return va1ue
case /<=/:

< parselnt(parts[3]);

return va1ue
case /=/:
case /==/:
return va1ue
case />=/:

<= parselnt

(parts [3] I ;

== parselnt(parts[3]);

.css (parts [1] 11;

Este cdigo le dice a jQuery que css es una cadena vlida que puede seguir a dos
puntos en una expresin de selector, y que cuando se encuentra, la funcin dada se debera invocar para determinar si el elemento se debera incluir en el conjunto resultado.
Se pasan cuatro parmetros a la funcin que se evala aqu:

el ement: El elemento DOM bajo consideracin. Es necesario para la mayora de


selectores.

index: El ndice del elemento DOM dentro del conjunto resultado. Esto es de
utilidad para selectores como: eq () y : I t ( ) .

matches: Una tabla que contiene el resultado de la expresin regular que se


ha utilizado para analizar este selector. Tpicamente, matches [3] es el nico
elemento relevante en la tabla; en un selector de la forma: a (b), el elemento
matches [3] contiene b, el texto dentro de los parntesis.

set: El conjunto entero de elementos DOM que ha coincidido hasta este punto.
Este parmetro no suele ser necesario.

en la sombra.

Aadir una expresin de selector

jQuery.extend(jQuery.expr[/:/],
(
/css/: function(e1ement,
index, matches,
var parts = /([\W-]+)\s*([<>=l+)\s*(\d+)/
.exec(matches[3])
;

Los selectores de pseudo-clase necesitan utilizar la informacin contenida en estos


cuatro argumentos para determinar si el elemento pertenece o no al conjunto resultado.
En este caso, eIement y matches es todo lo que necesitamos.
En nuestra funcin selector, primero desglosamos el selector en partes que se pueden utilizar con una expresin regular. Queremos un selector como: css (width <
200) para devolver todos los elementos con un width de menos de 200. Por lo tanto
necesitamos examinar el texto dentro de los parntesis para recuperar el nombre de la
propiedad (w .dt.h), operador de comparacin (e), y valor con el que comparar (200).
La expresin regular / ( [\ w-] +) \ s * ( [<>=] +) \ s * (\ d-s ) / realiza esta bsqueda, situando estas tres partes de la cadena en la tabla parts para nuestro uso.
A continuacin, necesitamos ir a buscar el valor actual de la propiedad. Podemos
utilizar el mtodo. css () de jQuery para devolver el valor de la propiedad que se ha
nombrado en el selector. Puesto que esta propiedad se devuelve como una cadena, utilizamos parseFIoat
() para convertirlo en nmero. Por ltimo, realizamos la comparacin.
Una sentencia swi tch determina qu tipo de comparacin se realiza dependiendo del
contenido del selector, y se devuelve el resultado de la comparacin (true o false).
Ahora tenemos una nueva expresin de selector que podemos utilizar en cualquier
lado en nuestro cdigo jQuery. Un sencillo documento HTML puede demostrar esto,
como se ve en la figura 11.19.
<body>
<div>Deserunt mollit anim id est laborum</div>
<div>Ullamco</div>
<div>Ut enim ad minim veniam laboris</div>

"EJ'"

lIImI

11. Desarrollar plug-ins

Aprende jQuery 1.3

<div>Quis nostrud exercitation


<div>ut aliquip</div>

consequat

nisi</div>

su cdigo. Antes de esto, sin embargo, deberamos aseguramos de que el plug-in est
preparado par;!el pblico.
Existen algunas reglas a seguir al escribir plug-ins para que funcione bien con otro
cdigo. Ya hemos tratado algunas de ellas, pero las recopilamos aqu por comodidad.

<div>Cornmodo</div>
<div>Lorem

ipsum

dolor

sit

amet

ex

l1mI

ea</div>

</body>

Convenciones de nombrado
1~~~,~g,i~~~~.~~J
h ..~ .." ,

[~;=j~~~'~~

~~~~

I~J
~!~~~~,t~~~.~,~!
Figura 11.19. Documento HTML.
"

Todos los archivos de plug-in se deberan nombrar jQuery. myPlugin. j s donde.


, myPlugin es el nombre del plug-in. Dentro del archivo, todas las funciones globales se
l deberan agrupar en un objeto denominado j Query .myPl ugin, a menos que haya solamente uno, en cuyo caso puede ser una funcin denominada j Query . myPl ugin ( ) .
Los nombres de mtodo son ms flexibles, pero se deberan mantener tan nicos
_ como sea posible. Si solamente se define un mtodo, se debera denominar j Query .
fn. myPl ugin () . Si se define ms de uno, intente prefijar cada nombre de mtodo con
el nombre del plug-in para impedir confusin. Evite nombres cortos y ambiguos como
. load () o . get () que se pueden confundir con mtodos definidos en otros plugins.

Con nuestro nuevo selector, se hace trivial resaltar los elementos ms pequeos en
esta lista, como muestra la figura 11.20.

--

[il~~I.f~~J"E~_~;1

~;-;~~~~~~~:I
&~~~"'~~lij

II'J,~,~~!N~_~~~*~I

Uso del' alias $


Los plug-ins jQuery pueden no asumir que el alias $ se encuentra disponible. En su
lugar, se debe escribir el nombre j Query completo cada vez.
En plug-ins ms extensos, muchos desarrolladores encuentran que la ausencia del
mtodo abreviado $ hace que el cdigo sea ms difcil de leer. Para combatir esto, el
mtodo abreviado se puede definir localmente para el mbito de aplicacin del plug-in
al definir y ejecutar una funcin. La sintaxis para definir y ejecutar una funcin a la vez
se parece a esto:
(function($)
// Cdigo
}) (jQuery) ;

(
va aqui

Figura 11.20. Utilizar el nuevo selector.


$ (document)

.ready(function()

$ (/div:css(width

})

< 1001/) .addClass(/highlight/);

Compartir un plug-in con el mundo


Una vez completo un plug-in, podemos querer publicado de modo que otros puedan
beneficiarse, y posiblemente mejorar, el cdigo. Podemos hacer esto en el repositorio
de plug-ns jQuery oficial en http://plugins.jquery
. com/. Aqu podemos registramos, y seguir las instrucciones para describir el plug-in y subir un archivo. zip de

La funcin toma un solo parmetro, al que pasamos el objeto global jQuery. El parmetro se nombra $, por lo que dentro de la funcin podemos utilizar el alias $ sin
conflictos.

Interfaces de mtodo
Todos los mtodos jQuery se invocan dentro del contexto de un objeto jQuery, de
modo que thi s hace referencia a un objeto que puede hacer referencia a uno o ms elementos DOM. Todos los mtodos deben comportarse correctamente con independencia
del nmero de elementos coincidentes. En general, los mtodos deberan invocar thi s .
each () para pasar por los elementos coincidentes, operando sobre cada uno en turno.

mi

11. Desarrollar plug-ins

Los mtodos deberan devolver el objeto jQuery para preservar encadenamiento. Si


el conjunto de objetos coincidentes se modifica, se debera crear un nuevo objeto al invocar . pushSt.ack () y se debera devolver este objeto en su lugar. Si se devuelve alguna
cosa diferente, se debe documentar de forma perceptible.
Si los mtodos toman varias opciones, es preferible utilizar un mapa como argumento de modo que las opciones se etiqueten y se puedan especificar en cualquier orden.
Los valores predeterminados se deberan definir en un mapa que se puede anular si es
necesario.
Las definiciones de mtodo deben terminar en un punto y coma (;) de modo que los
compresores de cdigo puedan analizar adecuadamente los archivos. Adems, los plugins pueden empezar con un punto y coma, de modo que otros scripts mal codificados
no causen conflictos despus de la compresin.

Estilo de la documentacin
La documentacin archivada se debera anexar delante de cada definicin de
funcin o mtodo en formato ScriptDoc. Este formato se documenta en :tp: //www.
scriptdoc.org/.

Resumen
En este ltimo captulo, hemos visto cmo la funcionalidad que proporciona jQuery
no necesita limitar las posibilidades de uso de la librera. Los plug-ins que se encuentran
disponibles amplan el men de caractersticas substancialmente, y podemos fcilmente
crear el nuestro propio que ampla an ms los lmites.
Los plug-ins que hemos creado contienen varias caractersticas, incluidas funciones
globales que utilizan la librera jQuery, nuevos mtodos del objeto jQuery para actuar
sobre elementos DOM, mtodos ampliables que se pueden personalizar fcilmente, y
expresiones de selector mejoradas para encontrar elementos DOM en nuevas maneras.
Con estas herramientas a nuestra disposicin, podemos configurar jQuery, y nuestro
propio cdigo JavaScript, en la forma que queramos.

l'

f>W
I
I

,,

,..

Apndice A
Recursos online

Los siguientes recursos representan un punto de partida para aprender ms sobre


jQuery, JavaScript, y desarrollo Web en general, ms all de lo que se trata en este libro.
Existen demasiados recursos de informacin de calidad en la Web para que este apndice
pueda llegar a ser algo parecido a una lista exhaustiva. Adems, aunque otras publicaciones impresas tambin pueden proporcionar informacin valiosa, no se sealan aqu.

Documentacin jQuery
Estos recursos ofrecen referencias y detalles sobre la librera jQuery.

Wiki jQuery
La documentacin en j query . com est en la forma de un wiki, lo que significa que
el contenido es editable por el pblico. El sitio incluye la API jQuery, tutoriales, guas
de inicio y mucho ms:
http://docs.jquery.com/

API jQuery
Adems de la documentacin oficial en j query . com, la API est disponible en la
siguiente ubicacin:
http://remysharp.com/jquery-api/

mi

1"

Apndice A. Recursos online

Navegador de la API jQuery


Iorn Zaeferrer ha creado un navegador con vista en rbol de la API jQuery con una
caracterstica de bsqueda y ordenacin alfabtica o por categoras:
http://jquery.bassistance.de/api-browser-l.2/

Aprende jQuery 1.3

liD

Referencia JScript MSDN


La referencia JScript MSDN proporciona descripciones de todo el conjunto de funciones, objetos, etc. Es especialmente de utilidad para entender la implementacin de
Microsoft del estndar ECMAScript en Internet Explorer:
http://msdn.microsoft.com/en-us/library/x85xXsf4(VS.71)

.aspx

jQuery visual
Este navegador de API diseado por Yehuda Katz, y actualizado por Remy Sharp,
es tanto bonito como apropiado. Tambin proporciona visualizacin rpida de mtodos
para un nmero de plug-ins jQuery:
http://www.visualjquery.com/

/ Quirksmode
El sitio Quirksmode de Peter-Paul Koch es un extraordinario recurso para entender las
diferencias en la forma en que los navegadores implementan varias funciones JavaScript,
as como muchas propiedades CSS:
http://www.qirksmode.org/

Visor jQueryAPI Adobe AIR


Remy Sharp ha incluido la API jQuery en una aplicacin Adobe AIR para visualizacin cuando se est desconectado:
http://remysharp.com/downloads/jquery-api-browser.air.zip

Referencia JavaScript
Estos sitios ofrecen referencias y guas a JavaScript como lenguaje en general, en lugar
de jQuery en particular.

Centro de desarrollo Mozilla


Este sitio tiene una exhaustiva referencia JavaScript, una gua para programar con
JavaScript, vnculos a herramientas de utilidad, y mucho ms:
http://developer.mozilla.org/en/docs/JavaScript/

Dev.opera
Aunque centrado principalmente en su propia plataforma de navegador, el sitio Opera
para desarrolladores Web incluye una serie de artculos de utilidad sobre JavaScript:
http://dev.opera.com/articles/

JavaScript Toolbox
JavaScript Too1boxde Matt Kruse ofrece una gran variedad de libreras JavaScript, as
como consejo sobre mejores prcticas JavaScript y una coleccin de recursos JavaScript
examinados en otra parte en la Web:
http://www.javascripttoolbox.com/

Compresores

de cdigo JavaScript

Cuando se dan los ltimos toques a un sitio, a menudo es aconsejable comprimir el


cdigo JavaScript. Este proceso reduce el tiempo de descarga para todos los usuarios
del sitio.

Compresor YUI
Este compresor JavaScript de la librera de interfaz de usuario Yahoo! (Yahoo! UI
Library) se utiliza para reducir el tamao del cdigo fuente jQuery. La herramienta de
lnea de comando basada en [ava es una descarga gratuita, El cdigo resultante es muy
eficiente en tamao de archivo y rendimiento, y se puede reducir an ms con compresin Gzip si se desea:
http://developer.yahoo.com/yui/compressor/

E&lI

Apndice A. Recursos online

Aprende jQuery 1.3

JSMin

la chuleta CSS de Mezzoblue

Creado por Douglas Crockford, JSMin es un filtro que elimina comentarios y espacio
en blanco innecesario de archivos JavaScript. Normalmente reduce el tamao de archivo
a la mitad, resultando en descargas ms rpidas, especialmente cuando se combina con
compresin de archivo basada en servidor:

Dave Shea proporciona esta chuleta CSS de utilidad en un intento por hacer que el
proceso de diseo sea ms sencillo, y proporciona una referencia rpida a comprobar
cuando encuentra problemas:
http://mezzoblue.com/css/cribsheet/

http://www.crockford.com/javascript/jsmin.html

Pretty printer
Esta herramienta embellece JavaScript que se ha comprimido, restaurando los saltos
de lnea y sangrando donde es posible. Proporciona una serie de opciones para adaptar
los resultados:

ID

. Position is everything
Este sitio incluye un catlogo de errores de navegador en CSS junto con explicaciones de cmo soluconarlos:
http://www.positioniseverything.net/

http://www.prettyprinter.de/

Referencia (X)HTML
La librera jQuery se encuentra en su mejor momento cuando trabaja con documentos 'o,
semnticos HTML y XHTML, con forma to apropiado. El recurso a continuacin proporciona asistencia con estos lenguajes de marcacin.

Pgina principal de W3C


El World Wide Web Consortium (W3C) establece el estndar para (X)HTML, y la
pgina principal HTML es un estupendo punto de lanzamiento para sus especificaciones y directrices:

Blogs de utilidad
Nuevas tcnicas y caractersticas se estn desarrollando e incorporando continuamente
para cualquier tecnologa viva. Mantenerse al tanto de las innovaciones puede ser fcil
al comprobar estas fuentes de noticias de desarrollo Web de vez en cuando.

El blog jQuery
[ohn Resig y otros colaboradores en el blog jQuery oficial publican anuncios sobre
nuevas versiones y otras iniciativas entre el equipo del proyecto, as como tutoriales y
otros datos.
http://jquery.com/blog/

http://www.w3.org/MarkUp/

Referencia CSS
Los efectos y animaciones que hemos visto una y otra vez se basan en el potencial
de las hojas de estilo en cascada. Para incorporar los detalles visuales que deseamos en
nuestros sitios, podemos necesitar recurrir a estos recursos CSS para orientacin.

learning jQuery
Karl Swedberg dirige este blog para tutoriales, tcnicas y anuncios jQuery. Autores
invitados incluyen miembros del equipo jQuery como Mike Alsup y Brandon Aaron:
http://www.learningjquery.com/

Pgina principal CSS de W3C

Ajaxian

La pgina principal CSS de W3C proporciona vnculos a tutoriales, especificaciones,


suites de prueba, y otros recursos:

Este blog actualizado con frecuencia iniciado por Dion Almaer y Ben Galbraith
proporciona una tremenda cantidad de noticias y caractersticas, y el tutorial sobre
JavaScript:

http://www.w3.org/Style/cSS/

http://ajaxian.com/

lIiI

Aprende jQuery 1.3

Apndice A. Recursos online

[ohn Resig

lIiiI

DOM scripting
El blog de jeremy Keith empieza donde lo deja el popular libro de programacin
DOM, un recurso fantstico para JavaScript sencillo:

El creador de jQuery, [ohn Resig, trata temas JavaScript avanzados en su blog:


http://ejohn.org/

http://domscripting.com/blog/

JavaScript ant
Este sitio contiene un repositorio de artculos relacionados con JavaScripty su uso en
navegadores Web modernos, as como una lista organizada de recursos JavaScript:
http://javascriptant.com/

Robert ' S talk


Robert Nyman escribe acerca de desarrollar para Internet, especialmente programacin del lado del cliente:

http://www.robertnyrnan.com/

As days pass by
l'

Stuart Langridge experimenta con uso avanzado del DOM del navegador:
http://www.kryogenix.org/code/browser/

A list apart
A List Apart explora el diseo, desarrollo y significado de contenido Web, con un
foco especial en estndares Web y mejores prcticas:
http://www.alistapart.com/

Estndares Web con imaginacin


Elblog de Dustin Daz contiene artculos sobre diseo y desarrollo Weben JavaScript:
http://www.dustindiaz.com/

Snook
El blog de programacin/ desarrollo Web de [onathan Snook:
http://snook.ca/

Marcos de trabajo de desarrollo Web


utilizando jQuery
A medida que los desarrolladores de proyectos de cdigo abierto son conscientes de
: jQuery, muchos estn incorporando la librera JavaScript en sus propios sistemas. Lo
siguiente es una lista abreviada de estos seguidores:

Digitalus

Site Manager: http://code.google.com/p/digitalus-si

manager/

Recurso JavaScript de Matt Snider

Drupal: http://drupal.

Elblog de Matt Snider est dedicado a comprender JavaScripty sus marcos de trabajo:

DutchPIPE: http://dutchpipe

http://mattsnider.com/

Hpricot: http://code.whytheluckystiff

JobberBase: http://www.jobberbase.com/

Laconica: http://laconi

Piwik:http://piwik.org/

Pornrno: http://pommo

symfony:http://www.syrnfony-project.org/

SPIP:http://www.spip.net/

lean "t
Tres sitios de Christian Heilmann proporcionan entradas de blog, cdigo de muestra
y extensos artculos relacionados con JavaScript y desarrollo Web:
http://icant.co.uk/
http://www.wait-till-i.com/
http://www.onlinetools.org/

org/
.org/

. cal

. org/

. net/hpricot/

te-

ElI!I

Apndice A. Recursos online

Textpattem:

Trac:http://trac.edgewall.org/

WordPress: http://wordpress

Z-Blog:http://www.rainbowsoft.org/zblog

http://www.textpattern.com/

.org/
.

Para una lista completa, visite la pgina Sites Using jQuery en: http://docs

jquery.com/Sites_Using_jQuery.
/

'

r'

,,

'

pndice B
Herramientas
de desarrollo

La documentacin puede ayudar en temas de solucin de problemas con nuestras


aplicaciones JavaScript, pero no hay sustituto para un buen conjunto de herramientas
de desarrollo de software. Afortunadamente, existen muchos paquetes de software disponibles para inspeccionar y depurar cdigo JavaScript, y la mayora de ellos estn disponibles de forma gratuita.

Herramientas para Firefox


Mozilla Firefox es el navegador de eleccin para la mayor parte de los desarrolladores Web, y por lo tanto tenemos algunas de las herramientas de desarrollo ms amplas
y bien consideradas.

firebug
La extensin Firebug para Firefox es indispensable para desarrollo jQuery:
http://www.getfirebug.com/
Algunas de las caractersticas de Prebug son:

<,

Un excelente inspector DOM para encontrar nombres y selectores para partes del
documento.

'r'!

mi

Apndice B. Herramientas

Aprende jQuery 1.3

de desarrollo

Herramientas de manipulacin CSS para averiguar por qu una pgina tiene un


determinado aspecto y cambiarlo.

E1I

y modificar en el momento con nuevas reglas CSS. Tambin proporciona otras ayudas
variadas de desarrollo, como una regla para medir elementos de pgina:
.

Una consola JavaScript interactiva.

http://w..{w.microsoft.com/downloads/details.aspx?FamilyID=
e59c3964'- 672d-4511-bb3e-2d5eldb91038

Un depurador JavaScript que puede observar variables y seguir la ejecucin de


cdigo.

Mierosoft Visual Web Developer


Barra de herramientas de desarrollador Web

El paquete Visual Studio de Microsoft se puede utilizar para inspeccionar y depurar


,cdigo JavaScript:

Esto no solamente solapa Firebug en el mbito de inspeccin DOM, sino que tambin
contiene herramientas para tareas comunes como manipulacin de cookie, inspeccin
.de formulario, y cambio de tamao de pgina. Tambin puede utilizar esta barra para
desactivar rpida y fcilmente JavaScript para un sitio para asegurarse de que la funcionalidad se degrada bien cuando el navegador del usuario es menos compatible:
http://chrispederick.com/wark/web-developer/

http://msdn.microsoft.com/vstudio/express/vwd/

Para ejecutar el depurador de forma interactiva en la versin gratuita (Visual Web


Developer Express), siga el proceso detallado aqu:
http://www.berniecode.com/blog/2007/03/08/how-to-debugjavascriptwith-visual-web-developer-express/

"

Venkman
Venkman es el depurador JavaScript oficial para el proyecto Mozilla. Proporciona
un entorno de solucin de problemas que es una reminiscencia del sistema GDB para
programas de depuracin que se escriben en otros lenguajes.
http://www.mozilla.org/projects/venkman/

Comprobador de expresiones regulares


Las expresiones regulares para hacer coincidir cadenas en JavaScript son difciles de
disear. Esta extensin para Firefox permite experimentacin sencilla con expresiones
regulares utilizando una interfaz para incorporar texto de bsqueda:

DebugBar
Proporciona un inspector DOM as como una consola JavaScript para depurar:
http://www.debugbar.com/

Drip
Prdidas de memoria en cdigo JavaScript pueden causar problemas de rendimien, to y estabilidad para Internet Explorer. Drip ayuda a detectar y aislar estos problemas
de memoria:
http://Sourceforge.net/projects/ieleak/

Para aprender ms sobre las prdidas de memoria Explorer, consulte el apndice C.

http://sebastianzartner.ath.cx/new/downloads/RExT/

Herramientas para Safari


Herramientas para Internet Explorer
Los sitios a menudo se comportan de forma diferente en lE que en otros navegadores
Web, por lo que tener herramientas de depuracin par~ esta plataforma es importante.

Safari contina siendo el recin llegado como plataforma de desarrollo, pero todava
existen herramientas disponibles para situaciones en las que el cdigo se comporta de
forma diferente en este navegador frente a otros lugares.

Men Develop
Microsoft Internet Explorer Developer Toolbar
La barra de herramientas de des arrollador proporciona principalmente una vista
del rbol DOM para una pgina Web. Los elementos se pueden localizar visualmente,

En Safari 3.1, una opcin en la pestaa de opciones avanzadas del men Preferences
(Preferencias) proporciona un men especial denominado Develop (Desarrollo). Con este
men activado, se encuentran disponibles un Inspector Web y Consola JavaScript.

lID

Aprende jQuery 1.3

Apndice B. Herramientas de desarrollo

Inspector Web
Safari 3 incluye la posibilidad de inspeccionar elementos de pgina individuales
recopilar informacin especialmente sobre las reglas CSS que se aplican a cada una.

lID

en su DOM e inspeccin de objeto, aunque tambin dispone de una buena consola. La


consola y el inspector se pueden invocar al incluir una referencia al archivo JavaSript
Nitobi y llamar a ni tobi . Debug . log ( ) .
r

http://www.nitobibug.com/

http://trac.webkit.org/wiki/web%20Inspector
Desarrollos actuales de WebKit han mejorado sustancialmente esta herramienta de
inspector Web, concediendo muchas de las excelentes caractersticas de Firebug como
un depurador JavaScript integrado denominado Drosera.
http://trac.webkit.org/wiki/Drosera

Herramientas para Opera

Paquete TextMate jQuery


Esta extensin para el popular editor de texto Mac OS X TextMate permite resaltar
"sintaxis para mtodos y selectores jQuery, completar cdigo para mtodos y una referencia API rpida desde su cdigo. El paquete tambin es compatible con el editor de
texto E para Windows:
http://github.com/kswedberg/jquery-tmbundle/

Aunque tiene una cuota de mercado limitada como navegador de escritorio, Opera
desempea un papel importante en sistemas incorporados y dispositivos mviles, y sus
posibilidades de uso se deberan considerar cuidadosamente en el desarrollo Web.

Charles

Dragonfly

Cuando se desarrollan aplicaciones intensivas en AJAX, puede ser de utilidad ver


exactamente qu datos se envan entre el navegador y el servidor. El proxy de depuracin Web Charles muestra todo el trfico HTTP entre dos puntos, incluidas peticiones
Web normales, trfico HTTPS, y respuestas AJAX:

Aunque todava en sus primeras etapas, Dragonfly es un prometedor entorno de depuracin para navegadores Opera en ordenadores y dispositivos mviles. El conjunto
de caractersticas de Dragonfly es similar al de Firebug, incluida depuracin JavaScript,
as como inspeccin y edicin CSS y DOM.

Otras herramientas
Aunque las herramientas anteriores se centran en un navegador
lidades tienen un mbito de aplicacin ms amplio.

especfico, estas uti-

Firebug Lite
Aunque la extensin Firebug est limitada al navegador Web Firefox. algunas de las
caractersticas se pueden replicar al incluir el script FrebugLite en la pgina Web. Este
paquete simula la consola Firebug, incluido permitir llamadas a console
.log () para
funcionar en todos los navegadores y no lanzar errores JavaScript:
.
http://www.getfirebug.com/lite.html

NitobiBug
Como Firebug Lite, NitobiBug es una herramienta multiplataforma que trata algunas
de las mismas cosas que el ms robusto y refinado Firebug. Su fortaleza se encuentra

http://www.xk72.com/charles/

Fiddler
Fiddler es otro proxy de depuracin HTTP de utilidad con caractersticas similares a
las de Charles. Segn su sitio, Fiddler "incluye un potente subsistema de script basado
en eventos, y se puede ampliar utilizando cualquier lenguaje .NET":
http://www.fiddlertool.com/fiddler/

Aptana
Este IDE (Integrated Development Environment o Entorno de desarrollo integrado) de
desarrollo Web basado en Java es gratuito y multiplataforma. Junto con las caractersticas
de edicin de cdigo estndar y avanzadas, incorpora una copia completa de la documentacin API jQuery, y tiene su propio depurador JavaScript basado en Firebug.
http://www.aptana.com/

"'0 \ ~

li.I

~
!l3

"""

):!\

/;.~

.
L.~

.~..
..
..~

@'

",
~

~
.')

15@).

-,
'.1
,~

~;
__ .
. 7$\'~'
\~

_-~

r'"'\

-@

'~,

~\

,f,1),.,/
~_~.

'""..- ...."

'~

\
~;{"~

,",

"i'i',

0.'

'.

....

1@"

,~

t@1'~

, .... ~"'"
:'.-'::'

, ~..
,

@)

:")

- \!J '"
,..-,.
~, ~',o:~'
'..
/
i\
~-._'
~:.,'"
,c"l'-~~~'
-~0\"
\
'@'i.
. ~'-...--..
O
'~

()

'\'4;

,/
.-,:'

l'

".

15'.
'

"<!I,

.".

~,"~\

\.~

.~ ';':'~,-'''''~i;-

fr -',
e
o
,~,

.'~,'
' /@J ?~ l~,:~

'~

"~

iWt

\ ,""

13"

f;.

'~

..

'\

.
(@';,

\"'~--'--.

.'

Apndice e
JavaScript
Closures

En este libro hemos visto muchos mtodos jQuery que toman funciones como parmetros. Nuestros ejemplos han creado, invocado y pasado funciones una y otra vez.
Aunque podemos hacer esto con solamente un conocimiento somero de la mecnica
interna JavaScript, a veces los efectos secundarios de nuestras acciones pueden parecer
extraos si no tenemos conocimiento de las caractersticas del lenguaje. En este apndice,
estudiaremos una de las construcciones basadas en funciones ms esotricas denominada c/osures. Nuestra explicacin implicar muchos pequeos ejemplos de cdigo, con
los que queremos mostrar un conjunto de mensajes. En lugar de utilizar un mecanismo
de registro especfico de un navegador (como console. Loq() de Firefox), o crear una
serie de cuadros de dilogo alert (), utilizaremos un pequeo mtodo de plug-in:
jQuery.fn.print
= function(message)
return this.each(function()
{
$(rcdiv
class="result"
/>')
,text(String(message))
.appendTo($(this)
.find(' .results'));

})

};

Con este mtodo definido, podemos invocar $ ( '#example' ) .print


para aadir el mensaje "hello'' dentro de <di v id=" example" >.

( 'hello'

Funciones internas
J avaScript es afortunado de incluirse entre los lenguajes de programacin que sopor"
tan declaraciones de funciones internas, Muchos lenguajes de programacin tradicionales, como C, recopilan todas las funciones en un nico mbito de nivel superior. Los

lIiIiI

Aprende jQuery 1.3

Apndice C. JavaScript Closures

lenguajes con funciones internas, por otro lado, nos permiten reunir pequeas funciones
de utilidad donde son necesarias, evitando la polucin del espacio de nombres.
Una funcin interna es simplemente una funcin que se define dentro de otra funcin. Por ejemplo:
function outerFn() {
function innerFn()

funciones padre. JavaScript, por otro lado, nos permite pasar funciones como si fueran
cualquier otro tipo de datos. Esto significa que las funciones internas pueden escapar
de sus captores.
La ruta de escape puede resultar en muchas direcciones diferentes. Por ejemplo, suponga que la funcin se asigna a una variable global:
var globalVar;
function outerFn() {
,
$('#example-3
.print('Outer function
function innerFn() {
'/
$ ( #example-3 I ) . print ( 'Inner function 1) ;
1)

Aqu, innerFn () es una funcin interna, contenida dentro del mbito de outerFn (). Esto significa que una llamada a innerFn () es vlida dentro de outerFn (),
pero no fuera de ella. El siguiente cdigo resulta en un error JavaScript:

.print('innerFn(),

');

Sin embargo, podemos ejecutar con xito el cdigo al invocarinnerFn


outerFn() :

1);

globalVar

innerFn

function outerFn() {
$('#example-2') .print('Outer functiont)
function innerFn() {
$('#example-l') .print(IInner Function');
}
$('#example-l')
innerFn ();

mi

$('#example-3')
outerFn() ;
$('#example-3')
global Var ();

.'
() desde

,);

.print('globalVar(),

,);

La llamada a outerFn () despus de la definicin de la funcin modifica la variable


global global Varo Ahora es una referencia a innerFn () . Esto significa que la ltima
llamada a global Var () opera como lo hara una llamada interna a innerFn (), y se
llega a las sentencias print:
outerFn()

function outerFn() {
$('#example-2') .print('Outer function');
function innerFn() {
$(I#example-2
.print('Inner function');

.print('outerFn(),

Outer function
'globalVar ():
Inner function

1)

innerFn() ;
}
$ ('#example-2') .print('outerFn(),
outerFn() ;

');

Esto tiene este resultado:


outerFn()

Outer function
Inner function

Esta tcnica es especialmente til para pequeas funciones de una sola finalidad. Por
ejemplo, los algoritmos que son recursivos, pero tienen un envoltorio API no recursivo,
a veces se expresan mejor con una funcin interna como elemento de ayuda.

El

gran escape

La trama se complica cuando las referencias de funcin entran en juego. Algunos


lenguajes, como Pascal, permiten el uso de funciones internas para la finalidad de
ocultar cdigo solamente; esas funciones estn para siempre enterradas dentro de sus

Observe que una llamada a innerFn () desde fuera de outerFn () sigue devolviendo un error. Aunque la funcin ha escapado por medio de la referencia almacenada en
. la variable global, el nombre de la funcin sigue atrapado dentro del mbito de aplicacin de outerFn () .
Una referencia de funcin tambin puede encontrar su camino fuera de una funcin
padre por medio de un valor de retorno:
function outerFn() {
$('#example-4') .print('Outer function
function innerFn() {
$('#example-4') .print('Inner function');
l

);

return

innerFn;

}
$('#example-4') .print('var fnRef = outerFn(), ');
var fnRef = outerFn();
$('#example-4') .print (fnRef (),');
fnRef() ;

Aqu, no hay variable global modificada dentro de ou t erFn ( ) . En su lugar, ou terFn () devuelve una referencia a innerFn () . La llamada a outerFn () resulta en esta
referencia, que se almacena y se invoca en turno, activando el mensaje de nuevo:

l1iPI

Aprende jQuery 1.3

Apndice C. javaScript Closures

~nRef();
fnRef();
var fnRef2
fnRef2 ();
fnRef2() ;

var fnRef = outerFn():


Outer function
fnRef

() :

Inner funetion

Elhecho de que las funciones internas se puedan invocar por medio de una referencia
incluso despus de que la funcin est fuera de mbito, significa que JavaScript necesita mantener disponibles funciones referenciadas siempre y cuando se puedan invocar.
Cada variable que hace referencia a la funcin se registra por el tiempo de ejecucin
JavaScript, y una vez que ha desaparecido la ltima, el recolector de basura JavaScript
viene y libera un poco de memoria.

Las funciones internas pueden por supuesto tener sus propias variables, que estn
restringidas en mbito de aplicacin en la propia funcin:

1)

o{,terFn() ;

Ahora nuestra funcin incrementar la variable con cada llamada:


=

globalVar
globalVar
globalVar
globalVar

1
= 2
= 3
= 4

Pero qu pasa si la variable es local a la funcin padre? Puesto que la funcin interna hereda el mbito de aplicacin de su padre, tambin se puede hacer referencia a
esta variable:

mbito de aplicacin de variables

function outerFn() (
function innerFn()
var innerVar = Oi
innerVar++i
$('#example-5
.print('innerVar

"

function outerFn()
var outerVar = o;
function innerFn()
outerVar++
$(I#example-7
.print('outerVar
1)

return
1

1m

outerVar)

innerFn

innerVar);
v r fnRef = outerFn{);
fnRef() ;
fnRef ();
var fnRef2 = outerFn();
fnRef2 ();
fnRef2 ();
1

return

innerFn

var fnRef
fnRef() ;
fnRef();
var fnRef2
fnRef2 ();
fnRef2() ;

outerFn() ;

= out.e r Fn ()

Ahora nuestras llamadas de funcin tienen comportamiento ms interesante:

Cada vez que se invoca la funcin, por medio de una referencia u alguna otra cosa,
se crea una nueva variable innerVar, incrementada, y se muestra:
innerVar
innerVar
innerVar
innerVar

:::;
1
= 1
= 1
= 1

Las funciones internas pueden hacer referencia a variables globales en la misma forma
que cualquier otra funcin:
var globalVar
= Oi
function outerFn()
function innerFn()
globalVar++;
$('#example-6') .print('globalVar
return
var fnRef

innerFn
=

outerFn();

, + global Var) ;

outerVar
outerVar
outerVar
outerVar

= 2
=
=

1
2

Obtenemos una mezcla de los dos efectos anteriores. Las llamadas a Lrme r Pn () por
medio de cada referencia incrementan outerVar independientemente. Observe que la
segunda llamada a outerFn () no vuelve a establecer el valor de outerVar, sino que
crea una nueva instancia de outerVar, vinculada al mbito de aplicacin de la segunda
'lamada de funcin. El resultado de esto es que despus de las llamadas anteriores, otra
llamada a fnRef () imprimir el valor 3, y una llamada siguiente a fnRef2 () tambin
imprimir 3. Los dos contadores estn completamente separados. Cuando una referencia
a una funcin interna encuentra su camino fuera del mbito de aplicacin en el que se
defini la funcin, esto crea un closure en esa funcin. Llamamos a las variables que no
son ni parmetros ni locales a la funcin interna variables libres, y el entorno de la llamada d' funcin exterio' las cierra' Esenc'alment', el hecho de'que la func'n haga'refere'cia a
una variable local e' la funcin ex'erior oto'ga a la variable un aplazamiento. La memoria
no se libera cuando la funcin se completa, ya que lo sigue necesitando el closure.

li!I

Aprende jQuery 1.3

Apndice C. [auabcript Closures

1m

Interacciones entre closures

Closures en jQuery

Cuando existe ms de una funcin interna, los closures pueden tener efectos que no
son tan fciles de anticipar. Suponga que emparejamos nuestra funcin de incremento
con otra funcin, sta incrementada por dos:

Los mtodos 'que hemos visto a lo largo de la librera jQuery a menudo toman al
menos una funcin como parmetro. Por 'conveniencia, a menudo utilizamos funciones
annimas de modo que podemos definir el comportamiento de funcin cuando se necesita. Esto significa que las funciones raramente estn en el espacio de nombre de nivel
superior; son normalmente funciones internas, lo que significa que pueden fcilmente
crear closures.

function outerFn()
{
var outerVar = o;
function
innerFn1()
outerVar++i
$('#example-B')
.print(' (1) outerVar
}
function
innerFn2()
{
QuterVar += 2;
$('#example-B')
.print(' (2) outerVar

+ outerVar)

Argumentos para $(document).readyO


= '

outerVar);

}
return

{r fnl ": innerFnl,

fn2 ": innerFn2}

var fnRef = outerFn() i


fnRef.fn1() ;
fnRef.fn2() ;
fnRef.fn1() ;
var fnRef2 = outerFn();
fnRef2.fn1();
fnRef2.fn2();
fnRef2.fn1() ;

Devolvemos referencias a ambas funciones, utilizando un mapa para hacerlo. Ambas


funciones se invocan por medio de las referencias:
(1)
(2)
(1)
(1)
(2)
(1)

outerVar
QuterVar
outerVar
outerVar
outerVar
outerVar

= 3
= 4
1
3
4

Las dos funciones internas hacen referencia a la misma variable local, de modo que
comparten el mismo entorno de cierre. Cuando innerFnl () incrementa outerVar
en 1, esto establece el nuevo valor de partida de outerVar cuando se invoca innerFn2 ( ) , y viceversa. Sin embargo, una vez ms, vemos que cualquier llamada siguiente
a outerFn () crea nuevas instancias de estos closures con un nuevo entorno de cierre
con el que coincidir.
Los seguidores de la programacin orientada a objetos observarn que hemos creado un nuevo objeto, con las variables libres actuando como variables de instancia, y los
closures actuando como mtodos de instancia.
Las variables son tambin privadas, ya que no se pueden referenciar directamente
fuera del mbito de aplicacin en el que se encuentran, permitiendo verdadera privacidad de datos orientados a objetos.

Casi todo el cdigo que escribimos utilizando jQuery acaba situndose dentro de una
funcin pasada como un argumento a $ (document) . ready ( ) . Realizamos esto para
garantizar que el DOM se ha cargado antes de ejecutarse el cdigo, lo que es normalmente un requisito para cdigo jQuery interesante. Cuando se crea una funcin y se pasa a
. ready ( ) , una referencia a la funcin se almacena como parte del objeto global jQuery.
Esta referencia se invoca luego en un momento posterior, cuando el DOM est listo.
Normalmente situamos la construccin $ (document) . ready () en el nivel superior de la estructura de cdigo, de modo que esta funcin no es en realidad parte de un
closure. Sin embargo, puesto que nuestro cdigo se escribe normalmente dentro de esta
funcin, el resto es una funcin interna:
$ (document) .ready(function()
var readyVar = o;
function
innerFn()
(
readyVar++
$('#example-9')
.print('readyVar
}
innerFn() ;
innerFn() ;
}) ;

, + readyVar);

Esto se parece a muchos de nuestros ejemplos anteriores, excepto que en este caso, la
funcin exterior es la rellamada pasada a $ (document) . ready () . Puesto que innerFn () se define dentro de ello, y hace referencia a rea?yVar que est en el mbito de aplicacin de la funcin de rellamada, innerFn () y su entorno crean un closure. Podemos
ver esto al observar que el valor de readyVar persiste entre llamadas a la funcin:
readyVar
readyVar

=
=

1
:2

El hecho de que la mayor parte del cdigo jQuery est dentro de un cuerpo de funcin es de utilidad, ya que esto puede proteger contra algunas colisiones de espacio de
nombre. Por ejemplo, es esta caracterstica la que nos permite utilizar j Query . no Con f 1i ct () para liberar el mtodo abreviado $ para otras libreras, mientras se puede seguir
definiendo el mtodo abreviado localmente para uso en $ (document) . ready ( ) .

lmI

Aprende jQuery 1.3

Apndice C. JavaScript Closures

Estos ejemplos han utilizado funciones annimas, como ha sido nuestra costumbre
en cdigo jQuery. Esto no cambia nada en la construccin de closures; los closures pueden proceder de funciones con nombre o annimas. Por ejemplo, podemos escribir una
funcin annima para informar del m.diee de un elemento dentro de un objeto jQuery:

Manejadores de evento
La construccin $ (document) . ready () normalmente engloba el resto de nuestro
cdigo, incluida la asignacin de manejadores de evento. Puesto que los manejadores
son funciones, se convierten en funciones internas. Puesto que estas funciones internas
se almacenan e invocan ms tarde, pueden crear closures. Un sencillo manejador el i ck
puede ilustrar esto:
$ (document) .ready(function()
var counter = o;
$('#example-lO
a.add') .click(function()
counter++i
$('#example-lO') .print('counter =
return false

})

counter);

Puesto que la variable counter se declara dentro del manejador . ready (), solamente se encuentra disponible para el cdigo jQuery dentro de este bloque y no para
cdigo de fuera. Se puede hacer referencia por el cdigo en el manejador di ck que, sin
embargo incrementa y muestra el valor de la variable. Puesto que se crea un closure, la
misma instancia de counter se hace referencia cada vez que se hace clic en el vnculo.
Esto significa que los mensajes muestran un conjunto en continuo crecimiento de valores, no simplemente 1 cada vez:
=

counter
counter

= 2
e

Puesto que la funcin ms interna se define dentro de la rellamada . each ( ) , este cdigo crea tantas funciones como vnculos hay. Cada una de estas funciones se anexa como
un manejador el i ck a uno de los vnculos. Las funciones tienen index en su entorno de
cierre, ya que es un parmetro para la rellamada . each () . Esto se comporta de la misma
forma como si el manejador click estuviera escrito como una funcin cori nombre:
$ (document) .ready(function()
{
$('#example-13
a') .each(function(index)
function
clickHandler()
(
$('#example-13')
.print('index
return false

})

})

Los manejadores de evento pueden compartir sus entornos de cierre, como hacen
otras funciones:
$ (document) .ready(function()
{
var counter = Oi
$('#example-ll
a.add') .click(function()
counter++
$('#example-ll') .print('counter =
return false

})

counter)

index);

.click(clickHandler);

La versin con la funcin annima es algo ms corta. La posicin de esta funcin con
nombre sigue siendo relevante, sin embargo:
$ (document) .ready(function()
(
function
clickHandler()
(
$ ('#example-14')
.print('index
return false

'

= '

+ index);

$(this)
counter

= '

j);
})

});

})

$ (document) .ready(function()
{
$('#example-12
a') .each(function(index)
$(this) .click(function()
(
$('#example-12')
.print('index
return false
/

lliII

index);

$ ('#example-14
a') .each(function(index)
$ (this) .click (clickHandler)
;

$('#example-ll
a.subtract')
.click(function()
counter--
$('#example-ll') .print('counter =
+ counter);
return false
j);

})

})

Esta versin activar un error JavaScript siempre que se haga clie en un vnculo porque index no se encuentra en el entorno de cierre de clickHandler
() . Sigue siendo
una variable libre, y por lo tanto no definida en este contexto.

Puesto que ambas funciones hacen referencia a la misma variable counter, las operaciones de incremento y decremento de los dos vnculos afectan al mismo valor en lugar
de ser independientes:

Peligros de prdidas de memoria

counter
counter
counter
counter

JavaScript gestiona su memoria utilizando una tcnica conocida como recoleccin


de basura. Esto contrasta con los lenguajes de bajo nivel como C, que requieren programadores para reservar explcitamente bloques de memoria y liberarlos cuando ya no

= 1

2
1
lI:l

1j,

lmlII

Aprende jQuery 1.3

Apndice C. lavaScript Closures

se utilizan. Otros lenguajes como Objective-C ayudan al programador al implementar


un sistema de conteo de referencias, que permite al usuario tomar nota de cuntas piezas del programa estn utilizando una determinada pieza de memoria de modo que se
puede limpiar cuando ya no se utiliza. JavaScript es un lenguaje de alto nivel, por otro
lado, y por lo general se ocupa de esta contabilidad por detrs.
Siempre que un nuevo elemento residente en memoria como un objeto o funcin aparece en cdigo JavaScript, un bloque de memoria se reserva para este elemento. Cuando
el objeto se pasa a funciones y se asigna a variables, ms piezas de cdigo empiezan a
apuntar al objeto. JavaScript mantiene registro de estos punteros, y cuando el ltimo
desaparece, la memoria ocupada por el objeto se libera. Considere una cadena de punteros, como muestra la figura el.

alert(outerVar)

}
outerVar.fn ~ innerFn
return innerFnn;

};

Aqu, un objeto denominado outerVar se crea y referencia desde dentro de la funcin interna innerFn () . Luego, se crea una propiedad de outerVar
que apunta a
innerFn (), y se devuelve innerFn () . Esto crea un closure en innerFn () que hace
referencia a outerVar, que a su vez hace referencia a innerFn () . Pero el bucle puede
ser ms insidioso que esto:
('

function
outerFn()
(
var outerVar
= {};
function innerFn()
alert ("he Ll.o') ;
outerVar.fn = innerFn
return innerFn;

Figura C.1. Cadena de punteros.

Aqu el objeto A tiene una propiedad que apunta a B, y B tiene una propiedad que
apunta a e Incluso si el objeto A aqu es el nico que es una variable en el mbito actual, los tres objetos deben permanecer en memoria debido a los punteros hacia ellos.
Cuando A sale del mbito de aplicacin, sin embargo (como al final de la funcin en la
que se declar), entonces se puede liberar por el recolector de basura. Ahora B no tiene
nada apuntando hacia l, por lo que se puede liberar, y finalmente C tambin se puede
liberar. Puede ser ms difcil tratar con organizaciones de referencias ms complicadas,
como muestra la figura e2.

la

};

Aqu, hemos cambiado innerFn () de modo que ya no haga referencia a outerVaro Sin embargo, esto no rompe el bucle. Aunque outerVar no se hace nunca referencia desde innerFn (), sigue estando en el entorno de cierre de innerFn () . Todas
las variables en el mbito de outerFn () se les hace referencia implcitamente por innerFn () debido al closure. Por lo tanto, los closures facilitan la creacin accidental de
estos bucles.

El problema de prdidas de memoria de Internet Explorer


Figura C.2. Organizacin

ms compleja.

Ahora hemos aadido una propiedad al objeto C que hace referencia a B. En este
caso, cuando se libera A, B sigue teniendo un puntero hacia l desde e Este bucle de
referencia se tiene que gestionar especialmente por JavaScript, que debe observar que
todo el bucle se asla de las variables que estn en mbito.

Bucles de referencia accidentales


Los closures pueden hacer que se creen bucles de referencia sin darse cuenta. Puesto
que las funciones son objetos que se deben guardar en memoria, cualquier variable que
tengan en su entorno de cierre tambin se mantiene en memoria:
function outerFn()
(
var outerVar
= {};
function
innerFn()

Todo esto normalmente no es un problema porque JavaScript puede detectar estos


bucles y limpiarlos cuando se convierten en hurfanos. Internet Explorer, sin embargo,
tiene dificultad para gestionar una determina clase de bucles de referencia. Cuando un
bucle contiene elementos DOM y objetos JavaScript normales, lE no puede liberar ninguno porque se gestiona por diferentes gestores de memoria. Estos bucles nunca se liberan
hasta que se cierra el navegador, lo que consume una gran cantidad de memoria en el
tiempo. Una causa comn de un bucle as es un sencillo manejador de evento:
$ (document) .ready(function()
(
var div'= document.getElementByld('foo');
div.onclick
= function()
{
alert ('hello' ) ;

};
})

Cuando se asigna el manejador el ck, esto crea un closure con di ven el entorno de
cierre. Pero di v ahora contiene una referencia de vuelta al closure, la propia propiedad
onclick. De esta forma, el bucle resultante no se puede liberar por Internet Explorer
incluso cuando nos alejamos de la pgina.

lIl1!I

Apndice C. ]avaScript Closures

la buena noticia
Ahora, escribamos el mismo cdigo, pero utilizando construcciones jQuery normales:
$ (document) .ready(function()
var $div = $('#foo');
$div.click(function()
alert ('hello' ) ;

})
})

Aunque todava est creado un closure, causando el mismo tipo de bucle que antes,
no tenemos una prdida de memoria lE de este cdigo. Afortunadamente, jQuery es
consciente del potencial de prdidas, y libera manualmente todos los manejadores de
evento que asigna. Siempre y cuando sigamos utilizando los mtodos de vinculacin de
evento jQuery para nuestros manejadores, no tenemos que temer prdidas.
Esto no significa que estemos totalmente liberados; debemos continuar teniendo cuidado cuando llevamos a cabo otras tareas con elementos DOM. Anexar objetos JavaScript
a elementos DOM puede seguir causando prdidas de memoria en Internet Explorer;
jQuery ayuda a que esta situacin sea menos frecuente.
Debido a esto, jQuery nos proporciona otra herramienta para ayudar a evitar estas
prdidas. En el captulo 7 vimos que el mtodo. data () nos permite anexar informacin a elementos DOM de la misma forma que lo hacemos con propiedades expando.
Puesto que estos datos no se almacenan directamente como un expando (jQuery utiliza un mapa interno para almacenar los datos utilizando las identificaciones que crea),
el bucle de referencia nunca se forma y nosotros evitamos el problema de prdida de
memoria. Siempre que un expando parece un mecanismo de almacenamiento de datos
conveniente, deberamos considerar si . data () es una alternativa ms segura.

Resumen
Los closures JavaScript son una potente caracterstica del lenguaje. A menudo son
bastante tiles al ocultar variables de otro cdigo, de modo que no pisamos nombres
de variables utilizadas en algn otro sitio. Debido a la dependencia frecuente de jQuery
de funciones como argumentos de mtodo, tambin se pueden crear sin darse cuenta
bastante a menudo. Entenderlo nos permite escribir cdigo ms eficiente y conciso, y
con un poco de cuidado y el uso de las precauciones incorporadas de jQuery, podemos
evitar los peligros relacionados con memoria que pueden introducir.

./

i't'\'&

,,

./

.'

Apndice O
Referencia rpida

Este apndice est pensado como una referencia rpida para la API jQuery, incluidos expresiones de selector y mtodos, Una explicacin ms detallada de este tema se
encuentra disponible en la documentacin jQuery en, http : / / docs . j query . com,

Expresiones de selector
La funcin factory jQuery $ () se utiliza para encontrar elementos en la pgina con
los que trabajar. Esta funcin toma una cadena compuesta de sintaxis a modo CSS, denominada una expresin de selector. Las expresiones de selector se tratan en detalle en
el captulo 2.

Todos los elementos.

#id

El elemento con el ID dado,

element

Todos los elementos del tipo dado.

.class

Todos los elementos con la clase dada .

a, b

Elementos que coinciden por a O b.

ab

Elementos b que son descendientes

a>b

Elementos b que son hijos de a.

de a.

lll!I

Apndice D. Referencia rpida

Aprende jQuery 1.3

a+b

Elementos b a continuacin

a-b

Elementos que son hermanos de a.

:first

de a.

l:I!'a

:nth-chilq~formula)

Elementos que son el hijo n de su elemento padre (base 1). Las


frmulas son de la forma an-sb para enteros a y b.

El primer elemento en el conjunto resultado.

: first-child

Elementos que son el primer hijo de su padre.

:last

El ltimo elemento en el conjunto resultado.

:last-child

Elementos que son el ltimo hijo de su padre.

:not(a)

Todos los elementos en el conjunto resultado que no coinciden


por a.

:even

Elementos pares en el conjunto resultado (en base O).

:odd

Elementos impares en el conjunto resultado (en base O).

: eq(index)

Un elemento numerado en el conjunto resultado (en base O).

:gt (index)

Todos los elementos en el conjunto


despus del ndice dado (en base O).

resultado

(mayor

que)

"

:only-child

Elementos que son el nico hijo de su padre.

: input

Todos los elementos


<button>.

:text

Elementos <input>

con t ype

:password

Elementos <input>

con type~"password".

: radio

Elementos <input>

con type~"radio".

:checkbox

Elementos < input>

con type~"

:submit

Elementos <input>

con type~"submit".

:image

Elementos <input>

con type~"image".

:reset

Elementos < input>

con t.ype

<input>,

-cs e Le c t.>, <textarea>,y

e v

t.ext ".

checkbox".

:lt(index)

Todos los elementos en el conjunto resultado antes (menor que)


el ndice dado (base O).

:header

Elementos de encabezado

:animated

Elementos con una animacin en progreso.

:contains(text)

Elementos que contienen el texto facilitado.

:empty.

Elementos sin nadas hijo.

:file

:has(a)

Elementos que contienen un elemento descendiente que coincide


con a.

:enabled

Elementos de formulario activados.

:disabled

Elementos de formulario desactivados.

:parent

Elementos que tienen nadas hijo,

:checked

Casillas de verificacin y botones de opcin seleccionados.

:hidden

Elementos que estn ocultos, por medio de CSS o porque son


<input
type~"hidden"
/>.

:selected

Elementos e opt .on seleccionados.

:visible

Lo inverso de : hidden.

[attrl

Elementos que tienen el atributo attr.

Ia t t reva Lue l

Elementos cuyo atributo attr

[attr!

~valuel

(por ejemplo. <hl >, <h2 .

:button

Elementos

<input>

e "

reset".

con t.ype

bu t t on

v ,

y elementos

but t.on .

Elementos <input>

con type~"file".

Mtodos transversales DOM

es value.

Elementos cuyo atributo attr

no es value.

[attrA~valuel

Elementos cuyo atributo attr

empieza con value.

[attr$~valuel

Elementos cuyo atributo attr

termina con value.

[attr*~valuel

Elementos cuyo atributo attr

contiene la subcadena value.

:nth-child(index)

Elementos que son el hijo index

Despus de crear un objeto jQuery utilizando $ () r podemos alterar el conjunto


de elementos coincidentes con el que estamos trabajando al invocar uno de estos mtodos transversales DOM. Los mtodos transversales DOM se tratan en detalle en el
captulo 2.

de su elemento padre (base 1).

:nth-child(even)

Elementos que son un hijo par de su elemento padre (base 1).

:nth-child(odd)

Elementos que son un hijo impar de su elemento padre (base 1).

.filter(selector)

Elementos seleccionados
tado.

que coinciden con el selector facili-

lI!IlI

Aprende jQuery 1.3

Apndice D. Referencia rpida

ID

Mtodos de evento
.filter(callback)

Elementos seleccionados
devuelve true.

para los que la funcin de callback

. eq(index)

El elemento seleccionado

en el ndice en base O facilitado .

Elementos
base O.

seleccionados

en el rango facilitado de ndices en

Elementos
facilitado.

seleccionados

slice

(start,

[endl )

.not(selector)

que no coinciden

con el selector
/

.add(selector)

Elementos seleccionados, ms cualquier elemento adicional que


coincide con el selector facilitado.

.find(selector)

Elemento descendiente

contents

()

Nodos hijo (incluidos nodos de texto).

children

( [selectorl)

next ( [selectorl

prev ( [selectorl

prevAll ( [selectorl

siblings

. parents

( [selectorl

closest

se lector

offsetParent

()

Vincular handler a invocar cuando el DOMy CSS se han


cargado totalmente.

. bi nd (type,
handler)

Vincular handler a invocar cuando el tipo facilitado de evento


se enva al elemento.

.one (type,
handler)

[dat.a} ,

[datal,

. unbind ( [typel ,
[handlerl)

Elimina las vinculaciones en el elemento (para un tipo de evento,


un manejador determinado, o todas las vinculaciones) .

Todos los hermanos que siguen a cada elemento seleccionado,


opcionalmente filtrados por un selector.

. live (type, handler)

Vincular handler a invocar cuando el tipo facilitado de evento


se enva al elemento, utilizando delegacin de evento.

El hermano inmediatamente delante de cada elemento seleccionado, opcionalmente filtrado por un selector.

.die(type,

Elimina las vinculaciones


con .live ().

Todos los hermanos que preceden cada elemento seleccionado,


opcional mente filtrados por un selector.

.blur(handler)

Vincular handler a invocar cuando el elemento pierde el foco


del teclado.

.change(handler)

Vincular
cambia.

handler

.click(handler)

Vincular
mento .

handler

a invocar cuando se hace clic en el ele-

.dblclick(handler)

Vincular handler
elemento.

a invocar cuando se hace doble clic en el

. error

Vincular handler a invocar cuando el elemento recibe un evento


error (depende del navegador).

El padre de cada elemento seleccionado, opcionalmente


por un selector.

Vincular handler a invocar cuando el tipo de evento dado se


enva al elemento. Elimina la vinculacin cuando se invoca el
manejador.

El hermano inmediatamente a continuacin de cada elemento


seleccionado, opcional mente filtrado por un selector.

Todos los hermanos, opcional mente filtrados por un selector.

( [selectorl)

parent ( [selectorl

que coincide con el selector.

. ready(handler)

Nodos hijo, opcional mente filtrados por un selector-'

nextAll ( [selectorl

Para reaccionar al comportamiento


del usuario, necesitamos registrar nuestros manejadores utilizando estos mtodos de evento. Observe que muchos eventos DOM solamente aplican a ciertos tipos de elementos; estos detalles no se tratan aqu. Los mtodos
de evento se tratan en detalle en el captulo 3.

filtrado

Todos los ancestros, opcional mente filtrados porun se lector.


El primer elemento que coincide con el selector, empezando en
el elemento seleccionado y desplazndose hacia arriba por sus
ancestrosen el rbol DOM.
El padre posicionado (por ejemplo, relati
primer elemento seleccionado.
.

ve, absolute)

del

[handlerl)

(handler)

en el elemento previamente vinculado

a invocar

cuando

el valor del elemento

.focus(handler)

Vincular handler a invocar cuando el elemento recibe foco del


teclado.

andSel f ()

Los elementos seleccionados, ms el conjunto previo de elementos seleccionados en la pila jQuery interna.

. keydown(handler)

Vincular handler a invocar cuando se pulsa una tecla y el


elemento tiene foco del teclado.

end ()

El conjunto previo de elementos seleccionados


interna.

.keypress(handler)

Vincular handler a invocar cuando ocurre una pulsacin de


teclado y el elemento tiene foco del teclado.

map(callback)

El resultado de la funcin callback


elemento seleccionado.

.keyup(handler)

Vincular handler a invocar cuando se suelta una tecla y el


elemento tiene foco del teclado.

en la pila jQuery

cuando se invoca en cada

1"

lB

Aprende jQuery 1.3

Apndice D. Referencia rpida

.load (handler)

Vincular handler
cargarse.

.mousedown(handler)

.mouseenter(handler)

. mouseleave(handler)

a invocar cuando el elemento termina

dblclick

de

error

Vincular handler a invocar cuando el botn del ratn se pulsa


dentro del elemento.

Vincular handler a invocar cuando el puntero del ratn abandona


el elemento. No afectado por burbujeo de evento.

.mousemove(handler)

Vincular handler a invocar cuando el puntero del ratn se


mueve dentro del elemento.

.mouseout(handler)

Vincular handler a invocar cuando el puntero del ratn abandona


el elemento.

.mouseover(handler)

Vincular handler
en el elemento.

a invocar cuando el puntero del latn entra

.mouseup(handler)

Vincular handler
en el elemento.

a invocar cuando el botn del ratn se suelta

.resize(handler)

Vincular handler
tamao.

.scroll(handler)

Vincular handler a invocar cuando la posicin de la barra de


desplazamiento del elemento cambia.

.select(handler)

Vincular handler
elemento.

a invocar cuando el elemento

Activar el evento dblclick.

(~

Activar eJ"evento error.

()

Activar el evento focus.

focus ()

Vincular handler a invocar cuando el puntero delratn entra


en el elemento. No se ve afectado por burbujeo de evento.
l'

. keydown()

Activar el evento keydown.

keypress

Activar el evento keypress.

()

.keyup ()

Activar el evento keyup .

.select()

Activar el evento selecto

submit ()

Activar el evento submit.

Mtodos de efecto
Estos mtodos de efecto se pueden utilizar para llevar a cabo animaciones en elementos DOM. Los mtodos de efecto se tratan en detalle en el captulo 4.

cambia de

show()

Muestra los elementos coincidentes.

a invocar cuando se selecciona texto en el

hide ()

Oculta los elementos coincidentes.


Muestra los elementos coincidentes al animar altura, anchura y
opacidad.

.submit(handler)

Vincular handler
formulario.

a invocar cuando se enva el elemento de

show (speed,
[callbackl)

.unload(handler)

Vincular handler
de la memoria.

a invocar cuando el elemento se descarga

.hide(speed,
[calll:;Jackl )

Oculta los elementos


opacidad.

Vincular enter a invocar cuando el ratn entra en el elemento,


y leave cuando el ratn sale de l.

toggle ( [speedl ,
[callbackl)

Muestra u oculta los elementos coincidentes.

.hover(enter,leave)

.toggle(handlerl,
handler2,
... )

Vincular handlerl a invocar cuando se hace clccon el ratn en


el elemento, seguido de handler2, etc., para siguientes clics.

slideDown ( [speedl ,
[callbackl)

Muestra los elementos


zante.

slideUp ( [speedl ,
[callback] )

Oculta los elementos


zante.

. trigger

(type,

[data])

Activar manejadores para el evento en el elemento, y ejecutar


la accin predeterminada para el evento.

. triggerHandler(type,
[data] )

Activar manejadores para el evento en el elemento sin ejecutar


ninguna accin predeterminada.

. blur()

Activar el evento blur .

. change ()

Activar el evento change .

. click

Activar el evento click .

()

lB

.slideToggle([speed]
[callbackl)

al animar altura, anchura y

coincidentes

coincidentes

coincidentes

con un movimiento

desli-

con un movimiento

desli-

Muestra u oculta los elementos coincidentes con un movimiento


deslizante.

fadeln ( [speedl ,
[callback] )

Muestra los elementos coincidentes al desvanecerlos

.fadeOut( [speedl,
[callbackl)

Oculta los elementos coincidentes


rentes.

al desvanecerlos

a opaco.

a transpa-

lIIiI

Aprende jQuery 1.3

Apndice D. Referencia rpida

.fadeTo(speed,
opacity, [callbackl)

Ajusta la opacidad de los elementos coincidentes .

html (vaLue )

.animate(attributes,
[speedl, [easingl,
[callbackl)

Lleva a cabo una animacin personalizada de los atributos CSS


especificados.

text ()

.animate(attributes,
options)

Una interfaz de bajo nivel para. animate (),permitiendo control


sobre la cola de animacin.

.stop( [clearQueuel,
[jumpToEndl )

Detener la animacin actualmente en curso, luego empezar las


animaciones en cola, si alguna.

.queue ()

Recuperar la cola de animaciones


cidente.

en el primer elemento coin-

Aadir callback al final de la cola .

.queue(newQueue)

Reemplazar

.dequeue ()

Ejecutar la siguiente animacin en la cola .

la cola con una nueva .

Mtodos de manipulacin

Establecer el contenido HTML de cada elemento coincidente en

value,

.text(value)

.queue(callback)

11III

.'

Obtener el contenido textual de todos los elementos coincidentes


como una sola cadena.
Establecer

el contenido textual de cada elemento coincidente

en value.

,..

val ()

Obtener el atributo valor del primero elemento coincidente.

.val(value)

Establecer el atributo valor de cada elemento en value .

.css(key)

Obtener el atributo CSS denominado

css (key, value)

Establecer el atributo CSS denominado

.css(map)

Establecer valores
clave-valor.

.offset()

Obtener las coordenadas de pixel superior e izquierda del primer


elemento coincidente, relativo al visor.

.position()

Obtener las coordenadas de pixel superior e izquierda del


primer elemento coincidente, relativo al elemento devuelto por

scrollTop ()

Obtener la posicin de desplazamiento


elemento coincidente.

vertical

.scrollTop(value)

Establecer la posicin de desplazamiento


elementos coincidentes en value.

vertical de todos los

.scrollLeft()

Obtener la posicin de desplazamiento


elemento coincidente.

.scrollLeft(value)

Establecer la posicin de desplazamiento


los elementos coincidentes en value.

.height ()

Obtener el ancho del primer elemento coincidente .

de atributo

key .
key en value.

CSS, facilitados

como pares

.offsetParent ().

DOM

Los mtodos de manipulacin DOM se tratan en el captulo 5.

.attr(key)

Obtener el atributo denominado

.attr(key, value)

Establecer el atributo denominado

.attr(key, fn)

Establecer el atributo denominado key en el resultado de fn


(llamado por separado en cada elemento coincidente).

.attr(map)

Establecer valores de atributo, dados como pares clave-valor .

.removeAttr(key)

Eliminar el atributo denominado

.addClass(class)

Aadir la clase dada a cada elemento coincidente .

key .
key en value .

key .

.removeClass(class)

Eliminar la clase dada desde cada elemento coincidente .

.toggleClass(class)

Eliminar la clase dada, si est presente, y aadirla si no lo est,


para cada elemento coincidente.

.hasClass(class)

Devolver true si cualquiera de los elementos coincidentes tiene


la clase facilitada.

.html ()

Obtener el contenido HTMLdel

primer elemento coincidente.

.height(value)

Establecer

del primero

horizontal

del primer

horizontal de todos

la altura de todos los elementos

coincidentes

en

value.
.width()
.width(value)

Obtener el ancho del primer elemento coincidente .


Establecer

el ancho de todos los elementos

coincidentes

en

value.
innerHeight ()

Obtener la altura del primero elemento


relleno, pero no borde.

coincidente,

incluido

innerWidth ()

Obtener el ancho del elemento coincidente, incluido relleno, pero


no borde.

.outerHeight
(includeMargin)

Obtener la altura del primer elemento coincidente, incluido relleno,


borde y margen opcional.

Apndice D. Referencia rpida

Aprende jQuery 1.3

11II

Mtodos AJAX
.outerWidth
(includeMargin)

Obtener el ancho del primer elemento coincidente,


relleno, borde y margen opcional.

. append(content)

Insertar content
dente.

.appendTo(selector)

Insertar los elementos coincidentes al final del interior de los


elementos coincidentes por selector.

.prepend(content)

Insertar content
coi ncidente.

.prependTo(selector)

incluido

Podemos r,ecuperar informacin del servidor sin requerir un refresco de pgina al


invocar uno de estos mtodos AJAX.Los mtodos AJAXse tratan en el captulo 6.

al final del interior de cada elemento coinci-

al principio del interior de cada elemento

Insertar los elementos coincidentes al principio del interior de


los elementos coincidentes por selector.

.after(content)

Insertar content

.insertAfter(sel~ctor)

. before(content)

Insertar los elementos coincidentes despus de cada uno de los


elementos coincidentes por selector.
"
Insertar content
delante de cada elemento coincidente .

.insertBefore
(selector)

Insertar los elementos coincidentes delante de cada uno de los


elementos coincidentes por selector.

.wrap(content)

Situar cada uno de Ioselernentos coincidentes dentro de content.

.wrapAll(content)

wraplnner

detrs de cada elemento coincidente.

Realizar una peticin AJPIX utilizando el conjunto proporcionado


de opciones. Se trata de mtodo de bajo nivel que normalmente
se invoca va otros mtodos de conveniencia.

$.ajax(options)
l'

.load (url,
[callback)

[data),

Realizar una peticin AJPIX a url,


elementos coincidentes.

[data),

Realizar una peticin AJPIX a url

$ . get (url,
[callback)
[returnType)

y situar la respuesta en los


utilizando el mtodo GET.

,
)

$. getJSON (url,
[callback)
)

[data),

Realizar una peticin AJPIX a url, interpretando la respuesta


como una estructura de datos JSON.

$.getScript(url,
[callback)
)

Realizar una peticinAJPIX a url,


JavaScripl.

ejecutando la respuesta como

$. post (url,
[data),
[callback)
,
[returnType)
)

Realizar una peticin AJPIX a url

utilizando el mtodo POST.

Situar todos los elementos coincidentes como una sola unidad


dentro de contento

aj axComplete

Vincular handler
a invocar cuando se completa cualquier
transaccin AJPIX.

(content)

Situar los contenidos interiores de cada uno de los elementos


coincidentes dentro de contento

aj axError

replaceWi

th (content)

Reemplazar los elementos coincidente con contento

aj axSend (handler)

Vincular handler
saccin AJPIX.

replaceAll

(selector)

Reemplazar los elementos coincidente por selector


elementos coincidentes.

.ajaxStart

Vincular handler
a invocar cuando comienza cualquier transaccin AJPIX, y ninguna otra est activa.

empty ()

(handler)

Vincular handler a invocar cuando cualquier transaccin AJPIX


se completa con un error.
a invocar cuando comienza cualquier tran-

con los
(handler)

Eliminar los nodos hijo de cada elemento coincidente.


aj axStop

remove ( [selector)

clone

(handler)

( [wi thHandlers))

data (key)

Eliminar los nodos coincidentes


selector)
del DOM.

(handler)

(opcionalmente filtrados por

Realizar una copia de todos los elementos coincidente, opcionalmente tambin copiando manejadores de evento.
Obtener el elemento de datos denominado key asociado con
el primer elemento coincidente.

da ta (key,

val ue)

Establecer el elemento de datos denominado key asociado con


cada elemento coincidente en value.

removeData

(key)

Eliminar el elemento de datos denominado key asociado con


cada elemento coincidente.

aj axSuccess

$ . aj axSetup

serialize

(handler)

(options)

()

serializeArray

$ . param (map)

Vincularhandler
a invocar cuando termina cualquier transaccin
AJPIX, y ninguna otra est todava activa.
Vincular handler a invocar cuando cualquier transaccin AJPIX
se completa con xito.
Establecer opciones predeterminadas para todas las transacciones AJPIX siguientes.
Codificar los valores de un conjunto de controles de formulario
en una cadena de consulta.

()

Codificar los valores de un conjunto de controles de formulario


en una estructura de datos JSON.
Codificar un mapa arbitrario de valores en una cadena de consulta.

In~'

,~
,

.
lndice

Apndice D. Referencia rpida

Mtodos variados

Estos mtodos no encajan bien en las categoras anteriores, pero son a menudo de
utilidad cuando se escriben scripts utilizando jQuery.

$.support

Devolver un mapa de propiedades indicando si el navegador


soporta varias caractersticas y estndares.

$.each(collection,
callback)

Iterar sobre collection,


elemento.

$.extend(target,
addition,
... )

Modificar el objeto target


objetos proporcionados.

$.grep(array,
callback,
[invert])

Filtrar array

$.makeArray(object)

Convertir obj ect en una tabla.

$. map(array,

Construir una nueva tabla que consta del resultado de invocar


callback en cada elemento.

callback).

$. inArray (value,
$ . merge (arrayl,

array)
array2)

ejecutando

callback

para cada

al aadir propiedades desde los otros

al utilizar callback

como una prueba.

Determinar si value est en array.


Combinar los contenidos de arrayl

y array2.

$ . unique (array)

Eliminar cualquier elemento DOM duplicado de array.

$ . isFunct ion (obj ect)

Determinar si obj ect es una funcin.

$. trim(string)

Eliminar el espacio en blanco de los extremos de string.

$ . noConf 1 i ct
( [extreme] )

Devolver $ a su definicin pre-jQuery.

hasClass

Determinar
tada.

(className)

alfabtico

si algn elemento coincidente

tiene la clase facili-

is (selector)

Determinar si algn elemento coincidente coincide por la expresin de selector facilitada.

each (callback)

Iterar sobre los elementos coincidentes,


para cada elemento.

ejecutando callback

.length

Obtener el nmero de elementos coincidentes.

get ()

Obtener una tabla de nodos DOM correspondientes


mentos coincidentes.

get (index)

Obtener el nodo DOM correspondiente


en el ndice facilitado.

index (element)

Obtener el ndice del nodo DOM facilitado dentro del conjunto


de elementos coincidentes.

a los ele-

al elemento coincidente

$0, funcin factory


bloques principales
clase, 42
evitar iteracin explcita, 37
ID,42
nombre de etiqueta, 42
caractersticas, 42
definicin, 42
insertar mtodos con, 115

A
acciones, jQuery
acceder a elementos
en un documento, 30
alterar el contenido
de un documento, 30
animar cambios realizados a un
documento, 30
Asynchronous JavaScript y XML
(AJAX),30

modificar la apariencia de una pgina


Web,30
recuperar informacin de un servidor
sin refrescar una pgina, 30
responder a la interaccin
de un usuario, 30
simplificar tareas JavaScript
comunes,30
ARAR,137
AJAX
acciones predeterminadas, 77
archivos XML, 146
cargar datos bajo demanda, 136
cargar partes de una pgina lITML, 165
datos
aadir RTML, 137
cargar un documento XML, 146
el mtodo AJAX de bajo nivel, 164
elegir de archivos
JavaScript, 150
JSON,150
elegir de documentos XML, 150

11III

fndice alfabtico

elegir de fragmentos HTML, 150


limitaciones de seguridad, 161
opciones adicionales, 163
recuperar un objeto JavaScript, 140
trabajar con objetos JavaScript, 140
definicin, 134
delegacin de evento, 78
detener la propagacin de evento, 76
elegir formato de datos, 150
eventos, 160
limitaciones de seguridad, 161
utilizar JSONP para datos
remotos, 162
mtodo
.ajaxfitartt), 158
.ajaxStop, 158
AJAX de bajo nivel, 164
mtodos, 413
opciones predeterminadas, 164
XMLHttpRequest, objeto, 135
alterar, eventos, 75
acciones predeterminadas, 77
delegacin de evento, 78
destinos de los eventos, 76
detener la propagacin, 76
objeto event, 75
ampliar imagen
animar la ampliacin de la portada, 309
aadir un indicador de carga, 314
aplazar las animaciones hasta que la
imagen se carga, 313
mostrar un botn cerrar, 307
ocultar la portada ampliada, 305
sobre ampliar imagen, 304
animaciones personalizadas
crear
.animatet),
mtodo,98
forma
primera,98
segunda, 99

ndice atjabtico

.fadelru). mtodo, 99
.fade'I'ogglef), mtodo, 99
posicionar con CSS, 101
efectos
alternar aparecer y desaparecer
paulatino, 99
animar mltiples propiedades, 100
crear, 98
posicionar con CSS, 101
apariencia de tabla,
filtrado
comportamiento
expandir,211
ocultar, 211
implementar, 211
interactuar con otro cdigo, 214
invertir los filtros, 213
opciones de filtro, 212
modificar
contraer secciones, 209
descripciones emergentes, 204
expandir secciones, 209
resaltar filas, 197
Aptana, herramienta, 387
Asynchronous HTTP y HTML, 137
Asynchronous JavaScript y XML, 134
atributos,
la funcin factory $0 revisada, 114
que no son clase, 112 _
manipular, 111
autocompletar, formularios compactos
autocompletar frente a live
search,253
completar el campo de bsqueda, 249
definir, 246
eliminar la lista de sugerencias, 253
en el navegador, 247
en el servidor, 247
gestionar las teclas del cursor, 251
insertar sugerencias en el campo, 252
navegacin por medio de teclado, 249

B
bajo demanda, .eargar datos,
aadir HTML, 137
cargar un documento XML, 146
definicin, 136
funciones jQuery globales, 141
trabajar con objetos JavaScript, 140
ltajo nivel, mtodo AJAX, 164
blogs
A list apart, 379
Ajaxian, 377
As days pass by, 379
DOM scripting, 379
el blog jQuery, 377
Estndares Web con imaginacin, 378
1can't, 378
JavaScript ant, 378
John Resig, 378
learning jQuery, 377
Recurso JavaScript de Matt Zinder, 378
Robert's talk, 378
Snook,378

e
clculos numricos, datos de formulario
numricos
analizar formato moneda,261
aplicar formato a moneda, 261
otros clculos, 264
redondear valores, 265
toques finales, 265
tratar con decimales, 262
caractersticas jQuery
abstraer fallos de navegador, 31
aprovechar conocimiento de CSS, 31
permitir mltiples acciones, 31
soportar extensiones, 31
trabajar con conjuntos, 31

lIfI

cargar datos bajo demanda,


aadir HTML, 137
cargar un documento XML, 146
definicin, 136
funciones jQuery globales, 141
trabajar con objetos JavaScript, 140
cargar la pgina
coexistir con otras libreras, 60
mtodos abreviados para cdigo, 60
mltiples scripts en una pgina, 58
planificacin de la ejecucin
de cdigo, 57
Cascading Style Sheets (CSS), 6
Charles, herramienta, 387
closures
argumentos para $(document).
readyO,395
en jQuery, 395
interacciones entre closures, 394
manejadores de evento, 396
compartir un plug-in
con el mundo, 368
convenciones de nombrado, 369
estilo de documentacin, 370
interfaces de mtodo, 369
compresores de cdigo JavaScript, 375
compressor YUI, 375
JSMin,375
Pretty printer, 376
referencia (X)HTML, 376
compuestos
efectos, 97
eventos
.hovert), mtodo, 70
.toggle), mtodo, 70
destacar elementos sobre
los que se hace clic, 71
mostrar caractersticas
avanzadas, 70
ocultar caractersticas
avanzadas, 70

lIlI

ndice

ndice alfabtico

configurar la pgina, carrusel


de imgenes, 294
revisar los estilos con JavaScript, 296
conmutador de estilo, eventos
contexto de manejador de evento, 65
eventos de teclado, 84
habilitar otros botones, 63
mayor consolidacin, 67
copiar elementos, 125
donar citas, 126
donar con eventos, 126
de vuelta al cdigo, 127
embellecer las citas, 129
una desviacin CSS, 127
CSS, 6
modificaciones en lnea
.add'Classt), mtodo, 89
.cssf), mtodo, 89
definicin, 89

D
datos, AJAX
aadir HTML, 137
cargar un documento XML, 146
el mtodo AJAX de bajo nivel, 164
elegir de
archivos JavaScript, 150
archivos JSON, 150
documentos XML, 150
fragmentos HTML, 150
limitaciones de seguridad, 161
opciones adicionales, 163
recuperar un objeto JavaScript, 140
trabajar con objetos JavaScript, 140
datos de formulario numricos, trabajar
con,256
clculos numricos, 260
editar informacin de envo, 270
eliminar elementos, 266

estructura de tabla de carro


de la compra, 256
documentacin jQuery
API jQuery, 373
jQuery visual, 374
navegador de la API jQuery, 374
visor jQuery API Adobe AIR, 374
Wiki jQuery, 373
Document Object Model, (DOM), 41
DOM
definicin, 41
ejemplo, 41
elementos
burbujeo de eventos, 74
desventajas, 74
captura de eventos, 73 "
jerarqua, 72
mtodos de manipulacin, 131
mtodos transversales, 353
aplicar estilo a celdas especficas, 52
definicin, 51
encadenar, 53
funcin filter, 52
recorrer el DOM, 52
ventajas de encadenar, 53

E
efecto, mtodos, 409
efectos
animaciones personalizadas
alternar aparecer y desaparecer
paultino, 99
animar mltiples propiedades, 100
crear, 98
posicionar con CSS, 101
efectos simultneos, crear, 102
en cola, 102
mtodos bsicos, 93
rellamadas, 107

trabajar con mltiples conjuntos


de elementos, 105
trabajar con un solo conjunto
de elementos, 102
velocidad
aparecer de forma paulatina, 96
aplicar velocidad, 95
desaparecer de forma paulatina, 96
elementos
anexar pies de pgina, 122
donar citas, 126
donar con eventos, 126
copiar, 125
donar
citas, 126
con eventos, 126
de vuelta al cdigo, 127
embellecer las citas, 129
una desviacin CSS, 127
embellecer las citas, 129
insertar nuevos elementos, 115
marcar contexto, 121
mover elementos, 118
marcar el contexto, 121
numerar el contexto, 121
vincular el contexto, 121
numerar contexto, 121
situar elementos alrededor
de otros, 124
vincular contexto, 121
.wrap), mtodo, 124
elementos DOM
burbujeo de eventos, 74
desventajas, 74
captura de eventos, 73
jerarqua, 72
en lnea, modificaciones CSS
.addClassO, mtodo, 89
..csst), mtodo, 89
definicin, 89
espacio de nombres de evento, 80

alfabtico

EDil

estilo de formulario
definicin, 221
expresin regular, 227
leyenda, 228
manipulacin de casilla
de verificacin, 238
evento, mtodos, 407
evento, objeto
.ist) mtodo, utilizar, 79
.preventDefaultO, mtodo, 77
.stopPropagationO, mtodo, 77
acciones predeterminadas, 77
definicin, 75
delegacin de evento, 78
destinos de los eventos, 76
propiedad evenUarget, 78
eventos
abreviados, 68
alterar, 75
acciones predeterminadas, 77
delegacin de evento, 78
destinos de los eventos, 76
detener la propagacin, 76
objeto event, 75
compuestos, 70
.hovert), mtodo, 70
.togglef), mtodo, 70
destacar elementos sobre
los que se hace clic, 71
mostrar caractersticas avanzadas, 70
ocultar caractersticas avanzadas, 70
conmutador de estilo,
contexto de manejador de evento, 65
habilitar otros botones, 63
mayor consolidacin, 67
de te dado, 84
de usuario,
hoverIntent,342
Live Query, 342
efectos secundarios del burbujeo
de eventos, 74

1m

ndice alfabtico

ndice alfabtico

eliminar manejador de evento, 80


espacio de nombres de evento, 80
manejador de evento, 80
objeto event, 75
sencillos, 61
vincular eventos, 81
expresiones de selector
#id,403
*,403
.class, 403
:animated, 404
:button, 405
:checkbox, 405
:checked, 405
:contains(text),404
:disabled, 405
:empty,404
:enabled, 405
:eq(index), 404
:even, 404
:file, 405
:first, 404
:first-child, 405
:gt(index), 404
:has(a),404
:header, 404
:hidden, 404
:image, 405
:input, 405
:last, 404
:last-child, 405
:lt(index),404
:not(a),404
:nth-child(even),404
:nth-child(formula),405
:nth-child(index), 404
:nth-child(odd),404
:odd,404
:only-child, 405
:parent, 404
:password, 405

:radio, 405
:reset, 405
:selected, 405
:submit, 405
:text, 405
:visible, 404
[attrl=value], 404
[attr$=value], 404
[attr*=value], 404
[attr],404
[attrl\=value],404
[attr=value],404
a - b, 404
a + b, 404
a> b, 403
a b, 403
.'
a,b,403
aadir pseudos-clase, 366
crear, 366
element, 403
parmetros
element, 367
index,367
matches, 367
set, 367
utilizar, 366

F
fadelru), mtodo, 97
fadeOutO, mtodo, 97
Fiddler, herramienta, 387
filas, apariencia de la pgina, 197
alternar color de filas, 198
avanzado, 200
resaltar filas, 197
basado en interaccin del usuario, 202
filtrado, apariencia de tabla
comportamiento expandir, 211
comportamiento ocultar, 211

implementar,211
interactuar con otro cdigo, 214
invertir los fi~tros, 213
opciones de filtro, 212
Firebug Lite, herramienta, 386
Firefox, herramientas
barra de herramientas
de desarrollador Web, 384
comprobador de expresiones
/
regulares, 384
Firebug, 383
Venkman, 384
Form, plug-in
.ajaxf'ormf), mtodo, 323
.ajaxSubmitf), mtodo, 323
definicin, 323
opcin
beforeSubmit, 323
success, 323
target, 323
formulario,
compactos
autocompletar, 246
completar el campo
de bsqueda, 249
eliminar la lista de sugerencias, 253
en el navegador, 247
en el servidor, 247
gestionar las teclas del cursor, 251
insertar sugerencias
en el campo, 252
navegacin por medio
de teclado, 249
sobre autocompletar, 246
completar el campo de bsqueda, 249
sobre formularios compactos, 243
definicin, 229
estilo
definicin, 221
expresin regular, 227
leyenda, 228

ID

manipulacin de casilla
de verificacin, 238
estilo de formulario mejorado, 222
mejorar un formulario bsico, 221
validacin, 231
campos obligatorios, 231
campos, 231
expresin regular, 235
formatos de entrada de datos, 234
formatos obligatorios, 231
regla, 231
tareas de cdigo, 235
ltima comprobacin, 231
validacin del lado del servidor, 231
formularios, plug-ins
Autocomplete, 333
Jeditable, 334
Masket input, 335
Validation, 334
funcin factory $0
bloques principales
clase, 42
evitar iteracin explcita, 37
nombre de etiqueta, 42
caractersticas, 42
definicin, 42
insertar mtodos con, 115
funciones globales,
aadir mltiples funciones, 346
crear un mtodo de utilidad, 347
ventaja, 347
funciones internas,
definicin, 389
el gran escape, 390

G
GNU, licencia pblica, 32
grficas, plug-ins
Flot, 341
Sparklines, 341

lB

lndice aifabtico

lndice alfabiico

H
herramientas
otras herramientas,
Aptana,387
Charles, 387
Fiddler, 387
Firebug Lite, 386
NitobiBug, 386
paquete TextMate jQuery, 387
para Firefox, 383
barra de herramientas
de des arrollador Web, 384
comprobador de expresiones
regulares, 384
Firebug, 383
Venkman, 384
para Internet Explorer, 384
DebugBar, 385
Drip, 385
Microsoft Internet Explorer
Developer Toolbar, 384
Microsoft Visual Web Developer, 385
para Opera, 386
Dragonfly, 386
Inspector W eb, 386
para Safari, 385
Inspector Web,386
men Develop, 385
HTML, elementos de formulario, 229

1
imgenes, carrusel
ampliar imagen
animar la ampliacin
de la portada, 309
aadir un indicador de carga, 314
aplazar las animaciones hasta
que la imagen se carga, 313

mostrar un botn cerrar, 307


ocultar la portada ampliada, 305
sobre ampliar imagen, 304
configurar la pgina, 294
mover las imgenes cuando
se hace clic, 297
aadir animacin deslizable, 299
mostrar iconos de accin, 301
imgenes, plug-ns
Jcrop,337
Magnify,337
Internet Explorer, herramientas
DebugBar, 385
Drip,385
Microsoft Internet Explorer
Developer Toolbar, 384,'
Microsoft Visual Web Developer, 385

J
JavaScript
closures, 395
compresores de cdigo, 375
compressor YUI, 375
JSMin,375
Pretty printer, 376
referencia (X)HTML, 376
objeto,
"
$.getJSONO, funcin, "
como funcin global, 141
$.getJSONO, funcin, definicin, 141
$.getJSONO, funcin, mtodo
de clase, 141
funciones jQuery globales, 141
recuperar objeto, 140
ordenacin,
alternar la direccin
de ordenacin, 186
etiquetas de agrupacin, 175
manipular teclas de ordenar, 182

ordenacin alfabtica bsica, 175


ordenar otros tipos de datos, 183
plug-ins, 17~ .
rendimiento, 180
resaltar columna, 186
paginacin, 190
habilitar los botones
del paginador, 192
marcar la pgina actual, 183
mostrar el paginador, 191
paginacin con ordenacin, 194
referencia, 374
Centro de desarrollo Mozilla, 374
Dev.opera, 374
JavaScript Toolbox, 375
Quirksmode, 375
Referencia [script MSDN, 375
JavaScript Object Notation, (JSON), 162
jQuery
.animatef), mtodo, 98
.insert.Afterf), mtodo, 115
.nsertlefore), mtodo, 115
acciones, 29
acceder a elementos
en un documento, 30
alterar el contenido
de un documento, 30
animar cambios realizados
a un documento, 30
Asynchronous JavaScript y XML
(AJAX),30
modificar la apariencia
de una pgina Web, 30
recuperar informacin
de un servidor sin refrescar
una pgina, 30
responder a la interaccin
de un usuario, 30
simplificar tareas JavaScript
comunes,30
aadir, 36

aadir mtodos de objeto


contexto del mtodo de objeto, 349
encadenar mtodos, 352
caractersticas
abstraer fallos de navegador, 31
aprovechar conocimiento de CSS, 31
permitir mltiples acciones, 31
soportar extensiones, 31
trabajar con conjuntos, 31
configurar el elemento HTML, 33
definicin, 28
descargar jQuery, 36
documentacin
API jQuery, 373
jQuery visual, 374
navegador de la API jQuery, 374
visor jQuery API Adobe AIR, 374
Wiki jQuery, 373
empezar a trabajar, 28
encontrar el texto del poema, 36
historia del proyecto jQuery, 32
jQueryUI
librera de plug-ins
componentes de interaccin, 327
definicin de jQuery UI, 325
efectos, 325
ThemeRoller, 332
Widgets, 330
efectos
aceleracin y desaceleracin
avanzada,326
animaciones
de clase, 326
de color, 325
efectos adicionales, 327
la funcin factory $0, 42
marcos de trabajo de desarrollo
Web,379
mtodos
de manipulacin DOM, 129
transversales DOM, 51

&1

ndice aIfabtico

aplicar estilo a celdas especficas, 52


encadenar, 53
proyecto
fase de desarrollo pblico, 32
jQuery 1.1, 32
jQuery 1.1.3, 32
jQuery 1.2, 32
jQuery 1.2.6, 33
jQuery 1.3, 33
jQuery UI, 32
recursos online, 372
blogs,377
compresor de cdigo JavaScript, 375
documentacin jQuery, 373
referencia CSS, 376
referencia JavaScript, 374
referencia
expresiones de selector, 403
mtodos
AJAX, 413
de efecto, 409
de evento, 407
de manipulacin DOM, 410
transversales DOM, 405
variados, 414
selectores
CSS,43
personalizados, 48
utilizar funciones de rellamada, 363
jQueryUI
efectos
aceleracin y des aceleracin
avanzada,326
animaciones
de clase, 326
de color, 325
efectos adicionales, 327
librera de plug-ins
componentes de interaccin, 327
definicin de jQuery UI, 325
efectos, 325

ndice aIfabtico

ThemeRoller, 332
Widgets, 330
JSON,162
JSONP, 162

licencia pblica GNU, 32


Lightbox, plug-ins
BlockUI,340
FancyBox, 338
jqModal, 340
Thickbox,339
limitaciones de seguridad,
cargar datos remotos, 161
utilizar
.'
etiqueta HTML <iframe>, 162
JSONP para datos remotos, 162

mtodos abreviados,
aadir, 356 ,
mostrar elementos, 357
ocultar elementos, 357
personalizados, 358
mtodos de objeto jQuery, 15
mtodos transversales, DOM
aplicar estilo a celdas especficas, 52
, definicin, 51
(
encadenar, 53
funcin filter, 52
recorrer el DOM, 52
ventajas de encadenar, 53
mover elementos, 118
marcar el contexto, 121
numerar el contexto, 121
vincular el contexto, 121
MSDN Script, 375

manejador de evento, 80
eliminar, 80
espacio de nombres de evento, 80
volver a vincular eventos, 81
manipulacin de tabla
filtrado, 211
modificar apariencia de la tabla, 197
ordenacin JavaScript, 173
ordenar y paginar, 172
paginacin
del lado del servidor, 186
JavaScript, 190
memoria, peligros de prdidas, 397
bucles de referencia accidentales, 398
problema de prdidas de memoria de
Internet Explorer, 399
mensajes de campo, formulario
expresin regular, 227
insertar, 225
leyenda, 227

NitobiBug, herramienta,

386

o
objeto evento
.istt) mtodo, utilizar, 79
.preventfzefaultf), mtodo, 77
.stopf'ropagationf), mtodo, 77
acciones predeterminadas, 77
definicin, 75
delegacin de evento, 78
destinos de los eventos, 76
propiedad evenUarget, 78
objeto JavaScript,
$.getJSONO, funcin,
como funcin global, 141
definicin, 141
mtodo de clase, 141
funciones jQuery globales, 141
recuperar, 140

ID

Opera, herramientas
Dragonfly, 386
ordenacin JavaScript, 173
alternar la direccin
de la ordenacin, 186
el poder de los plug-ins, 179
etiquetas de agrupacin de filas, 175
manipular teclas de ordenar, 182
ordenacin alfabtica bsica, 175
ordenar otros tipos de datos, 183
plug-ins, 179
rendimiento, 180
resaltar columna, 186

p
pgina, cargar
coexistir con otras libreras, 60
mtodos abreviados para cdigo, 60
mltiples scripts en una pgina, 58
planificacin de la ejecucin
de cdigo, 57
paginacin, datos
paginacin del lado del servidor, 188
paginacin JavaScript, 190
paginacin del lado del servidor
definicin, 188
ordenar y paginar, 188
paginacin JavaScript, 190
habilitar los botones del pagnador, 192
marcar la pgina actual, 183
mostrar el paginador, 191
paginacin con ordenacin, 194
parmetros de mtodo
definicin, 359
funciones de rellamada, 363
mapas de parmetro, 361
parmetros sencillos, 360
predeterminados personalizables, 364
valores de parmetro
predeterminados, 362

I!B

ndice alfubetico

pasar datos al servidor, 151


funciones de rellamada, 363
llevar a cabo una peticin
GET,151
POST,154
serializar un formulario, 156
peligros de prdidas de memoria, 397
bucles de referencia accidentales, 398
problema de prdidas de memoria de
Internet Explorer, 399
prdidas de memoria, peligros, 397
bucles de referencia accidentales, 398
problema de prdidas de memoria de
Internet Explorer, 399
personalizados, selectores, 48
aplicar estilo a filas alternas, 48
numeracin
en base cero, 49
en base uno, 49
selectores de formulario, 51
plug-ins
compartir un plug-in con el mundo, 368
convenciones de nombrado, 369
estilo de documentacin, 370
interfaces de mtodo, 369
desarrollar,
aadir nuevas funciones globales, 345
aadir nuevos mtodos
abreviados, 356
aadir una expresin de selector, 366
compartir un plug-in
con el mundo, 368
mtodos transversales DOM, 353
parmetros de mtodo, 359
encontrar, 321
eventos de usuario,
hoverlntent,342
Live Query, 342
grficas
Flot, 341
Sparklines, 341

ndice alfabtico

imgenes
Jcrop, 337
Magnify, 337
librera de plug-ins jQuery DI, 325
Lightbox
BlockDI,340
FancyBox, 338
jqModal, 340
Thickbox, 339
tablas,
Flexigrid, 337
jqGrid,336
Tablesorter, 336
proyecto jQuery
fase de desarrollo pblico, 32
jQuery 1.1, 32
.'
jQuery 1.1.3, 32
jQuery 1.2, 32
jQuery 1.2.6, 33
jQuery 1.3, 33
jQuery DI, 32

jQuery
expresiones de selector, 403
mtodos f
AJAX, 413
de efecto, 409
de evento, 407
de manipulacin DOM, 410
transversales DOM, 405
.
variados, 414
l'
(X)HTML
pgina principal de W3C, 376
rotativos
aadir un indicador de carga, 289
configurar, 282
definicin, 276
detenerse al pasar por encima, 286
efecto degradado, 290
funcin rotar titular, 283
recuperar un feed de un dominio
diferente, 288
titular rotativo, 277

recursos online jQuery


blogs,377
compresor de cdigo JavaScript, 375
documentacin jQuery, 373
referencia CSS, 376 :
referencia JavaScript, 374
referencia
CSS
la chuleta CSS de Mezzoblue, 376
pgina principal CSS de W3C, 376
position is everything, 377
JavaScript
Centro de desarrollo Mozilla, 374
Dev.opera, 374
JavaScript Toolbox, 375
Quirksmode, 375
Referencia JScript MSDN, 375

.show), mtodo, 95
.show('fast'), mtodo, 96
.show('normal'), mtodo, 96
.show('slow'), mtodo, 96
Safari, herramientas
definicin, 385
inspector Web, 386
men Develop, 385
seguridad, limitaciones,
cargar datos remotos, 161
utilizar JSONP para datos remotos, 162
utilizar etiqueta HTML <iframe>, 162
selecto res .

cSS
aplicar estilo a niveles
de elementos de lista, 44
definicin, 43

EflI

de atributo
aplicar estilo a vnculos, 46
definicin, 46
personalizados
aplicar estilo a filas alternas, 48
definicin, 48
numeracin
en base
cero, 49
uno,49
selectores de formulario, 51
smbolos
$.ajax(options),413
$.ajaxSetup(options),413
$.each(collection, callback), 414
$.extend(target, addition, ..."),414
$.get(url, [data],[ callback],
[returnType]),413
$.getJSON(url, [data],[callback]), 413
$.getScript(url,[callback]),413
.
$.grep(array, callback,[invert]), 414
$.grep(array, callback,[invert]), 414
$.inArray(value, array), 414
$.inArray(value, array), 414
$.isFunction( object)
$.isFunction(object),414
$.makeArray(object),414
$.map(array, callback), 414
$.merge(arrayl, array2), 414
$.noConflict ([extreme]), 414
$.param(map),413
$.post(url, [data],[callback],
[returnType]),413
$.trim(string),414
$.trim(string),414
$.unique(array),414
$.unique(array),414
(X)HTML, referencia
.add(selector),406
.addClass(class),410
.after(content),412

mi

ndice alfabtico

ndice alfabtico

.ajaxComplete(handler),413
.ajaxComplete(handler),413
.ajaxError(handler),413
.ajaxSend(handler),413
.ajaxStart(handler),413
.ajaxStart(handler),413
.ajaxStop(handler), 413
.ajaxStop(handler), 413
.ajaxSuccess(handler),413
.ajaxSuccess(handler), 413
.andSelf0,406
.animate), mtodo, 98
.animate(attributes, [speed],
[easing],[ callback D, 410
.animate(attributes,options),41O
.append(content),412
.appendTo(selector),412
.attr(key),41O
.attr(key, fn), 410
.attr(key, value), 410
.attr(map),410
.before(content),412
.bind('load'), sintaxis, 314
.bind(type, [data],handler), 407
.blur0,408
.blur(handler),407
.changeO,408
.change(handler),407
.children([selectorD,406
.click0,408
.click(handler),407
.clone([withHandlersD,412
.closest selector, 406
.contents0,406
.css(key), 411
.css(key, value), 411
.css(map),411
.data(key), 412
.data(key, value), 412
.dblclickO, 409
.dblclick(handler),407

.dequeuer), 410
.die(type, [handler]), 407
.each(callback),414
.empty0,412
.end0,406
.eq(index),406
.errort), 409
.error(handler),407
.fadeIn([ speed ],[callback]), 409
.fadeOut( [speed],[ callback]), 409
.fadeTo(speed, opacity.] callback]), 410
.filter(callback),406
.filter( selector), 405
.find(selector),406
.focusO,409
.focus(handler),407
.getO,414
.get(index),414
.hasClass(class),410
.hasClass(className),414
.height0,411
.height(value),411
.hdet), 409
.hidet), mtodo, 83
.hide(speed,[callback]),409
.hover(enter,leave),408
.htmlt), 410
.htrnl(value),411
.index(element),414:
"
.innerHeight0,411
.innerWidth0,411
.insertAfter(selector),412
.insertBefore(selector),412
.is(selector),414
.keydowru), 409
.keydown(handler),407
.keypress), 409
.keypress(handler),407
.keyupt), 409
.keyup(handler),407
.length,414

.live(type, handler), 407


.load(handler); 408
.load(url, [dataj.lcallbackj), 413
.map(callback),406
.mousedown(handler),408
.mouseenter(handler),408
.mouseleave(handler),408
.mousemove(handler),
408
.mouseout(handler),408
,...mouseover(handler), 408
.mouseup(handler),408
.next([selector]),406
.nextAll([selectorD, 406 .
.not(selector),406
.offset0,411
.offsetParent0,406
.one(type, [data],handler), 407
.outerHeight (includeMargin), 411
.outerWidth (includeMargin), 412
.parent([selectorD,406
.parents([ selector D, 406
.positon.dl l
.prepend(content),412
.prependTo(selector),412
.prev([selectorD,406
.prev All( [selector D, 406
.queue), 410
.queue), mtodo, 105
.queue(callback),410
.queue(newQueue),410
.ready(handler),407,
.remove([selectorD,412
.removeAttr(key),410
.removeClass(class),410
.removeData(key), 412
.replaceAll(selector),412
.replaceWith(content),412
.resize(handler),408
.scroll(handler),408
.scrollLeft0,411
.scrollLeft(value), 411

ID

.scrollTop0,411
.scrollTop(value), 411
.select), 409
.select(handler),408
.serializef), 413
.serialize.Arrayl), 413
.show), 409
.showr). mtodo, 93
.show(speed,[callbackD,409
.siblings([selectorD,406
.slice(start, [endD, 406
.slideDown([speed ],[callback D, 409
.slideToggle([speed],[ callbackj), 409
.slideUp([speed],[callbackD,409
.stop([ clearQueue ],[jump ToEnd D, 410
.submit), 409
.submit(handler),408
.text0,411
.textvalue), 411
.toggle([speedl,[callbackD,409
.toggle(handler1,handler2,
...),408
.toggleClass( class), 410
.trigger(type, [data]), 408
.triggert), mtodo, 83
implementar degradacin, 83
mtodos abreviados, 84
pgina, contraer, 83
pgina, expandir, 83
.triggerHandler(type,[dataD,408
.unbind([type],[handler]),407
.unload(handler),408
.valO,411
.val(value),411
.width0,411
.width(value),411
.wrap), mtodo, 124
.wrap(content),412
.wrapAll(content),412
.wrapInner(content),412
W3C hypertext markup language,
pgina principal, 376

lEIlI

ndice alfabiico

tablas
apariencia
contraer secciones, 209
descripciones emergentes, 204
expandir secciones, 209
resaltar filas, 197
manipulacin
filtrado, 211
modificar apariencia de la tabla, 197
ordenacin JavaScript, 173
ordenar y paginar, 172
paginacin del lado del servidor, 186
paginacin JavaScript, 190
plug-ins
Flexigrid, 337
jqGrid,336
Tablesorter, 336
teclado, eventos de
.keyCode, propiedad, 84
aadir, 84
keydown,84
keypress, 84
keyup,84
TextMate jQuery, herramienta, 387
titular, rotativo
aadir un indicador de carga, 289
recuperar un feed de un dominio
diferente, 288

validacin de formulario, 231


campos, 231
obligatorios, 231
expresin regular, 235
formatos de entrada de datos, 234
formatos obligatorios, 231
regla, 231
tareas de cdigo, 235
ltima comprobacin, 231
validacin del lado del servidor, 231
velocidad y efectos
aparecer de forma paulatina, 96
aplicar velocidad, 95
,
desaparecer de forma paulatina, 96
Venkman, herramientas Firefox, 384

w
W3C,376
Wide Web Consortium,

(W3C), 376

x
XMLPath, lenguaje (XPath), 32

You might also like