Vous êtes sur la page 1sur 478

jQuery Cookbook

jQuery Cookbook
jQucry Community Expcrts
Beijing Cambridge Farnham Kln Sebastopol Taipei Tokyo
jQuery Cookbook
Ly jQueiy Community Expeits
Copyiight 2010 Couy Linuley. All iights ieseiveu.
Piinteu in the Uniteu States ol Ameiica.
PuLlisheu Ly O`Reilly Meuia, Inc., 1005 Giavenstein Highway Noith, SeLastopol, CA 95+72.
O`Reilly Looks may Le puichaseu loi euucational, Lusiness, oi sales piomotional use. Online euitions
aie also availaLle loi most titles (http://ny.sajariboo|son|inc.con). Foi moie inloimation, contact oui
coipoiate/institutional sales uepaitment: S00-99S-993S oi corporatcorci||y.con.
Editor: Simon St.Lauient
Production Editor: Saiah Schneiuei
Copyeditor: Kim Vimpsett
Proofreader: Anuiea Fox
Production Services: Molly Shaip
Indexer: Fieu Biown
Cover Designer: Kaien Montgomeiy
Interior Designer: Daviu Futato
Illustrator: RoLeit Romano
Printing History:
NovemLei 2009: Fiist Euition.
O`Reilly anu the O`Reilly logo aie iegisteieu tiauemaiks ol O`Reilly Meuia, Inc. jQucry Coo|boo|, the
image ol an eimine, anu ielateu tiaue uiess aie tiauemaiks ol O`Reilly Meuia, Inc.
Many ol the uesignations useu Ly manulactuieis anu selleis to uistinguish theii piouucts aie claimeu as
tiauemaiks. Vheie those uesignations appeai in this Look, anu O`Reilly Meuia, Inc. was awaie ol a
tiauemaik claim, the uesignations have Leen piinteu in caps oi initial caps.
Vhile eveiy piecaution has Leen taken in the piepaiation ol this Look, the puLlishei anu authoi assume
no iesponsiLility loi eiiois oi omissions, oi loi uamages iesulting liom the use ol the inloimation con-
taineu heiein.
TM
This Look uses RepKovei, a uuiaLle anu llexiLle lay-llat Linuing.
ISBN: 97S-0-596-15977-1
S
125777++09
Table of Contents
Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
1. jQuery Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Incluuing the jQueiy LiLiaiy Coue in an HTML Page 9
1.2 Executing jQueiy/]avaSciipt Coueu Altei the DOM Has Loaueu
Lut Beloie Complete Page Loau 10
1.3 Selecting DOM Elements Using Selectois anu the jQueiy Function 13
1.+ Selecting DOM Elements Vithin a Specilieu Context 15
1.5 Filteiing a Viappei Set ol DOM Elements 16
1.6 Finuing Descenuant Elements Vithin the Cuiiently Selecteu
Viappei Set 1S
1.7 Retuining to the Piioi Selection Beloie a Destiuctive Change 19
1.S Incluuing the Pievious Selection with the Cuiient Selection 20
1.9 Tiaveising the DOM Baseu on Youi Cuiient Context to Acguiie a
New Set ol DOM Elements 21
1.10 Cieating, Opeiating on, anu Inseiting DOM Elements 23
1.11 Removing DOM Elements 2+
1.12 Replacing DOM Elements 26
1.13 Cloning DOM Elements 27
1.1+ Getting, Setting, anu Removing DOM Element AttiiLutes 29
1.15 Getting anu Setting HTML Content 30
1.16 Getting anu Setting Text Content 31
1.17 Using the $ Alias Vithout Cieating GloLal Conllicts 32
2. Selecting Elements with jQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1 Selecting Chilu Elements Only 36
2.2 Selecting Specilic SiLlings 37
v
2.3 Selecting Elements Ly Inuex Oiuei 39
2.+ Selecting Elements That Aie Cuiiently Animating +1
2.5 Selecting Elements Baseu on Vhat They Contain +2
2.6 Selecting Elements Ly Vhat They Don`t Match +3
2.7 Selecting Elements Baseu on Theii VisiLility +3
2.S Selecting Elements Baseu on AttiiLutes ++
2.9 Selecting Foim Elements Ly Type +6
2.10 Selecting an Element with Specilic Chaiacteiistics +7
2.11 Using the Context Paiametei +S
2.12 Cieating a Custom Filtei Selectoi 50
3. Beyond the Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.1 Looping Thiough a Set ol Selecteu Results 53
3.2 Reuucing the Selection Set to a Specilieu Item 56
3.3 Conveit a Selecteu jQueiy OLject into a Raw DOM OLject 59
3.+ Getting the Inuex ol an Item in a Selection 62
3.5 Making a Unigue Aiiay ol Values liom an Existing Aiiay 6+
3.6 Peiloiming an Action on a SuLset ol the Selecteu Set 67
3.7 Conliguiing jQueiy Not to Conllict with Othei LiLiaiies 69
3.S Auuing Functionality with Plugins 72
3.9 Deteimining the Exact Queiy That Vas Useu 7+
4. jQuery Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
+.1 Detecting Featuies with jQueiy.suppoit 77
+.2 Iteiating Ovei Aiiays anu OLjects with jQueiy.each 79
+.3 Filteiing Aiiays with jQueiy.giep S0
+.+ Iteiating anu Mouilying Aiiay Entiies with jQueiy.map S1
+.5 ComLining Two Aiiays with jQueiy.meige S1
+.6 Filteiing Out Duplicate Aiiay Entiies with jQueiy.unigue S2
+.7 Testing CallLack Functions with jQueiy.isFunction S2
+.S Removing Vhitespace liom Stiings oi Foim Values with
jQueiy.tiim S3
+.9 Attaching OLjects anu Data to DOM with jQueiy.uata S+
+.10 Extenuing OLjects with jQueiy.extenu S5
5. Faster, Simpler, More Fun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.1 That`s Not jQueiy, It`s ]avaSciipt! S7
5.2 Vhat`s Viong with $(this)? SS
5.3 Removing Reuunuant Repetition 91
5.+ Foimatting Youi jQueiy Chains 92
5.5 Boiiowing Coue liom Othei LiLiaiies 9+
5.6 Viiting a Custom Iteiatoi 96
5.7 Toggling an AttiiLute 99
vi | Table of Contents
5.S Finuing the Bottlenecks 101
5.9 Caching Youi jQueiy OLjects 105
5.10 Viiting Fastei Selectois 107
5.11 Loauing TaLles Fastei 109
5.12 Couing Baie-Metal Loops 112
5.13 Reuucing Name Lookups 115
5.1+ Upuating the DOM Fastei with .inneiHTML 117
5.15 DeLugging? Bieak Those Chains 11S
5.16 Is It a jQueiy Bug? 120
5.17 Tiacing into jQueiy 121
5.1S Making Fewei Seivei Reguests 123
5.19 Viiting UnoLtiusive ]avaSciipt 126
5.20 Using jQueiy loi Piogiessive Enhancement 12S
5.21 Making Youi Pages AccessiLle 130
6. Dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
6.1 Finuing the Dimensions ol the Vinuow anu Document 135
6.2 Finuing the Dimensions ol an Element 137
6.3 Finuing the Ollset ol an Element 139
6.+ Sciolling an Element into View 1+1
6.5 Deteimining Vhethei an Element Is Vithin the Viewpoit 1+3
6.6 Centeiing an Element Vithin the Viewpoit 1+6
6.7 ALsolutely Positioning an Element at Its Cuiient Position 1+7
6.S Positioning an Element Relative to Anothei Element 1+7
6.9 Switching Stylesheets Baseu on Biowsei Viuth 1+S
7. Effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
7.1 Sliuing anu Fauing Elements in anu out ol View 153
7.2 Making Elements VisiLle Ly Sliuing Them Up 156
7.3 Cieating a Hoiizontal Accoiuion 157
7.+ Simultaneously Sliuing anu Fauing Elements 161
7.5 Applying Seguential Ellects 162
7.6 Deteimining Vhethei Elements Aie Cuiiently Being Animateu 16+
7.7 Stopping anu Resetting Animations 165
7.S Using Custom Easing Methous loi Ellects 166
7.9 DisaLling All Ellects 16S
7.10 Using jQueiy UI loi Auvanceu Ellects 16S
8. Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
S.1 Attaching a Hanulei to Many Events 172
S.2 Reusing a Hanulei Function with Dilleient Data 173
S.3 Removing a Vhole Set ol Event Hanuleis 175
S.+ Tiiggeiing Specilic Event Hanuleis 176
Table of Contents | vii
S.5 Passing Dynamic Data to Event Hanuleis 177
S.6 Accessing an Element ASAP (Beloie uocument.ieauy) 179
S.7 Stopping the Hanulei Execution Loop 1S2
S.S Getting the Coiiect Element Vhen Using event.taiget 1S+
S.9 Avoiu Multiple hovei() Animations in Paiallel 1S5
S.10 Making Event Hanuleis Voik loi Newly Auueu Elements 1S7
9. Advanced Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
9.1 Getting jQueiy to Voik Vhen Loaueu Dynamically 191
9.2 Speeuing Up GloLal Event Tiiggeiing 192
9.3 Cieating Youi Own Events 195
9.+ Letting Event Hanuleis Pioviue Neeueu Data 19S
9.5 Cieating Event-Diiven Plugins 201
9.6 Getting Notilieu Vhen jQueiy Methous Aie Calleu 205
9.7 Using OLjects` Methous as Event Listeneis 20S
10. HTML Form Enhancements from Scratch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
10.1 Focusing a Text Input on Page Loau 212
10.2 DisaLling anu EnaLling Foim Elements 213
10.3 Selecting Rauio Buttons Automatically 216
10.+ (De)selecting All CheckLoxes Using Deuicateu Links 21S
10.5 (De)selecting All CheckLoxes Using a Single Toggle 219
10.6 Auuing anu Removing Select Options 221
10.7 AutotaLLing Baseu on Chaiactei Count 222
10.S Displaying Remaining Chaiactei Count 22+
10.9 Constiaining Text Input to Specilic Chaiacteis 226
10.10 SuLmitting a Foim Using Ajax 22S
10.11 Valiuating Foims 229
11. HTML Form Enhancements with Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
11.1 Valiuating Foims 23S
11.2 Cieating Maskeu Input Fielus 2+7
11.3 Autocompleting Text Fielus 2+9
11.+ Selecting a Range ol Values 250
11.5 Enteiing a Range-Constiaineu Value 253
11.6 Uploauing Files in the Backgiounu 255
11.7 Limiting the Length ol Text Inputs 256
11.S Displaying LaLels ALove Input Fielus 257
11.9 Giowing an Input with Its Content 259
11.10 Choosing a Date 260
12. jQuery Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
12.1 Vheie Do You Finu jQueiy Plugins? 263
viii | Table of Contents
12.2 Vhen Shoulu You Viite a jQueiy Plugin? 265
12.3 Viiting Youi Fiist jQueiy Plugin 267
12.+ Passing Options into Youi Plugin 26S
12.5 Using the $ Shoitcut in Youi Plugin 270
12.6 Incluuing Piivate Functions in Youi Plugin 272
12.7 Suppoiting the Metauata Plugin 273
12.S Auuing a Static Function to Youi Plugin 275
12.9 Unit Testing Youi Plugin with QUnit 277
13. Interface Components from Scratch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
13.1 Cieating Custom Tool Tips 2S0
13.2 Navigating with a File-Tiee Expanuei 2S5
13.3 Expanuing an Accoiuion 2SS
13.+ TaLLing Thiough a Document 293
13.5 Displaying a Simple Moual Vinuow 296
13.6 Builuing Diop-Down Menus 303
13.7 Cioss-Fauing Rotating Images 305
13.S Sliuing Panels 310
14. User Interfaces with jQuery UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
1+.1 Incluuing the Entiie jQueiy UI Suite 317
1+.2 Incluuing an Inuiviuual jQueiy UI Plugin oi Two 31S
1+.3 Initializing a jQueiy UI Plugin with Delault Options 319
1+.+ Initializing a jQueiy UI Plugin with Custom Options 320
1+.5 Cieating Youi Veiy Own jQueiy UI Plugin Delaults 321
1+.6 Getting anu Setting jQueiy UI Plugin Options 323
1+.7 Calling jQueiy UI Plugin Methous 323
1+.S Hanuling jQueiy UI Plugin Events 32+
1+.9 Destioying a jQueiy UI Plugin 326
1+.10 Cieating a jQueiy UI Music Playei 327
15. jQuery UI Theming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
15.1 Styling jQueiy UI Viugets with ThemeRollei 3+5
15.2 Oveiiiuing jQueiy UI Layout anu Theme Styles 360
15.3 Applying a Theme to Non-jQueiy UI Components 370
15.+ Releiencing Multiple Themes on a Single Page 379
15.5 Appenuix: Auuitional CSS Resouices 3SS
16. jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP . . . . . . . . . . . . . . . . . . . . . . . 391
16.1 jQueiy anu Ajax 391
16.2 Using Ajax on Youi Vhole Site 39+
16.3 Using Simple Ajax with Usei FeeuLack 396
16.+ Using Ajax Shoitcuts anu Data Types +00
Table of Contents | ix
16.5 Using HTML Fiagments anu jQueiy +03
16.6 Conveiting XML to DOM +0+
16.7 Cieating ]SON +05
16.S Paising ]SON +06
16.9 Using jQueiy anu ]SONP +07
17. Using jQuery in Large Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
17.1 Using Client-Siue Stoiage +11
17.2 Saving Application State loi a Single Session +1+
17.3 Saving Application State Between Sessions +16
17.+ Using a ]avaSciipt Template Engine +17
17.5 Queuing Ajax Reguests +20
17.6 Dealing with Ajax anu the Back Button +22
17.7 Putting ]avaSciipt at the Enu ol a Page +23
18. Unit Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
1S.1 Automating Unit Testing +25
1S.2 Asseiting Results +27
1S.3 Testing Synchionous CallLacks +29
1S.+ Testing Asynchionous CallLacks +29
1S.5 Testing Usei Actions +31
1S.6 Keeping Tests Atomic +32
1S.7 Giouping Tests +33
1S.S Selecting Tests to Run +3+
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
x | Table of Contents
Foreword
Vhen I liist staiteu woik on Luiluing jQueiy, Lack in 2005, I hau a simple goal in minu:
I wanteu to Le aLle to wiite a weL application anu have it woik in all the majoi
Liowseiswithout luithei tinkeiing anu Lug lixing. It was a couple ol months Leloie
I hau a set ol utilities that weie staLle enough to achieve that goal loi my peisonal use.
I thought I was ielatively uone at this point; little uiu I know that my woik was just
Leginning.
Since those simple Leginnings, jQueiy has giown anu auapteu as new useis use the
liLiaiy loi theii piojects. This has pioven to Le the most challenging pait ol ueveloping
a ]avaSciipt liLiaiy; while it is guite easy to Luilu a liLiaiy that`ll woik loi youisell oi
a specilic application, it Lecomes incieuiLly challenging to uevelop a liLiaiy that`ll woik
in as many enviionments as possiLle (olu Liowseis, legacy weL pages, anu stiange
maikup aLounu). Suipiisingly, even as jQueiy has auapteu to hanule moie use cases,
most ol the oiiginal API has stayeu intact.
One thing I linu paiticulaily inteiesting is to see how uevelopeis use jQueiy anu make
it theii own. As someone with a Lackgiounu in computei science, I linu it guite sui-
piising that so many uesigneis anu nonpiogiammeis linu jQueiy to Le compelling.
Seeing how they inteiact with the liLiaiy has given me a Lettei appieciation ol simple
API uesign. Auuitionally, seeing many auvanceu piogiammeis take jQueiy anu uevelop
laige, complex applications with it has Leen guite illuminating. The Lest pait ol all ol
this, though, is the aLility to leain liom eveiyone who uses the liLiaiy.
A siue Lenelit ol using jQueiy is its extensiLle plugin stiuctuie. Vhen I liist uevelopeu
jQueiy, I was suie to incluue some simple ways loi uevelopeis to extenu the API that
it pioviueu. This has Llossomeu into a laige anu vaiieu community ol plugins, encom-
passing a whole ecosystem ol applications, uevelopeis, anu use cases. Much ol jQueiy`s
giowth has Leen lueleu Ly this communitywithout it, the liLiaiy woulun`t Le wheie
it is touay, so I`m glau that theie aie chapteis ueuicateu to some ol the most inteiesting
plugins anu what you can uo with them. One ol the Lest ways to expanu youi piecon-
ceiveu notion ol what you can uo with jQueiy is to leain anu use coue liom the jQueiy
plugin community.
xi
This is laigely what makes something like a cookLook so inteiesting: it takes the cool
things that uevelopeis have uone, anu have leaineu, in theii uay-to-uay couing anu
uistills it to Lite-sizeu chunks loi latei consumption. Peisonally, I linu a cookLook to
Le one ol the Lest ways to challenge my pieconceiveu notions ol a language oi liLiaiy.
I love seeing cases wheie an API that I thought I knew well is tuineu aiounu anu useu
in new anu inteiesting ways. I hope this Look is aLle to seive you well, teaching you
new anu inteiesting ways to use jQueiy.
]ohn Resig
Cieatoi, Leau Developei, jQueiy
xii | Foreword
Contributors
Chapter Authors
-RQDWKDQ6KDUS has Leen passionate aLout the Inteinet anu weL uevelopment since
1996. Ovei the yeais that have lolloweu, he has woikeu loi staitups anu loi Foitune
500 coipoiations. ]onathan lounueu Out Vest Meuia, LLC, in gieatei Omaha, Ne-
Liaska, anu pioviues liontenu engineeiing anu aichitectuie seivices with a locus on
custom XHTML, CSS, anu jQueiy uevelopment. ]onathan is a jQueiy coie team mem-
Lei anu an authoi anu piesentei when not couing. ]onathan is most giatelul loi his
wile, Eiin; uaughtei, Noel; two uogs, anu two hoises.
5RE%XUQV uevelops inteiactive weL applications at A Mountain Top, LLC. Foi the
past 12 yeais he has Leen exploiing weLsite uevelopment using a wiue iange ol tools
anu technologies. In his spaie time, he enjoys natuial-language piocessing anu the
wealth ol oppoitunity in open souice soltwaie piojects.
5HEHFFD0XUSKH\ is an inuepenuent liontenu aichitectuie consultant, cialting cus-
tom liontenu solutions that seive as the glue Letween seivei anu Liowsei. She also
pioviues tiaining in liontenu uevelopment, with an emphasis on the jQueiy liLiaiy.
She lives with hei paitnei, two uogs, anu two cats in Duiham, Noith Caiolina.
$ULHO)OHVOHU is a weL uevelopei anu a viueo game piogiammei. He`s Leen contiiLuting
to jQueiy since ]anuaiy 2007 anu joineu the coie team in May 200S. He is 23 yeais olu
anu was Loin in Buenos Aiies, Aigentina. He`s stuuying at the National Technological
Univeisity (Aigentina) anu is hoping to Lecome a systems analyst Ly 2010 anu a systems
engineei Ly 2012. He staiteu woiking as an ASP.NET(C=) piogiammei anu then
switcheu to client-siue uevelopment ol XHTML sites anu Ajax applications. He`s cui-
iently woiking at QB9 wheie he uevelops AS3-Laseu casual games anu MMOs.
&RG\/LQGOH\ is a Chiistian, husLanu, son, lathei, Liothei, outuooi enthusiast, anu
piolessional client-siue engineei. Since 1997 he has Leen passionate aLout HTML, CSS,
]avaSciipt, Flash, inteiaction uesign, inteilace uesign, anu HCI. He is most well known
in the jQueiy community loi the cieation ol ThickBox, a moual/uialog solution. In
200S he ollicially joineu the jQueiy team as an evangelist. His cuiient locus has Leen
xiii
on client-siue optimization technigues as well as speaking anu wiiting aLout jQueiy.
His weLsite is http://www.cody|ind|cy.con.
5HP\6KDUS is a uevelopei, authoi, speakei, anu Lloggei. Remy staiteu his piolessional
weL uevelopment caieei in 1999 as the sole uevelopei loi a linance weLsite anu, as
such, was exposeu to all aspects ol iunning the weLsite uuiing, anu long altei, the
uotcom Loom. Touay he iuns his own uevelopment company calleu Lelt Logic in
Biighton, UK, wiiting anu couing ]avaSciipt, jQueiy, HTML 5, CSS, PHP, Peil, anu
anything else he can get his hanus on.
0LNH+RVWHWOHU is an inventoi, entiepieneui, piogiammei, anu piouu lathei. Having
woikeu with weL technologies since the miu-1990s, Mike has hau extensive expeiience
ueveloping weL applications with PHP anu ]avaSciipt. Cuiiently, Mike woiks at the
helm ol A Mountain Top, LLC, a weL technology consulting liim in Denvei, Coloiauo.
Heavily involveu in open souice, Mike is a memLei ol the jQueiy coie team, leaus the
QCuLeu PHP5 Fiamewoik pioject, anu paiticipates in the Diupal pioject. Vhen not
in liont ol a computei, Mike enjoys hiking, lly lishing, snowLoaiuing, anu spenuing
time with his lamily.
5DOSK:KLWEHFN is a giauuate ol the Rochestei Institute ol Technology anu is cuiiently
a senioi uevelopei loi BianuLogic Coipoiation in Rochestei, New Yoik. His iespon-
siLilities at BianuLogic incluue inteilace uesign, usaLility testing, anu weL anu appli-
cation uevelopment. Ralph is aLle to piogiam complex weL application systems in
ASP.NET, C=, anu SQL Seivei anu also uses client-siue technologies such as XHTML,
CSS, anu ]avaSciipt/jQueiy in oiuei to implement client-appioveu uesigns. Ralph ol-
licially joineu the jQueiy team as an evangelist in OctoLei 2009. Ralph enjoys spenuing
time with his wile, Hope, anu his thiee Loys, Bianuon, ]oiuan, anu Ralphie. You can
linu out moie aLout Ralph on his peisonal Llog.
1DWKDQ6PLWK is a gooly guy who has Leen Luiluing weLsites since late last centuiy.
He enjoys hanu-couing HTML, CSS, anu ]avaSciipt. He also uaLLles in uesign anu
inloimation aichitectuie. He has wiitten loi online anu papei puLlications such as
AuoLe Developei Centei, Digital VeL, anu .NET Magazine. He has spoken at venues
incluuing AuoLe MAX, BiLleTech, Diupal Camp, Echo Conleience, Ministiy 2.0, Re-
liesh Dallas, anu VeLmastei ]am Session. Nathan woiks as a UX uevelopei at Fellow-
shipTech.com. He holus a Mastei ol Divinity uegiee liom AsLuiy Theological Semi-
naiy. He staiteu GouLit.com, a community iesouice aimeu at helping chuiches anu
ministiies make Lettei use ol the VeL. He also cieateu the 960 Giiu System, a liame-
woik loi sketching, uesigning, anu couing page layouts.
%ULDQ &KHUQH is a soltwaie uevelopei with moie than a uecaue ol expeiience Llue-
piinting anu Luiluing weL-Laseu applications, kiosks, anu high-tiallic e-commeice
weLsites. He is also the authoi ol the hoveiIntent jQueiy plugin. Vhen not geeking
out with coue, Biian can Le lounu Lallioom uancing, piacticing maitial aits, oi stuuying
Russian cultuie anu language.
xiv | Contributors
-|UQ=DHIIHUHU is a piolessional soltwaie uevelopei liom Cologne, Geimany. He cie-
ates application piogiamming inteilaces (APIs), giaphical usei inteilaces (GUIs), solt-
waie aichitectuies, anu uataLases, loi Loth weL anu uesktop applications. His woik
locuses on the ]ava platloim, while his client-siue sciipting ievolves aiounu jQueiy.
He staiteu contiiLuting to jQueiy in miu-2006 anu has since cocieateu anu maintaineu
QUnit, jQueiy`s unit testing liamewoik; ieleaseu anu maintaineu a hall uozen veiy
populai jQueiy plugins; anu contiiLuteu to jQueiy Looks as Loth authoi anu tech
ieviewei. He is also a leau uevelopei loi jQueiy UI.
-DPHV3DGROVH\ is an enthusiastic weL uevelopei anu Lloggei Laseu in Lonuon, UK.
He`s Leen ciazy aLout jQueiy since he liist uiscoveieu it; he`s wiitten tutoiials teaching
it, aiticles anu Llog posts uiscussing it, anu plenty ol plugins loi the community. ]ames`
plans loi the lutuie incluue a computei science uegiee liom the Univeisity ol Kent anu
a caieei that allows him to continually push Lounuaiies. His weLsite is http://jancs
.pado|scy.con.
6FRWW*RQ]iOH] is a weL application uevelopei living in Raleigh, Noith Caiolina, who
enjoys Luiluing highly uynamic systems anu llexiLle, scalaLle liamewoiks. He has Leen
contiiLuting to jQueiy since 2007 anu is cuiiently the uevelopment leau loi jQueiy UI,
jQueiy`s ollicial usei inteilace liLiaiy. Scott also wiites tutoiials aLout jQueiy anu
jQueiy UI on nemikoi.com anu speaks aLout jQueiy at conleiences.
0LFKDHO*HDU\ staiteu ueveloping soltwaie when euiting coue meant punching a papei
tape on a Teletype machine, anu stanuaius-compliant meant lollowing ECMA-10
Stanuaiu loi Data Inteichange on Puncheu Tape. Touay Mike is a weL anu Anuioiu
uevelopei with a paiticulai inteiest in wiiting last, clean, anu simple coue, anu he enjoys
helping othei uevelopeis on the jQueiy mailing lists. Mike`s iecent piojects incluue a
seiies ol 200S election iesult anu votei inloimation maps loi Google; anu StiataLogic,
a mashup ol tiauitional classioom wall maps anu atlases oveilaiu on Google Eaith. His
weLsite is http://ng.to.
0DJJLH:DFKV, 6FRWW-HKO, 7RGG3DUNHU, anu 3DWW\7RODQG aie Filament Gioup.
Togethei, they uesign anu uevelop highly lunctional usei inteilaces loi consumei- anu
Lusiness-oiienteu weLsites, wiieless uevices, anu installeu anu weL-Laseu applications,
with a specilic locus on ueliveiing intuitive anu usaLle expeiiences that aie also Lioauly
accessiLle. They aie sponsoi anu uesign leaus ol the jQueiy UI team, loi whom they
uesigneu anu uevelopeu ThemeRollei.com, anu they actively contiiLute to ongoing
uevelopment ol the ollicial jQueiy UI liLiaiy anu CSS Fiamewoik.
5LFKDUG':RUWK is a weL UI uevelopei. He is the ielease managei loi jQueiy UI anu
one ol its longest-contiiLuting uevelopeis. He is authoi oi coauthoi ol the Dialog,
PiogiessLai, SelectaLle, anu Sliuei plugins. Richaiu also enjoys speaking anu consulting
on jQueiy anu jQueiy UI aiounu the woilu. Richaiu is iaising a giowing lamily in
Noithein Viiginia (Vashington, D.C. suLuiLs) with his lovely wile, Nancy. They have
Leen Llesseu to uate with thiee Leautilul chiluien: Naomi, Ashei, anu Isaiah.
Richaiu`s weLsite is http://rdworth.org/.
Contributors | xv
Tech Editors
.DUO6ZHGEHUJ, altei having taught high school English, euiteu copy loi an auveitising
agency, anu owneu a collee house, Legan his caieei as a weL uevelopei loui yeais ago.
He now woiks loi Fusionaiy Meuia in Gianu Rapius, Michigan, wheie he specializes
in client-siue sciipting anu inteiaction uesign. Kail is a memLei ol the jQueiy pioject
team anu coauthoi ol Lcarning jQucry 1.3 anu jQucry Rcjcrcncc Guidc (Loth puLlisheu
Ly Packt). You can linu some ol his tips anu tutoiials at http://www.|carningjqucry.con.
'DYH0HWKYLQ is the chiel technology ollicei at PCPitstop.com anu one ol the lounuing
paitneis ol the company. He has Leen using jQueiy since 2006, is active on the jQueiy
help gioups, anu has contiiLuteu seveial populai jQueiy plugins incluuing Coinei anu
Splittei. Beloie joining PC Pitstop, Dave seiveu as executive euitoi at Loth PC Tcch
journa| anu Windows Magazinc, wheie he wiote a column on ]avaSciipt. He continues
to wiite loi seveial PC-ielateu weLsites incluuing InloimationVeek. Dave holus Lach-
eloi`s anu mastei`s uegiees in computei science liom the Univeisity ol Viiginia.
'DYLG6HUGXNH is a liontenu piogiammei who is iecently spenuing much ol his time
seivei siue. Altei piogiamming loi many yeais, he staiteu using jQueiy in late 2007
anu shoitly altei joineu the jQueiy coie team. Daviu is cuiiently cieating weLsites loi
linancial institutions anu Liinging the Lenelits ol jQueiy to ASP.NET enteipiise ap-
plications. Daviu lives in noithein Caliloinia wheie he ieceiveu a Lacheloi`s uegiee
liom the Univeisity ol Caliloinia at Beikeley in electiical engineeiing anu an MBA liom
St. Maiy`s College.
6FRWW0DUN is an enteipiise application aichitect at Meutionic. He woiks on weL-Laseu
peisonalizeu inloimation poitals anu tiansactional applications with an eye towaiu
maintaining high usaLility in a iegulateu enviionment. His key inteiest aieas at the
moment aie iich Inteinet applications anu multitouch usei inteilace technologies. Scott
lives in Minnesota with his lovely wile, two sons, anu a Llack laL. He Llogs aLout
technology at http://scottnar|.wordprcss.con anu long-uistance tiail iunning at http://
run|i|cnon|cy.con.
xvi | Contributors
Preface
The jQueiy liLiaiy has taken the liontenu uevelopment woilu Ly stoim. Its ueau-simple
syntax makes once-complicateu tasks uowniight tiivialenjoyaLle, even. Many a ue-
velopei has Leen guickly seuuceu Ly its elegance anu claiity. Il you`ve staiteu using the
liLiaiy, you`ie alieauy auuing iich, inteiactive expeiiences to youi piojects.
Getting staiteu is easy, Lut as is the case with many ol the tools we use to uevelop
weLsites, it can take months oi even yeais to lully appieciate the Lieauth anu uepth ol
the jQueiy liLiaiy. The liLiaiy is chock-lull ol leatuies you might nevei have known to
wish loi. Once you know aLout them, they can uiamatically change how you appioach
the pioLlems you`ie calleu upon to solve.
The goal ol this cookLook is to expose you, ueai ieauei, to the patteins anu piactices
ol some ol the leauing liontenu uevelopeis who use jQueiy in theii eveiyuay piojects.
Ovei the couise ol 1S chapteis, they`ll guiue you thiough solutions to pioLlems that
iange liom stiaightloiwaiu to complex. Vhethei you`ie a jQueiy newcomei oi a giiz-
zleu ]avaSciipt veteian, you`ie likely to gain new insight into hainessing the lull powei
ol jQueiy to cieate compelling, ioLust, high-peiloimance usei inteilaces.
Who This Book Is For
MayLe you`ie a uesignei who is intiigueu Ly the inteiactivity that jQueiy can pioviue.
MayLe you`ie a liontenu uevelopei who has woikeu with jQueiy Leloie anu wants to
see how othei people accomplish common tasks. MayLe you`ie a seivei-siue uevelopei
who`s lieguently calleu upon to wiite client-siue coue.
Tiuth Le tolu, this cookLook will Le valuaLle to anyone who woiks with jQueiyoi
who hopes to woik with jQueiy. Il you`ie just staiting out with the liLiaiy, you may
want to consiuei paiiing this Look with Lcarning jQucry 1.3 liom Packt, oi jQucry in
Action liom Manning. Il you`ie alieauy using jQueiy in youi piojects, this Look will
seive to enhance youi knowleuge ol the liLiaiy`s leatuies, hiuuen gems, anu
iuiosynciasies.
xvii
What Youll Learn
Ve`ll stait out Ly coveiing the Lasics anu geneial Lest piacticesincluuing jQueiy in
youi page, making selections, anu tiaveising anu manipulation. Even lieguent jQueiy
useis aie likely to pick up a tip oi two. Fiom theie, we move on to ieal-woilu use cases,
walking you thiough tiieu-anu-tiue (anu testeu) solutions to lieguent pioLlems
involving events, ellects, uimensions, loims, anu usei inteilace elements (with anu
without the help ol jQueiy UI). At the enu, we`ll take a look at testing youi jQueiy
applications anu integiating jQueiy into complex sites.
Along the way, you`ll leain stiategies loi leveiaging jQueiy to solve pioLlems that go
lai Leyonu the Lasics. Ve`ll exploie how to make the most ol jQueiy`s event manage-
ment system, incluuing custom events anu custom event uata; how to piogiessively
enhance loims; how to position anu ieposition elements on the page; how to cieate
usei inteilace elements such as taLs, accoiuions, anu mouals liom sciatch; how to cialt
youi coue loi ieauaLility anu maintainaLility; how to optimize youi coue to ease testing,
eliminate Lottlenecks, anu ensuie peak peiloimance; anu moie.
Because this is a cookLook anu not a manual, you`ie ol couise welcome to cheiiy-pick
the iecipes you ieau; the inuiviuual iecipes alone aie woith the piice ol aumission. As
a whole, though, the Look pioviues a iaie glimpse into the pioLlem-solving appioaches
ol some ol the Lest anu Liightest in the jQueiy community. Vith that in minu, we
encouiage you to at least skim it liom liont to Lackyou nevei know which line ol
coue will pioviue the Aha! moment you neeu to take youi skills to the next level.
jQuery Style and Conventions
jQueiy places a heavy emphasis on chainingcalling methous on element selections
in seguence, conliuent in the knowleuge that each methou will give you Lack a selection
ol elements you can continue to woik with. This pattein is explaineu in uepth in
Chaptei 1il you`ie new to the liLiaiy, you`ll want to unueistanu this concept, Lecause
it is useu heavily in suLseguent chapteis.
jQueiy`s leatuies aie oiganizeu into a hanulul ol simple categoiies: coie lunctionality,
selecting, manipulating, tiaveising, CSS, attiiLutes, events, ellects, Ajax, anu utilities.
Leaining these categoiies, anu how methous lit into them, will gieatly enhance youi
unueistanuing ol the mateiial in this Look.
One ol the Lest piactices this Look will covei is the concept ol stoiing element selections
in a vaiiaLle, iathei than making the same selection iepeateuly. Vhen a selection is
stoieu in a vaiiaLle, it is commonplace loi that vaiiaLle to Legin with the $ chaiactei,
inuicating that it is a jQueiy oLject. This can make coue easiei to ieau anu maintain,
Lut it shoulu Le unueistoou that staiting the vaiiaLle name with the $ chaiactei is meiely
a convention; it caiiies no special meaning, unlike in othei languages such as PHP.
xviii | Preface
In geneial, the coue examples in this Look stiive loi claiity anu ieauaLility ovei com-
pactness, so the examples may Le moie veiLose than is stiictly necessaiy. Il you see an
oppoitunity loi optimization, you shoulu not hesitate to take it. At the same time, you`ll
uo well to stiive loi claiity anu ieauaLility in youi own coue anu use minilication tools
to piepaie youi coue loi piouuction use.
Other Options
Il you`ie looking loi othei jQueiy iesouices, heie aie some we iecommenu:
Lcarning jQucry 1.3, Ly ]onathan Challei, Kail SweuLeig, anu ]ohn Resig (Packt)
jQucry in Action, Ly Beai BiLeault, Yehuua Katz, anu ]ohn Resig (Manning)
jQucry U| 1.: Thc Uscr |ntcrjacc Library jor jQucry, Ly Dan Vellman (Packt)
If You Have Problems Making Examples Work
Beloie you check anything else, ensuie that you aie loauing the jQueiy liLiaiy on the
pageyou`u Le suipiiseu how many times this is the solution to the It`s not woiking!
pioLlem. Il you aie using jQueiy with anothei ]avaSciipt liLiaiy, you may neeu to use
jQuery.noConflict() to make it play well with otheis. Il you`ie loauing sciipts that
ieguiie the piesence ol jQueiy, make suie you aie loauing them altei you`ve loaueu the
jQueiy liLiaiy.
Much ol the coue in this Look ieguiies the uocument to Le ieauy Leloie ]avaSciipt
can inteiact with it. Il you`ve incluueu coue in the heau ol the uocument, make suie
youi coue is encloseu in $(document).ready(function() { ... }); so that it knows to
wait until the uocument is ieauy loi inteiaction.
Some ol the leatuies uiscusseu in this Look aie availaLle only in jQueiy 1.3 anu latei.
Il you aie upgiauing liom an oluei veision ol jQueiy, make suie you`ve upgiaueu any
plugins you`ie using as welloutuateu plugins can leau to unpieuictaLle Lehavioi.
Il you`ie having uilliculty getting an example to woik in an existing application, make
suie you can get the example woiking on its own Leloie tiying to integiate it with youi
existing coue. Il that woiks, tools such as FiieLug loi the Fiielox Liowsei can Le uselul
in iuentilying the souice ol the pioLlem.
Il you`ie incluuing a minilieu veision ol jQueiy anu iunning into eiiois that point to
the jQueiy liLiaiy itsell, you may want to consiuei switching to the lull veision ol
jQueiy while you aie ueLugging the issue. You`ll have a much easiei time locating the
line that is causing you tiouLle, which will olten leau you in the uiiection ol a solution.
Il you`ie still stuck, consiuei posting youi guestion to the jQueiy Google gioup. Many
ol this Look`s authois aie iegulai paiticipants in the gioup, anu moie olten than not,
someone in the gioup will Le aLle to ollei uselul auvice. The #jquery IRC channel on
Fieenoue is anothei valuaLle iesouice loi tiouLleshooting issues.
Preface | xix
Il none ol this woiks, it`s possiLle we maue a mistake. Ve woikeu haiu to test anu
ieview all ol the coue in the Look, Lut eiiois uo cieep thiough. Check the eiiata (ue-
sciiLeu in the next section) anu uownloau the sample coue, which will Le upuateu to
auuiess any eiiata we uiscovei.
If You Like (or Dont Like) This Book
Il you likeoi uon`t likethis Look, Ly all means, please let people know. Amazon
ieviews aie one populai way to shaie youi happiness (oi lack ol happiness), oi you can
leave ieviews at the site loi the Look:
http://orci||y.con/cata|og/978059159771/
Theie`s also a link to eiiata theie. Eiiata gives ieaueis a way to let us know aLout typos,
eiiois, anu othei pioLlems with the Look. That eiiata will Le visiLle on the page im-
meuiately, anu we`ll conliim it altei checking it out. O`Reilly can also lix eiiata in lutuie
piintings ol the Look anu on Salaii, making loi a Lettei ieauei expeiience pietty guickly.
Ve hope to keep this Look upuateu loi lutuie veisions ol jQueiy, anu will also incoi-
poiate suggestions anu complaints into lutuie euitions.
Conventions Used in This Book
The lollowing typogiaphical conventions aie useu in this Look:
|ta|ic
Inuicates Inteinet auuiesses, such as uomain names anu URLs, anu new items
wheie they aie uelineu.
Constant width
Inuicates commanu lines anu options that shoulu Le typeu veiLatim; names anu
keywoius in piogiams, incluuing methou names, vaiiaLle names, anu class names;
anu HTML element tags, switches, attiiLutes, keys, lunctions, types, namespaces,
mouules, piopeities, paiameteis, values, oLjects, events, event hanuleis, macios,
the contents ol liles, oi the output liom commanus.
Constant width bold
Inuicates emphasis in piogiam coue lines.
Constant width italic
Inuicates text that shoulu Le ieplaceu with usei-supplieu values.
This icon signilies a tip, suggestion, oi geneial note.
xx | Preface
This icon inuicates a waining oi caution.
Using Code Examples
This Look is heie to help you get youi joL uone. In geneial, you may use the coue in
this Look in youi piogiams anu uocumentation. You uo not neeu to contact us loi
peimission unless you`ie iepiouucing a signilicant poition ol the coue. Foi example,
wiiting a piogiam that uses seveial chunks ol coue liom this Look uoes not ieguiie
peimission. Answeiing a guestion Ly citing this Look anu guoting example coue uoes
not ieguiie peimission. Selling oi uistiiLuting a CD-ROM ol examples liom O`Reilly
Looks docs ieguiie peimission. Incoipoiating a signilicant amount ol example coue
liom this Look into youi piouuct`s uocumentation docs ieguiie peimission.
Ve appieciate, Lut uo not ieguiie, attiiLution. An attiiLution usually incluues the title,
authoi, puLlishei, anu ISBN. Foi example: jQucry Coo|boo|, Ly Couy Linuley. Copy-
iight 2010 Couy Linuley, 97S-0-596-15977-1. Il you leel youi use ol coue examples
lalls outsiue laii use oi the peimission given aLove, leel liee to contact us at
pcrnissionsorci||y.con.
Safari Books Online
Salaii Books Online is an on-uemanu uigital liLiaiy that lets you easily
seaich ovei 7,500 technology anu cieative ieleience Looks anu viueos to
linu the answeis you neeu guickly.
Vith a suLsciiption, you can ieau any page anu watch any viueo liom oui liLiaiy online.
Reau Looks on youi cell phone anu moLile uevices. Access new titles Leloie they aie
availaLle loi piint, anu get exclusive access to manusciipts in uevelopment anu post
leeuLack loi the authois. Copy anu paste coue samples, oiganize youi lavoiites, uown-
loau chapteis, Lookmaik key sections, cieate notes, piint out pages, anu Lenelit liom
tons ol othei time-saving leatuies.
O`Reilly Meuia has uploaueu this Look to the Salaii Books Online seivice. To have lull
uigital access to this Look anu otheis on similai topics liom O`Reilly anu othei puL-
lisheis, sign up loi liee at http://ny.sajariboo|son|inc.con.
How to Contact Us
Please auuiess comments anu guestions conceining this Look to the puLlishei:
O`Reilly Meuia, Inc.
1005 Giavenstein Highway Noith
SeLastopol, CA 95+72
Preface | xxi
S00-99S-993S (in the Uniteu States oi Canaua)
707-S29-0515 (inteinational oi local)
707-S29-010+ (lax)
To comment oi ask technical guestions aLout this Look, senu email to:
boo|qucstionsorci||y.con
Foi moie inloimation aLout oui Looks, conleiences, Resouice Centeis, anu the
O`Reilly Netwoik, see oui weLsite at:
http://orci||y.con
ReLecca Muiphey anu Couy Linuley
xxii | Preface
CHAPTER 1
jQuery Basics
Cody Lindlcy
1.0 Introduction
Since you`ve pickeu up a cookLook aLout jQueiy, the authois ol this Look loi the most
pait aie going to assume that you have a loose iuea aLout what exactly jQueiy is anu
what it uoes. Fiankly, cookLooks in geneial aie typically wiitten loi an auuience who
seeks to enhance a lounuation ol knowleuge that has alieauy Leen estaLlisheu. Thus,
the iecipe-solution-uiscussion loimat is useu to guickly get you solutions to common
pioLlems. Howevei, il you aie a jQueiy newLie, uon`t thiow this Look against the wall
anu cuise us just yet. Ve`ve ueuicateu this chaptei to you.
Il you aie in neeu ol a ieview oi aie jumping into this cookLook with little oi no woiking
knowleuge ol jQueiy, this liist chaptei alone (the othei chapteis assume you know the
Lasics) will aiu you in leaining the jQueiy essentials. Now, iealistically, il you have
aLsolutely zeio knowleuge ol ]avaSciipt anu the DOM, you might want to take a step
Lack anu ask youisell whethei appioaching jQueiy without a Lasic unueistanuing ol
the ]avaSciipt coie language anu its ielationship with the DOM is plausiLle. It woulu
Le my iecommenuation to stuuy up on the DOM anu ]avaSciipt coie Leloie appioach-
ing jQueiy. I highly iecommenu javaScript: Thc Dcjinitivc Guidc Ly Daviu Flanagan
(O`Reilly) as a piimei Leloie ieauing this Look. But uon`t let my humLle opinion stop
you il you aie attempting to leain jQueiy Leloie you leain aLout the DOM anu ]ava-
Sciipt. Many have come to a woiking knowleuge ol these technologies Ly way ol
jQueiy. Anu while not iueal, let`s lace it, it can still Le uone.
Vith that saiu, let`s take a look at a loimal uelinition ol jQueiy anu a Liiel uesciiption
ol its lunctionality:
jQueiy is an open souice ]avaSciipt liLiaiy that simplilies the inteiactions Letween an
HTML uocument, oi moie piecisely the Document OLject Mouel (aka the DOM), anu
]avaSciipt.
In plain woius, anu loi the olu-school ]avaSciipt hackeis out theie, jQueiy makes Dy-
namic HTML (DHTML) ueau easy. Specilically, jQueiy simplilies HTML uocument
1
tiaveising anu manipulation, Liowsei event hanuling, DOM animations, Ajax intei-
actions, anu cioss-Liowsei ]avaSciipt uevelopment.
Vith a loimal explanation ol jQueiy unuei oui Lelts, let`s next exploie why you might
choose to use jQueiy.
Why jQuery?
It might seem a Lit silly to speak aLout the meiits ol jQueiy within this cookLook,
especially since you`ie ieauing this cookLook anu aie likely alieauy awaie ol the meiits.
So, while I might Le pieaching to the choii heie, we`ie going to take a guick look at
why a uevelopei might choose to use jQueiy. My point in uoing this is to lostei youi
Lasic knowleuge ol jQueiy Ly liist explaining the why Leloie we look at the how.
In Luiluing a case loi jQueiy, I`m not going to compaie jQueiy to its competitois in
oiuei to elevate jQueiy`s signilicance. That`s Lecause I just uon`t Lelieve that theie
ieally is a uiiect competitoi. Also, I Lelieve the only liLiaiy availaLle touay that meets
the neeus ol Loth uesignei types anu piogiammei types is jQueiy. In this context,
jQueiy is in a class ol its own.
Ol the notoiious ]avaSciipt liLiaiies anu liamewoiks in the wilu, I tiuly Lelieve each
has its own niche anu value. A Lioau compaiison is silly, Lut it`s neveitheless attempteu
all the time. Heck, I am even guilty ol it mysell. Howevei, altei much thought on the
topic, I tiuly Lelieve that all ]avaSciipt liLiaiies aie goou at something. They all have
value. Vhat makes one moie valuaLle than the othei uepenus moie upon who is using
it anu how it`s Leing useu than what it actually uoes. Besiues, it has Leen my oLseivation
that micio uilleiences acioss ]avaSciipt liLiaiies aie olten tiivial in consiueiation ol the
Lioauei goals ol ]avaSciipt uevelopment. So, without luithei philosophical iamLlings,
heie is a list ol attiiLutes that Luilus a case loi why you shoulu use jQueiy:
It`s open souice, anu the pioject is licenseu unuei an MIT anu a GNU Geneial
PuLlic License (GPL) license. It`s liee, yo, in multiple ways!
It`s small (1S KB minilieu) anu gzippeu (11+ KB, uncompiesseu).
It`s incieuiLly populai, which is to say it has a laige community ol useis anu a
healthy amount ol contiiLutois who paiticipate as uevelopeis anu evangelists.
It noimalizes the uilleiences Letween weL Liowseis so that you uon`t have to.
It`s intentionally a lightweight lootpiint with a simple yet clevei plugin
aichitectuie.
Its iepositoiy ol plugins is vast anu has seen steauy giowth since jQueiy`s ielease.
Its API is lully uocumenteu, incluuing inline coue examples, which in the woilu
ol ]avaSciipt liLiaiies is a luxuiy. Heck, any uocumentation at all was a luxuiy loi
yeais.
It`s liienuly, which is to say it pioviues helplul ways to avoiu conllicts with othei
]avaSciipt liLiaiies.
2 | Chapter 1:jQuery Basics
Its community suppoit is actually laiily uselul, incluuing seveial mailing lists, IRC
channels, anu a lieakishly insane amount ol tutoiials, aiticles, anu Llog posts liom
the jQueiy community.
It`s openly uevelopeu, which means anyone can contiiLute Lug lixes, enhance-
ments, anu uevelopment help.
Its uevelopment is steauy anu consistent, which is to say the uevelopment team is
not aliaiu ol ieleasing upuates.
Its auoption Ly laige oiganizations has anu will continue to Lieeu longevity anu
staLility (e.g., Miciosolt, Dell, Bank ol Ameiica, Digg, CBS, Netllix).
It`s incoipoiating specilications liom the V3C Leloie the Liowseis uo. As an ex-
ample, jQueiy suppoits a goou majoiity ol the CSS3 selectois.
It`s cuiiently testeu anu optimizeu loi uevelopment on mouein Liowseis
(Chiome 1, Chiome Nightly, IE 6, IE 7, IE S, Opeia 9.6, Salaii 3.2, VeLKit Nightly,
Fiielox 2, Fiielox 3, Fiielox Nightly).
It`s uowniight poweilul in the hanus ol uesignei types as well as piogiammeis.
jQueiy uoes not uisciiminate.
Its elegance, methouologies, anu philosophy ol changing the way ]avaSciipt is
wiitten is Lecoming a stanuaiu in anu ol itsell. Consiuei just how many othei
solutions have Loiioweu the selectoi anu chaining patteins.
Its unexplainaLle Ly-piouuct ol leel-goou piogiamming is contagious anu ceitainly
unavoiuaLle; even the ciitics seem to lall in love with aspects ol jQueiy.
Its uocumentation has many outlets (e.g., API Liowsei, uashLoaiu apps, cheat
sheets) incluuing an ollline API Liowsei (AIR application).
It`s puiposely Lent to lacilitate unoLtiusive ]avaSciipt piactices.
It has iemaineu a ]avaSciipt liLiaiy (as opposeu to a liamewoik) at heait while at
the same time pioviuing a sistei pioject loi usei inteilace wiugets anu application
uevelopment (jQueiy UI).
Its leaining cuive is appioachaLle Lecause it Luilus upon concepts that most ue-
velopeis anu uesigneis alieauy unueistanu (e.g., CSS anu HTML).
It is my opinion that the comLination ol the aloiementioneu jQueiy points, anu not
any single attiiLute on its own, sets it apait liom all othei solutions. The total jQueiy
package is simply unmatcheu as a ]avaSciipt tool.
The jQuery Philosophy
The jQueiy philosophy is Viite less, uo moie. This philosophy can Le luithei Lioken
uown into thiee concepts:
Finuing some elements (via CSS selectois) anu uoing something with them (via
jQueiy methous)
Chaining multiple jQueiy methous on a set ol elements
1.0 Introduction | 3
Using the jQueiy wiappei anu implicit iteiation
Unueistanuing these thiee concepts in uetail is lounuational when it comes time to
wiite youi own jQueiy coue oi augment the iecipes lounu in this Look. Let`s examine
each ol these concepts in uetail.
Find some elements and do something with them
Oi moie specilically stateu, locate a set ol elements in the DOM, anu then uo something
with that set ol elements. Foi example, let`s examine a scenaiio wheie you want to hiue
a <div> liom the usei, loau some new text content into the hiuuen <div>, change an
attiiLute ol the selecteu <div>, anu then linally make the hiuuen <div> visiLle again.
This last sentence tianslateu into jQueiy coue woulu look something like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<div>old content</div>
<script>
//hide all divs on the page
jQuery('div').hide();
//update the text contained inside of all divs
jQuery('div').text('new content');
//add a class attribute with a value of updatedContent to all divs
jQuery('div').addClass("updatedContent");
//show all divs on the page
jQuery('div').show();
</script>
</body>
</html>
Let`s step thiough these loui jQueiy statements:
Hiue the <div> element on the page so it`s hiuuen liom the usei`s view.
Replace the text insiue the hiuuen <div> with some new text (new content).
Upuate the <div> element with a new attiiLute (class) anu value (updatedContent).
Show the <div> element on the page so it`s visiLle again to the viewing usei.
Il the jQueiy coue at this point is mystical syntax to you, that`s OK. Ve`ll uive into the
Lasics with the liist iecipe in this chaptei. Again, what you neeu to take away liom this
coue example is the jQueiy concept ol linu some elements anu uo something with
4 | Chapter 1:jQuery Basics
them. In oui coue example, we lounu all the <div> elements in the HTML page using
the jQueiy lunction (jQuery()), anu then using jQueiy methous we uiu something with
them (e.g., hide(), text(), addClass(), show()).
Chaining
jQueiy is constiucteu in a mannei that will allow jQueiy methous to Le chaineu. Foi
example, why not linu an element once anu then chain opeiations onto that element?
Oui loimei coue example uemonstiating the Finu some elements anu uo something
with them concept coulu Le iewiitten to a single ]avaSciipt statement using chaining.
This coue, using chaining, can Le changeu liom this:
//hide all divs on the page
jQuery('div').hide();
//update the text contained inside of the div
jQuery('div').text('new content');
//add a class attribute with a value of updatedContent to all divs
jQuery('div').addClass("updatedContent");
//show all divs on the page
jQuery('div').show();
to this:
jQuery('div').hide().text('new content').addClass("updatedContent").show();
oi, with inuenting anu line Lieaks, to this:
jQuery('div')
.hide()
.text('new content')
.addClass("updatedContent")
.show();
Plainly speaking, chaining simply allows you to apply an enuless chain ol jQueiy meth-
ous on the elements that aie cuiiently selecteu (cuiiently wiappeu with jQueiy lunc-
tionality) using the jQueiy lunction. Behinu the scenes, the elements pieviously selecteu
Leloie a jQueiy methou was applieu aie always ietuineu so that the chain can continue.
As you will see in lutuie iecipes, plugins aie also constiucteu in this mannei (ietuining
wiappeu elements) so that using a plugin uoes not Lieak the chain.
Il it`s not immeuiately oLvious, anu Laseu on the coue in guestion, chaining also cuts
uown on piocessing oveiheau Ly selecting a set ol DOM elements only once, to then
Le opeiateu on numeious times Ly jQueiy methous Ly way ol chaining. Avoiuing un-
necessaiy DOM tiaveising is a ciitical pait ol page peiloimance enhancements. Vhen-
evei possiLle, ieuse oi cache a set ol selecteu DOM elements.
1.0 Introduction | 5
The jQuery wrapper set
A goou majoiity ol the time, il jQueiy is involveu, you`ie going to Le getting what is
known as a wrappcr. In othei woius, you`ll Le selecting DOM elements liom an HTML
page that will Le wiappeu with jQueiy lunctionality. Peisonally, I olten ielei to this as
a wiappei set oi wiappeu set Lecause it`s a set ol elements wiappeu with jQueiy
lunctionality. Sometimes this wiappei set will contain one DOM element; othei times
it will contain seveial. Theie aie even cases wheie the wiappei set will contain no
elements. In these situations, the methous/piopeities that jQueiy pioviues will lail
silently il methous aie calleu on an empty wiappei set, which can Le hanuy in avoiuing
unneeueu if statements.
Now, Laseu on the coue we useu to uemonstiate the Finu some elements anu uo
something with them concept, what uo you think woulu happen il we auueu multiple
<div> elements to the weL page? In the lollowing upuateu coue example, I have auueu
thiee auuitional <div> elements to the HTML page, loi a total ol loui <div> elements:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/JavaScript" src="http://ajax.googleapis.com/ajax/libs/
jquery/1.3.0/jquery.min.js"></script> </head>
<body>
<div>old content</div>
<div>old content</div>
<div>old content</div>
<div>old content</div>
<script>
//hide all divs on the page
jQuery('div').hide().text('new content').addClass("updatedContent").show();
</script>
</body>
</html>
You may not have explicitly wiitten any piogiammatic loops heie, Lut guess what?
jQueiy is going to scan the page anu place all <div> elements in the wiappei set so that
the jQueiy methous I am using heie aie peiloimeu (aka implicit iteiation) on each
DOM element in the set. Foi example, the .hide() methou actually applies to each
element in the set. So il you look at oui coue again, you will see that each methou that
we use will Le applieu to each <div> element on the page. It`s as il you hau wiitten a
loop heie to invoke each jQueiy methou on each DOM element. The upuateu coue
example will iesult in each <div> in the page Leing hiuuen, lilleu with upuateu text,
given a new class value, anu then maue visiLle again.
Viapping youi heau aiounu (pun intenueu) the wiappei set anu its uelault looping
system (aka implicit iteiation) is ciitical loi Luiluing auvanceu concepts aiounu loop-
ing. ]ust keep in minu that a simple loop is occuiiing heie Leloie you actually uo any
auuitional looping (e.g., jQuery('div').each(function(){}). Oi anothei way to look at
6 | Chapter 1:jQuery Basics
this is each element in the wiappei will typically Le changeu Ly the jQueiy methou(s)
that aie calleu.
Something to keep in minu heie is theie aie scenaiios that you will leain aLout in the
coming chapteis wheie only the liist element, anu not all the elements in the wiappei
set, is allecteu Ly the jQueiy methou (e.g., attr()).
How the jQuery API Is Organized
Theie is no guestion that when I liist staiteu out with jQueiy, my main ieason loi
selecting it as my ]avaSciipt liLiaiy was simply that it hau Leen piopeily uocumenteu
(anu the gazillion plugins!). Latei, I iealizeu anothei lactoi that cementeu my love allaii
with jQueiy was the lact that the API was oiganizeu into logical categoiies. ]ust Ly
looking at how the API was oiganizeu, I coulu naiiow uown the lunctionality I neeueu.
Beloie you ieally get staiteu with jQueiy, I suggest visiting the uocumentation online
anu simply uigesting how the API is oiganizeu. By unueistanuing how the API is oi-
ganizeu, you`ll moie guickly navigate the uocumentation to the exact inloimation you
neeu, which is actually a signilicant auvantage given that theie aie ieally a lot ol uilleient
ways to coue a jQueiy solution. It`s so ioLust that it`s easy to get hung up on imple-
mentation Lecause ol the numLei ol solutions loi a single pioLlem. I`ve ieplicateu heie
loi you how the API is oiganizeu. I suggest memoiizing the API outline, oi at the veiy
least the top-level categoiies.
jQueiy Coie
The jQueiy Function
jQueiy OLject Accessois
Data
Plugins
InteiopeiaLility
Selectois
Basics
Hieiaichy
Basic Filteis
Content Filteis
VisiLility Filteis
AttiiLute Filteis
Chilu Filteis
Foims
Foim Filteis
AttiiLutes
1.0 Introduction | 7
Atti
Class
HTML
Text
Value
Tiaveising
Filteiing
Finuing
Chaining
Manipulation
Changing Contents
Inseiting Insiue
Inseiting Outsiue
Inseiting Aiounu
Replacing
Removing
Copying
CSS
CSS
Positioning
Height anu Viuths
Events
Page Loau
Event Hanuling
Live Events
Inteiaction Helpeis
Event Helpeis
Ellects
Basics
Sliuing
Fauing
Custom
Settings
Ajax
A]AX Reguests
8 | Chapter 1:jQuery Basics
A]AX Events
Misc.
Utilities
Biowsei anu Featuie Detection
Aiiay anu OLject Opeiations
Test Opeiations
Stiing Opeiations
Uils
Beloie we jump into a seguence ol Lasic jQueiy iecipes, I woulu like to mention that
the iecipes lounu in this chaptei Luilu on each othei. That is, theie is a logical loimation
ol knowleuge as you piogiess liom the liist iecipe to the last. It`s my suggestion, loi
youi liist ieauing ol these iecipes, that you ieau them in oiuei liom 1.1 to 1.17.
1.1 Including the jQuery Library Code in an HTML Page
Problem
You want to use the jQueiy ]avaSciipt liLiaiy on a weL page.
Solution
Theie aie cuiiently two iueal solutions loi emLeuuing the jQueiy liLiaiy in a weL page:
Use the Google-hosteu content ueliveiy netwoik (CDN) to incluue a veision ol
jQueiy (useu in this chaptei).
Downloau youi own veision ol jQueiy liom jQueiy.com anu host it on youi own
seivei oi local lilesystem.
Discussion
Incluuing the jQueiy ]avaSciipt liLiaiy isn`t any uilleient liom incluuing any othei
exteinal ]avaSciipt lile. You simply use the HTML <script> element anu pioviue the
element a value (URL oi uiiectoiy path) loi its src="" attiiLute, anu the exteinal lile
you aie linking to will Le incluueu in the weL page. Foi example, the lollowing is a
template that incluues the jQueiy liLiaiy that you can use to stait any jQueiy pioject:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
1.1 Including the jQuery Library Code in an HTML Page | 9
<script type="text/JavaScript">
alert('jQuery ' + jQuery.fn.jquery);
</script>
</body>
</html>
Notice that I am usinganu highly iecommenu using loi puLlic weL pagesthe
Google-hosteu minilieu veision ol jQueiy. Howevei, ueLugging ]avaSciipt eiiois in
minilieu coue is not iueal. Duiing coue uevelopment, oi on the piouuction site, it ac-
tually might Le Lettei to use the nonminilieu veision liom Google loi the puipose ol
ueLugging potential ]avaSciipt eiiois. Foi moie inloimation aLout using the Google-
hosteu veision ol jQueiy, you can visit the Ajax liLiaiies API site on the VeL at http://
codc.goog|c.con/apis/ajax|ibs/.
It`s ol couise also possiLle, anu mostly likely olu hat, to host a copy ol the jQueiy coue
youisell. In most ciicumstances, howevei, this woulu Le silly to uo Lecause Google has
Leen kinu enough to host it loi you. By using a Google-hosteu veision ol jQueiy, you
Lenelit liom a staLle, ieliaLle, high-speeu, anu gloLally availaLle copy ol jQueiy. As
well, you ieap the Lenelit ol uecieaseu latency, incieaseu paiallelism, anu Lettei cach-
ing. This ol couise coulu Le accomplisheu without using Google`s solution, Lut it woulu
most likely cost you a uime oi two.
Now, loi whatevei ieason, you might not want to use the Google-hosteu veision ol
jQueiy. You might want a customizeu veision ol jQueiy, oi youi usage might not
ieguiie/have access to an Inteinet connection. Oi, you simply might Lelieve that Google
is The Man anu wish not to suLmit to usage Lecause you aie a contiol lieak anu
conspiiacy lanatic. So, loi those who uo not neeu, oi simply who uo not want, to use
a Google-hosteu copy ol the jQueiy coue, jQueiy can Le uownloaueu liom
jQueiy.com anu hosteu locally on youi own seivei oi local lilesystem. Baseu on the
template I`ve pioviueu in this iecipe, you woulu simply ieplace the src attiiLute value
with a URL oi uiiectoiy path to the location ol the jQueiy ]avaSciipt lile you`ve uown-
loaueu.
1.2 Executing jQuery/JavaScript Coded After the DOM Has
Loaded but Before Complete Page Load
Problem
Mouein ]avaSciipt applications using unoLtiusive ]avaSciipt methouologies typically
execute ]avaSciipt coue only altei the DOM has Leen completely loaueu. Anu the ieality
ol the situation is that any DOM tiaveising anu manipulation will ieguiie that the DOM
is loaueu Leloie it can Le opeiateu on. Vhat`s neeueu is a way to ueteimine when the
client, most olten a weL Liowsei, has completely loaueu the DOM Lut has possiLly not
yet completely loaueu all assets such as images anu SVF liles. Il we weie to use the
window.onload event in this situation, the entiie uocument incluuing all assets woulu
10 | Chapter 1:jQuery Basics
neeu to Le completely loaueu Leloie the onload event liieu. That`s just too time-
consuming loi most weL suileis. Vhat`s neeueu is an event that will tell us when the
DOM alone is ieauy to Le tiaveiseu anu manipulateu.
Solution
jQueiy pioviues the ready() methou, which is a custom event hanulei that is typically
Lounu to the DOM`s uocument oLject. The ready() methou is passeu a single paiam-
etei, a lunction, that contains the ]avaSciipt coue that shoulu Le executeu once the
DOM is ieauy to Le tiaveiseu anu manipulateu. The lollowing is a simple example ol
this event opening an alert() winuow once the DOM is ieauy Lut Leloie the page is
completely loaueu:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery(document).ready(function(){//DOM not loaded, must use ready event
alert(jQuery('p').text());
});
</script>
</head>
<body>
<p>The DOM is ready!</p>
</body>
</html>
Discussion
The ready() event hanulei methou is jQueiy`s ieplacement loi using the ]avaSciipt coie
window.onload event. It can Le useu as many times as you like. Vhen using this custom
event, it`s auvisaLle that it Le incluueu in youi weL pages altei the inclusion ol stylesheet
ueclaiations anu incluues. Doing this will ensuie that all element piopeities aie coi-
iectly uelineu Leloie any jQueiy coue oi ]avaSciipt coue will Le executeu Ly the
ready() event.
Auuitionally, the jQueiy lunction itsell pioviues a shoitcut loi using the jQueiy custom
ieauy event. Using this shoitcut, the lollowing alert() example can Le iewiitten like so:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery(function(){ //DOM not loaded, must use ready event
1.2 Executing jQuery/JavaScript Coded After the DOM Has Loaded but Before Complete Page Load | 11
alert(jQuery('p').text());
});
</script>
</head>
<body>
<p>The DOM is ready!</p>
</body>
</html>
The use ol this custom jQueiy event is necessaiy only il ]avaSciipt has to Le emLeuueu
in the uocument llow at the top ol the page anu encapsulateu in the <head> element. I
simply avoiu the usage ol the ready() event Ly placing all ]avaSciipt incluues anu inline
coue Leloie the closing <body> element. I uo this loi two ieasons.
Fiist, mouein optimization technigues have ueclaieu that pages loau lastei when the
]avaSciipt is loaueu Ly the Liowsei at the enu ol a page paise. In othei woius, il you
put ]avaSciipt coue at the Lottom ol a weL page, then the Liowsei will loau eveiything
in liont ol it Leloie it loaus the ]avaSciipt. This is a goou thing Lecause most Liowseis
will typically stop piocessing othei loauing initiatives until the ]avaSciipt engine has
compileu the ]avaSciipt containeu in a weL page. It`s soit ol a Lottleneck in a sense
that you have ]avaSciipt at the top ol a weL page uocument. I iealize that loi some
situations it`s easiei to place ]avaSciipt in the <head> element. But honestly, I`ve nevei
seen a situation wheie this is aLsolutely ieguiieu. Any oLstacle that I`ve encounteieu
uuiing my uevelopment Ly placing ]avaSciipt at the Lottom ol the page has Leen easily
oveicome anu well woith the optimization gains.
Seconu, il speeuy weL pages aie oui goal, why wiap moie lunctionality aiounu a sit-
uation that can Le elevateu Ly simply moving the coue to the Lottom ol the page? Vhen
given the choice Letween moie coue oi less coue, I choose less coue. Not using the
ready() event iesults in using less coue, especially since less coue always iuns lastei
than moie coue.
Vith some iationale out ol the way, heie is an example ol oui alert() coue that uoes
not use the ready() event:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>The DOM is ready!</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
alert(jQuery('p').text());//go for it the DOM is loaded
</script>
</body>
</html>
12 | Chapter 1:jQuery Basics
Notice that I have placeu all ol my ]avaSciipt Leloie the closing </body> element. Any
auuitional maikup shoulu Le placeu aLove the ]avaSciipt in the HTML uocument.
1.3 Selecting DOM Elements Using Selectors and the jQuery
Function
Problem
You neeu to select a single DOM element anu/oi a set ol DOM elements in oiuei to
opeiate on the element(s) using jQueiy methous.
Solution
jQueiy pioviues two options when you neeu to select element(s) liom the DOM. Both
options ieguiie the use ol the jQueiy lunction (jQuery() oi alias $()). The liist option,
which uses CSS selectois anu custom selectois, is Ly lai the most useu anu most elo-
guent solution. By passing the jQueiy lunction a stiing containing a selectoi expiession,
the lunction will tiaveise the DOM anu locate the DOM noues uelineu Ly the expies-
sion. As an example, the lollowing coue will select all the <a> elements in the HTML
uocument:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
//alerts there are 6 elements
alert('Page contains ' + jQuery('a').length + ' <a> elements!');
</script>
</body>
</html>
Il you weie to iun this HTML page in a weL Liowsei, you woulu see that the coue
executes a Liowsei alert() that inloims us that the page contains six <a> elements. I
passeu this value to the alert() methou Ly liist selecting all the <a> elements anu then
using the length piopeity to ietuin the numLei ol elements in the jQueiy wiappei set.
1.3 Selecting DOM Elements Using Selectors and the jQuery Function | 13
You shoulu Le awaie that the liist paiametei ol the jQueiy lunction, as we aie using it
heie, will also accept multiple expiessions. To uo this, simply sepaiate multiple selec-
tois with a comma insiue the same stiing that is passeu as the liist paiametei to the
jQueiy lunction. Heie is an example ol what that might look like:
jQuery('selector1, selector2, selector3').length;
Oui seconu option loi selecting DOM elements anu the less common option is to pass
the jQueiy lunction an actual ]avaSciipt ieleience to DOM element(s). As an example,
the lollowing coue will select all the <a> elements in the HTML uocument. Notice that
I`m passing the jQueiy lunction an aiiay ol <a> elements collecteu using the
getElementsByTagName DOM methou. This example piouuces the same exact iesults as
oui pievious coue example:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body bgcolor="yellow"> <!-- yes the attribute is depreciated, I know, roll
with it -->
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<a href='#'>link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
//alerts there are 6 elements
alert('Page contains ' + jQuery(document.getElementsByTagName('a')).length +
' <a> Elements, And has a '
+ jQuery(document.body).attr('bgcolor') + ' background');
</script>
</body>
</html>
Discussion
The heavy lilting that jQueiy is known loi is paitially Laseu on the selectoi engine,
Sizzle, that selects DOM element(s) liom an HTML uocument. Vhile you have the
option, anu it`s a nice option when you neeu it, passing the jQueiy lunction DOM
ieleiences is not what put jQueiy on eveiyone`s iauai. It`s the vast anu poweilul options
availaLle with selectois that make jQueiy so unigue.
Thioughout the iest ol the Look, you will linu poweilul anu ioLust selectois. Vhen
you see one, make suie you lully unueistanu its lunction. This knowleuge will seive
you well with lutuie couing enueavois using jQueiy.
14 | Chapter 1:jQuery Basics
1.4 Selecting DOM Elements Within a Specified Context
Problem
You neeu a ieleience to a single DOM element oi a set ol DOM elements in the context
ol anothei DOM element oi uocument in oiuei to opeiate on the element(s) using
jQueiy methous.
Solution
The jQueiy lunction when passeu a CSS expiession will also accept a seconu paiametei
that tells the jQueiy lunction to which context it shoulu seaich loi the DOM elements
Laseu on the expiession. The seconu paiametei in this case can Le a DOM ieleience,
jQueiy wiappei, oi uocument. In the lollowing coue, theie aie 12 <input> elements.
Notice how I use a specilic context, Laseu on the <form> element, to select only pai-
ticulai <input> elements:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form>
<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />
</form>
<form>
<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />
</form>
<input name="" type="checkbox" />
<input name="" type="radio" />
<input name="" type="text" />
<input name="" type="button" />
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
//searches within all form elements, using a wrapper for context, alerts "8 inputs"
alert('selected ' + jQuery('input',$('form')).length + ' inputs');
//search with the first form element, using DOM reference as the context, alerts
1.4 Selecting DOM Elements Within a Specified Context | 15
//"4 inputs"
alert('selected' + jQuery('input',document.forms[0]).length + ' inputs');
//search within the body element for all input elements using an expression,
//alerts "12 inputs"
alert('selected' + jQuery('input','body').length + ' inputs');
</script>
</body>
</html>
Discussion
It`s also possiLle, as mentioneu in the solution ol this iecipe, to select uocuments as
the context loi seaiching. Foi example, it`s possiLle to seaich within the context ol an
XML uocument that is sent Lack liom uoing an XHR ieguest (Ajax). You can linu moie
uetails aLout this usage in Chaptei 16.
1.5 Filtering a Wrapper Set of DOM Elements
Problem
You have a set ol selecteu DOM elements in a jQueiy wiappei set Lut want to iemove
DOM elements liom the set that uo not match a new specilieu expiession(s) in oiuei
to cieate a new set ol elements to opeiate on.
Solution
The jQueiy liltei methou, useu on a jQueiy wiappei set ol DOM elements, can excluue
elements that do not match a specilieu expiession(s). In shoit, the filter() methou
allows you to liltei the cuiient set ol elements. This is an impoitant uistinction liom
the jQueiy linu methou, which will ieuuce a wiappeu set ol DOM elements Ly linuing
(via a new selectoi expiession) new elements, incluuing chilu elements ol the cuiient
wiappeu set.
To unueistanu the liltei methou, let`s examine the lollowing coue:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a href="#" class="external">link</a>
<a href="#" class="external">link</a>
<a href="#"></a>
<a href="#" class="external">link</a>
<a href="#" class="external">link</a>
<a href="#"></a></li>
16 | Chapter 1:jQuery Basics
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
//alerts 4 left in the set
alert(jQuery('a').filter('.external').length + ' external links');
</script>
</body>
</html>
The HTML page in the coue example just shown contains a weL page with 10 <a>
elements. Those links that aie exteinal links aie given a class name ol external. Using
the jQueiy lunction, we select all <a> elements on the page. Then, using the liltei meth-
ou, all those elements that uo not have a class attiiLute value ol external aie iemoveu
liom the oiiginal set. Once the initial set ol DOM elements aie alteieu using the
filter() methou, I invoke the length piopeity, which will tell me how many elements
aie now in my new set altei the liltei has Leen applieu.
Discussion
It`s also possiLle to senu the filter() methou a lunction that can Le useu to liltei the
wiappeu set. Oui pievious coue example, which passes the filter() methou a stiing
expiession, can Le changeu to use a lunction insteau:
alert(
jQuery('a')
.filter(function(index){ return $(this).hasClass('external');})
.length + ' external links'
);
Notice that I am now passing the filter() methou an anonymous lunction. This lunc-
tion is calleu with a context egual to the cuiient element. That means when I use
$(this) within the lunction, I am actually ieleiiing to each DOM element in the wiap-
pei set. Vithin the lunction, I am checking each <a> element in the wiappei set to see
whethei the element has a class value (hasClass()) ol external. Il it uoes, Boolean tiue,
then keep the element in the set, anu il it uoesn`t (lalse), then iemove the element liom
the set. Anothei way to look at this is il the lunction ietuins lalse, then the element is
iemoveu. Il the lunction ietuins any othei uata value Lesiues lalse, then the element
will iemain in the wiappei set.
You may have noticeu that I have passeu the lunction a paiametei nameu index that I
am not using. This paiametei, il neeueu, can Le useu to ielei numeiically to the inuex
ol the element in the jQueiy wiappei set.
1.5 Filtering a Wrapper Set of DOM Elements | 17
1.6 Finding Descendant Elements Within the Currently
Selected Wrapper Set
Problem
You have a set ol selecteu DOM elements (oi a single element) anu want to linu ue-
scenuant (chiluien) elements within the context ol the cuiiently selecteu elements.
Solution
Use the .find() methou to cieate a new wiappei set ol elements Laseu on the context
ol the cuiient set anu theii uescenuants. Foi example, say that you have a weL page
that contains seveial paiagiaphs. Encapsulateu insiue ol these paiagiaphs aie woius
that aie emphasizeu (italic). Il you`u like to select only <em> elements containeu within
<p> elements, you coulu uo so like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Ut ad videntur facilisis <em>elit</em> cum. Nibh insitam erat facit
<em>saepius</em> magna. Nam ex liber iriure et imperdiet. Et mirum eros
iis te habent. </p>
<p>Claram claritatem eu amet dignissim magna. Dignissim quam elit facer eros
illum. Et qui ex esse <em>tincidunt</em> anteposuerit. Nulla nam odio ii
vulputate feugait.</p>
<p>In quis <em>laoreet</em> te legunt euismod. Claritatem <em>consuetudium</em>
wisi sit velit facilisi.</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
//alerts total italic words found inside of <p> elements
alert('The three paragraphs in all contain ' +
jQuery('p').find('em').length + '
italic words');
</script>
</body>
</html>
Keep in minu that we coulu have also wiitten this coue Ly passing a contextual ieleience
as a seconu paiametei to the jQueiy lunction:
alert('The three paragraphs in all contain ' + jQuery('em',$('p')).length +
' italic words');
Auuitionally, it`s woith mentioning that the last two coue examples aie uemonstiative
in puipose. It is likely moie logical, il not piagmatic, to use a CSS selectoi expiession
to select all the uescenuant italic elements containeu within the ancestoi <p> elements.
18 | Chapter 1:jQuery Basics
alert('The three paragraphs in all contain ' + jQuery('p em').length +
' italic words');
Discussion
The jQueiy .find() methou can Le useu to cieate a new set ol elements Laseu on context
ol the cuiient set ol DOM elements anu theii chiluien elements. People olten conluse
the use ol the .filter() methou anu .find() methou. The easiest way to iememLei
the uilleience is to keep in minu that .find() will opeiate/select the chiluien ol the
cuiient set while .filter() will only opeiate on the cuiient set ol elements. In othei
woius, il you want to change the cuiient wiappei set Ly using it as a context to luithei
select the chiluien ol the elements selecteu, use .find(). Il you only want to liltei the
cuiient wiappeu set anu get a new suLset ol the cuiient DOM elements in the set only,
use .filter(). To Loil this uown even moie, find() ietuins chiluien elements, while
filter() only lilteis what is in the cuiient wiappei set.
1.7 Returning to the Prior Selection Before a Destructive
Change
Problem
A uestiuctive jQueiy methou (e.g., filter() oi find()) that was useu on a set ol ele-
ments neeus to Le iemoveu so that the set piioi to the use ol the uestiuctive methou is
ietuineu to its pievious state anu can then Le opeiateu as il the uestiuctive methou hau
nevei Leen invokeu.
Solution
jQueiy pioviues the end() methou so that you can ietuin to the pievious set ol DOM
elements that weie selecteu Leloie using a uestiuctive methou. To unueistanu the
end() methou, let`s examine the lollowing HTML.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>text</p>
<p class="middle">Middle <span>text</span></p>
<p>text</p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
alert(jQuery('p').filter('.middle').length); //alerts 1
alert(jQuery('p').filter('.middle').end().length); //alerts 3
alert(jQuery('p').filter('.middle').find('span')
1.7 Returning to the Prior Selection Before a Destructive Change | 19
.end().end().length); //alerts 3
</script>
</body>
</html>
The liist alert() statement in the coue contains a jQueiy statement that will seaich the
uocument loi all <p> elements anu then apply filter() to the selecteu <p> elements in
the set selecting only the one(s) with a class ol middle. The length piopeity then iepoits
how many elements aie lelt in the set:
alert(jQuery('p').filter('.middle').length); //alerts 1
The next alert() statement makes use ol the end() methou. Heie we aie uoing eveiy-
thing we uiu in the piioi statement except that we aie unuoing the filter() methou
anu ietuining to the set ol elements containeu in the wiappei set Leloie the filter()
methou was applieu:
alert(jQuery('p').filter('.middle').end().length); //alerts 3
The last alert() statement uemonstiates how the end() methou is useu twice to iemove
Loth the filter() anu find() uestiuctive changes, ietuining the wiappei set to its oiig-
inal composition:
alert(jQuery('p').filter('.middle').find('span').end().end().length); //alerts 3
Discussion
Il the end() methou is useu anu theie weie no piioi uestiuctive opeiations peiloimeu,
an empty set is ietuineu. A uestiuctive opeiation is any opeiation that changes the
set ol matcheu jQueiy elements, which means any tiaveising oi manipulation methou
that ietuins a jQueiy oLject, incluuing add(), andSelf(), children(), closes(),
filter(), find(), map(), next(), nextAll(), not(), parent(), parents(), prev(),
prevAll(), siblings(), slice(), clone(), appendTo(), prependTo(), insertBefore(),
insertAfter(), anu replaceAll().
1.8 Including the Previous Selection with the Current Selection
Problem
You have just manipulateu a set ol elements in oiuei to acguiie a new set ol elements.
Howevei, you want to opeiate on the piioi set as well as the cuiient set.
Solution
You can comLine a piioi selection ol DOM elements with the cuiient selection Ly using
the andSelf() methou. Foi example, in the lollowing coue, we aie liist selecting all
<div> elements on the page. Next we manipulate this set ol elements Ly linuing all
<p> elements containeu within the <div> elements. Now, in oiuei to opeiate on Loth
the <div> anu the <p> elements lounu within the <div>, we coulu incluue the <div> into
20 | Chapter 1:jQuery Basics
the cuiient set Ly using andSelf(). Hau I omitteu the andSelf(), the Loiuei coloi woulu
have only Leen applieu to the <p> elements:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div>
<p>Paragraph</p>
<p>Paragraph</p>
</div>
<script type="text/JavaScript" src="http://ajax.googleapis.com/
ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('div').find('p').andSelf().css('border','1px solid #993300');
</script>
</body>
</html>
Discussion
Keep in minu that when you use the andSelf() methou, it will only auu into the cuiient
set Leing opeiateu on anu the piioi set, Lut not all piioi sets.
1.9 Traversing the DOM Based on Your Current Context to
Acquire a New Set of DOM Elements
Problem
You have selecteu a set ol DOM elements, anu Laseu on the position ol the selections
within the DOM tiee stiuctuie, you want to tiaveise the DOM to acguiie a new set ol
elements to opeiate on.
Solution
jQueiy pioviues a set ol methous loi tiaveising the DOM Laseu on the context ol the
cuiiently selecteu DOM element(s).
Foi example, let`s examine the lollowing HTML snippet:
<div>
<ul>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
<li><a href="#">link</a></li>
</ul>
</div>
1.9 Traversing the DOM Based on Your Current Context to Acquire a New Set of DOM Elements | 21
Now, let`s select the seconu <li> element using the :eq() inuex custom selectoi:
//selects the second element in the set of <li>'s by index, index starts at 0
jQuery('li:eq(1)');
Ve now have a context, a staiting point within the HTML stiuctuie. Oui staiting point
is the seconu <li> element. Fiom heie we can go anywheiewell, almost anywheie.
Let`s see wheie we can go using a couple ol the methous jQueiy pioviues loi tiaveising
the DOM. Reau the comments in the coue loi claiilication:
jQuery('li:eq(1)').next() //selects the third <li>
jQuery('li:eq(1)').prev() //selects the first <li>
jQuery('li:eq(1)').parent() //selects the <ul>
jQuery('li:eq(1)').parent().children() //selects all <li>s
jQuery('li:eq(1)').nextAll() //selects all the <li>s after the second <li>
jQuery('li:eq(1)').prevAll() //selects all the <li>s before the second <li>
Keep in minu that these tiaveising methous piouuce a new wiappei set, anu to ietuin
to the pievious wiappei set, you can use end().
Discussion
The tiaveising methous shown thus lai have uemonstiateu simple tiaveises. Theie aie
two auuitional concepts that aie impoitant to know aLout tiaveising.
The liist concept anu likely most oLvious is that tiaveising methous can Le chaineu.
Let`s examine again the lollowing jQueiy statement liom eailiei:
jQuery('li:eq(1)').parent().children() //selects all <li>'s
Notice that I have tiaveiseu liom the seconu <li> element to the paient <ul> element
anu then again tiaveiseu liom the paient element to selecting all the chiluien elements
ol the <ul> element. The jQueiy wiappei set will now contain all the <li> elements
containeu within the <ul>. Ol couise, this is a contiiveu example loi the puipose ol
uemonstiating tiaveising methous. Hau we ieally wanteu a wiappei set ol just <li>
elements, it woulu have Leen much simplei to select all the <li> elements liom the
get-go (e.g., jQuery('li')).
The seconu concept that you neeu to keep in minu when uealing with the tiaveising
methous is that many ol the methous will accept an optional paiametei that can Le
useu to liltei the selections. Let`s take oui chaineu example again anu look at how we
coulu change it so that only the last <li> element was selecteu. Keep in minu that this
is a contiiveu example loi the puipose ol uemonstiating how a tiaveising methou can
Le passeu an expiession useu loi selecting a veiy specilic element:
jQuery('li:eq(1)').parent().children(':last') //selects the last <li>
22 | Chapter 1:jQuery Basics
jQueiy pioviues auuitional tiaveising methous that weie not shown heie. Foi a com-
plete list anu uocumentation, have a look at http://docs.jqucry.con/Travcrsing. You will
linu these auuitional tiaveising methous useu thioughout this Look.
1.10 Creating, Operating on, and Inserting DOM Elements
Problem
You want to cieate new DOM elements (oi a single element) that aie immeuiately
selecteu, opeiateu on, anu then injecteu into the DOM.
Solution
Il you haven`t liguieu it out yet, the jQueiy lunction is multilaceteu in that this one
lunction peiloims uilleiently uepenuing upon the makeup ol the paiametei(s) you senu
it. Il you pioviue the lunction with a text stiing ol iaw HTML, it will cieate these
elements loi you on the lly. Foi example, the lollowing statement will cieate an <a>
element wiappeu insiue ol a <p> element with a text noue encapsulateu insiue ol the
<p> anu <a> elements:
jQuery('<p><a>jQuery</a></p>');
Now, with an element cieateu, you can use jQueiy methous to luithei opeiate on the
elements you just cieateu. It`s as il you hau selecteu the <p> element liom the get-go in
an existing HTML uocument. Foi example, we coulu opeiate on the <a> Ly using
the .find() methou to select the <a> element anu then set one ol its attiiLutes. In the
case ol the lollowing coue, we aie setting the href attiiLute with a value ol http://
www.jquery.com:
jQuery('<p><a>jQuery</a></p>').find('a').attr('href','http://www.jquery.com');
This is gieat, iight? Vell, it`s aLout to get Lettei Lecause all we have uone so lai is cieate
elements on the lly anu manipulate those elements in coue. Ve have yet to actually
change the cuiiently loaueu DOM, so to speak. To uo this, we`ll have to use the ma-
nipulation methous pioviueu Ly jQueiy. The lollowing is oui coue in the context ol an
HTML uocument. Heie we aie cieating elements, opeiating on those elements, anu
then inseiting those elements into the DOM using the appendTo() manipulation
methou:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
1.10 Creating, Operating on, and Inserting DOM Elements | 23
jQuery('<p><a>jQuery</a></p>').find('a').attr('href','http://www.jquery.com')
.end().appendTo('body');
</script>
</body>
</html>
Notice how I am using the end() methou heie to unuo the find() methou so that when
I call the appendTo() methou, it appenus what was oiiginally containeu in the initial
wiappei set.
Discussion
In this iecipe we`ve passeu the jQueiy lunction a stiing ol iaw HTML that is taken anu
useu to cieate DOM elements on the lly. It`s also possiLle to simply pass the jQueiy
lunction a DOM oLject cieateu Ly the DOM methou createElement():
jQuery(document.createElement('p')).appendTo('body'); //adds an empty p element
to the page
Ol couise, this coulu Le iathei laLoiious uepenuing upon the specilics ol the usage
when a stiing ol HTML containing multiple elements will woik just line.
It`s also woith mentioning heie that we`ve only sciatcheu the suilace ol the manipu-
lation methous Ly using the appendTo() methou. In auuition to the appendTo() methou,
theie aie also the lollowing manipulation methous:
append()
prepend()
prependTo()
after()
before()
insertAfter()
insertBefore()
wrap()
wrapAll()
wrapInner()
1.11 Removing DOM Elements
Problem
You want to iemove elements liom the DOM.
24 | Chapter 1:jQuery Basics
Solution
The remove() methou can Le useu to iemove a selecteu set ol elements anu theii chiluien
elements liom the DOM. Examine the lollowing coue:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Anchors</h3>
<a href='#'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('a').remove();
</script>
</body>
</html>
Vhen the pieceuing coue is loaueu into a Liowsei, the anchoi elements will iemain in
the page until the ]avaSciipt is executeu. Once the remove() methou is useu to iemove
all anchoi elements liom the DOM, the page will visually contain only an <h3> element.
It`s also possiLle to pass the methou an expiession to liltei the set ol elements to Le
iemoveu. Foi example, oui coue coulu change to iemove only anchois with a specilic
class:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Anchors</h3>
<a href='#' class='remove'>Anchor Element</a>
<a href='#'>Anchor Element</a>
<a href='#' class="remove">Anchor Element</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('a').remove('.remove');
</script>
</body>
</html>
Discussion
Vhen using the jQueiy remove() methou, you neeu to keep two things in minu:
1.11 Removing DOM Elements | 25
Vhile the elements selecteu aie iemoveu liom the DOM using remove(), they have
not Leen iemoveu liom the jQueiy wiappei set. That means in theoiy you coulu
continue opeiating on them anu even auu them Lack into the DOM il uesiieu.
This methou will not only iemove the elements liom the DOM, Lut it will also
iemove all event hanuleis anu inteinally cacheu uata that the elements iemoveu
might have containeu.
1.12 Replacing DOM Elements
Problem
You neeu to ieplace DOM noues cuiiently in the DOM with new DOM noues.
Solution
Using the replaceWith() methou, we can select a set ol DOM elements loi ieplacement.
In the lollowing coue example, we use the replaceWith() methou to ieplace all <li>
elements with a class attiiLute ol remove with a new DOM stiuctuie:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
<li>name</li>
<li class='remove'>name</li>
</ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('li.remove').replaceWith('<li>removed</li>');
</script>
</body>
</html>
The new DOM stiuctuie auueu to the DOM is a stiing paiametei passeu into the
replaceWith() methou. In oui example, all the <li> elements, incluuing chiluien ele-
ments, aie ieplaceu with the new stiuctuie, <li>removed</li>.
26 | Chapter 1:jQuery Basics
Discussion
jQueiy pioviues an inveise to this methou calleu replaceAll() that uoes the same task
with the paiameteis ieveiseu. Foi example, we coulu iewiite the jQueiy coue lounu in
oui iecipe coue like so:
jQuery('<li>removed</li>').replaceAll('li.remove');
Heie we aie passing the jQueiy lunction the HTML stiing anu then using the
replaceAll() methou to select the DOM noue anu its chiluien that we want to Le
iemoveu anu ieplaceu.
1.13 Cloning DOM Elements
Problem
You neeu to clone/copy a poition ol the DOM.
Solution
jQueiy pioviues the clone() methou loi copying DOM elements. Its usage is stiaight-
loiwaiu. Simply select the DOM elements using the jQueiy lunction, anu then call the
clone() methou on the selecteu set ol element(s). The iesult is a copy ol the DOM
stiuctuie Leing ietuineu loi chaining insteau ol the oiiginally selecteu DOM elements.
In the lollowing coue, I am cloning the <ul> element anu then appenuing this copy Lack
into the DOM using the inseiting methou appendTo(). Essentially, I am auuing anothei
<ul> stiuctuie to the page exactly like the one that is alieauy theie:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul>
<li>list</li>
<li>list</li>
<li>list</li>
<li>list</li>
</ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>
1.13 Cloning DOM Elements | 27
Discussion
The cloning methou is actually veiy hanuy loi moving DOM snippets aiounu insiue ol
the DOM. It`s especially uselul when you want to not only copy anu move the DOM
elements Lut also the events attacheu to the cloneu DOM elements. Closely examine
the HTML anu jQueiy heie:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<ul id="a">
<li>list</li>
<li>list</li>
<li>list</li>
<li>list</li>
</ul>
<ul id="b"></ul>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/JavaScript">
jQuery('ul#a li')
.click(function(){alert('List Item Clicked')})
.parent()
.clone(true)
.find('li')
.appendTo('#b')
.end()
.end()
.remove();
</script>
</body>
</html>
Il you weie to iun this coue in a Liowsei, it woulu clone the <li> elements on the page
that have a click event attacheu to them, inseit these newly cloneu elements (incluuing
events) into the empty <ul>, anu then iemove the <ul> element that we cloneu.
This might stietch a new jQueiy uevelopei`s minu, so let`s examine this jQueiy state-
ment Ly stepping thiough this coue in oiuei to explain the chaineu methous:
1. jQuery('ul#a li') = Select <ul> element with an id attiiLute ol a anu then select
all the <li> elements insiue ol the <ul>.
2. .click(function(){alert('List Item Clicked')}) = Auu a click event to each <li>.
3. .parent() = Tiaveise the DOM, Ly changing my selecteu set to the <ul> element.
+. .clone(true) = Clone the <ul> element anu all its chiluien, incluuing any events
attacheu to the elements that aie Leing cloneu. This is uone Ly passing the
clone() methou a Boolean value ol true.
28 | Chapter 1:jQuery Basics
5. .find('li') = Now, within the cloneu elements, change the set ol elements to only
the <li> elements containeu within the cloneu <ul> element.
6. .appendTo('#b') = Take these selecteu cloneu <li> elements anu place them insiue
ol the <ul> element that has an id attiiLute value ol b.
7. .end() = Retuin to the pievious selecteu set ol elements, which was the cloneu
<ul> element.
S. .end() = Retuin to the pievious selecteu set ol elements, which was the oiiginal
<ul> element we cloneu.
9. .remove() = Remove the oiiginal <ul> element.
Il it`s not oLvious, unueistanuing how to manipulate the selecteu set ol elements oi
ieveit to the pievious selecteu set is ciucial loi complex jQueiy statements.
1.14 Getting, Setting, and Removing DOM Element Attributes
Problem
You have selecteu a DOM element using the jQueiy lunction anu neeu to get oi set the
value ol the DOM element`s attiiLute.
Solution
jQueiy pioviues the attr() methou loi getting anu setting attiiLute values. In the lol-
lowing coue, we aie going to Le setting anu then getting the value ol an <a> element`s
href attiiLute:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<a>jquery.com</a>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
// alerts the jQuery home page URL
alert(
jQuery('a').attr('href','http://www.jquery.com').attr('href')
);
</script>
</body>
</html>
As you can see in the coue example, we aie selecting the only <a> element in the HTML
uocument, setting its href attiiLute, anu then getting its value with the same attr()
1.14 Getting, Setting, and Removing DOM Element Attributes | 29
methou Ly passing the methou the attiiLute name alone. Hau theie Leen multiple
<a> elements in the uocument, the attr() methou woulu access the liist matcheu ele-
ment. The coue when loaueu into a Liowsei will alert() the value that we set loi the
href attiiLute.
Now, since most elements have moie than one attiiLute availaLle, it`s also possiLle to
set multiple attiiLute values using a single attr() methou. Foi example, we coulu also
set the title attiiLute in the pievious example Ly passing the attr() methou an oLject
insteau ol two stiing paiameteis:
jQuery('a').attr({'href':'http://www.jquery.com','title':'jquery.com'}).attr('href')
Vith the aLility to auu attiiLutes to elements also comes the aLility to iemove attiiLutes
anu theii values. The removeAttr() methou can Le useu to iemove attiiLutes liom
HTML elements. To use this methou, simply pass it a stiing value ol the attiiLute you`u
like to iemove (e.g., jQuery('a')removeAttr('title')).
Discussion
In auuition to the attr() methou, jQueiy pioviues a veiy specilic set ol methous loi
woiking with the HTML element class attiiLute. Since the class attiiLute can contain
seveial values (e.g., class="class1 class2 class3"), these unigue attiiLute methous
aie useu to manage these values.
These jQueiy methous aie as lollows:
addClass()
Upuates the class attiiLute value with a new class/value incluuing any classes that
weie alieauy set
hasClass()
Checks the value ol the class attiiLute loi a specilic class
removeClass()
Removes a unigue class liom the class attiiLute while keeping any values alieauy
set
toggleClass()
Auus the specilieu class il it is not piesent; iemoves the specilieu class il it is piesent
1.15 Getting and Setting HTML Content
Problem
You neeu to get oi set a chunk ol HTML content in the cuiient weL page.
30 | Chapter 1:jQuery Basics
Solution
jQueiy pioviues the html() methou loi getting anu setting chunks (oi DOM stiuctuies)
ol HTML elements. In the lollowing coue, we use this methou to set anu then get the
HTML value ol the <p> element lounu in the HTML uocument:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p></p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
jQuery('p').html('<strong>Hello World</strong>, I am a <em>&lt;p&gt;</em> element.');
alert(jQuery('p').html());
</script>
</body>
</html>
Running this coue in a Liowsei will iesult in a Liowsei aleiting the HTML content
containeu within the <p> element, which we set using the html() methou anu then
ietiieveu using the html() methou.
Discussion
This methou uses the DOM innerHTML piopeity to get anu set chunks ol HTML. You
shoulu also Le awaie that html() is not availaLle on XML uocuments (although it will
woik loi XHTML uocuments).
1.16 Getting and Setting Text Content
Problem
You neeu to get oi set the text that is containeu insiue ol an HTML element(s).
Solution
jQueiy pioviues the text() methou loi getting anu setting the text content ol elements.
In the lollowing coue, we use this methou to set anu then get the text value ol the <p>
element lounu in the HTML uocument:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
1.16 Getting and Setting Text Content | 31
</head>
<body>
<p></p>
<script type="text/JavaScript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/JavaScript">
jQuery('p').text('Hello World, I am a <p> element.');
alert(jQuery('p').text());
</script>
</body>
</html>
Running this coue in a Liowsei will iesult in a Liowsei aleiting the content ol the <p>
element, which we set using the text() methou anu then ietiieveu using the text()
methou.
Discussion
It`s impoitant to iememLei that the text() methou is not unlike html() except that the
text() methou will escape HTML (ieplace < anu > with theii HTML entities). This
means that il you place tags insiue ol the text stiing passeu to the text() methou, it will
conveit these tags to theii HTML entities (&lt; anu &gt;).
1.17 Using the $ Alias Without Creating Global Conflicts
Problem
You want to use the shoitcut $ alias insteau ol typing the gloLal namespace name
(jQueiy) without leai ol gloLal conllicts.
Solution
The solution heie is to cieate an anonymous sell-invoking lunction that we pass the
jQueiy oLject to anu then use the $ chaiactei as a paiametei pointei to the jQueiy
oLject.
Foi example, all jQueiy coue coulu Le encapsulateu insiue the lollowing sell-invoking
lunction:
(function($){ //function to create private scope with $ parameter
//private scope and using $ without worry of conflict
})(jQuery); //invoke nameless function and pass it the jQuery object
Discussion
Essentially, what is going on heie is that we have passeu the gloLal ieleience to jQueiy
to a lunction that cieates a piivate scope. Hau we not uone this anu chosen to use the
shoithanu $ alias in the gloLal scope, we woulu Le taking a iisk Ly assuming that no
32 | Chapter 1:jQuery Basics
othei sciipts incluueu in the HTML uocument (oi sciipts incluueu in the lutuie) use
the $ chaiactei. Vhy iisk it when you can just cieate youi own piivate scope?
Anothei auvantage to uoing this is that coue incluueu insiue ol the anonymous sell-
invoking lunction will iun in its own piivate scope. You can iest assuieu that anything
that is placeu insiue the lunction will likely nevei cause a conllict with othei ]avaSciipt
coue wiitten in the gloLal scope. So, again, why iisk piogiammatic collisions? ]ust
cieate youi own piivate scope.
1.17 Using the $ Alias Without Creating Global Conflicts | 33
CHAPTER 2
Selecting Elements with jQuery
]amcs Padolscy
2.0 Introduction
At the veiy coie ol jQueiy is its selectoi engine, allowing you to select elements within
any uocument Laseu on names, attiiLutes, states, anu moie. Because ol CSS`s popu-
laiity, it maue sense to auopt its selectoi syntax to make it simple to select elements in
jQueiy. As well as suppoiting most ol the selectois specilieu in the CSS 13 specilica-
tions, jQueiy auus guite a lew custon sc|cctors that can Le useu to select elements Laseu
on special states anu chaiacteiistics. Auuitionally, you can cieate youi own custom
selectois! This chaptei uiscusses some ol the moie common pioLlems encounteieu
while selecting elements with jQueiy.
Beloie the liist iecipe, let`s uiscuss a lew Lasic piinciples.
The easiest way to taiget a specilic element oi a set ol elements within a uocument is
Ly using a CSS selectoi within the jQueiy wiappei lunction, like so:
jQuery('#content p a');
// Select all anchor elements within all paragraph elements within #content
Now that we`ve selecteu the elements we`ie altei, we can iun any ol jQueiy`s methous
on that collection. Foi example, auuing a class ol selected to all links is as simple as:
jQuery('#content p a').addClass('selected');
jQueiy olleis many DOM tiaveisal methous to aiu in the element selection piocess,
such as next(), prev(), anu parent(). These anu othei methous accept a selectoi ex-
piession as theii only paiametei, which lilteis the ietuineu iesults accoiuingly. So, you
can use CSS selectois in a numLei ol places, not just within jQuery(...).
Vhen constiucting selectois, theie`s one geneial iule loi optimization: Le only as spe-
cilic as you neeu to Le. It`s impoitant to iememLei that the moie complicateu a selectoi
is, the moie time it will take jQueiy to piocess the stiing. jQueiy uses native DOM
methous to ietiieve the elements you`ie altei. The lact that you can use selectois is only
a piouuct ol a nicely polisheu aLstiaction; theie`s nothing wiong with this, Lut it is
35
veiy impoitant to unueistanu the iamilications ol what you`ie wiiting. Heie is a typical
example ol an unnecessaiily complicateu selectoi:
jQuery('body div#wrapper div#content');
A highei uegiee ol specilicity uoes not necessaiily mean it`s lastei. The pievious selectoi
can Le iewiitten to this:
jQuery('#content');
This has the same ellect Lut manages to shave oll the oveiheau ol the pievious veision.
Also note that sometimes you can luithei optimize Ly specilying a context loi youi
selectois; this will Le uiscusseu latei in the chaptei (see Recipe 2.11).
2.1 Selecting Child Elements Only
Problem
You neeu to select one oi moie uiiect chiluien ol a paiticulai element.
Solution
Use the dircct dcsccndant comLinatoi (>). This comLinatoi expects two selectoi ex-
piessions, one on eithei siue. Foi example, il you want to select all anchoi elements
that iesiue uiiectly Leneath list items, you coulu use this selectoi: li > a. This woulu
select all anchois that aie chiluien ol a list item; in othei woius, all anchois that exist
uiiectly Leneath list items. Heie`s an example:
<a href="/category">Category</a>
<ul id="nav">
<li><a href="#anchor1">Anchor 1</a></li>
<li><a href="#anchor2">Anchor 2</a></li>
<li><span><a href="#anchor3">Anchor 3</a></span></li>
</ul>
Now, to select only the anchois within each list item, you woulu call jQueiy like so:
jQuery('#nav li > a');
// This selects two elements, as expected
The thiiu anchoi within the #nav list is not selecteu Lecause it`s not a chilu ol a list item;
it`s a chilu ol a <span> element.
Discussion
It`s impoitant to uistinguish Letween a chilu anu a uescenuant. A dcsccndant is any
element existing within anothei element, wheieas a chi|d is a uiiect uescenuant; the
analogy ol chiluien anu paients helps massively since the DOM`s hieiaichy is laigely
similai to that.
36 | Chapter 2:Selecting Elements with jQuery
It`s woith noting that comLinatois like > can Le useu without an expiession on the lelt
siue il a context is alieauy specilieu:
jQuery('> p', '#content');
// Fundamentally the same as jQuery('#content > p')
Selecting chiluien in a moie piogiammatic enviionment shoulu Le uone using jQueiy`s
children() methou, to which you can pass a selectoi to liltei the ietuineu elements.
This woulu select all uiiect chiluien ol the #content element:
jQuery('#content').children();
The pieceuing coue is essentially the same as jQuery('#content > *') with one impoi-
tant uilleience; it`s lastei. Insteau ol paising youi selectoi, jQueiy knows what you
want immeuiately. The lact that it`s lastei is not a uselul uilleiential, though. Plus, in
some situations, the speeu uilleience is maiginal veiging on iiielevant, uepenuing on
the Liowsei anu what you`ie tiying to select. Using the children() methou is especially
uselul when you`ie uealing with jQueiy oLjects stoieu unuei vaiiaLles. Foi example:
var anchors = jQuery('a');
// Getting all direct children of all anchor elements
// can be achieved in three ways:
// #1
anchors.children();
// #2
jQuery('> *', anchors);
// #3
anchors.find('> *');
In lact, theie aie even moie ways ol achieving it! In this situation, the liist methou is
the lastest. As stateu eailiei, you can pass a selectoi expiession to the children() meth-
ou to liltei the iesults:
jQuery('#content').children('p');
Only paiagiaph elements that aie uiiect chiluien ol #content will Le ietuineu.
2.2 Selecting Specific Siblings
Problem
You neeu to select only a specilic set ol siLlings ol a paiticulai element.
Solution
Il you`ie looking to select the aujacent siLling ol a paiticulai element, then you can use
the adjaccnt sib|ing comLinatoi (+). Similai to the chilu (>) comLinatoi, the siLling
comLinatoi expects a selectoi expiession on each siue. The iighthanu expiession is the
2.2 Selecting Specific Siblings | 37
suLject ol the selectoi, anu the lelthanu expiession is the siLling you want to match.
Heie`s some example HTML maikup:
<div id="content">
<h1>Main title</h1>
<h2>Section title</h2>
<p>Some content...</p>
<h2>Section title</h2>
<p>More content...</p>
</div>
Il you want to select only <h2> elements that immeuiately lollow <h1> elements, you
can use the lollowing selectoi:
jQuery('h1 + h2');
// Selects ALL H2 elements that are adjacent siblings of H1 elements
In this example, only one <h2> element will Le selecteu (the liist one). The seconu one
is not selecteu Lecause, while it is a siLling, it is not an adjaccnt siLling ol the <h1>
element.
Il, on the othei hanu, you want to select anu liltei all siLlings ol an element, aujacent
oi not, then you can use jQueiy`s siblings() methou to taiget them, anu you can pass
an optional selectoi expiession to liltei the selection:
jQuery('h1').siblings('h2,h3,p');
// Selects all H2, H3, and P elements that are siblings of H1 elements.
Sometimes you`ll want to taiget siLlings uepenuent on theii position ielative to othei
elements; loi example, heie`s some typical HTML maikup:
<ul>
<li>First item</li>
<li class="selected">Second item</li>
<li>Third item</li>
<li>Fourth item</li>
<li>Fifth item</li>
</ul>
To select all list items Leyonu the seconu (altei li.selected), you coulu use the lol-
lowing methou:
jQuery('li.selected').nextAll('li');
The nextAll() methou, just like siblings(), accepts a selectoi expiession to liltei the
selection Leloie it`s ietuineu. Il you uon`t pass a selectoi, then nextAll() will ietuin all
siLlings ol the suLject element that exist altei the suLject element, although not
Leloie it.
Vith the pieceuing example, you coulu also use anothei CSS comLinatoi to select all
list items Leyonu the seconu. The gcncra| sib|ing comLinatoi (~) was auueu in CSS3,
so you pioLaLly haven`t Leen aLle to use it in youi actual style sheets yet, Lut loitunately
you can use it in jQueiy without woiiying aLout suppoit, oi lack theieol. It woiks in
exactly the same lashion as the aujacent siLling comLinatoi (-) except that it selects
38 | Chapter 2:Selecting Elements with jQuery
a|| siLlings that lollow, not just the aujacent one. Using the pieviously specilieu maikup,
you woulu select all list items altei li.selected with the lollowing selectoi:
jQuery('li.selected ~ li');
Discussion
The aujacent siLling comLinatoi can Le conceptually tiicky to use Lecause it uoesn`t
lollow the top-uown hieiaichical appioach ol most othei selectoi expiessions. Still, it`s
woith knowing aLout anu is ceitainly a uselul way ol selecting what you want with
minimal hassle.
The same lunctionality might Le achieveu without a selectoi, in the lollowing way:
jQuery('h1').next('h2');
The next() methou can make a nice alteinative to the selectoi syntax, especially in
a piogiammatic setting when you`ie uealing with jQueiy oLjects as vaiiaLles, loi
example:
var topHeaders = jQuery('h1');
topHeaders.next('h2').css('margin','0');
2.3 Selecting Elements by Index Order
Problem
You neeu to select elements Laseu on theii oiuei among othei elements.
Solution
Depenuing on what you want to uo, you have the lollowing lilteis at youi uisposal.
These may look like CSS pseuuoclasses, Lut in jQueiy they`ie calleu ji|tcrs:
:first
Matches the liist selecteu element
:last
Matches the last selecteu element
:even
Matches even elements (zeio-inuexeu)
:odd
Matches ouu elements (zeio-inuexeu)
:eq(n)
Matches a single element Ly its inuex (n)
:lt(n)
Matches all elements with an inuex Lelow n
2.3 Selecting Elements by Index Order | 39
:gt(n)
Matches all elements with an inuex aLove n
Assuming the lollowing HTML maikup:
<ol>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
<li>Fourth item</li>
</ol>
the liist item in the list coulu Le selecteu in a numLei ol uilleient ways:
jQuery('ol li:first');
jQuery('ol li:eq(0)');
jQuery('ol li:lt(1)');
Notice that Loth the eq() anu lt() lilteis accept a numLei; since it`s zeio-inuexeu, the
liist item is 0, the seconu is 1, etc.
A common ieguiiement is to have alteinating styles on taLle iows; this can Le achieveu
with the :even anu :odd lilteis:
<table>
<tr><td>0</td><td>even</td></tr>
<tr><td>1</td><td>odd</td></tr>
<tr><td>2</td><td>even</td></tr>
<tr><td>3</td><td>odd</td></tr>
<tr><td>4</td><td>even</td></tr>
</table>
You can apply a uilleient class uepenuent on the inuex ol each taLle iow:
jQuery('tr:even').addClass('even');
You`u have to specily the coiiesponuing class (even) in youi CSS style sheet:
table tr.even {
background: #CCC;
}
This coue woulu piouuce the ellect shown in Figuie 2-1.
Iigurc 2-1. Tab|c with cvcn rows dar|cncd
40 | Chapter 2:Selecting Elements with jQuery
Discussion
As mentioneu, an element`s inuex is zeio-Laseu, so il an element is the liist one, then
its inuex is zeio. Apait liom that lact, using the pieceuing lilteis is veiy simple. Anothei
thing to note is that these lilteis ieguiie a collection to match against; the inuex can Le
ueteimineu only il an initial collection is specilieu. So, this selectoi woulun`t woik:
jQuery(':even');
Actually, this selectoi uoes woik, Lut only Lecause jQueiy uoes some
coiiective postpiocessing ol youi selectoi Lehinu the scenes. Il no initial
collection is specilieu, then jQueiy will assume you meant all elements
within the uocument. So, the selectoi woulu actually woik, since it`s
ellectively iuentical to this: jQuery('*:even').
An initial collection is ieguiieu on the lelthanu siue ol the liltei, i.e., something to apply
the liltei to. The collection can Le within an alieauy instantiateu jQueiy oLject, as
shown heie:
jQuery('ul li').filter(':first');
The liltei methou is Leing iun on an alieauy instantiateu jQueiy oLject (containing the
list items).
2.4 Selecting Elements That Are Currently Animating
Problem
You neeu to select elements Laseu on whethei they`ie animating.
Solution
jQueiy olleis a convenient liltei loi this veiy puipose. The :animated liltei will match
only elements that aie cuiiently animating:
jQuery('div:animated');
This selectoi woulu select all <div> elements cuiiently animating. Ellectively, jQueiy
is selecting all elements that have a nonempty animation gueue.
Discussion
This liltei is especially uselul when you neeu to apply a Llanket lunction to all elements
that aie not cuiiently animateu. Foi example, to Legin animating all <div> elements
that aie not alieauy animating, it`s as simple as this:
jQuery('div:not(div:animated)').animate({height:100});
2.4 Selecting Elements That Are Currently Animating | 41
Sometimes you might want to check whethei an element is animating. This can Le uone
with jQueiy`s uselul is() methou:
var myElem = jQuery('#elem');
if( myElem.is(':animated') ) {
// Do something.
}
2.5 Selecting Elements Based on What They Contain
Problem
You neeu to select an element Laseu on what it contains.
Solution
Theie aie noimally only two things you woulu want to gueiy in this iespect: the text
contents anu the element contents (othei elements). Foi the loimei, you can use
the :contains() liltei:
<!-- HTML -->
<span>Hello Bob!</span>
// Select all SPANs with 'Bob' in:
jQuery('span:contains("Bob")');
Note that it`s case sensitive, so this selectoi woulun`t match anything il we seaicheu
loi bob (with a loweicase b). Also, guotes aie not ieguiieu in all situations, Lut it`s a
goou piactice just in case you encountei a situation wheie they aie ieguiieu (e.g., when
you want to use paientheses).
To test loi nesteu elements, you can use the :has() liltei. You can pass any valiu selectoi
to this liltei:
jQuery('div:has(p a)');
This selectoi woulu match all <div> elements that encapsulate <a> elements (anchois)
within <p> elements (paiagiaphs).
Discussion
The :contains() liltei might not lit youi ieguiiements. You may neeu moie contiol
ovei what text to allow anu what to uisallow. Il you neeu that contiol, I suggest using
a iegulai expiession anu testing against the text ol the element, like so:
jQuery('p').filter(function(){
return /(^|\s)(apple|orange|lemon)(\s|$)/.test(jQuery(this).text());
});
This woulu select all paiagiaphs containing the woiu app|c, orangc, oi |cnon. To ieau
moie aLout jQueiy`s filter() methou, have a look at Recipe 2.10.
42 | Chapter 2:Selecting Elements with jQuery
2.6 Selecting Elements by What They Dont Match
Problem
You neeu to select a numLei ol elements that uon`t match a specilic selectoi.
Solution
Foi this, jQueiy gives us the :not liltei, which you can use in the lollowing way:
jQuery('div:not(#content)'); // Select all DIV elements except #content
This liltei will iemove any elements liom the cuiient collection that aie matcheu Ly
the passeu selectoi. The selectoi can Le as complex as you like; it uoesn`t have to Le a
simple expiession, e.g.:
jQuery('a:not(div.important a, a.nav)');
// Selects anchors that do not reside within 'div.important' or have the class 'nav'
Passing complex selectois to the :not liltei is possiLle only in jQueiy
veision 1.3 anu Leyonu. In veisions pievious to that, only simple selectoi
expiessions weie acceptaLle.
Discussion
In auuition to the mentioneu :not liltei, jQueiy also supplies a methou with veiy similai
lunctionality. This methou accepts Loth selectois anu DOM collections/noues. Heie`s
an example:
var $anchors = jQuery('a');
$anchors.click(function(){
$anchors.not(this).addClass('not-clicked');
});
Accoiuing to this coue, when an anchoi is clickeu, all anchois apait liom that one will
have the class not-clicked auueu. The this keywoiu ieleis to the clickeu element.
The not() methou also accepts selectois:
$('#nav a').not('a.active');
This coue selects all anchois iesiuing within #nav that uo not have a class ol active.
2.7 Selecting Elements Based on Their Visibility
Problem
You neeu to select an element Laseu on whethei it`s visiLle.
2.7 Selecting Elements Based on Their Visibility | 43
Solution
You can use eithei the :hidden oi :visible liltei as necessaiy:
jQuery('div:hidden');
Heie aie some othei examples ol usage:
if (jQuery('#elem').is(':hidden')) {
// Do something conditionally
}
jQuery('p:visible').hide(); // Hiding only elements that are currently visible
Discussion
Since jQueiy 1.3.2, these lilteis have uiamatically changeu. Beloie 1.3.2
Loth lilteis woulu iesponu like you woulu expect loi the CSS
visibility piopeity, Lut that is no longei taken into account. Insteau,
jQueiy tests loi the height anu wiuth ol the element in guestion (ielative
to its offsetParent). Il eithei ol these uimensions is zeio, then the ele-
ment is consiueieu hiuuen; otheiwise, it`s consiueieu visiLle.
Il you neeu moie contiol, you can always use jQueiy`s filter() methou, which allows
you to test the element in any way you want. Foi example, you may want to select all
elements that aie set to display:none Lut not those that aie set to visibility:hidden.
Using the :hidden liltei won`t woik Lecause it matches elements with eithei ol those
chaiacteiistics (< v1.3.2) oi uoesn`t take eithei piopeity into consiueiation at all
(>= v1.3.2):
jQuery('*').filter(function(){
return jQuery(this).css('display') === 'none'
&& jQuery(this).css('visibility') !== 'hidden';
});
The pieceuing coue shoulu leave you with a collection ol elements that aie set to
display:none Lut not visibility:hidden. Note that, usually, such a selection won`t Le
necessaiythe :hidden liltei is peilectly suitaLle in most situations.
2.8 Selecting Elements Based on Attributes
Problem
You neeu to select elements Laseu on attiiLutes anu those attiiLutes` values.
Solution
Use an attiiLute selectoi to match specilic attiiLutes anu coiiesponuing values:
jQuery('a[href="http://google.com"]');
44 | Chapter 2:Selecting Elements with jQuery
The pieceuing selectoi woulu select all anchoi elements with an href attiiLute egual
to the value specilieu (http://google.com).
Theie aie a numLei ol ways you can make use ol the attiiLute selectoi:
[attr]
Matches elements that have the specilieu attiiLute
[attr=val]
Matches elements that have the specilieu attiiLute with a ceitain value
[attr!=val]
Matches elements that uon`t have the specilieu attiiLute oi value
[attr^=val]
Matches elements with the specilieu attiiLute anu that stait with a ceitain value
[attr$=val]
Matches elements that have the specilieu attiiLute anu that enu with a ceitain value
[attr~=val]
Matches elements that contain the specilieu value with spaces, on eithei siue (i.e.,
car matches car Lut not cart)
Piioi to jQueiy 1.2 you hau to use XPath syntax (i.e., putting an @ sign
Leloie an attiiLute name). This is now uepiecateu.
You can also comLine multiple attiiLute selectois:
// Select all elements with a TITLE and HREF:
jQuery('*[title][href]');
Discussion
As always, loi special ieguiiements it may Le moie suitaLle to use the filter() methou
to moie specilically outline what you`ie looking loi:
jQuery('a').filter(function(){
return (new RegExp('http:\/\/(?!' + location.hostname + ')')).test(this.href);
});
In this liltei, a iegulai expiession is Leing useu to test the href attiiLute ol each anchoi.
It selects all exteinal links within any page.
The attiiLute selectoi is especially uselul loi selecting elements Laseu on slightly vaiying
attiiLutes. Foi example, il we hau the lollowing HTML:
<div id="content-sec-1">...</div>
<div id="content-sec-2">...</div>
<div id="content-sec-3">...</div>
<div id="content-sec-4">...</div>
2.8 Selecting Elements Based on Attributes | 45
we coulu use the lollowing selectoi to match all ol the <div> elements:
jQuery('div[id^="content-sec-"]');
2.9 Selecting Form Elements by Type
Problem
You neeu to select loim elements Laseu on theii types (hidden, text, checkbox, etc.).
Solution
jQueiy gives us a Lunch ol uselul lilteis loi this veiy puipose, as shown in TaLle 2-1.
Tab|c 2-1. jQucry jorn ji|tcrs
jQuery selector syntax Selects what?
:text <input type="text" />
:password <input type="password" />
:radio <input type="radio" />
:checkbox <input type="checkbox" />
:submit <input type="submit" />
:image <input type="image" />
:reset <input type="reset" />
:button <input type="button" />
:file <input type="file" />
:hidden <input type="hidden" />
So, as an example, il you neeueu to select all text inputs, you woulu simply uo this:
jQuery(':text');
Theie is also an :input liltei that selects all input, textarea, button, anu select
elements.
Discussion
Note that the :hidden liltei, as uiscusseu eailiei, uoes not test loi the type hidden; it
woiks Ly checking the computeu height ol the element. This woiks with input elements
ol the type hidden Lecause they, like othei hiuuen elements, have an offsetHeight
ol zeio.
As with all selectois, you can mix anu match as uesiieu:
jQuery(':input:not(:hidden)');
// Selects all input elements except those that are hidden.
46 | Chapter 2:Selecting Elements with jQuery
These lilteis can also Le useu with iegulai CSS syntax. Foi example, selecting all text
input elements plus all <textarea> elements can Le uone in the lollowing way:
jQuery(':text, textarea');
2.10 Selecting an Element with Specific Characteristics
Problem
You neeu to select an element Laseu not only on its ielationship to othei elements oi
simple attiiLute values Lut also on vaiying chaiacteiistics such as piogiammatic states
not expiessiLle as selectoi expiessions.
Solution
Il you`ie looking loi an element with veiy specilic chaiacteiistics, selectoi expiessions
may not Le the Lest tool. Using jQueiy`s DOM lilteiing methou (filter()), you can
select elements Laseu on anything expiessiLle within a lunction.
The liltei methou in jQueiy allows you to pass eithei a stiing (i.e., a selectoi expiession)
oi a lunction. Il you pass a lunction, then its ietuin value will ueline whethei ceitain
elements aie selecteu. The lunction you pass is iun against eveiy element in the cuiient
selection; eveiy time the lunction ietuins lalse, the coiiesponuing element is iemoveu
liom the collection, anu eveiy time you ietuin tiue, the coiiesponuing element is not
allecteu (i.e., it iemains in the collection):
jQuery('*').filter(function(){
return !!jQuery(this).css('backgroundImage');
});
The pieceuing coue selects all elements with a Lackgiounu image.
The initial collection is ol all elements (*); then the filter() methou is calleu with a
lunction. This lunction will ietuin tiue when a backgroundImage is specilieu loi the
element in guestion. The !! that you see is a guick way ol conveiting any type in ]ava-
Sciipt to its Boolean expiession. Things that evaluate to lalse incluue an empty stiing,
the numLei zeio, the value undefined, the null type, anu, ol couise, the lalse Boolean
itsell. Il any ol these things aie ietuineu liom gueiying the backgroundImage, the lunc-
tion will ietuin lalse, thus iemoving any elements without Lackgiounu images liom
the collection. Most ol what I just saiu is not unigue to jQueiy; it`s just ]avaSciipt
lunuamentals.
In lact, the !! is not necessaiy Lecause jQueiy evaluates the ietuin value into a Boolean
itsell, Lut keeping it theie is still a goou iuea; anyone looking at youi coue can Le
aLsolutely suie ol what you intenueu (it aius ieauaLility).
2.10 Selecting an Element with Specific Characteristics | 47
Vithin the lunction you pass to filter(), you can ielei to the cuiient element via the
this keywoiu. To make it into a jQueiy oLject (so you can access anu peiloim jQueiy
methous), simply wiap it in the jQueiy lunction:
this; // Regular element object
jQuery(this); // jQuery object
Heie aie some othei lilteiing examples to spaik youi imagination:
// Select all DIV elements with a width between 100px and 200px:
jQuery('div').filter(function(){
var width = jQuery(this).width();
return width > 100 && width < 200;
});
// Select all images with a common image extension:
jQuery('img').filter(function(){
return /\.(jpe?g|png|bmp|gif)(\?.+)?$/.test(this.src);
});
// Select all elements that have either 10 or 20 children:
jQuery('*').filter(function(){
var children = jQuery(this).children().length;
return children === 10 || children === 20;
});
Discussion
Theie will always Le seveial uilleient ways to uo something; this is no less tiue when
selecting elements with jQueiy. The key uilleiential is usually going to Le speeu; some
ways aie last, otheis aie slow. Vhen you use a complicateu selectoi, you shoulu Le
thinking aLout how much piocessing jQueiy has to uo in the Lackgiounu. A longei
anu moie complex selectoi will take longei to ietuin iesults. jQueiy`s native methous
can sometimes Le much lastei than using a single selectoi, plus theie`s the auueu Lenelit
ol ieauaLility. Compaie these two technigues:
jQuery('div a:not([href^=http://]), p a:not([href^=http://])');
jQuery('div, p').find('a').not('[href^=http://]');
The seconu technigue is shoitei anu much moie ieauaLle than the liist. Testing in
Fiielox (v3) anu Salaii (v+) ieveals that it`s also lastei than the liist technigue.
2.11 Using the Context Parameter
Problem
You`ve heaiu ol the context paiametei Lut have yet to encountei a situation wheie it`s
uselul.
48 | Chapter 2:Selecting Elements with jQuery
Solution
As well as passing a selectoi expiession to jQuery() oi $(), you can pass a seconu
aigument that specilies the context. The context is wheie jQueiy will seaich loi the
elements matcheu Ly youi selectoi expiession.
The context paiametei is pioLaLly one ol the most unueiuseu ol jQueiy`s leatuies. The
way to use it is incieuiLly simple: pass a selectoi expiession, a jQueiy oLject, a DOM
collection, oi a DOM noue to the context aigument, anu jQueiy will seaich only loi
elements within that context.
Heie`s an example: you want to select all input lielus within a loim Leloie it`s
suLmitteu:
jQuery('form').bind('submit', function(){
var allInputs = jQuery('input', this);
// Now you would do something with 'allInputs'
});
Notice that this was passeu as the seconu aigument; within the hanulei just shown,
this ieleis to the loim element. Since it`s set as the context, jQueiy will only ietuin
input elements within that loim. Il we uiun`t incluue that seconu aigument, then all ol
the uocument`s input elements woulu Le selecteunot what we want.
As mentioneu, you can also pass a iegulai selectoi as the context:
jQuery('p', '#content');
The pieceuing coue ietuins exactly the same collection as the lollowing selectoi:
jQuery('#content p');
Specilying a context can aiu in ieauaLility anu speeu. It`s a uselul leatuie to know aLout!
Discussion
The uelault context useu Ly jQueiy is document, i.e., the topmost item in the DOM
hieiaichy. Only specily a context il it`s uilleient liom this uelault. Using a context can
Le expiesseu in the lollowing way:
jQuery( context ).find( selector );
In lact, this is exactly what jQueiy uoes Lehinu the scenes.
Consiueiing this, il you alieauy have a ieleience to the context, then you shoulu pass
that insteau ol a selectoitheie`s no point in making jQueiy go thiough the selection
piocess again.
2.11 Using the Context Parameter | 49
2.12 Creating a Custom Filter Selector
Problem
You neeu a ieusaLle liltei to taiget specilic elements Laseu on theii chaiacteiistics. You
want something that is succinct anu can Le incluueu within youi selectoi expiessions.
Solution
You can extenu jQueiy`s selectoi expiessions unuei the jQuery.expr[':'] oLject; this
is an alias loi Sizzle.selectors.filters. Each new liltei expiession is uelineu as a
piopeity ol this oLject, like so:
jQuery.expr[':'].newFilter = function(elem, index, match){
return true; // Return true/false like you would on the filter() method
};
The lunction will Le iun on all elements in the cuiient collection anu neeus to ietuin
tiue (to keep the element in the collection) oi lalse (to iemove the element liom the
collection). Thiee Lits ol inloimation aie passeu to this lunction: the element in gues-
tion, the inuex ol this element among the entiie collection, anu a match aiiay ietuineu
liom a iegulai expiession match that contains impoitant inloimation loi the moie
complex expiessions.
Foi example, you might want to taiget all elements that have a ceitain piopeity. This
liltei matches all elements that aie uisplayeu inline:
jQuery.expr[':'].inline = function(elem) {
return jQuery(elem).css('display') === 'inline';
};
Now that we have cieateu a custom selectoi, we can use it in any selectoi expiession:
// E.g. #1
jQuery('div a:inline').css('color', 'red');
// E.g. #2
jQuery('span').filter(':not(:inline)').css('color', 'blue')
jQueiy`s custom selectois (:radio, :hidden, etc.) aie cieateu in this way.
Discussion
As mentioneu, the thiiu paiametei passeu to youi liltei lunction is an aiiay ietuineu
liom a iegulai expiession match that jQueiy peiloims on the selectoi stiing. This match
is especially uselul il you want to cieate a liltei expiession that accepts paranctcrs. Let`s
say that we want to cieate a selectoi that gueiies loi uata helu Ly jQueiy:
jQuery('span').data('something', 123);
// We want to be able to do this:
jQuery('*:data(something,123)');
50 | Chapter 2:Selecting Elements with jQuery
The puipose ol the selectoi woulu Le to select all elements that have hau uata attacheu
to them via jQueiy`s data() methouit specilically taigets elements with a uatakey ol
something, egual to the numLei 123.
The pioposeu liltei (:data) coulu Le cieateu as lollows:
jQuery.expr[':'].data = function(elem, index, m) {

// Remove ":data(" and the trailing ")" from
// the match, as these parts aren't needed:
m[0] = m[0].replace(/:data\(|\)$/g, '');

var regex = new RegExp('([\'"]?)((?:\\\\\\1|.)+?)\\1(,|$)', 'g'),
// Retrieve data key:
key = regex.exec( m[0] )[2],
// Retrieve data value to test against:
val = regex.exec( m[0] );

if (val) {
val = val[2];
}

// If a value was passed then we test for it, otherwise
// we test that the value evaluates to true:
return val ? jQuery(elem).data(key) == val : !!jQuery(elem).data(key);

};
The ieason loi such a complex iegulai expiession is that we want to make it as llexiLle
as possiLle. The new selectoi can Le useu in a numLei ol uilleient ways:
// As we originally mused (above):
jQuery('div:data("something",123)');
// Check if 'something' is a "truthy" value
jQuery('div:data(something)');
// With or without (inner) quotes:
jQuery('div:data(something, "something else")');
Now we have a totally new way ol gueiying uata helu Ly jQueiy on an element.
Il you evei want to auu moie than one new selectoi at the same time, it`s Lest to use
jQueiy`s extend() methou:
jQuery.extend(jQuery.expr[':'], {
newFilter1 : function(elem, index, match){
// Return true or false.
},
newFilter2 : function(elem, index, match){
// Return true or false.
},
newFilter3 : function(elem, index, match){
// Return true or false.
}
});
2.12 Creating a Custom Filter Selector | 51
CHAPTER 3
Beyond the Basics
Ralph Whitbcck
3.0 Introduction
jQueiy is a veiy lightweight liLiaiy that is capaLle ol helping you uo the simple selec-
tions ol DOM elements on youi page. You saw these simple uses in Chaptei 1. In this
chaptei, we`ll exploie how jQueiy can Le useu to manipulate, tiaveise, anu extenu
jQueiy to inlinite possiLilities. As lightweight as jQueiy is, it was Luilt to Le ioLust anu
expanuaLle.
3.1 Looping Through a Set of Selected Results
Problem
You neeu to cieate a list liom youi selecteu set ol DOM elements, Lut peiloiming any
action on the selecteu set is uone on the set as a whole. To Le aLle to cieate a list with
each inuiviuual element, you`ll neeu to peiloim a sepaiate action on each element ol
the selecteu set.
Solution
Let`s say you wanteu to make a list ol eveiy link within a ceitain DOM element (peihaps
it`s a site with a lot ol usei-pioviueu content, anu you wanteu to guickly glance at the
suLmitteu links Leing pioviueu Ly useis). Ve woulu liist cieate oui jQueiy selection,
$("div#post a[href]"), which will select all links with an href attiiLute within the
<div> with the id ol post. Then we want to loop thiough each matcheu element anu
appenu it to an aiiay. See the lollowing coue example:
var urls = [];
$("div#post a[href]").each(function(i) {
urls[i] = $(this).attr('href');
});
53
alert(urls.join(","));
Ve weie aLle to make an aiiay Lecause we iteiateu thiough each element in the jQueiy
oLject Ly using the $().each(); methou. Ve aie aLle to access the inuiviuual elements
anu execute jQueiy methous against those elements Lecause we wiappeu the this
vaiiaLle in a jQueiy wiappei, $(), thus making it a jQueiy oLject.
Discussion
jQueiy pioviues a coie methou that you can use to loop thiough youi set ol selecteu
DOM elements. $().each() is jQueiy`s for loop, which will loop thiough anu pioviue
a sepaiate lunction scope loi each element in the set. $().each(); will iteiate exclusively
thiough jQueiy oLjects.
$().each(); is not the same as the jQueiy utility methou
jQuery.each(object, callback);. The jQuery.each methou is a moie
geneializeu iteiatoi methou that will iteiate thiough Loth oLjects anu
aiiays. See jQueiy`s online uocumentation loi moie inloimation on
jQuery.each() at http://docs.jqucry.con/Uti|itics/jQucry.cach.
In each iteiation, we aie getting the href attiiLute ol the cuiient element liom the main
selection. Ve aie aLle to get the cuiient DOM element Ly using the this keywoiu. Ve
then wiap it in the jQueiy oLject, $(this), so that we can peiloim jQueiy methous/
actions against itin oui case, pulling the href attiiLute liom the DOM element. The
last action is to assign the href attiiLute to a gloLal aiiay, urls.
]ust so we can see what we have, the aiiay URL is joineu togethei with a , anu uisplayeu
to the usei in an aleit Lox. Ve coulu also have auueu the list to an unoiueieu list DOM
element loi uisplay to the usei. Moie piactically, we might want to loimat the list ol
URLs into ]SON loimat anu senu it to the seivei loi piocessing into a uataLase.
Let`s look at anothei example using $().each();. This example is pioLaLly the most
oLvious use ol $().each();. Let`s say we have an unoiueieu list ol names, anu we want
each name to stanu out. One way to accomplish this is to set an alteinate Lackgiounu
coloi loi eveiy othei list item:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 1 - Looping through a set of selected results</title>
<style type="text/css">
.even { background-color: #ffffff; }
.odd { background-color: #cccccc; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"
type="text/javascript"></script>
54 | Chapter 3:Beyond the Basics
<script type="text/javascript">
(function($){
$(document).ready(function() {
$("ul > li").each(function(i) {
if (i % 2 == 1)
{
$(this).addClass("odd");
}
else
{
$(this).addClass("even");
}
});
});
})(jQuery);
</script>
</head>
<body>
<h2>Family Members</h2>
<ul>
<li>Ralph</li>
<li>Hope</li>
<li>Brandon</li>
<li>Jordan</li>
<li>Ralphie</li>
</ul>
</body>
</html>
Figuie 3-1 shows the coue output.
Iigurc 3-1. Codc output
As we iteiate thiough each <li> element, we aie testing whethei the cuiient inuex,
which is passeu in as a single aigument to the lunction when executeu, mouueu Ly 2
is egual to 1. Baseu on that conuition, we eithei set one CSS class (.odd) oi anothei CSS
class (.even).
3.1 Looping Through a Set of Selected Results | 55
Even though this may Le the most oLvious way to use $().each(), it
isn`t the most ellicient way to hanule making alteinating Lackgiounu
colois. Ve coulu have accomplisheu this with one line:
$("ul > li:odd").addClass("odd");
All we neeueu to uo was set all the <li> elements to the class .even in
the CSS so that we coulu oveiiiue the ouu <li> elements with the .odd
class with jQueiy.
The Lasic lunction ol $.each(); is to take the matcheu set anu iteiate thiough each
element via ieleience ol the inuex, peiloim some action, anu iteiate to the next element
in the matcheu set until theie aie no moie elements lelt.
3.2 Reducing the Selection Set to a Specified Item
Problem
A jQueiy selectoi is Lioau anu selects all elements on the page Laseu on youi gueiy.
The neeu may iise when you neeu to select a single item, Laseu on its position, Lut
theie isn`t an easy way to select that item without euiting the coue.
Solution
Altei you make youi selection with jQueiy, you can chain the .eq() methou anu pass
in the inuex ol the selection you want to woik with.
The selection inuex is zeio-Laseu, so the liist item in the selection woulu
Le $().eq(0); wheie 0 iepiesents the liist item in the selection. $
().eq(4); iepiesents the lilth item.
Let`s use the enu ol the season stanuings loi the National Hockey League (NHL) con-
leiences as an example ol how we can show which teams maue the playolls anu which
uiun`t. Vhat we neeu to uo is list all the teams in each conleience in the oiuei they
linisheu the season in. Since the top eight teams in each conleience make it to the playoll
iounu, we just neeu to liguie out the eighth entiy in each list anu uiaw a line:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 2 - Reducing the selection set to specified item</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
56 | Chapter 3:Beyond the Basics
<script type="text/javascript">
(function($){
$(document).ready(function(){
$("ol#east > li").eq(7).css("border-bottom", "1px solid #000000");
$("ol#west > li").eq(7).css("border-bottom", "1px solid #000000");
});
})(jQuery);
</script>
</head>
<body>
<h2>Eastern Conference</h2>
<ol id="east">
<li>Boston Bruins</li>
<li>Washington Capitals</li>
<li>New Jersey Devils</li>
<li>Pittsburgh Penguins</li>
<li>Philadelphia Flyers</li>
<li>Carolina Hurricanes</li>
<li>New York Rangers</li>
<li>Montreal Canadians</li>
<li>Florida Panthers</li>
<li>Buffalo Sabres</li>
<li>Ottawa Senators</li>
<li>Toronto Maple Leafs</li>
<li>Atlanta Thrashers</li>
<li>Tampa Bay Lightning</li>
<li>New York Islanders</li>
</ol>
<h2>Western Conference</h2>
<ol id="west">
<li>San Jose Sharks</li>
<li>Detroit Red Wings</li>
<li>Vancouver Canucks</li>
<li>Chicago Blackhawks</li>
<li>Calgary Flames</li>
<li>St. Louis Blues</li>
<li>Columbus Blue Jackets</li>
<li>Anaheim Ducks</li>
<li>Minnesota Wild</li>
<li>Nashville Predators</li>
<li>Edmonton Oilers</li>
<li>Dallas Stars</li>
<li>Phoenix Coyotes</li>
<li>Los Angeles Kings</li>
<li>Colorado Avalanche</li>
</ol>
</body>
</html>
Figuie 3-2 shows the coue output.
3.2 Reducing the Selection Set to a Specified Item | 57
Iigurc 3-2. Codc output
As you can see, we just use an oiueieu list to list the teams in the oiuei they placeu,
then we use jQueiy to auu a Lottom Loiuei to the eighth item in each list. Ve neeu to
auu an ID to each oiueieu list so that we can specily each list in a sepaiate gueiy. Il we
weie to uo $("li").eq(7);, it woulu select only liom the liist list Lecause the gueiy
woulu have counteu all the <li> elements on the page togethei.
58 | Chapter 3:Beyond the Basics
Discussion
The .eq() methou is useu to take a selection set anu ieuuce it to a single item liom that
set. The aigument is the inuex that you want to ieuuce youi selection to. The inuex
staits at 0 anu goes to length -1. Il the aigument is an invaliu inuex, the methou will
ietuin an empty set ol elements insteau ol null.
The .eq() methou is similai to using the $(":eq()"); iight in youi selection, Lut
the .eq() methou allows you to chain to the selection anu line-tune luithei. Foi
example:
$("li").css("background-color","#CCCCCC").eq(0).css("background-color","#ff0000");
This will change the Lackgiounu coloi ol all <li> elements anu then select the liist one
anu give it a uilleient coloi to signily that it is peihaps a heauei item.
3.3 Convert a Selected jQuery Object into a Raw DOM Object
Problem
Selecting elements on a page with jQueiy ietuins a set as a jQueiy oLject anu not as a
iaw DOM oLject. Because it`s a jQueiy oLject, you can only iun jQueiy methous against
the selecteu set. To Le aLle to iun DOM methous anu piopeities against the selecteu
set, the set neeus to Le conveiteu to a iaw DOM oLject.
Solution
jQueiy pioviues a coie methou get(), which will conveit all matcheu jQueiy oLjects
Lack into an aiiay ol DOM oLjects. Auuitionally, you can pass an inuex value in as an
aigument ol get(), which will ietuin the element at the inuex ol the matcheu set as a
DOM oLject, $.get(1);. Now, even though you can get at a single element`s DOM
oLject via $.get(index), it is theie loi histoiical ieasons; the Lest piactices way is to
use the [] notation, $("div")[1];.
Ve aie uiscussing the coie .get() methou, which tiansloims a jQueiy
oLject to a DOM aiiay. Ve aie not uiscussing the Ajax get methou,
which will loau a iemote page using an HTTP GET ieguest.
Because get() ietuins an aiiay, you can tiaveise the aiiay to get at each DOM element.
Once it`s a DOM element, you can then call tiauitional DOM piopeities anu methous
against it. Let`s exploie a simple example ol pulling the innerHTML ol an element:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
3.3 Convert a Selected jQuery Object into a Raw DOM Object | 59
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 3 - Converting a selected jQuery object into a
raw DOM object</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
(function($){
$(document).ready(function(){
var inner = $("div")[0].innerHTML;
alert(inner);
});
})(jQuery);
</script>
</head>
<body>
<div>
<p>
jQuery, the write less, do more JavaScript library. Saving the day
for web developers since 2006.
</p>
</div>
</body>
</html>
Figuie 3-3 shows the output.
Iigurc 3-3. Codc output
Ve stait Ly selecting all the <div> elements on the page anu calling [0]. Ve pass in the
inuex ol the selection we want to woik with; since theie is only one <div> on the page,
we can pass in inuex 0. Finally, we call a piopeity, in this case innerHTML, to ietiieve the
iaw DOM element.
60 | Chapter 3:Beyond the Basics
Discussion
The coie get() methou can Le veiy uselul, as theie aie some non-]avaSciipt methous
that we can utilize loi oui auvantage. Let`s say we have a list anu we neeu to show that
list in ieveise oiuei. Since get() ietuins an aiiay, we can use native aiiay methous to
ieveise soit the list anu then ieuisplay the list:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 3 - Converting a selected jQuery object into a raw DOM
object</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
<!--
(function($){
$(document).ready(function(){
var lis = $("ol li").get().reverse();
$("ol").empty();
$.each(lis, function(i){
$("ol").append("<li>" + lis[i].innerHTML + "</li>");
});
});
})(jQuery);
//-->
</script>
</head>
<body>
<h2>New York Yankees - Batting Line-up</h2>
<ol>
<li>Jeter</li>
<li>Damon</li>
<li>Teixeira</li>
<li>Posada</li>
<li>Swisher</li>
<li>Cano</li>
<li>Cabrera</li>
<li>Molina</li>
<li>Ransom</li>
</ol>
</body>
</html>
Figuie 3-+ shows the output.
3.3 Convert a Selected jQuery Object into a Raw DOM Object | 61
Iigurc 3-1. Codc output
3.4 Getting the Index of an Item in a Selection
Problem
Vhen Linuing an event loi a wiue iange ol selecteu elements on a page, you neeu to
know exactly which item was clickeu liom the selecteu set to peisonalize the action
ol the Lounu event.
Solution
Vhen we click an item, we can use the coie methou index() to seaich thiough a
selection to see what inuex the item is at:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 4 - Getting the index of an item in a selection</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
<!--
(function($){
$(document).ready(function(){
$("div").click(function() {
alert("You clicked on div with an index of " +
$("div").index(this));
62 | Chapter 3:Beyond the Basics
});
});
})(jQuery);
//-->
</script>
</head>
<body>
<div>click me</div>
<div class="test">test</div>
<div>click me</div>
</body>
</html>
Figuie 3-5 shows the output.
Iigurc 3-5. Codc output
Ve stait Ly Linuing all <div> elements to a click event. Then when a <div> is clickeu,
we can liguie out which <div> was clickeu Ly seaiching loi the item in the same selec-
tion: $("div").index(this);, wheie this is the <div> that was clickeu.
3.4 Getting the Index of an Item in a Selection | 63
Discussion
The coie methou index() allows you to get the inuex ol the DOM element you aie
looking loi liom a jQueiy set. As ol jQueiy 1.2.6, you can also pass in the inuex ol a
jQueiy collection to seaich loi. The methou will ietuin the inuex ol the liist occuiience
it linus:
var test = $("div.test");
$("div").each(function(i){
if ($(this).index(test) >= 0)
{
//do something
}
else
{
//do something else
}
});
Ve`ll see whethei the <div> in the loop matches the collection we saveu in the vaiiaLle
test, anu il so, it will peiloim a custom action on the matcheu collection.
Il the inuex methou cannot linu the suLject that was passeu in, it will
ietuin -1.
3.5 Making a Unique Array of Values from an Existing Array
Problem
You have an oiueieu list on youi page. You select all the <li> elements ol that list using
jQueiy; now you neeu to tiansloim that list into anothei list.
Solution
Let`s say we have a list ol people in an oiueieu list. Ve woulu like to uisplay the liist
thiee people liom that oiueieu list as a sentence:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 5 - Making a unique array of values from an existing
array</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
64 | Chapter 3:Beyond the Basics
<!--
(function($){
$(document).ready(function(){
var arr = $.map($("LI"), function(item, index){
while (index < 3)
{
return $(item).html();
}
return null;
});
$(document.body).append("<span>The first three authors are: " +
arr.join(", ") + "</span>");
});
})(jQuery);
//-->
</script>
</head>
<body>
<h1>jQuery Cookbook Authors</h1>
<ol>
<li>John Resig</li>
<li>Cody Lindley</li>
<li>James Padolsey</li>
<li>Ralph Whitbeck</li>
<li>Jonathan Sharp</li>
<li>Michael Geary</li>
<li>Scott Gonzlez</li>
<li>Rebecca Murphey</li>
<li>Remy Sharp</li>
<li>Ariel Flesler</li>
<li>Brian Cherne</li>
<li>Jrn Zaefferer</li>
<li>Mike Hostetler</li>
<li>Nathan Smith</li>
<li>Richard D. Worth</li>
<li>Maggie Wachs</li>
<li>Scott Jehl</li>
<li>Todd Parker</li>
<li>Patty Toland</li>
<li>Rob Burns</li>
</ol>
</body>
</html>
Figuie 3-6 shows the output.
Ve stait Ly making an aiiay ol the <li> elements liom the oiueieu list. Ve will select
all <li> elements on the page Ly using a jQueiy selectoi anu pass that in as an aigument
ol the jQueiy utility methou $.map(), which will take an existing aiiay anu map it
into anothei aiiay. The seconu aigument is the lunction that will iteiate thiough the
aiiay, peiloim tianslations, anu ietuin a new value to Le stoieu into a new aiiay.
3.5 Making a Unique Array of Values from an Existing Array | 65
In the pieceuing example, we iteiate thiough the aiiay we maue, ietuin only the
html() values ol the liist thiee list elements, anu map these values into a new aiiay. Ve
then take that aiiay anu use the join methou to make a single stiing out ol the aiiay
anu inject it into the enu ol the uocument.
Discussion
In the solution, we aie using the jQueiy utility methou $.map(), which will tiansloim
an existing aiiay into anothei aiiay ol items. $.map() takes two aiguments, an aiiay
anu a callLack lunction:
$.map([1,2,3], function(n,i) { return n+i;});
//Output: [1,3,5]
$.map() will iteiate thiough each item ol the oiiginal aiiay anu pass in the item to Le
tianslateu anu the inuex ol the cuiient location within the aiiay. The methou is ex-
pecting a value to Le ietuineu. The ietuineu value will Le inseiteu into the new aiiay.
Il the null value is ietuineu, no value will Le saveu into the new aiiay.
Retuining null Lasically iemoves the item liom the new aiiay.
Iigurc 3-. Codc output
66 | Chapter 3:Beyond the Basics
3.6 Performing an Action on a Subset of the Selected Set
Problem
You neeu to peiloim an action on a set ol tags, Lut theie is no way to isolate these tags
liom all the othei tags on the page in a jQueiy selection set.
Solution
Ve can use the slice() methou to liltei the selection set to a suLset. Ve pass it a staiting
inuex value anu an enuing inuex value, then we can chain oui action at the enu:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 6 - Performing an action on a subset of the selected
set</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
<!--
(function($){
$(document).ready(function(){
$("p").slice(1,3).wrap("<i></i>");
});
})(jQuery);
//-->
</script>
</head>
<body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin eget nibh ut
tortor egestas pharetra. Nullam a hendrerit urna. Aenean augue arcu, vestibulum eget
faucibus nec, auctor vel velit. Fusce eget velit non nunc auctor rutrum id et ante.
Donec nec malesuada arcu. Suspendisse eu nibh nulla, congue aliquet metus. Integer
porta dignissim magna, eu facilisis magna luctus ac. Aliquam convallis condimentum
purus, at lacinia nisi semper volutpat. Nulla non risus justo. In ac elit vitae elit
posuere adipiscing.
</p>
<p>
Aliquam gravida metus sit amet orci facilisis eu ultricies risus iaculis. Nunc
tempus tristique magna, molestie adipiscing nibh bibendum vel. Donec sed nisi luctus
sapien scelerisque pretium id eu augue. Mauris ipsum arcu, feugiat non tempor
tincidunt, tincidunt sit amet turpis. Vestibulum scelerisque rutrum luctus. Curabitur
eu ornare nisl. Cras in sem ut eros consequat fringilla nec vitae felis. Nulla
facilisi. Mauris suscipit feugiat odio, a condimentum felis luctus in. Nulla interdum
dictum risus, accumsan dignissim tortor ultricies in. Duis justo mauris, posuere vel
convallis ut, auctor non libero. Ut a diam magna, ut egestas dolor. Nulla convallis,
orci in sodales blandit, lorem augue feugiat nulla, vitae dapibus mi ligula quis
3.6 Performing an Action on a Subset of the Selected Set | 67
ligula. Aenean mattis pulvinar est quis bibendum.
</p>
<p>
Donec posuere pulvinar ligula, nec sagittis lacus pharetra ac. Cras nec
tortor mi. Pellentesque et magna vel erat consequat commodo a id nunc. Donec velit
elit, vulputate nec tristique vitae, scelerisque ac sem. Proin blandit quam ut magna
ultrices porttitor. Fusce rhoncus faucibus tincidunt. Cras ac erat lacus, dictum
elementum urna. Nulla facilisi. Praesent ac neque nulla, in rutrum ipsum. Aenean
imperdiet, turpis sit amet porttitor hendrerit, ante dui eleifend purus, eu fermentum
dolor enim et elit.
</p>
<p>
Suspendisse facilisis molestie hendrerit. Aenean congue congue sapien, ac
luctus nulla rutrum vel. Fusce vitae dui urna. Fusce iaculis mattis justo sit amet
varius. Duis velit massa, varius in congue ut, tristique sit amet lorem. Curabitur
porta, mauris non pretium ultrices, justo elit tristique enim, et elementum tellus
enim sit amet felis. Sed sollicitudin rutrum libero sit amet malesuada. Duis vitae
gravida purus. Proin in nunc at ligula bibendum pharetra sit amet sit amet felis.
Integer ut justo at massa ullamcorper sagittis. Mauris blandit tortor lacus,
convallis iaculis libero. Etiam non pellentesque dolor. Fusce ac facilisis ipsum.
Suspendisse eget ornare ligula. Aliquam erat volutpat. Aliquam in porttitor purus.
</p>
<p>
Suspendisse facilisis euismod purus in dictum. Vivamus ac neque ut sapien
fermentum placerat. Sed malesuada pellentesque tempor. Aenean cursus, metus a
lacinia scelerisque, nulla mi malesuada nisi, eget laoreet massa risus eu felis.
Vivamus imperdiet rutrum convallis. Proin porta, nunc a interdum facilisis, nunc dui
aliquet sapien, non consectetur ipsum nisi et felis. Nullam quis ligula nisi, sed
scelerisque arcu. Nam lorem arcu, mollis ac sodales eget, aliquet ac eros. Duis
hendrerit mi vitae odio convallis eget lobortis nibh sodales. Nunc ut nunc vitae
nibh scelerisque tempor at malesuada sapien. Nullam elementum rutrum odio nec aliquet.
</p>
</body>
</html>
Figuie 3-7 shows the output.
The pieceuing example selects the suLset staiting at inuex 1 anu enuing Leloie inuex
3 anu wiaps an italics tag aiounu the suLselection.
Discussion
The jQueiy methou slice() takes a couple ol options; the liist is the staiting inuex
position, anu the seconu aigument, which is optional, is the enuing inuex position. So,
say you wanteu all <P> tags except the liist one; you coulu uo $("p").slice(1), anu it
woulu stait the selection at the seconu item anu select the iest that is in the jQueiy
selection.
slice() also takes a negative numLei. Il a negative numLei is given, it`ll count in liom
the selection`s enu. So, $("p").slice(1); will select the last item in the selection. Au-
uitionally, $("p").slice(1, 2); will stait the selection at the seconu item anu select
to the seconu-to-last item.
68 | Chapter 3:Beyond the Basics
3.7 Configuring jQuery Not to Conflict with Other Libraries
Problem
Il jQueiy is loaueu on the same page as anothei ]avaSciipt liLiaiy, Loth liLiaiies may
have implementeu the $ vaiiaLle, which iesults in only one ol those methous woiking
coiiectly.
Iigurc 3-7. Codc output
3.7 Configuring jQuery Not to Conflict with Other Libraries | 69
Solution
Let`s say you inheiit a weL page that you neeu to upuate, anu the pievious piogiammei
useu anothei ]avaSciipt liLiaiy like Piototype, Lut you still want to use jQueiy. This
will cause a conllict, anu one ol the two liLiaiies will not woik Laseu on which liLiaiy
is listeu last in the page heau.
Il we just ueclaie Loth jQueiy anu Piototype on the same page like so:
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js"></script>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
this will cause a ]avaSciipt eiioi: element.dispatchEvent is not a function in
prototype.js. Thanklully, jQueiy pioviues a woikaiounu with the jQuery.noCon
flict() methou:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 7 - Configuring jQuery to free up a conflict with
another library</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js"></script>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
<!--
jQuery.noConflict();
// Use jQuery via jQuery(...)
jQuery(document).ready(function(){
jQuery("div#jQuery").css("font-weight","bold");
});
// Use Prototype with $(...), etc.
document.observe("dom:loaded", function() {
$('prototype').setStyle({
fontSize: '10px'
});
});
//-->
</script>
</head>
<body>
<div id="jQuery">Hello, I am a jQuery div</div>
<div id="prototype">Hello, I am a Prototype div</div>
</body>
</html>
70 | Chapter 3:Beyond the Basics
Figuie 3-S shows the output.
Iigurc 3-8. Codc output
Vhen you call jQuery.noConflict(), it gives contiol ol the $ vaiiaLle Lack to whomevei
implementeu it liist. Once you liee up the $ vaiiaLle, you only will Le aLle to access
jQueiy with the jQuery vaiiaLle. Foi example, when you useu to use $("div p"), you
woulu now use jQuery("div p").
Discussion
The jQueiy liLiaiy anu viitually all ol its plugins aie constiaineu Ly the jQueiy name-
space. You shoulun`t get a conllict with the jQueiy vaiiaLle anu any othei liLiaiy (i.e.,
Piototype, YUI, etc.). jQueiy uoes howevei use $ as a shoitcut loi the jQueiy oLject.
This shoitcut uelinition is what conllicts with othei liLiaiies that also use the $ vaiiaLle.
As we`ve seen in the solution, we can liee jQueiy ol the $ shoitcut anu ieveit to using
the jQueiy oLject.
Theie is anothei option. Il you want to make suie jQueiy won`t conllict with anothei
liLiaiy Lut still have the Lenelit ol a shoit name, you can call jQuery.noConflict() anu
assign it to a vaiiaLle:
var j = jQuery.noConflict();
j(document).ready(function(){
j("div#jQuery").css("font-weight","bold");
});
You can ueline youi own shoit name Ly choosing the vaiiaLle name you assign,
jQuery.noConflict().
Finally, anothei option is to encapsulate youi jQueiy coue insiue a closuie:
jQuery.noConflict();
(function($){
$("div#jQuery").css("font-weight","bold");
})(jQuery);
By using a closuie, you tempoiaiily make the $ vaiiaLle availaLle to the jQueiy oLject
while Leing iun insiue the lunction. Once the lunction enus, the $ vaiiaLle will ieveit
to the liLiaiy that hau initial contiol.
3.7 Configuring jQuery Not to Conflict with Other Libraries | 71
Il you use this technigue, you will not Le aLle to use othei liLiaiies`
methous within the encapsulateu lunction that expect the $.
3.8 Adding Functionality with Plugins
Problem
The jQueiy liLiaiy is a small, slick, poweilul ]avaSciipt liLiaiy, Lut it uoesn`t come
pieloaueu with eveiy piece ol lunctionality that you may neeu.
Solution
jQueiy was Luilt with extensiLility in minu. Il the coie jQueiy liLiaiy can`t uo what
you want, chances aie a jQueiy plugin authoi has wiitten a plugin that will hanule youi
neeu, pioLaLly in as little as one line ol coue.
To incluue a plugin on youi page, all you neeu to uo is uownloau the plugin .js lile,
incluue the jQueiy liLiaiy on the page, then immeuiately altei, incluue youi plugin on
the page. Then, in eithei anothei .js lile oi in a sciipt Llock on the page, you`ll typically
neeu to call the plugin anu pioviue any options that may Le ieguiieu.
Heie is an example using the jQueiy cycle plugin uevelopeu Ly Mike Alsup:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 8 - Adding Functionality with Plugins</title>
<style type="text/css">
.pics {
height: 232px;
width: 232px;
padding: 0;
margin: 0;
}
.pics img {
padding: 15px;
border: 1px solid #ccc;
background-color: #eee;
width: 200px;
height: 200px;
top: 0;
left: 0
}
</style>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<!--Now include your plugin declarations after you've declared jQuery on the page-->
72 | Chapter 3:Beyond the Basics
<script type="text/javascript" src="scripts/2.8/jquery.cycle.all.min.js?
v2.60"></script>
<script type="text/javascript">
<!--
(function($){
$(document).ready(function(){
$('.pics').cycle('fade');
});
})(jQuery);
//-->
</script>
</head>
<body>
<div class="pics">
<img src="images/2.8/beach1.jpg" width="200" height="200" alt="Beach 1" />
<img src="images/2.8/beach2.jpg" width="200" height="200" alt="Beach 2" />
<img src="images/2.8/beach3.jpg" width="200" height="200" alt="Beach 3" />
</div>
</body>
</html>
Figuie 3-9 shows the output.
Iigurc 3-9. Codc output (onc inagc jading into anothcr)
Vith one line ol coue, we aie aLle to make a sliueshow ellect that will show one image
at a time anu then laue to the next image automatically. The cycle plugin is also ex-
tensiLle Lecause it was wiitten so uevelopeis can pioviue uilleient options to have
uilleient tiansition ellects anu layouts.
Discussion
jQueiy has one ol the laigest communities ol uevelopeis ol any ol the ]avaSciipt liLia-
iies. This laige community contiiLutes to a laige Lase ol plugins anu tutoiials that aie
3.8 Adding Functionality with Plugins | 73
availaLle on the VeL. jQueiy hosts a iepositoiy ol plugins that have Leen wiitten anu
suLmitteu to http://p|ugins.jqucry.con Ly the authois. Theie aie cuiiently moie than
1,600 plugins listeu in the iepositoiy, anu you can linu plugins in many uilleient cat-
egoiies. Plugin authois aie inviteu to suLmit theii plugins anu to give a uesciiption, a
link to the plugin, anu a link to the plugin`s uocumentation. The iepositoiy makes it
easy loi uevelopeis to seaich loi the specilic lunctionality they want.
Chances aie that, as a uevelopei, you will eventually linu a plugin that meets youi
ieguiiements. But on the oll chance that a plugin uoesn`t exist, cieating a plugin youi-
sell is laiily stiaightloiwaiu. Heie aie some points to iememLei:
Name youi lile jqucry.jnanc oj p|uginj.js, as in jqucry.dcbug.js.
All new methous aie attacheu to the jQuery.fn oLject; all lunctions to the jQueiy
oLject.
Insiue methous, this is a ieleience to the cuiient jQueiy oLject.
Any methous oi lunctions you attach must have a semicolon (;) at the enu
otheiwise, the coue will Lieak when compiesseu.
Youi methou must ietuin the jQueiy oLject, unless explicitly noteu otheiwise.
You shoulu use this.each to iteiate ovei the cuiient set ol matcheu elementsit
piouuces clean anu compatiLle coue that way.
Always use jQuery insteau ol $ insiue youi plugin couethat allows useis to change
the alias loi jQueiy in a single place.
Foi moie inloimation anu examples on cieating plugins, you can go to the Authoiing
page on the jQueiy uocumentation site, oi you can skip aheau to Chaptei 12 wheie
Mike Hostetlei will go into moie uetail.
3.9 Determining the Exact Query That Was Used
Problem
Vhile wiiting a plugin oi a methou that extenus jQueiy, you neeu to know exactly
what the selection anu the context useu when calling the methou so that the methou
can Le iecalleu.
Solution
Ve can use the coie piopeities .selector anu .context in conjunction with each othei
so we can ie-cieate the oiiginal gueiy that was passeu thiough. Ve neeu to use Loth
in conjunction Lecause not all gueiies to oui lunction oi plugin will Le within the
uelault uocument context:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
74 | Chapter 3:Beyond the Basics
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title>Chapter 3 - Recipe 9 - Determining the exact query that was used</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
<!--
(function($){
$.fn.ShowQuery = function(i) {
alert("$(\""+ $(this).selector + "\", " + $(this).context +")");
if (i < 3)
{
$($(this).selector, $(this).context).ShowQuery(i+1);
}
};
$("div").ShowQuery(1);
})(jQuery);
//-->
</script>
</head>
<body>
<div>
This is a div.
</div>
</body>
</html>
Figuie 3-10 shows the output.
Iigurc 3-10. Codc output (a|crt box)
3.9 Determining the Exact Query That Was Used | 75
Discussion
In the pieceuing example, we ueline a methou that can Le calleu liom a jQueiy selec-
tion, ShowQuery. Vithin that methou, we aleit the gueiy as it was passeu in anu then
iecuisively iecall ShowQuery again with the same jQueiy selectoi. The if statement is
theie so that we uon`t get into a iecuisive loop.
The coie piopeities .selector anu .context weie intiouuceu in jQueiy 1.3, which was
ieleaseu in ]anuaiy 2009. These methous aie geaieu moie towaiu plugin uevelopeis
who may neeu to peiloim an action against the oiiginal gueiy passeu in. A potential
use case ol using these methous is to ieiun the selection gueiy oi to check to see whethei
an element is in the selection.
.selector ietuins as a stiing the actual selectoi that was useu to match the given ele-
ments. .selector will ietuin the whole selectoi il, say, the selection is Lioken up wheie
theie is a selectoi anu then the matcheu set is naiioweu with the use ol the find()
methou:
$("div").find("a").selector;
//returns: "div a"
.context will ietuin the DOM noue oiiginally passeu in to jQuery(). Il no context was
set in the selectoi, the context will uelault to the uocument.
76 | Chapter 3:Beyond the Basics
CHAPTER 4
jQuery Utilities
]onathan Sharp
4.0 Introduction
Olten, when thinking anu talking aLout jQueiy, the main concepts that come to minu
aie DOM anu style manipulation anu Lehavioi (events). Yet theie aie also a numLei
ol coie leatuies anu utility lunctions tuckeu away loi the uevelopei`s Lenelit. This
chaptei is locuseu on exposing, uisclosing, anu explaining these not-so-common utility
methous ol jQueiy.
4.1 Detecting Features with jQuery.support
Problem
You neeu to attach a special click hanulei to all anchoi tags that have just a hash loi
the cuiient page, anu you uon`t want to iisk it Lieaking Lecause ol Liowsei suppoit
issues.
Solution
(function($) {
$(document).ready(function() {
$('a')
.filter(function() {
var href = $(this).attr('href');
// Normalize the URL
if ( !jQuery.support.hrefNormalized ) {
var loc = window.location;
href = href.replace( loc.protocol + '//' + loc.host + loc.pathname,
'');
}
// This anchor tag is of the form <a href="#hash">
return ( href.substr(0, 1) == '#' );
})
77
.click(function() {
// Special click handler code
});
});
})(jQuery);
Discussion
The jQuery.support oLject was auueu in veision 1.3 anu contains Boolean llags to help
wiite coue using Liowsei leatuie uetection. In oui example, Inteinet Exploiei (IE) has
a uilleient Lehavioi in how it hanules the href attiiLute. IE will ietuin the lull URL
insteau ol the exact href attiiLute. Using the hrefNormalized attiiLute, we have lutuie-
piooleu oui solution in the event that a latei veision ol IE changes this Lehavioi. Oth-
eiwise, we woulu have neeueu a conuitional that containeu specilic Liowsei veisions.
Vhile it may Le tempting, it is Lest to avoiu this appioach Lecause it ieguiies lutuie
maintenance as new veisions ol Liowseis aie ieleaseu. Anothei ieason to avoiu taiget-
ing specilic Liowseis is that it is possiLle loi clients to intentionally oi unintentionally
iepoit an incoiiect usei agent stiing. In auuition to the hrefNormalized attiiLute, a
numLei ol auuitional attiiLutes exist:
boxModel
Tiue il the Liowsei ienueis accoiuing to the V3C CSS Lox mouel specilication
cssFloat
Tiue il style.cssFloat is useu to get the cuiient CSS lloat value
hrefNormalized
Tiue il the Liowsei leaves intact the iesults liom getAttribute('href')
htmlSerialize
Tiue il the Liowsei piopeily seiializes link elements with the innerHTML attiiLute
leadingWhitespace
Tiue il the Liowsei pieseives leauing whitespace when innerHTML is useu
noCloneEvent
Tiue il the Liowsei uoes not clone event hanuleis when elements aie cloneu
objectAll
Tiue il getElementsByTagName('*') on an element ietuins all uescenuant elements
opacity
Tiue il the Liowsei can inteipiet the CSS opacity style
scriptEval
Tiue il using appendChild loi a <script> tag will execute the sciipt
style
Tiue il getAttribute('style') is aLle to ietuin the inline style specilieu Ly an
element
tbody
Tiue il the Liowsei allows <table> elements without a <tbody> element
78 | Chapter 4:jQuery Utilities
4.2 Iterating Over Arrays and Objects with jQuery.each
Problem
You neeu to iteiate oi loop ovei each element in an aiiay oi attiiLute ol an oLject.
Solution
(function($) {
$(document).ready(function() {
var months = [ 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'];
$.each(months, function(index, value) {
$('#months').append('<li>' + value + '</li>');
});
var days = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3,
Thursday: 4, Friday: 5, Saturday: 6 };
$.each(days, function(key, value) {
$('#days').append('<li>' + key + ' (' + value + ')</li>');
});
});
})(jQuery);
Discussion
In this iecipe, we iteiate ovei Loth an aiiay anu an oLject using $.each(), which pioviues
an elegant inteilace to the common task ol iteiation. The liist aigument to the
$.each() methou is the aiiay oi oLject to iteiate ovei, with the seconu aigument Leing
the callLack methou that is executeu loi each element. (Note that this is slightly uil-
leient liom the jQueiy collection methou $('div').each(), whose liist aigument is the
callLack lunction.)
Vhen the callLack lunction uelineu Ly the uevelopei is executeu, the this vaiiaLle is
set to the value ol the element cuiiently Leing iteiateu. Thus, the pievious iecipe coulu
Le iewiitten as lollows:
(function($) {
$(document).ready(function() {
var months = [ 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'];
$.each(months, function() {
$('#months').append('<li>' + this + '</li>');
});
var days = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3,
Thursday: 4, Friday: 5, Saturday: 6 };
$.each(days, function(key) {
$('#days').append('<li>' + key + ' (' + this + ')</li>');
});
4.2 Iterating Over Arrays and Objects with jQuery.each | 79
});
})(jQuery);
4.3 Filtering Arrays with jQuery.grep
Problem
You neeu to liltei anu iemove elements in an aiiay.
Solution
(function($) {
$(document).ready(function() {
var months = [ 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'];
months = $.grep(months, function(value, i) {
return ( value.indexOf('J') == 0 );
});
$('#months').html( '<li>' + months.join('</li><li>') + '</li>' );
});
})(jQuery);
Discussion
This iecipe uses the $.grep() methou to liltei the months aiiay so that it only incluues
entiies that Legin with the capital lettei J. The $.grep methou ietuins the lilteieu aiiay.
The callLack methou uelineu Ly the uevelopei takes two aiguments anu is expecteu to
ietuin a Boolean value ol true to keep an element oi false to have it iemoveu. The liist
aigument specilieu is the value ol the aiiay element (in this case, the month), anu the
seconu aigument passeu in is the inciemental value ol the numLei ol times the
$.grep() methou has loopeu. So, loi example, il you want to iemove eveiy othei month,
you coulu test whethei ( i % 2 ) == 0, which ietuins the iemainuei ol i / 2. (The % is
the mouulus opeiatoi, which ietuins the iemainuei ol a uivision opeiation. So, when
i = 4, i uiviueu Ly 2 has a iemainuei ol 0.)
(function($) {
$(document).ready(function() {
var months = [ 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'];
months = $.grep(months, function(value, i) {
return ( i % 2 ) == 0;
});
$('#months').html( '<li>' + months.join('</li><li>') + '</li>' );
});
})(jQuery);
80 | Chapter 4:jQuery Utilities
4.4 Iterating and Modifying Array Entries with jQuery.map
Problem
You neeu to loop ovei each element in an aiiay anu mouily its value.
Solution
(function($) {
$(document).ready(function() {
var months = [ 'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'];
months = $.map(months, function(value, i) {
return value.substr(0, 3);
});
$('#months').html( '<li>' + months.join('</li><li>') + '</li>' );
});
})(jQuery);
Discussion
In this iecipe, $.map() is iteiating ovei the months aiiay anu ietuins the aLLieviation
(liist thiee chaiacteis). The $.map() methou takes an aiiay anu a callLack methou as
aiguments anu iteiates ovei each aiiay element executing the callLack as uelineu Ly
the uevelopei. The aiiay entiy will Le upuateu with the ietuin value ol the callLack.
4.5 Combining Two Arrays with jQuery.merge
Problem
You have two aiiays that you neeu to comLine oi concatenate.
Solution
(function($) {
$(document).ready(function() {
var horseBreeds = ['Quarter Horse', 'Thoroughbred', 'Arabian'];
var draftBreeds = ['Belgian', 'Percheron'];
var breeds = $.merge( horseBreeds, draftBreeds );
$('#horses').html( '<li>' + breeds.join('</li><li>') + '</li>' );
});
})(jQuery);
4.5 Combining Two Arrays with jQuery.merge | 81
Discussion
In this example, we have two aiiays that contain a list ol hoise Lieeus. The aiiays aie
comLineu in the oiuei ol liist - seconu. So, the linal breeds aiiay will look like this:
['Quarter Horse', 'Thoroughbred', 'Arabian', 'Belgian', 'Percheron']
4.6 Filtering Out Duplicate Array Entries with jQuery.unique
Problem
You have two jQueiy DOM collections that neeu to have uuplicate elements iemoveu:
(function($) {
$(document).ready(function() {
var animals = $('li.animals').get();
var horses = $('li.horses').get();
$('#animals')
.append( $(animals).clone() )
.append( $(horses).clone() );
});
})(jQuery);
Solution
(function($) {
$(document).ready(function() {
var animals = $('li.animals').get();
var horses = $('li.horses').get();
var tmp = $.merge( animals, horses );
tmp = $.unique( tmp );
$('#animals').append( $(tmp).clone() );
});
})(jQuery);
Discussion
jQueiy`s $.unique() lunction will iemove uuplicate DOM elements liom an aiiay oi
collection. In the pievious iecipe, we comLine the animals anu horses aiiays using
$.merge(). jQueiy makes use ol $.unique() thioughout most ol its coie anu inteinal
lunctions such as .find() anu .add(). Thus, the most common use case loi this methou
is when opeiating on an aiiay ol elements not constiucteu with jQueiy.
4.7 Testing Callback Functions with jQuery.isFunction
Problem
You have wiitten a plugin anu neeu to test whethei one ol the settings is a valiu callLack
lunction.
82 | Chapter 4:jQuery Utilities
Solution
(function($) {
$.fn.myPlugin = function(settings) {
return this.each(function() {
settings = $.extend({ onShow: null }, settings);
$(this).show();
if ( $.isFunction( settings.onShow ) ) {
settings.onShow.call(this);
}
});
};
$(document).ready(function() {
$('div').myPlugin({
onShow: function() {
alert('My callback!');
}
});
});
})(jQuery);
Discussion
Vhile the ]avaSciipt language pioviues the typeof opeiatoi, inconsistent iesults anu
euge cases acioss weL Liowseis neeu to Le taken into account. jQueiy pioviues
the .isFunction() methou to ease the uevelopei`s joL. Voith pointing out is that since
veision 1.3, this methou woiks loi usei-uelineu lunctions anu ietuins inconsistent ie-
sults with Luilt-in language lunctions such as this:
jQuery.isFunction( document.getElementById );
which ietuins lalse in veisions ol Inteinet Exploiei.
4.8 Removing Whitespace from Strings or Form Values with
jQuery.trim
Problem
You have an input loim anu neeu to iemove the whitespace that a usei may have enteieu
at eithei the Leginning oi enu ol a stiing.
Solution
<input type="text" name="first_name" class="cleanup" />
<input type="text" name="last_name" class="cleanup" />
(function($) {
$(document).ready(function() {
$('input.cleanup').blur(function() {
var value = $.trim( $(this).val() );
$(this).val( value );
4.8 Removing Whitespace from Strings or Form Values with jQuery.trim | 83
});
});
})(jQuery);
Discussion
Upon the usei Lluiiing a lielu, the value as enteieu Ly the usei$(this).val()is
ietiieveu anu passeu thiough the $.trim() methou that stiips all whitespace chaiacteis
(space, taL, anu newline chaiacteis) liom the Leginning anu enu ol the stiing. The
tiimmeu stiing is then set as the value ol the input lielu again.
4.9 Attaching Objects and Data to DOM with jQuery.data
Problem
Given the lollowing DOM coue:
var node = document.getElementById('myId');
node.onclick = function() {
// Click handler
};
node.myObject = {
label: document.getElementById('myLabel')
};
you have metauata associateu with a DOM element loi easy ieleience. Because ol
llaweu gaiLage collection implementations ol some weL Liowseis, the pieceuing coue
can cause memoiy leaks.
Solution
Piopeities auueu to an oLject oi DOM noue at iuntime (calleu cxpandos) exhiLit a
numLei ol issues Lecause ol llaweu gaiLage collection implementations in some weL
Liowseis. jQueiy pioviues uevelopeis with an intuitive anu elegant methou
calleu .data() that aius uevelopeis in avoiuing memoiy leak issues altogethei:
$('#myId').data('myObject', {
label: $('#myLabel')[0]
});
var myObject = $('#myId').data('myObject');
myObject.label;
Discussion
In this iecipe, we use the .data() methou, which manages access to oui uata anu pio-
viues a clean sepaiation ol uata anu maikup.
84 | Chapter 4:jQuery Utilities
One ol the othei Lenelits ol using the data() methou is that it implicitly tiiggeis get
Data anu setData events on the taiget element. So, given the lollowing HTML:
<div id="time" class="updateTime"></div>
we can sepaiate oui conceins (mouel anu view) Ly attaching a hanulei loi the
setData event, which ieceives thiee aiguments (the event oLject, uata key, anu uata
value):
// Listen for new data
$(document).bind('setData', function(evt, key, value) {
if ( key == 'clock' ) {
$('.updateTime').html( value );
}
});
The setData event is then tiiggeieu eveiy time we call .data() on the uocument element:
// Update the 'time' data on any element with the class 'updateTime'
setInterval(function() {
$(document).data('clock', (new Date()).toString() );
}, 1000);
So, in the pievious iecipe, eveiy 1 seconu (1,000 milliseconus) we upuate the clock uata
piopeity on the document oLject, which tiiggeis the setData event Lounu to the
document, which in tuin upuates oui uisplay ol the cuiient time.
4.10 Extending Objects with jQuery.extend
Problem
You have uevelopeu a plugin anu neeu to pioviue uelault options allowing enu useis
to oveiwiite them.
Solution
(function($) {
$.fn.myPlugin = function(options) {
options = $.extend({
message: 'Hello world',
css: {
color: 'red'
}
}, options);
return this.each(function() {
$(this).css(options.css).html(options.message);
});
};
})(jQuery);
4.10 Extending Objects with jQuery.extend | 85
Discussion
In this iecipe, we use the $.extend() methou pioviueu Ly jQueiy. $.extend() will ietuin
a ieleience to the liist oLject passeu in with the lattei oLjects oveiwiiting any piopeities
they ueline. The lollowing coue uemonstiates how this woiks in piactice:
var obj = { hello: 'world' };
obj = $.extend(obj, { hello: 'big world' }, { foo: 'bar' });
alert( obj.hello ); // Alerts 'big world'
alert( obj.foo ); // Alerts 'bar';
This allows loi myPlugin() in oui iecipe to accept an options oLject that will oveiwiite
oui uelault settings. The lollowing coue shows how an enu usei woulu oveiwiite the
uelault CSS color setting:
$('div').myPlugin({ css: { color: 'blue' } });
One special case ol the $.extend() methou is that when given a single oLject, it will
extenu the Lase jQueiy oLject. Thus, we coulu ueline oui plugin as lollows to extenu
the jQueiy coie:
$.fn.extend({
myPlugin: function() {
options = $.extend({
message: 'Hello world',
css: {
color: 'red'
}
}, options);
return this.each(function() {
$(this).css(options.css).html(options.message);
});
}
});
$.extend() also pioviues a lacility loi a ueep (oi iecuisive) copy. This is accomplisheu
Ly passing in Boolean true as the liist paiametei. Heie is an example ol how a ueep
copy woulu woik:
var obj1 = { foo: { bar: '123', baz: '456' }, hello: 'world' };
var obj2 = { foo: { car: '789' } };
var obj3 = $.extend( obj1, obj2 );
Vithout passing in true, obj3 woulu Le as lollows:
{ foo: { car: '789 }, hello: 'world' }
Il we specily a ueep copy, obj3 woulu Le as lollows altei iecuisively copying all
piopeities:
var obj3 = $.extend( true, obj1, obj2 );
// obj3
{ foo: { bar: '123', baz: '456', car: '789 }, hello: 'world' }
86 | Chapter 4:jQuery Utilities
CHAPTER 5
Faster, Simpler, More Fun
Michacl Gcary and Scott Gonzlcz
5.0 Introduction
Neaily eveiy uay, someone asks on the jQueiy Google Gioup how they can make theii
coue simplei oi lastei, oi how to ueLug a piece ol coue that isn`t woiking.
This chaptei will help you simplily youi jQueiy coue, making it easiei to ieau anu moie
lun to woik on. Anu we`ll shaie some tips loi linuing anu lixing those Lugs.
Ve`ll also help you make youi coue iun lastei, anu egually impoitant, linu out which
paits ol youi coue you neeu to speeu up. So youi site`s visitois will have moie lun using
the snappy pages on youi site.
That`s what we call a win-win situation. Happy couing!
5.1 Thats Not jQuery, Its JavaScript!
Problem
You`ie a weL uesignei who is new to jQueiy, anu you`ie having tiouLle with the syntax
ol an if/else statement. You know it must Le a simple pioLlem, anu Leloie asking on
the jQueiy mailing list, you uo youi homewoik: you seaich the jQueiy uocumentation
anu linu nothing. VeL seaiches loi teims like jqucry ij c|sc statcncnt aien`t pioving
helplul eithei.
You also neeu to split an email auuiess into two paits, sepaiating it at the @ sign. You`ve
heaiu that theie is a lunction to split stiings, Lut theie uoesn`t seem to Le any inloi-
mation in the jQueiy uocumentation aLout this eithei.
Is jQueiy ieally that pooily uocumenteu?
87
Solution
The if/else statement anu the .split() methou loi stiings aie pait ol ]avaSciipt, not
pait ol jQueiy.
So, these weL seaiches will tuin up moie uselul iesults:
javascript ij c|sc statcncnt
javascript sp|it string
Discussion
]avaSciipt expeits, please uon`t Lite the newLies.
NewLies, uon`t leel Lau il you`ve sciatcheu youi heau ovei something like this.
Il you`ie an olu pio at ]avaSciipt, you may laugh at these guestions. But they come up
laiily olten on the jQueiy mailing list, anu unueistanuaLly so. jQueiy is uesigneu to
make simple ]avaSciipt couing so easy that someone who`s nevei piogiammeu Leloie
can pick up the Lasics anu auu uselul ellects to a page, without having to leain a ieal
piogiamming language.
But jQueiy is ]avaSciipt. jQueiy itsell is 100 puie ]avaSciipt coue, anu eveiy line ol
jQueiy you wiite is also a line ol ]avaSciipt.
You can inueeu get many simple tasks uone with jQueiy without ieally unueistanuing
its ielationship to ]avaSciipt, Lut the moie you leain aLout the unueilying language,
the moie piouuctiveanu less liustiatingyoui jQueiy expeiience will Le.
5.2 Whats Wrong with $(this)?
Problem
You have an event hanulei that auus a class to a DOM element, waits one seconu using
setTimeout(), anu then iemoves that class:
$(document).ready( function() {
$('.clicky').click( function() {
$(this).addClass('clicked');
setTimeout( function() {
$(this).removeClass('clicked');
}, 1000 );
});
});
The class gets auueu when you click, Lut it nevei gets iemoveu. You have conliimeu
that the coue insiue setTimeout() is Leing calleu, Lut it uoesn`t seem to uo anything.
You`ve useu .removeClass() Leloie, anu that coue looks coiiect. You aie using
$(this) the same way in Loth places, Lut it uoesn`t seem to woik insiue the
setTimeout() call.
88 | Chapter 5:Faster, Simpler, More Fun
Solution
Save this in a vaiiaLle Leloie calling setTimeout():
$(document).ready( function() {
$('.clicky').click( function() {
var element = this;
$(element).addClass('clicked');
setTimeout( function() {
$(element).removeClass('clicked');
}, 1000 );
});
});
Even Lettei, since you`ie calling $() in Loth places, lollow the auvice in Recipe 5.3 anu
copy $(this) to a vaiiaLle insteau ol this:
$(document).ready( function() {
$('.clicky').click( function() {
var $element = $(this);
$element.addClass('clicked');
setTimeout( function() {
$element.removeClass('clicked');
}, 1000 );
});
});
Discussion
Vhat is $(this) anyway, anu why uoesn`t it always woik? It`s easiei to unueistanu il
you sepaiate it into its two paits, $() anu this.
$() looks mysteiious, Lut it ieally isn`t: it`s just a lunction call. $ is a ieleience to the
jQuery lunction, so $() is simply a shoitei way to wiite jQuery(). It`s just an oiuinaiy
]avaSciipt lunction call that happens to ietuin an oLject.
Il you`ie using anothei ]avaSciipt liLiaiy that ieuelines $, that`s a uil-
leient matteiLut then you woulun`t use $() in youi jQueiy coue;
you`u use jQuery() oi a custom alias.
this is one ol the moie conlusing leatuies in ]avaSciipt, Lecause it`s useu loi so many
uilleient things. In oLject-oiienteu ]avaSciipt piogiamming, this is useu in an oLject`s
methous to ielei to that oLject, just like self in Python oi RuLy:
function Foo( value ) {
this.value = value;
}
Foo.prototype.alert = function() {
alert( this.value );
};
5.2 Whats Wrong with $(this)? | 89
var foo = new Foo( 'bar' );
foo.alert(); // 'bar'
In the coue loi a tiauitional onevent attiiLute, this ieleis to the element ieceiving the
eventLut only in the attiiLute itsell, not in a lunction calleu liom the attiiLute:
<a href="#" id="test" onclick="clicked(this);">Test</a>
function clicked( it ) {
alert( it.id ); // 'test'
alert( this.id ); // undefined
alert( this === window ); // true (what?)
}
As you can see liom the thiiu alert(), this is actually the window oLject insiue the
lunction. Foi histoiical ieasons, window is the uelault meaning ol this when a lunction
is calleu uiiectly (i.e., not calleu as a methou ol an oLject).
In a jQueiy event hanulei, this is the DOM element hanuling the event, so $(this) is
a jQueiy wiappei loi that DOM element. That`s why $(this).addClass() woiks as
expecteu in oui PioLlem coue.
But the coue then calls setTimeout(), anu setTimeout() woiks like a uiiect lunction
call: this is the window oLject. So when the coue calls $(this).removeClass(), it`s ac-
tually tiying to iemove the class liom the window oLject!
Vhy uoes copying this oi $(this) into a local vaiiaLle lix this? (Pun intenueu.) ]ava-
Sciipt cieates a c|osurc loi the paiameteis anu local vaiiaLles ol a lunction.
Closuies may seem mysteiious at liist, Lut they ieally Loil uown to thiee simple iules:
You can nest ]avaSciipt lunctions one insiue anothei, with multiple levels ol
nesting.
A lunction can ieau anu wiite not only its own paiameteis anu local vaiiaLles Lut
also those ol any lunctions it`s nesteu in.
The pievious iule a|ways woiks, even il the outei lunction has alieauy ietuineu
anu the innei lunction is calleu latei (e.g., an event hanulei oi setTimeout()
callLack).
These iules apply egually to all lunctions, Loth nameu anu anonymous. Howevei,
this is not a lunction paiametei oi local vaiiaLleit`s a special ]avaSciipt keywoiu
so these iules uo not apply. By copying the value ol this into a local vaiiaLle, we take
auvantage ol the closuie to make that value availaLle in any nesteu lunctions.
90 | Chapter 5:Faster, Simpler, More Fun
5.3 Removing Redundant Repetition
Problem
You neeu to hiue, show, oi otheiwise manipulate some DOM elements when the page
loaus, anu you also neeu to take the same actions latei in iesponse to a couple ol
uilleient events:
$(document).ready( function() {
// Set visibility at startup
$('#state').toggle( $('#country').val() == 'US' );
$('#province').toggle( $('#country').val() == 'CA' );
// Update visibility when country selector changes via mouse
$('#country').change( function() {
$('#state').toggle( $(this).val() == 'US' );
$('#province').toggle( $(this).val() == 'CA' );
});
// Also update when country selector changes via keyboard
$('#country').keyup( function() {
$('#state').toggle( $(this).val() == 'US' );
$('#province').toggle( $(this).val() == 'CA' );
});
});
The coue is woiking, Lut you want to simplily it so theie`s not so much uuplicate coue.
Vhy hanule Loth the change anu keyup events? Many weLsites hanule
only the change event on a select list. This woiks line il you make a
selection with the mouse, Lut il you click the select list anu then use the
up anu uown aiiow keys to select among the options, nothing happens:
keystiokes in a select list uo not liie the change event. Il you also hanule
the keyup event, the select list will iesponu to the aiiow keys, pioviuing
a Lettei expeiience loi keyLoaiu useis.
Solution 1
Move the uuplicate coue into a lunction, anu call the lunction Loth at loau time anu
in iesponse to the event. Use jQueiy`s .bind() methou to wiie up Loth event hanuleis
at the same time. Anu save uata useu moie than once in vaiiaLles:
$(document).ready( function() {
var $country = $('#country');
function setVisibility() {
var value = $country.val();
$('#state').toggle( value == 'US' );
5.3 Removing Redundant Repetition | 91
$('#province').toggle( value == 'CA' );
}
setVisibility();
$country.bind( 'change keyup', setVisibility );
});
Solution 2
Use jQueiy`s event tiiggeiing to liie the event immeuiately altei attaching it, along with
the .bind() tiick anu local vaiiaLles liom solution 1:
$(document).ready( function() {
$('#country')
.bind( 'change keyup', function() {
var value = $(this).val();
$('#state').toggle( value == 'US' );
$('#province').toggle( value == 'CA' );
})
.trigger('change');
});
Discussion
It`s stanuaiu piogiamming piactice in just aLout any language to take uuplicate coue
anu move it into a sepaiate lunction that can Le calleu liom multiple places. Solution
1 lollows this appioach: insteau ol iepeating the coue to set the visiLility, it appeais
once in the setVisibility() lunction. The coue then calls that lunction uiiectly at
staitup anu inuiiectly when the change event is liieu.
Solution 2 also uses a common lunction loi Loth ol these cases. But insteau ol giving
the lunction a name so it can Le calleu uiiectly at staitup, the coue meiely sets the
lunction as the event hanulei loi the change event anu then uses the trigger() methou
to tiiggei that same eventthus calling the lunction inuiiectly.
These appioaches aie moie oi less inteichangeaLle; it`s laigely a mattei ol taste which
you pielei.
5.4 Formatting Your jQuery Chains
Problem
You have a lengthy jQueiy chain that incluues methous like .children() anu .end() to
opeiate on seveial ielateu gioups ol elements. It`s getting haiu to tell which opeiations
apply to which elements:
$('#box').addClass('contentBox').children(':header')
.addClass('contentTitle').click(function() {
$(this).siblings('.contentBody').toggle();
92 | Chapter 5:Faster, Simpler, More Fun
}).end().children(':not(.contentTitle)')
.addClass('contentBody').end()
.append('<div class="contentFooter"></div>')
.children('.contentFooter').text('generated content');
Solution
Put each methou call in the chain on its own line, anu put the . opeiatois at the Le-
ginning ol each line. Then, inuent each pait ol the chain to inuicate wheie you aie
switching to uilleient sets ol elements.
Inciease the inuentation when you use methous like .children() oi .siblings() to
select uilleient elements, anu ueciease the inuentation when you call .end() to ietuin
to the pievious jQueiy selection.
Il you`ie new to jQueiy, you`ll pioLaLly want to ieau the iecipes aLout Lasic chaining
anu .end() in Chaptei 1:
$('#box')
.addClass('contentBox')
.children(':header')
.addClass('contentTitle')
.click(function() {
$(this).siblings('.contentBody').toggle();
})
.end()
.children(':not(.contentTitle)')
.addClass('contentBody')
.end()
.append('<div class="contentFooter"></div>')
.children('.contentFooter')
.text('generated content');
Discussion
By Lieaking each call out onto its own line, it Lecomes veiy easy to scan the coue anu
see what is happening. Using inuentation to inuicate when you`ie mouilying the set ol
elements makes it easy to keep tiack ol when uestiuctive opeiations aie occuiiing anu
Leing unuone via .end().
This style ol inuentation iesults in eveiy call loi any given set ol elements always Leing
lineu up, even il they`ie not consecutive. Foi example, it`s cleai that the wiappei
<div> has an element piepenueu anu appenueu to it, even though theie aie opeiations
on othei elements in Letween.
Putting the . opeiatois at the Leginning ol the lines insteau ol the enu is just a linishing
touch: it gives a Lettei visual ieminuei that these aie methou calls anu not oiuinaiy
lunction calls.
5.4 Formatting Your jQuery Chains | 93
Diu jQueiy invent chaining? No. jQueiy uoes make veiy goou use ol
methou chaining, Lut it`s something that has Leen aiounu since the
eailiest uays ol ]avaSciipt.
Foi example, heie is a lamiliai use ol chaining with a stiing oLject:
function htmlEscape( text ) {
return text
.replace( '&', '&amp;' )
.replace( '<', '&lt;' )
.replace( '>', '&gt;' );
}
5.5 Borrowing Code from Other Libraries
Problem
You lounu a uselul lunction in anothei ]avaSciipt liLiaiy anu want to use the same
technigue in youi jQueiy coue. In this case, it`s the .radioClass() methou liom the
Ext Coie liLiaiy, which auus a class to the matching element(s) anu rcnovcs the same
class liom all siLlings ol the matching element(s).
The name .radioClass() comes liom the Lehavioi ol iauio Luttons in
Loth weL applications anu uesktop apps, wheie clicking one Lutton
selects it anu ueselects the othei Luttons in the same iauio Lutton gioup.
The name radio button loi those input elements comes liom the station
Luttons in olu cai iauiosthe mechanical ones wheie pushing in one
Lutton causeu all ol the othei Luttons to pop out.
Given this HTML:
<div>
<div id="one" class="hilite">One</div>
<div id="two">Two</div>
<div id="three">Three</div>
<div id="four">Four</div>
</div>
you`u like to iun coue like this:
// Add the 'hilite' class to div#three, and
// remove the class from all of its siblings
// (e.g. div#one)
$('#three').radioClass('hilite');
You may even want to allow a multiple-select iauio class:
// Add the 'hilite' class to div#two and
// div#four, and remove the class from the
94 | Chapter 5:Faster, Simpler, More Fun
// other siblings (div#one and div#three)
$('#two,#four').radioClass('hilite');
Solution
Viite a simple plugin to auu the .radioClass() methou to jQueiy:
// Remove the specified class from every sibling of the selected
// element(s), then add that class to the selected element(s).
// Doing it in that order allows multiple siblings to be selected.
//
// Thanks to Ext Core for the idea.
jQuery.fn.radioClass = function( cls ) {
return this.siblings().removeClass(cls).end().addClass(cls);
};
This is a shoit enough lunction that it`s not too haiu to lollow as a one-linei, Lut
inuenting the coue as uesciiLeu in Recipe 5.+ makes it completely cleai how it woiks:
jQuery.fn.radioClass = function( cls ) {
return this // Start chain, will return its result
.siblings() // Select all siblings of selected elements
.removeClass(cls) // Remove class from those siblings
.end() // Go back to original selection
.addClass(cls); // Add class to selected elements
};
Discussion
The composei Igoi Stiavinsky is iepoiteu to have saiu, Goou composeis Loiiow; gieat
composeis steal. He appaiently stole the guote liom T.S. Eliot, who wiote, Immatuie
poets imitate; matuie poets steal.
Goou iueas come liom many places, anu othei ]avaSciipt liLiaiies aie chock-lull ol
goou coue anu iueas. Il theie is coue in anothei open souice liLiaiy that you can use
oi that you can tianslate to woik with jQueiy, you`ie liee to uo thatil you iespect
the othei authoi`s copyiight anu license.
Foi inloimation on open souice anu liee soltwaie, see the lollowing
sites:
http://www.opcnsourcc.org/
http://www.jsj.org/
You may not even neeu the actual coue in a case like this one, wheie the implementation
is veiy simple anu just the idca ol having a iauio class methou is the missing link.
Vhile not ieguiieu, it`s a goou couitesy to give cieuit to the souice ol the iuea.
5.5 Borrowing Code from Other Libraries | 95
Vhethei the iuea comes liom elsewheie oi is something you thought ol youisell, in a
suipiising numLei ol cases you can wiite a uselul jQueiy plugin in one oi a lew lines
ol coue.
What Is jQuery.fn, and Why Do jQuery Plugins Use It?
jQuery.fn is a ieleience to the same oLject as jQuery.prototype. Vhen you auu a lunc-
tion to the jQuery.fn oLject, you`ie ieally auuing it to jQuery.prototype.
Vhen you cieate a jQueiy oLject with jQuery() oi $(), you`ie actually calling new
jQuery(). (The jQueiy coue automatically uoes the new loi you.) As with any othei
]avaSciipt constiuctoi, jQuery.prototype pioviues methous anu uelault piopeities loi
the oLjects ietuineu Ly each new jQuery() call. So, what you`ie ieally uoing when you
wiite a jQuery.fn plugin is tiauitional oLject-oiienteu ]avaSciipt piogiamming, auuing
a methou to an oLject using the constiuctoi`s piototype.
Then why uoes jQuery.fn exist at all? Vhy not just use jQuery.prototype like any othei
oLject-oiienteu ]avaSciipt coue? It`s not just to save a lew chaiacteis.
The veiy liist veision ol jQueiy (long Leloie 1.0) uiun`t use ]avaSciipt`s prototype
leatuie to pioviue the methous loi a jQueiy oLject. It copicd ieleiences to eveiy piopeity
anu methou in jQuery.fn (then calleu $.fn) into the jQueiy oLject Ly looping thiough
the oLject.
Since this coulu Le hunuieus ol methous anu it happeneu eveiy time you calleu $(), it
coulu Le iathei slow. So, the coue was changeu to use a ]avaSciipt piototype to elim-
inate all the copying. To avoiu Lieaking plugins that alieauy useu $.fn, it was maue an
alias ol $.prototype:
$.fn = $.prototype;
So that`s why jQuery.fn exists touayLecause plugins useu $.fn in eaily 2006!
5.6 Writing a Custom Iterator
Problem
You`ve selecteu multiple elements into a jQueiy oLject, anu you neeu to iteiate thiough
those elements with a pause Letween each iteiation, loi example, to ieveal elements
one Ly one:
<span class="reveal">Ready? </span>
<span class="reveal">On your mark! </span>
<span class="reveal">Get set! </span>
<span class="reveal">Go!</span>
You tiieu using each(), Lut ol couise that ievealeu the elements all at once:
$('.reveal').each( function() {
$(this).show();
});
96 | Chapter 5:Faster, Simpler, More Fun
// That was no better than this simpler version:
$('.reveal').show();
Solution
Viite a custom iteiatoi that uses setTimeout() to uelay the callLacks ovei time:
// Iterate over an array (typically a jQuery object, but can
// be any array) and call a callback function for each
// element, with a time delay between each of the callbacks.
// The callback receives the same arguments as an ordinary
// jQuery.each() callback.
jQuery.slowEach = function( array, interval, callback ) {
if( ! array.length ) return;
var i = 0;
next();
function next() {
if( callback.call( array[i], i, array[i] ) !== false )
if( ++i < array.length )
setTimeout( next, interval );
}
return array;
};
// Iterate over "this" (a jQuery object) and call a callback
// function for each element, with a time delay between each
// of the callbacks.
// The callback receives the same arguments as an ordinary
// jQuery(...).each() callback.
jQuery.fn.slowEach = function( interval, callback ) {
return jQuery.slowEach( this, interval, callback );
};
Then simply change youi .each() coue to use .slowEach() anu auu the timeout value:
// Show an element every half second
$('.reveal').slowEach( 500, function() {
$(this).show();
});
Discussion
jQueiy`s .each() methou is not iocket science. In lact, il we stiip the jQueiy 1.3.2
implementation uown to the coue actually useu in the most typical use (iteiating ovei
a jQueiy oLject), it`s a laiily stiaightloiwaiu loop:
jQuery.each = function( object, callback ) {
var value, i = 0, length = object.length;
for(
value = object[0];
i < length && callback.call( value, i, value ) !== false;
value = object[++i]
) {}
5.6 Writing a Custom Iterator | 97
return object;
};
That coulu also Le coueu in a moie lamiliai way:
jQuery.each = function( object, callback ) {
for(
var i = 0, length = object.length;
i < length;
++i
) {
var value = object[i];
if( callback.call( value, i, value ) === false )
break;
}
return object;
};
Ve can wiite similai lunctions to iteiate ovei aiiays oi jQueiy oLjects in othei uselul
ways. A simplei example than .slowEach() is a methou to iteiate ovei a jQueiy oLject
in ieveise:
// Iterate over an array or jQuery object in reverse order
jQuery.reverseEach = function( object, callback ) {
for( var value, i = object.length; --i >= 0; ) {
var value = object[i];
console.log( i, value );
if( callback.call( value, i, value ) === false )
break;
}
};
// Iterate over "this" (a jQuery object) in reverse order
jQuery.fn.reverseEach = function( callback ) {
jQuery.reverseEach( this, callback );
return this;
};
This uoesn`t attempt to hanule all ol the cases that .each() hanules, just the oiuinaiy
case loi typical jQueiy coue.
Inteiestingly enough, a custom iteiatoi may not use a loop at all. .reverseEach() anu
the stanuaiu .each() Loth use laiily conventional loops, Lut theie`s no explicit ]ava-
Sciipt loop in .slowEach(). Vhy is that, anu how uoes it iteiate thiough the elements
without a loop?
]avaSciipt in a weL Liowsei uoes not have a sleep() lunction as lounu in many lan-
guages. Theie`s no way to pause sciipt execution like this:
doSomething();
sleep( 1000 );
doSomethingLater();
Insteau, as with any asynchionous activity in ]avaSciipt, the setTimeout() lunction
takes a callLack that is calleu when the time inteival elapses. The .slowEach() methou
98 | Chapter 5:Faster, Simpler, More Fun
inciements the loop vaiiaLle i in the setTimeout() callLack, using a closuie to
pieseive the value ol that vaiiaLle Letween iteiations. (See Recipe 5.2 loi a uiscussion
ol closuies.)
Like .each(), .slowEach() opeiates uiiectly on the jQueiy oLject oi aiiay you give it,
so any changes you make to that aiiay Leloie it linishes iteiating will allect the iteiation.
Unlike .each(), .slowEach() is asynchionous (the calls to the callLack lunction happen
ajtcr .slowEach() ietuins), so il you change the jQueiy oLject oi its elements al-
tei .slowEach() ietuins Lut Leloie all the callLacks aie uone, that can also allect the
iteiation.
5.7 Toggling an Attribute
Problem
You neeu a way to toggle all ol the checkmaiks in a gioup ol checkLoxes. Each checkLox
shoulu Le toggleu inuepenuently ol the otheis.
Solution
Viite a .toggleCheck() plugin that woiks like the .toggle() anu .toggleClass() meth-
ous in the jQueiy coie to allow you to set, cleai, oi toggle a checkLox oi gioup ol
checkLoxes:
// Check or uncheck every checkbox element selected in this jQuery object
// Toggle the checked state of each one if check is omitted.
jQuery.fn.toggleCheck = function( check ) {
return this.toggleAttr( 'checked', true, false, check );
};
Then you can enaLle a gioup ol Luttons:
$('.toggleme').toggleCheck( true );
oi uisaLle them:
$('.toggleme').toggleCheck( false );
oi toggle them all, each one inuepenuent ol the iest:
$('.toggleme').toggleCheck();
This .toggleCheck() methou is Luilt on top ol a moie geneial-puipose .toggleAttr()
methou that woiks loi any attiiLute:
// For each element selected in this jQuery object,
// set the attribute 'name' to either 'onValue' or 'offValue'
// depending on the value of 'on. If 'on' is omitted,
// toggle the attribute of each element independently
// between 'onValue' and 'offValue'.
// If the selected value (either 'onValue' or 'offValue') is
5.7 Toggling an Attribute | 99
// null or undefined, remove the attribute.
jQuery.fn.toggleAttr = function( name, onValue, offValue, on ) {
function set( $element, on ) {
var value = on ? onValue : offValue;
return value == null ?
$element.removeAttr( name ) :
$element.attr( name, value );
}
return on !== undefined ?
set( this, on ) :
this.each( function( i, element ) {
var $element = $(element);
set( $element, $element.attr(name) !== onValue );
});
};
Vhy go to the tiouLle ol Luiluing something so geneial-puipose? Now we can wiite
similai toggleis loi othei attiiLutes with almost no elloit. Suppose you neeu to uo the
same thing as .toggleCheck(), Lut now you`ie enaLling anu uisaLling input contiols.
You can wiite a .toggleEnable() in one line ol coue:
// Enable or disable every input element selected in this jQuery object.
// Toggle the enable state of each one if enable is omitted.
jQuery.fn.toggleEnable = function( enable ) {
return this.toggleAttr( 'disabled', false, true, enable );
};
Note how the onValue anu offValue paiameteis let us swap the true anu false attiiLute
values, making it easy to talk aLout enaLling the element insteau ol the less intuitive
uisaLling that the disabled attiiLute pioviues noimally.
As anothei example, suppose we neeu to toggle a foo attiiLute wheie its on state is
the stiing value bar, anu its oll state is to iemove the attiiLute. That`s anothei
one-linei:
// Add or remove an attribute foo="bar".
// Toggle the presence of the attribute if add is omitted.
jQuery.fn.toggleFoo = function( add ) {
return this.toggleAttr( 'foo', 'bar', null, add );
};
Discussion
It`s always goou to Lewaie ol leeping cieatuiism (aka cieeping leatuiism). Il all we ieally
neeueu weie to toggle checkLoxes, we coulu coue the whole thing like this:
jQuery.fn.toggleCheck = function( on ) {
return on !== undefined ?
this.attr( 'checked', on ) :
this.each( function( i, element ) {
var $element = $(element);
$element.attr( 'checked', ! $element.attr('checked') );
100 | Chapter 5:Faster, Simpler, More Fun
});
};
That is a Lit simplei than oui .toggleAttr() methou, Lut it`s only uselul loi the
checked attiiLute anu nothing else. Vhat woulu we uo il we latei neeueu
that .toggleEnable() methou? Duplicate the whole thing anu change a lew names?
The extia woik in .toggleAttr() Luys us a lot ol llexiLility: we now can wiite a whole
lamily ol attiiLute toggleis as stiaightloiwaiu one-lineis.
Check the uocumentation loi the veision ol jQueiy you`ie using Leloie
wiiting new utility methous like this. It`s always possiLle that similai
methous coulu Le auueu to lutuie veisions ol jQueiy, saving you the
tiouLle ol wiiting youi own.
5.8 Finding the Bottlenecks
Problem
Youi site is too slow to loau oi too slow to iesponu to clicks anu othei usei inteiaction,
anu you uon`t know why. Vhat pait ol the coue is taking so much time?
Solution
Use a piolilei, eithei one ol the many availaLle ones oi a simple one you can coue
youisell.
Discussion
A piolilei is a way to linu the paits ol youi coue that take the most time. You pioLaLly
alieauy have at least one goou ]avaSciipt piolilei at youi lingeitips. FiieLug has one,
anu otheis aie Luilt into IE S anu Salaii +. These aie all lunction piolileis: you stait
pioliling, inteiact with youi page, anu stop pioliling, anu then you get a iepoit showing
how much time was spent in each lunction. That may Le enough iight theie to tell you
which coue you neeu to speeu up.
Theie aie also some piolileis specilic to jQueiy that you can linu with a weL seaich loi
jqucry proji|cr. These let you piolile selectoi peiloimance anu look moie ueeply at
jQueiy lunction peiloimance.
Foi ieally uetaileu pioliling, wheie you neeu to analyze inuiviuual sections ol coue
smallei than the lunction level, you can wiite a simple piolilei in just a lew lines ol
coue. You may have coueu this au hoc classic:
var t1 = +new Date;
// ... do stuff ...
var t2 = +new Date;
alert( ( t2 - t1 ) + ' milliseconds' );
5.8 Finding the Bottlenecks | 101
The +new Date in this coue is just a simplei way ol couing the moie
lamiliai new Date().getTime(): it ietuins the cuiient time in
milliseconus.
Vhy uoes it woik? Vell, the new Date pait is the same: it gives you a
Date oLject iepiesenting the cuiient time. (The () aie optional, as theie
aie no aiguments.) The + opeiatoi conveits that oLject to a numLei. The
way ]avaSciipt conveits an oLject to a numLei is Ly calling the oL-
ject`s .valueOf() methou. Anu the .valueOf() methou loi a Date
oLject happens to Le the same thing as .getTime(), giving the time in
milliseconus.
Ve can make something moie geneial-puipose anu easiei to use with only 15 lines
ol coue:
(function() {
var log = [], first, last;
time = function( message, since ) {
var now = +new Date;
var seconds = ( now - ( since || last ) ) / 1000;
log.push( seconds.toFixed(3) + ': ' + message + '<br />' );
return last = +new Date;
};
time.done = function( selector ) {
time( 'total', first );
$(selector).html( log.join('') );
};
first = last = +new Date;
})();
Now we have a time() lunction that we can call as olten as we want to log the elapseu
time since the last time() call (oi, optionally, since a specilic piioi time). Vhen we`ie
ieauy to iepoit the iesults, we call time.done(). Heie`s an example:
// do stuff
time( 'first' );
// do more stuff
time( 'second' );
// and more
time( 'third' );
time.done( '#log' );
That ]avaSciipt coue ieguiies this HTML coue to Le auueu to youi page:
<div id="log">
</div>
102 | Chapter 5:Faster, Simpler, More Fun
Altei the coue iuns, that <div> woulu get lilleu with a list like this:
0.102 liist
1.0++ seconu
0.0S9 thiiu
1.235 total
Ve can see that the laigest amount ol time is Leing spent Letween the time('first')
anu time('second') calls.
Bewaie ol FiieLug! Il you have FiieLug enaLleu on the page you aie
timing, it can thiow oll the iesults consiueiaLly. ]avaSciipt`s eval()
lunction, which jQueiy 1.3.2 anu eailiei use to evaluate uownloaueu
]SON uata, is allecteu to an extieme uegiee: an aiiay ol 10,000 names
anu auuiesses in the loimat liom Recipe 5.11 takes 0.2 seconus in Fiie-
lox noimally, Lut 55 scconds with FiieLug`s Sciipt panel enaLleu. Latei
veisions ol jQueiy use Function() loi this, which isn`t allecteu Ly
FiieLug.
Il FiieLug allects youi page as Lauly as that anu il you can`t linu a woik-
aiounu, you may want to uetect FiieLug anu uisplay a waining:
<div id="firebugWarning" style="display:none;">
Your warning here
</div>
$(document).ready( function() {
if( window.console && console.firebug )
$('#firebugWarning').show();
});
Foi many optimization exeicises, this coue may Le sullicient. But what il the coue we
neeu to test is insiue a loop?
for( var i = 0; i < 10; ++i ) {
// do stuff
time( 'first' );
// do more stuff
time( 'second' );
// and more
time( 'third' );
}
time.done( '#log' );
Now oui little piolilei will list those liist, seconu, anu thiiu entiies 10 times each! That`s
not too haiu to lixwe just neeu to accumulate the time spent loi each specilic message
laLel when it`s calleu multiple times:
5.8 Finding the Bottlenecks | 103
(function() {
var log = [], index = {}, first, last;
// Accumulate seconds for the specified message.
// Each message string has its own total seconds.
function add( message, seconds ) {
var i = index[message];
if( i == null ) {
i = log.length;
index[message] = i;
log[i] = { message:message, seconds:0 };
}
log[i].seconds += seconds;
}
time = function( message, since ) {
var now = +new Date;
add( message, ( now - ( since || last ) ) / 1000 );
return last = +new Date;
}
time.done = function( sel ) {
time( 'total', first );
$(sel).html(
$.map( log, function( item ) {
return(
item.seconds.toFixed(3) +
': ' +
item.message + '<br />'
);
}).join('')
);
};
first = last = +new Date;
})();
Vith this change, we`ll get uselul iesults liom that loop:
0.973 liist
9.719 seconu
0.S0+ thiiu
11.+96 total
When Timing Test Results Vary
Vhen you iun timing tests on a weL page, you won`t get the same iesult eveiy time. In
lact, the timing iesults will pioLaLly vaiy guite a Lit il you ieloau a page oi ieiun a test
multiple times.
Vhat shoulu you uo to get the ieal numLei? Aveiage the iesults?
PioLaLly not. Heie`s a chait ol the fillTable() timing liom Recipe 5.11 loi 50 con-
secutive iuns, taken aLout 10 seconus apait:
104 | Chapter 5:Faster, Simpler, More Fun
Theie`s a uistinct pattein heie: a laige majoiity ol iuns in the 150200 milliseconu
iange, with a small numLei ol scatteieu iuns taking longei. It seems likely that some-
thing aiounu 175 milliseconus is the ieal timing, anu the iuns taking much longei weie
allecteu Ly othei piocesses on the machine.
It`s also possiLle that some ol the longei iuns aie causeu Ly gaiLage collection in the
Liowsei. It woulu Le haiu to uistinguish that liom time taken Ly othei piocesses, so
the most piactical thing is pioLaLly just to uisiegaiu these outlieis.
5.9 Caching Your jQuery Objects
Problem
You`ie logging the vaiious piopeities ol the event oLject loi a mousemove event, anu the
coue lags Lehinu Lecause it uses $('.classname') selectois to linu anu upuate taLle
cells with the event uata.
Youi page contains this HTML coue loi the log:
<table id="log">
<tr><td>Client X:</td><td class="clientX"></td></tr>
<tr><td>Client Y:</td><td class="clientY"></td></tr>
<tr><td>Page X:</td><td class="pageX"></td></tr>
<tr><td>Page Y:</td><td class="pageY"></td></tr>
<tr><td>Screen X:</td><td class="screenX"></td></tr>
<tr><td>Screen Y:</td><td class="screenY"></td></tr>
</table>
anu this ]avaSciipt coue:
$('html').mousemove( function( event ) {
$('.clientX').html( event.clientX );
$('.clientY').html( event.clientY );
$('.pageX').html( event.pageX );
$('.pageY').html( event.pageY );
$('.screenX').html( event.screenX );
$('.screenY').html( event.screenY );
});
5.9 Caching Your jQuery Objects | 105
The page also contains a laige numLei (thousanus!) ol othei DOM elements. In a sim-
plei test page, the coue peiloims line, Lut in this complex page it is too slow.
Solution
Cache the jQueiy oLjects ietuineu Ly the $(...) calls, so the DOM gueiies only have
to Le iun once:
var
$clientX = $('.clientX'),
$clientY = $('.clientY'),
$pageX = $('.pageX'),
$pageY = $('.pageY'),
$screenX = $('.screenX'),
$screenY = $('.screenY');
$('html').mousemove( function( event ) {
$clientX.html( event.clientX );
$clientY.html( event.clientY );
$pageX.html( event.pageX );
$pageY.html( event.pageY );
$screenX.html( event.screenX );
$screenY.html( event.screenY );
});
You may also Le aLle to speeu up those selectois consiueiaLly; see the next iecipe loi
ways to uo that. But simply calling them once each insteau ol ovei anu ovei again may
Le enough ol an impiovement iight theie.
Discussion
One ol the classic ways to optimize coue is to hoist iepeateu calculations out ol a
loop so you have to uo them only once. Any values that uon`t change insiue the loop
shoulu Le calculateu one time, Leloie the loop staits. Il those aie expensive calculations,
the loop will then Le much lastei.
This woiks just as well when the loop is a seiies ol lieguently liieu events such as
mousemove anu the calculation is a jQueiy selectoi. Hoisting the selectoi out ol the
event hanulei makes the event hanulei iesponu lastei.
Ol couise, il you`ie calling multiple selectois insiue a loop, that will also Lenelit liom
moving them outsiue the loop in the same mannei.
106 | Chapter 5:Faster, Simpler, More Fun
Vhy uo $clientX anu the othei vaiiaLle names Legin with the $
chaiactei?
$ uoesn`t have any special meaning in ]avaSciiptit`s tieateu just like
a lettei ol the alphaLet. It`s simply a populai convention in jQueiy coue
to use the $ pielix as a ieminuei that the vaiiaLle contains a ieleience
to a jQueiy oLject anu not, say, a DOM element, Lecause a vaiiaLle
name ol $foobar has a visual iesemLlance to the jQueiy opeiation
$('#foobar').
This is especially helplul when you neeu to use Loth a jQueiy oLject anu
its unueilying DOM element, e.g.:
var $foo = $('#foo'), foo = $foo[0];
// Now you can use the jQuery object:
$foo.show();
// or the DOM element:
var id = foo.id;
5.10 Writing Faster Selectors
Problem
Youi coue contains a laige numLei ol $('.classname') selectois. You`ie caching them
as uesciiLeu in the pievious iecipe, Lut the selectois aie still allecting youi page loau
time. You neeu to make them lastei.
Solution
Fiist, make suie you aie using a iecent veision ol jQueiy (1.3.2 oi latei) loi lastei
selectoi peiloimance in most Liowseis, especially with class selectois.
Il you have contiol ovei the HTML page content, change the page to use id attiiLutes
anu '#xyz' selectois insteau ol class attiiLutes anu '.xyz' selectois:
<div class="foo"></div>
<div id="bar"></div>
$('.foo') // Slower
$('#bar') // Faster
Il you must use class name selectois, see whethei theie is a paient element that you can
linu with a lastei ID selectoi, anu then uiill uown liom theie to the chilu elements. Foi
example, using the HTML liom the pievious iecipe:
<table id="log">
<tr><td>Client X:</td><td id="clientX"></td></tr>
...
</table>
5.10 Writing Faster Selectors | 107
you coulu use this:
$('.clientX') // Slower
$('td.clientX') // May be faster
$('#log .clientX') // May be much faster
$('#log td.clientX') // Possibly faster in some browsers
Bewaie ol selectoi speeu test pages that uon`t iellect the actual page
content you aie using. In a veiy simple page, a simple $('.clientX')
selectoi may test out lastei than a lanciei selectoi like
$('#log td.clientX')even in Liowseis anu jQueiy veisions wheie
you might expect the class selectoi to Le slow.
That`s just Lecause the moie complicateu selectoi takes moie time to
set up, anu in a simple page that setup time may uominate peiloimance.
The test page loi this iecipe ueliLeiately contains a veiy laige numLei
ol elements to piovoke selectoi peiloimance pioLlems that only show
up in laige pages.
Neithei one, ol couise, shows exactly what any selectoi`s peiloimance
will Le in your page. The only way to Le suie which selectoi is lastest in
a paiticulai page is to test each in that page.
Discussion
It`s easy to loiget that an innocent-looking call like $('.clientX') may take consiuei-
aLle time. Depenuing on the Liowsei anu veision ol jQueiy, that selectoi may have to
make a list ol eveiy DOM element in youi page anu loop thiough it looking loi the
specilieu class.
jQueiy veisions piioi to 1.3 use this slow methou in cvcry Liowsei. jQueiy 1.3 intio-
uuceu the Sizzle selectoi engine, which takes auvantage ol lastei DOM APIs in newei
Liowseis such as getElementsByClassName() anu querySelectorAll().
Howevei, loi most weLsites you`ll pioLaLly neeu to suppoit IE 7 loi some time to come,
anu class selectois aie slow in IE 7 when you have a complex page.
Il you can use it, selecting Ly ID as in $('#myid') is geneially veiy last in all Liowseis,
Lecause it simply uses a single call to the getElementById() API.
It also helps to naiiow uown the numLei ol elements that neeu to Le seaicheu, eithei
Ly specilying a paient element, Ly making the class selectoi moie specilic with a tag
name, oi Ly comLining those anu othei tiicks.
108 | Chapter 5:Faster, Simpler, More Fun
5.11 Loading Tables Faster
Problem
You`ie loauing a ]SON uata oLject with 1,000 names anu auuiesses anu using jQueiy
to cieate a taLle with this uata. It takes 510 seconus to cieate the taLle in IE 7anu
that`s not even counting the uownloau time.
Youi ]SON uata is in this loimat:
{
"names": [
{
"first": "Azzie",
"last": "Zalenski",
"street": "9554 Niemann Crest",
"city": "Quinteros Divide",
"state": "VA",
"zip": "48786"
},
// and repeat for 1000 names
]
}
Youi ]avaSciipt coue is as lollows:
// Return a sanitized version of text with & < > escaped for HTML
function esc( text ) {
return text
.replace( '&', '&amp;' )
.replace( '<', '&lt;' )
.replace( '>', '&gt;' );
}
$(document).ready( function() {
function fillTable( names ) {
$.each( names, function() {
$('<tr>')
.append( $('<td>').addClass('name').html(
esc(this.first) + ' ' + esc(this.last)
) )
.append( $('<td>').addClass('address').html(
esc(this.street) + '<br />' +
esc(this.city) + ', ' +
esc(this.state) + ' ' + esc(this.zip)
) )
.appendTo('#nameTable');
});
}
$.getJSON( 'names/names-1000.json', function( json ) {
fillTable( json.names );
});
});
5.11 Loading Tables Faster | 109
Anu you have this HTML coue in youi uocument:
<table id="nameTable">
</table>
It woiks line, iesulting in the Liowsei uisplay shown in Figuie 5-1.
Iigurc 5-1. Browscr output jor nanc tab|c
It`s just much too slow.
Solution
ComLine seveial optimizations:
Inseit a single <table> oi <tbody> insteau ol multiple <tr> elements
Use .innerHTML oi .html() insteau ol DOM manipulation
Builu an aiiay with a[++i] anu .join() it insteau ol stiing concatenation
Use a Laie-metal for loop insteau ol $.each
Reuuce name lookups
The iesult is this new veision ol the coue (using the same esc() lunction as Leloie):
$(document).ready( function() {
function fillTable( names ) {
// Reduce name lookups with local function name
var e = esc;
//
var html = [], h = 1;
html[++h] = '<table id="nameTable">';
html[++h] = '<tbody>';
for( var name, i = 1; name = names[++i]; ) {
html[++h] = '<tr><td class="name">';
html[++h] = e(name.first);
110 | Chapter 5:Faster, Simpler, More Fun
html[++h] = ' ';
html[++h] = e(name.last);
html[++h] = '</td><td class="address">';
html[++h] = e(name.street);
html[++h] = '<br />';
html[++h] = e(name.city);
html[++h] = ', ';
html[++h] = e(name.state);
html[++h] = ' ';
html[++h] = e(name.zip);
html[++h] = '</td></tr>';
}
html[++h] = '</tbody>';
html[++h] = '</table>';
$('#container')[0].innerHTML = html.join('');
}
$.getJSON( 'names/names-1000.json', function( json ) {
fillTable( json.names );
});
});
The new coue ieguiies the HTML coue in youi uocument to Le changeu to the
lollowing:
<div id="container">
</div>
On one test system in IE 7, the new coue iuns in 0.2 seconus compaieu with 7 seconus
loi the oiiginal coue. That`s 35 times lastei!
Gianteu, the coue is not as clean anu elegant as the oiiginal, Lut youi site`s visitois will
nevei know oi caie aLout that. Vhat they will notice is how much lastei youi page
loaus.
Discussion
Sometimes you`ll get lucky anu linu that one specilic optimization is all it takes to lix
a peiloimance pioLlem. Sometimes, as in this iecipe, you`ll neeu seveial tiicks to get
the speeu you want.
The Liggest speeu Loost in this coue comes liom inseiting a single <table> element with
all its chiluien in a single DOM opeiation, insteau ol inseiting a lengthy seiies ol
<tr> elements one Ly one. In oiuei to uo this, you neeu to geneiate the entiie taLle as
HTML. That means you neeu to paste togethei a laige numLei ol stiings to Luilu the
HTML, which can Le veiy last oi veiy slow uepenuing on how you uo it. Anu with
1,000 items to loop though, it`s woith linuing the lastest way to wiite the loop itsell.
You may wonuei, Is this still jQueiy coue? It looks like plain olu ]avaSciipt! The
answei is yes, anu yes. It`s guite all iight to mix anu match jQueiy coue with othei
]avaSciipt coue. You can use simplei jQueiy ways ol couing in most ol youi site, anu
5.11 Loading Tables Faster | 111
when you uiscovei the slow paits, you can eithei linu lastei jQueiy technigues oi use
plain olu ]avaSciipt as neeueu loi peiloimance.
5.12 Coding Bare-Metal Loops
Problem
You`ie calling $.each(array,fn) oi $(selector).each(fn) to iteiate ovei thousanus ol
items in youi coue, anu you suspect that all those lunction calls may Le auuing to youi
loau time:
$.each( array, function() {
// do stuff with this
});
oi:
$('.lotsOfElements').each( function() {
// do stuff with this or $(this)
});
Solution
Use a for loop insteau ol .each(). To iteiate ovei an aiiay, it`s haiu to Leat this loop:
for( var item, i = 1; item = array[++i] ) {
// do stuff with item
}
But theie is a catch: this loop woiks only il youi aiiay has no lalse elements, that is,
elements whose value is undefined, null, false, 0, oi "". Even with that iestiiction, this
loop is uselul in many common cases, such as iteiating ovei a jQueiy oLject. ]ust Le
suie to cache the oLject in a vaiiaLle:
var $items = $('.lotsOfElements');
for( var item, i = 1; item = $item[++i] ) {
// do stuff with item (a DOM node)
}
It`s also common to have ]SON uata that contains an aiiay ol oLjects as in oui example
liom Recipe 5.11:
{
"names": [
{
// ...
"zip": "48786"
},
// and repeat for 1000 names
]
}
112 | Chapter 5:Faster, Simpler, More Fun
Il you know that none ol the oLjects making up the elements ol the names aiiay will
evei Le null, it`s sale to use the last loop.
Foi a moie geneial-puipose loop that woiks with any aiiay, theie is always the classic
loop that you`ll see in many places:
for( var i = 0; i < array.length; i++ ) {
var item = array[i];
// do stuff with item
}
But you can impiove that loop in thiee ways:
Cache the aiiay length.
Use ++i, which is lastei than i++ in some Liowseis.
ComLine the test anu inciement ol the loop vaiiaLle to iemove one name lookup.
The iesult is as lollows:
for( var i = 1, n = array.length; ++i < n; ) {
var item = array[i];
// do stuff with item
}
Voulu it Le even lastei to use a while loop oi a do...while loop? PioL-
aLly not. You coulu iewiite the pievious loop as lollows:
var i = 1, n = array.length;
while( ++i < n ) {
var item = array[i];
// do stuff with item
}
oi:
var i = 0, n = array.length;
if( i < n ) do {
var item = array[i];
// do stuff with item
}
while( ++i < n );
But neithei one is any lastei than the moie ieauaLle for loop.
To iteiate ovei an oLject (not an aiiay), you can use a for..in loop:
for( var key in object ) {
var item = object[key];
// do stuff with item
}
5.12 Coding Bare-Metal Loops | 113
A Warning About for..in Loops
Nevei use a for..in loop to iteiate ovei a jQueiy oLject oi an aiiay ol any type. Il the
aiiay has any custom piopeities oi methous, those will Le iteiateu along with the nu-
meiic aiiay elements. Foi example, this coue enumeiates a single DOM element, the
uocument Louy (with i = 0):
$('body').each( function( i ) { console.log( i ); });
This coue may look like it woulu uo the same thing, Lut it enumeiates all ol the jQueiy
methous such as show anu css along with the [0] element:
for( var i in $('body') ) console.log( i ); // BAD
Insteau, use one ol the aiiay loops listeu pieviously.
Even the sale use ol a for..in loop to iteiate ovei an oLject can get in tiouLle il any
coue on youi page has mouilieu Object.prototype to extenu all oLjects with auuitional
methous oi piopeities. The loop will enumeiate those methous oi piopeities along
with the ones you want.
Extenuing Object.prototype is stiongly uiscouiageu Lecause it Lieaks so much coue.
In lact, at least thiough jQueiy 1.3.2, it Lieaks jQueiy itsell Ly causing each() to enu-
meiate those auueu methous oi piopeities. Il youi coue has to woik in such an envi-
ionment, you neeu to take extia piecautions on all youi loops, such as testing the
hasOwnProperty() methou ol each oLject piopeity. Unloitunately, these extia tests slow
the coue uown, so you have to choose Letween speeu anu ioLustness.
Discussion
$(selector).each(fn) is the customaiy way to cieate a jQueiy oLject anu iteiate ovei
it, Lut it`s not the only way. The jQueiy oLject is an aiiay-like oLject with .length
anu [0], [1], ..., [length-1] piopeities. Theieloie, you can use any ol the looping
technigues you woulu use with any othei aiiay. Anu Lecause the jQueiy oLject nevei
contains lalse elements, you can use the lastest for loop listeu at the Leginning ol the
solution.
Il you use the time() lunction liom Recipe 5.2 oi anothei piolilei to measuie loop
peiloimance, Le suie to test youi actual coue, not a simplilieu test case that just iuns
the loop without the lull loop Louy. The simplilieu test woulu miss one potential Lenelit
ol the for loop: lewei name lookups iesulting liom less lunction nesting. See Rec-
ipe 5.13 loi the uetails.
114 | Chapter 5:Faster, Simpler, More Fun
5.13 Reducing Name Lookups
Problem
Youi coue has an innei loop, uown insiue seveial levels ol nesteu lunctions, that iuns
hunuieus oi thousanus ol times. The innei loop calls seveial gloLal lunctions, anu it
ieleiences some vaiiaLles uelineu in the outei lunctions oi gloLally.
Each ol these ieleiences is tiiggeiing seveial name lookups Lecause ol the nesteu lunc-
tions. It`s slowing uown youi coue, Lut piolileis uon`t show what the pioLlem is, anu
it isn`t oLvious liom looking at the coue that theie`s a pioLlem!
Solution
Investigate eveiy name that appeais in youi inneimost loop, anu liguie out how many
name lookups it ieguiies. Reuuce the numLei ol name lookups Ly caching oLject iel-
eiences locally oi using lewei nesteu lunctions.
Discussion
Closuies aie a wonueilul thing. They make it tiivial to captuie state inloimation anu
pass it along to asynchionous lunctions such as event hanuleis oi timei callLacks. Il
]avaSciipt uiun`t have closuies, then eveiy asynchionous callLack woulu neeu to have
a way to pass that state aiounu. Insteau, you can simply use a nesteu lunction.
The uynamic natuie ol ]avaSciipt is also a wonueilul thing. You can auu piopeities
anu methous to any oLject, any time, anu the ]avaSciipt iuntime will happily chase
uown those ieleiences when you neeu them.
Put these togethei, anu you can get a lot ol name lookups.
The most mouein ]avaSciipt inteipieteis have impioveu gieatly in this
aiea. But il you want youi coue to iun last in the most populai
Liowseissuch as any veision ol IE you still neeu to woiiy aLout the
numLei ol name lookups.
Consiuei this coue:
// A typical function wrapper to get a local scope
(function() {
// Find the largest absolute value in an array of numbers
function maxMagnitude( array ) {
var largest = -Infinity;
$.each( array, function() {
largest = Math.max( largest, Math.abs(this) );
});
return largest;
}
5.13 Reducing Name Lookups | 115
// Other code here calls maxMagnitude on a large array
})();
RememLei that ]avaSciipt looks up a name liist in the local scope (lunction), anu il the
name isn`t lounu theie, it woiks its way up thiough the paient nesteu lunctions anu
linally the gloLal scope. Not only uoes the ]avaSciipt iuntime have to look up each
name eveiy time you use it, it also has to iepeat those lookups when the names aie
actually uelineu in paient lunctions oi in the gloLal scope.
So, il this Llock ol coue is in the gloLal scope, the each() callLack uoes the lollowing
name lookups in eveiy iteiation:
1. largest in local scope lail
2. largest in MaxMagnitude() success
3. Math in local scope lail
+. Math in MaxMagnitude() lail
5. Math in anonymous wiappei lunction lail
6. Math in gloLal scope success
7. abs in Math oLject success
S. Math in local scope lail
9. Math in MaxMagnitude() lail
10. Math in anonymous wiappei lunction lail
11. Math in gloLal scope success
12. max in Math oLject success
13. largest in local scope lail
1+. largest in MaxMagnitude() success
Now iewiite the coue as lollows:
// A typical wrapper to get a local scope
(function() {
// Find the largest absolute value in an array of numbers
function maxMagnitude( array ) {
var abs = Math.abs, max = Math.max;
var largest = -Infinity;
for( var i = 1, n = array.length; ++i < n; ) {
largest = max( largest, abs(array[i]) );
}
return largest;
}
// Other code here calls maxMagnitude on a large array
})();
This not only eliminates the callLack lunction call in eveiy iteiation, it also ieuuces the
numLei ol name lookups pei iteiation Ly 10 oi moie. The loop Louy in this veision
uoes these name lookups:
1. laigest in local scope success
2. aLs in local scope success
3. max in local scope success
+. laigest in local scope success
That`s moie than a 70 peicent impiovement ovei the liist veision.
116 | Chapter 5:Faster, Simpler, More Fun
Il this coue is nesteu even ueepei insiue anothei lunction, the uilleience is even gieatei,
since each nesteu lunction auus one moie lookup loi each ol the Math oLject lookups.
In this uiscussion we`ie omitting the this anu array[i] lookups, as well
as the lookups in the for loop itsell. Those aie ioughly compaiaLle Le-
tween the two veisions.
In Recipe 5.11, a single name lookup optimization accounts loi a 100 ms impiovement.
That`s not a huge uilleience, Lut a tenth ol a seconu oll youi page loau time loi a one-
line coue change is goou value.
The oiiginal coue calls esc() six times in each loop iteiation, loi a total ol 6,000 calls
in the thousanu-name test case. These calls aie insiue thiee nesteu lunctions, anu
esc() is a gloLal lunction, so it takes loui name lookups simply to iesolve the lunction
name loi each call. That`s 2+,000 name lookups!
The impioveu coue ieuuces the lunction nesting Ly one, so that cuts it uown to 1S,000
name lookups (two nesteu lunctions anu the gloLal scope at 6,000 each), Lut then it
uses one last tiick in the inneimost lunction:
function fillTable( names ) {
var e = esc;
// and now call e() in the inner loop instead of esc()
}
Now, the 6,000 calls to e() aie each iesolveu in a single name lookup. That`s a
ieuuction ol 12,000 name lookups. No wonuei it knocks a tenth ol a seconu oll the
loau time.
5.14 Updating the DOM Faster with .innerHTML
Problem
You`ie cieating a laige Llock ol HTML coue anu using $('#mydiv').html(myhtml); to
inseit it into the DOM. You`ve piolileu the coue anu lounu that the .html() methou is
taking longei than expecteu.
Solution
Use $('#mydiv')[0].innerHTML = myhtml; loi lastei DOM upuatesil you uon`t
ieguiie any ol the special piocessing that .html() pioviues.
Discussion
The .html() methou uses the .innerHTML piopeity to actually inseit the HTML content
into the DOM, Lut it uoes guite a Lit ol piepiocessing liist. In most cases this won`t
5.14 Updating the DOM Faster with .innerHTML | 117
mattei, Lut in peiloimance-ciitical coue you can save some time Ly setting
the .innerHTML piopeity uiiectly.
It`s actually jQueiy`s inteinal .clean() methou that uoes this piocessing. Il you ieau
the souice coue loi .clean(), you`ll see that it goes to guite a Lit ol woik to clean up
the HTML input.
The easiest way to linu most methous in the jQueiy souice coue is to
seaich loi the methou name with a : altei it; e.g., to linu the .clean()
methou, seaich loi clean: in the unconprcsscd jQueiy souice.
The coue in Recipe 5.11 iuns aloul ol some ol this cleanup. That iecipe`s HTML coue
contains a laige numLei ol <br /> tags. Theie`s a iegulai expiession in .clean() that
linus all sell-closing tags (tags that enu with /> anu theieloie uo not ieguiie a closing
tag) anu checks that these tags aie inueeu in the limiteu set ol HTML tags that can Le
sell-closeu. Il not, then it conveits the HTML to an openclose tag.
Foi example, il you coue $('#test').html('<div />');, then this invaliu HTML is au-
tomatically conveiteu to $('#test').html('<div></div>');. This makes couing easiei,
Lut il you have a veiy long HTML stiing that contains many sell-closing
tags, .clean() has to check them alleven il all those tags aie valiu like the <br /> tags
in the othei iecipe.
The .html() methou ieplaces any existing content, anu it takes caie to avoiu memoiy
leaks Ly iemoving all event hanuleis that you`ve attacheu thiough jQueiy to any ol the
elements Leing ieplaceu. Il theie aie any event hanuleis in the content Leing ieplaceu,
you shoulu stick with .html(), oi il you just neeu this event hanulei cleanup Lut uon`t
neeu the othei HTML cleanup, you coulu possiLly use $('#test').empty()
[0].innerHTML = myhtml; to get the event cleanup only.
The Lottom line: il you know loi suie that youi coue uoesn`t ieguiie the event cleanup
oi HTML cleanup that jQueiy noimally pioviues, then with caution you can
use .innerHTML uiiectly. Otheiwise, stick with .html() loi salety.
5.15 Debugging? Break Those Chains
Problem
A chain ol jQueiy methous is lailing somewheie along the way. The HTML coue is as
lollows:
<div class="foo">
before
<span class="baz" style="display:none;">
test
</span>
118 | Chapter 5:Faster, Simpler, More Fun
after
</div>
anu the ]avaSciipt coue (pait ol a Lutton click event hanulei) is as lollows:
$('.foo').css({ fontsize: '18px' }).find('.bar').show();
But when you iun the coue, the lont size isn`t set, anu the hiuuen element isn`t shown.
You have FiieLug oi anothei ]avaSciipt ueLuggei, Lut it`s haiu to tiace thiough the
coue. How can you tell wheie in the chain it is lailing?
Solution
Bieak up the chain into inuiviuual statements, anu stoie each jQueiy oLject in a
vaiiaLle:
// $('.foo').css({ fontsize: '18px' }).find('.bar').show();
var $foo = $('.foo');
$foo.css({ fontsize: '18px' });
var $bar = $foo.find('.bar');
$bar.show();
Now you have seveial ueLugging options. One is to use the Step Ovei commanu in the
ueLuggei to single step ovei each statement anu oLseive youi vaiiaLles anu the state
ol the page altei each step.
In this coue, you`u want to check $foo anu $bar altei theii values aie assigneu. Vhat
is the value ol the .length piopeity ol each? That tells you how many DOM elements
weie selecteu. Does each oLject contain the DOM elements you expect? Check the [0],
[1], [2], etc., piopeities to see the DOM elements.
Assuming that $foo contains the coiiect DOM elements, what happens altei
the .css() methou is calleu? Vith FiieLug`s CSS Inspectoi, you`ll linu that the CSS
font-size piopeity is unchangeu altei the methou call. Vait a minute! It`s font-size,
not fontsize? Theie`s the pioLlem. Checking the uocs, you linu that the coiiect way
to wiite this is eithei ol these:
$foo.css({ fontSize: '18px' });
$foo.css({ 'font-size': '18px' });
That`s one pioLlem uown, Lut what aLout the othei one? Altei $bar is assigneu, il we
look at its .length piopeity, we`ll see that it is zeio. This tells us that we uiun`t succeeu
in selecting any elements. A look at the HTML anu ]avaSciipt coue will then ieveal that
we simply misspelleu the class name.
Now we can incoipoiate these two lixes Lack in the oiiginal chain:
$('.foo').css({ fontSize: '18px' }).find('.baz').show();
Anothei alteinative is to use FiieLug`s logging statements:
// $('.foo').css({ fontsize: '18px' }).find('.bar').show();
var $foo = $('.foo');
5.15 Debugging? Break Those Chains | 119
console.log( $foo );
$foo.css({ fontsize: '18px' });
console.log( $foo.css('fontsize') );
var $bar = $foo.find('.bar');
console.log( $bar );
$bar.show();
These console.log() calls will ieveal that $bar uoesn`t have any elements selecteu,
although we`ve lallen into a tiap on the call that attempts to log the lont size: we
misspelleu fontSize in the console.log() call as well!
This is wheie comLining multiple ueLugging technigues helps: log those vaiiaLles, use
FiieLug`s inspectois, ieau anu ieieau youi souice coue, anu have someone else look at
the pioLlem too.
Discussion
jQueiy`s chaining helps make it easy to wiite concise coue, Lut it can get in the way
when ueLugging, Lecause it is haiu to step thiough the inuiviuual steps ol the chain
anu see theii iesults. Bieaking up the chain into inuiviuual statements, even on a tem-
poiaiy Lasis while ueLugging, makes this task easiei.
5.16 Is It a jQuery Bug?
Problem
You`ie calling some jQueiy coue to show a hiuuen element anu set its HTML content
altei a time uelay using setTimeout():
function delayLog( text ) {
setTimeout( "$('#log').show().html(text)", 1000 );
}
// ... and somewhere else in the code ...
delayLog( 'Hello' );
The .show() call woiks, Lut the .html(text) call lails. The FiieLug console iepoits that
the text vaiiaLle is unuelineu. The same jQueiy coue woiks when you uon`t call it liom
setTimeout(). Is theie a pioLlem using jQueiy with setTimeout()?
Solution
One way to linu out whethei jQueiy is the souice ol a pioLlem is to ieplace youi jQueiy
coue with othei ]avaSciipt coue that uoesn`t use jQueiy. In this example, we can ieplace
the jQueiy coue with a simple alert():
function delayLog( text ) {
setTimeout( "alert(text)", 1000 );
}
120 | Chapter 5:Faster, Simpler, More Fun
Vhen we tiy this veision ol the coue, the same pioLlem occuis: theie is no aleit, anu
FiieLug again iepoits that text is unuelineu.
This uoesn`t iuentily the pioLlem, Lut it naiiows it uown a lot. It cleaily isn`t jQueiy
(unless the meie piesence ol the jQueiy liLiaiy is inteileiing with youi page, Lut you
can iule that out Ly iunning the coue in a simple test page that uoesn`t incluue jQueiy).
So, it must Le something wiong with this coue itsell, most likely to uo with the way
we`ie using setTimeout().
Inueeu, the pioLlem heie is that when a stiing aigument is passeu to setTimeout(), it
is executeu in the g|oba| scopc, i.e., as il the coue weie locateu outsiue ol any lunction.
The easiest way to lix it is to use a local lunction loi the callLack insteau ol a text stiing:
function delayLog( text ) {
setTimeout( function() {
alert(text);
}, 1000 );
}
Unlike coue in a stiing, a nesteu lunction has lull access to the outei lunction`s vaiiaLles
anu paiameteis. So, this coue will aleit the text as expecteu.
Anu linally, heie is a coiiecteu veision ol the oiiginal jQueiy coue:
function delayLog( text ) {
setTimeout( function() {
$('#log').show().html(text);
}, 1000 );
}
Discussion
Vhen ueLugging, il you aien`t suie what is causing a pioLlem, linuing out wheie the
pioLlem isn`t can help you tiack it uown. The puipose ol this iecipe isn`t to help you
tiouLleshoot setTimeout() pioLlemsaltei all, this is a jQueiy Look, not a geneial
]avaSciipt LookLut to help you locus youi ueLugging elloits Ly guickly iuling out
(oi conliiming!) jQueiy as the souice ol the pioLlem.
5.17 Tracing into jQuery
Problem 1
You`ie using the Step Into leatuie in FiieLug oi anothei ]avaSciipt ueLuggei to tiy to
step thiough the jQueiy coue to see what it actually uoes when you make a jQueiy call.
But when you step into the jQueiy coue, it`s all masheu into one long, unieauaLle line
ol coue anu you can`t step thiough it:
(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F)...
5.17 Tracing into jQuery | 121
Solution 1
You`ie using the ninijicd veision ol jQueiy. Insteau, loau the unconprcsscd veision ol
jQueiy into youi page loi testing.
Il you aie loauing the coue liom the Google Ajax LiLiaiies API with a <script> tag,
change it like this:
<!-- Comment out the minified jQuery -->
<!--
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
"></script>
-->
<!-- Use the uncompressed version for testing -->
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
Il you`ie using Google`s ]avaSciipt loauei, change it like this:
// Comment out the minified jQuery
// google.load( 'jquery', '1.3.2' );
// Use the uncompressed version for testing
google.load( 'jquery', '1.3.2', { uncompressed:true });
Now you will Le aLle to step into anu thiough the jQueiy coue.
Problem 2
Having lixeu that pioLlem, you want to leain how jQueiy`s .html() anu .show() meth-
ous woik. So, you aie tiying to tiace into this coue in the ueLuggei:
$('#test').html( 'test' ).show();
But when you use the Step Into commanu, the ueLuggei goes into the jQueiy con-
stiuctoi insteau ol eithei ol the methous that you`ie inteiesteu in.
Solution 2
The pievious line ol coue contains thrcc lunction calls: a call to the jQueiy ($) con-
stiuctoi lolloweu Ly calls to the .html() anu .show() methous. The Step Into commanu
steps into the liist ol those calls, the constiuctoi.
At that point you can immeuiately uo a Step Out lolloweu Ly anothei Step In. This
steps you out ol the jQueiy constiuctoi (thus putting you Lack in the nidd|c ol the
oiiginal line ol coue) anu then into the .html() methou.
To get to the .show() methou, use anothei paii ol Step Out anu Step In commanus.
Each time you uo this, you`ll woik youi way one step luithei thiough the jQueiy chain.
Il this gets teuious, Lieak the chain as uesciiLeu in Recipe 5.15, anu auu debugger;
statements wheievei you want to stop. Il you want to tiace into the .show() methou,
you can change the coue to the lollowing:
122 | Chapter 5:Faster, Simpler, More Fun
var $test = $('#test');
$test.html( 'test' );
debugger;
$test.show();
Now when the coue stops on the debugger; statement, you can just use Step In (twice,
liist to step to the $test.show(); statement anu then to step into that lunction call).
You coulu use Step Ovei to step liom the debugger; statement to the
next line, since altei all you`ie not yet stepping into anything, Lut it`s
easiei to click Step In (oi hit the F11 key in Vinuows) twice, anu it woiks
just as well. Oi, insteau ol the debugger; statement, you can set a Lieak-
point on the $test.show() line itsell, anu then a single Step In will go
into the coue loi the .show() methou.
Discussion
The minilieu veision ol jQueiy is gieat loi piouuction use Lut not so goou loi uevel-
opment. It collapses all ol the coue into one oi two lines, making it neaily impossiLle
to step thiough the coue in a ueLuggei. Also, the common use ol chaineu methous
makes it moie uillicult to step into jQueiy methous. Using the tips in this iecipe, you
can easily tiace thiough the jQueiy coue in the ueLuggei, whethei to chase uown a Lug
oi to leain how the coue woiks.
Do not let youi test-uiiven liienus talk you out ol using a ueLuggei! Even
il you linu most ol youi Lugs thiough unit testing anu othei means, one
ol the Lest ways to leain aLout a piece ol coue is to step thiough it in
the ueLuggei anu stuuy its vaiiaLles anu piopeities as you go.
Altei all, as you ieau coue, you have to step thiough it in youi heau anu
loim a mental mouel ol what its vaiiaLles contain. Vhy not let the
computei step thiough the coue anu show you what`s in those vaiiaLles?
5.18 Making Fewer Server Requests
Problem
You`ie incluuing jQueiy anu a numLei ol plugins in youi page. The sheei numLei ol
seivei ieguests is slowing uown youi page loau time:
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="superfish.js"></script>
<script type="text/javascript" src="cycle.js"></script>
<script type="text/javascript" src="history.js"></script>
<script type="text/javascript" src="hoverintent.js"></script>
<script type="text/javascript" src="jcarousel.js"></script>
5.18 Making Fewer Server Requests | 123
<script type="text/javascript" src="thickbox.js"></script>
<script type="text/javascript" src="validate.js"></script>
Altei the page loaus, you aie uownloauing some ]SON uata using $.getJSON(), thus
auuing yet anothei seivei ieguest:
$(document).ready( function() {
$.getJSON( 'myjson.php?q=test', function( json ) {
$('#demo').html( json.foo );
});
});
myjson.php is a sciipt on youi seivei that ietuins ]SON uata like this:
{
"foo": "bar"
}
Solution
Loau jQueiy liom Google`s Ajax liLiaiy, anu comLine all youi plugins into a single lile:
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="plugins.js">
</script>
Oi, comLine a|| ol the ]avaSciipt coue you use most lieguently (jQueiy, plugins, anu
youi own coue) into a single lile:
<script type="text/javascript" src="allmyscripts.js"></script>
Eithei way, it also helps to ninijy the .js liles (iemove comments anu extia whitespace)
to ieuuce theii size. Anu make suie youi seivei is using gzip compiession on the liles
it uownloaus.
Foi the ]SON uata, since this page is geneiateu Ly youi own seivei application, you
can Luin the ]SON uata uiiectly into the HTML page as it`s geneiateu, using a
<script> tag:
<script type="text/javascript">
var myJson = {
"foo": "bar"
};
</script>
The highlighteu poition ol that sciipt tag is iuentical to the ]SON uata uownloaueu Ly
myjson.php in the oiiginal coue. In most seivei languages it shoulu Le easy to incluue
the content in this way.
Now the jQueiy coue to use the ]SON uata is simply:
$(document).ready( function() {
$('#demo').html( myJson.foo );
});
124 | Chapter 5:Faster, Simpler, More Fun
This eliminates one moie seivei ieguest.
Discussion
One ol the keys to last page loauing is to simply minimize the numLei ol HTTP ieguests.
Making ieguests to uilleient seiveis can also help. Biowseis will make only a small
numLei ol simultaneous uownloaus liom any single uomain (oi suLuomain), Lut il you
uownloau some ol youi liles liom a uilleient uomain, the Liowsei may uownloau them
in paiallel as well.
Pointing uilleient <script> tags to uilleient uomains may allow them to
Le uownloaueu in paiallel, Lut it uoesn`t allect the oiuei ol cxccution.
<script> tags aie executeu in the oiuei they appeai in the HTML souice.
You can comLine ]avaSciipt liles Ly hanu Ly simply copying anu pasting them into one
Lig lile. This is inconvenient loi uevelopment Lut uoes speeu up uownloauing.
Theie aie a numLei ol lile comLinei/minilieis availaLle loi vaiious seivei languages.
RuLy on Rails:
Bunule-lu
AssetPackagei
The packagei Luilt into Rails 2.0
PHP:
Minily
Python:
]SCompile
]ava:
YUI Compiessoi
In auuition to ]avaSciipt coue, check youi CSS loi multiple .css liles. Some ol the tools
listeu can meige youi .css liles into a single uownloau, just as they uo loi .js liles.
At one time, packing ]avaSciipt was all the iage. This not only ie-
moves comments anu whitespace Lut also iewiites all ol the ]avaSciipt
coue so that it`s not even ]avaSciipt coue anymoie. Packing ieguiies an
unpacking step at iuntimeeveiy time the page loaus, even il the ]ava-
Sciipt coue is alieauy cacheu. Because ol this, packing has lallen out ol
lavoi, anu minilying the coue (iemoving comments anu whitespace)
is iecommenueu insteau, comLineu with gzip compiession. Much ol
the Lenelit ol packing comes liom iemoving uuplicate stiings, anu gzip
uoes that loi you anyway.
5.18 Making Fewer Server Requests | 125
5.19 Writing Unobtrusive JavaScript
Problem
You have a page with inline event hanulei attiiLutes cieating a hovei ellect loi a menu.
Youi content (HTML), piesentation (CSS), anu Lehavioi (]avaSciipt) aie all mixeu up,
making it haiu to maintain each on theii own anu iesulting in uuplicate ]avaSciipt anu
style settings:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Menu Demo</title>
<style type="text/css">
.menu {
background-color: #ccc;
list-style: none;
margin: 0;
padding: 0;
width: 10em;
}
.menu li {
margin: 0;
padding: 5px;
}
.menu a {
color: #333;
}
</style>
</head>
<body>
<ul class="menu">
<li onmouseover="this.style.backgroundColor='#999';"
onmouseout="this.style.backgroundColor='transparent';">
<a href="download.html">Download</a>
</li>
<li onmouseover="this.style.backgroundColor='#999';"
onmouseout="this.style.backgroundColor='transparent';">
<a href="documentation.html">Documentation</a>
</li>
<li onmouseover="this.style.backgroundColor='#999';"
onmouseout="this.style.backgroundColor='transparent';">
<a href="tutorials.html">Tutorials</a>
</li>
</ul>
</body>
</html>
126 | Chapter 5:Faster, Simpler, More Fun
Solution
Replace inline ]avaSciipt with jQueiy event hanuleis, anu auu/iemove classes insteau
ol manipulating the backgroundColor style uiiectly:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Menu Demo</title>
<style type="text/css">
.menu {
background-color: #ccc;
list-style: none;
margin: 0;
padding: 0;
width: 10em;
}
.menu li {
margin: 0;
padding: 5px;
}
.menu a {
color: #333;
}
.menuHover {
background-color: #999;
}
</style>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js">
</script>
<script type="text/javascript">
$(document).ready( function() {
$('li').hover(
function() {
$(this).addClass('menuHover');
},
function() {
$(this).removeClass('menuHover');
});
});
</script>
</head>
<body>
<ul class="menu">
<li><a href="download.html">Download</a></li>
5.19 Writing Unobtrusive JavaScript | 127
<li><a href="documentation.html">Documentation</a></li>
<li><a href="tutorials.html">Tutorials</a></li>
</ul>
</body>
</html>
Ve`ve iemoveu the inline event hanuleis anu ieplaceu them with jQueiy event han-
uleis, sepaiating the content anu Lehavioi. Now il we want to auu moie menu items,
we uon`t have to copy anu paste the same Latch ol event hanuleis; insteau, the event
hanulei will automatically Le auueu.
Ve have also moveu the style iules loi the hovei ellect into a CSS class, sepaiating the
Lehavioi anu piesentation. Il we want to change the styling loi the hovei ellect latei,
we can just upuate the stylesheet insteau ol having to mouily the maikup.
Discussion
Vhile an all in one HTML lile with onevent attiiLutes woiks line in a small, simple
page, it uoesn`t scale up veiy well. As youi pages get moie complex, sepaiating pie-
sentation anu Lehavioi makes the coue easiei to maintain.
Ve uiun`t uo it in this simple example, Lut il you have multiple pages using the same
]avaSciipt oi CSS coue, move that coue to a common .js oi .css lile. That way it will
Le uownloaueu into the Liowsei cache once, insteau ol Leing ie-sent on eveiy page
loau. As a iesult, once one ol youi pages has Leen visiteu, the iest will loau lastei.
5.20 Using jQuery for Progressive Enhancement
Problem
You want to Luilu a site that allows simple task management with a gieat usei expeii-
ence using animations anu Ajax, Lut you also want to suppoit useis who have ]avaSciipt
uisaLleu.
Solution
You can Luilu the site to woik without all the llashiness anu then unoLtiusively auu
the ]avaSciipt lunctionality:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Task List</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js">
</script>
128 | Chapter 5:Faster, Simpler, More Fun
<script type="text/javascript">
$(document).ready( function() {
var url = $('form').attr('action');
$(':checkbox').click(function() {
$.post(url, this.name + '=1');
$(this).parent().slideUp(function() {
$(this).remove();
});
});
$(':submit').hide();
});
</script>
</head>
<body>
<form method="post" action="tasklist.html">
<ul>
<li>
<input type="checkbox" name="task1" id="task1" />
<label for="task1">Learn jQuery</label>
</li>
<li>
<input type="checkbox" name="task2" id="task2" />
<label for="task2">Learn Progressive Enhancement</label>
</li>
<li>
<input type="checkbox" name="task3" id="task3" />
<label for="task3">Build Great Websites</label>
</li>
</ul>
<input type="submit" value="Mark Complete" />
</form>
</body>
</html>
The input loim in this page uoesn`t ieguiie ]avaSciipt. The usei checks oll the tasks
he has completeu anu suLmits the loim, anu then it woulu Le up to the seivei to loau
a new page with the completeu tasks iemoveu liom the list.
Now, we can piogiessively enhance the page using jQueiy: we Linu an event hanulei
to the checkLoxes that mimics a stanuaiu loim suLmit, Ly getting the suLmit URL loi
the loim anu geneiating POST uata showing that the checkLox was checkeu. Then we
animate the iemoval ol the task to pioviue leeuLack to the usei. Ve also hiue the suLmit
Lutton Lecause maiking tasks complete has Lecome an instantaneous piocess.
Discussion
Although lew people Liowse without ]avaSciipt these uays, it`s still a goou piactice
when possiLle to Luilu youi pages so they woik line without ]avaSciipt anu then use
jQueiy anu ]avaSciipt to enhance them.
5.20 Using jQuery for Progressive Enhancement | 129
Bewaie that you uon`t make the usei expeiience worsc with ]avaSciipt
enhancements. The non-]avaSciipt veision ol this page may not give
immeuiate leeuLack when you check oll a task, Lut it uoes give you a
way to change youi minu easily il you make a mistake: eithei uncheck
it Leloie suLmitting oi just uon`t suLmit the loim at all.
Il you suLmit each checkLox immeuiately when it`s clickeu, Le suie
you pioviue a way loi youi visitoi to unuo that action. Il the task item
uisappeais liom the page, people will Le aliaiu to click loi leai ol clicking
the wiong item. You coulu eithei leave the item in the page Lut move it
to a completeu section oi auu an explicit Unuo option.
5.21 Making Your Pages Accessible
Problem
You`ie Luiluing a weL application with complex wiugets anu lots ol Ajax lunctionality,
Lut you want to accommouate visitois with uisaLilities.
Solution
Auu keyLoaiu accessiLility anu AccessiLle Rich Inteinet Applications (ARIA) semantics
to youi wiugets. In the lollowing coue, the changes to suppoit these leatuies aie inui-
cateu in bold:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Dialog Demo</title>
<style type="text/css">
table {
border-collapse: collapse;
width: 500px;
}
th, td {
border: 1px solid #000;
padding: 2px 5px;
}
.dialog {
position: absolute;
background-color: #fff;
border: 1px solid #000;
width: 400px;
padding: 10px;
}
.dialog h1 {
margin: 0 0 10px;
}
130 | Chapter 5:Faster, Simpler, More Fun
.dialog .close {
position: absolute;
top: 10px;
right: 10px;
}
</style>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js">
</script>
<script type="text/javascript">
$(document).ready( function() {
function close() {
dialog.hide();
$('#add-user').focus();
}
var title = $('<h1>Add User</h1>')
.attr('id', 'add-user-title'),
closeButton = $('<button>close</button>')
.addClass('close')
.click(close)
.appendTo(title),
content = $('<div/>')
.load('add.html'),
dialog = $('<div/>')
.attr({
role: 'dialog',
'aria-labelledby': 'add-user-title'
})
.addClass('dialog')
.keypress(function(event) {
if (event.keyCode == 27) {
close();
}
})
.append(title)
.append(content)
.hide()
.appendTo('body');
$('#add-user').click(function() {
var height = dialog.height(),
width = dialog.width();
dialog
.css({
top: ($(window).height() - height) / 2
+ $(document).scrollTop(),
left: ($(window).width() - width) / 2
5.21 Making Your Pages Accessible | 131
+ $(document).scrollLeft()
})
.show();
dialog.find('#username').focus();
return false;
});
});
</script>
</head>
<body>
<h1>Users</h1>
<a id="add-user" href="add.html">add a user</a>
<table>
<thead>
<tr>
<th>User</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>jsmith</td>
<td>John</td>
<td>Smith</td>
</tr>
<tr>
<td>mrobertson</td>
<td>Mike</td>
<td>Robertson</td>
</tr>
<tr>
<td>arodriguez</td>
<td>Angela</td>
<td>Rodriguez</td>
</tr>
<tr>
<td>lsamseil</td>
<td>Lee</td>
<td>Samseil</td>
</tr>
<tr>
<td>lweick</td>
<td>Lauren</td>
<td>Weick</td>
</tr>
</tbody>
</table>
</body>
</html>
132 | Chapter 5:Faster, Simpler, More Fun
Ve`ve auueu seveial uselul leatuies with just a small amount ol auuitional coue:
Ve auueu ARIA semantics (role anu aria-labelledby) so that assistive technology
uevices such as scieen ieaueis know that oui <div> is a uialog anu not just auui-
tional content on the page.
Ve placeu the keyLoaiu locus in the uialog`s liist input lielu when it opens. This
is helplul loi all youi visitois, sighteu anu nonsighteu alike.
Ve moveu the keyLoaiu locus Lack to the Auu Useis link when the uialog closes.
Ve alloweu the uialog to Le canceleu with the Escape key.
Discussion
ARIA is a woik in piogiess, so Liowsei anu scieen ieauei suppoit loi it is still limiteu.
But Ly auuing it now, you`ll Le Lettei piepaieu loi those visitois who can use it. Anu
impioveu keyLoaiu access Lenelits all youi visitois.
Foi moie inloimation aLout ARIA, see the lollowing:
VAI-ARIA Oveiview
DHTML Style Guiue
Don`t Le thiown oll Ly the olu-school DHTML name; the DHTML Style
Guiue is an up-to-uate keyLoaiu accessiLility ieleience loi all the latest
wiugets.
5.21 Making Your Pages Accessible | 133
CHAPTER 6
Dimensions
Rcbccca Murphcy
6.0 Introduction
Dimensions aie a coie pait ol auuing auvanceu Lehaviois to a weLsite. Once you know
how to manipulate the uimensions ol elements anu theii position on the page, you will
have a new level ol contiol ovei youi usei inteilace, pioviuing uesktop-like Lehaviois
anu inteiactions in youi application.
6.1 Finding the Dimensions of the Window and Document
Problem
You want to get the wiuth anu height ol the winuow anu uocument in pixels.
Solution
jQueiy`s width anu height methous pioviue easy access to the Lasic uimensions ol the
winuow oi uocument:
jQuery(document).ready(function() {
alert('Window height: ' + jQuery(window).height()); // returns the height of
the viewport
alert('Window width: ' + jQuery(window).width()); // returns the width of the
viewport
alert('Document height: ' + jQuery(document).height()); // returns the height
of the document
alert('Document width: ' + jQuery(document).width()); // returns the width of
the document
});
135
Discussion
It`s impoitant to unueistanu that the wiuth anu height ol the uocument can (anu likely
will) Le uilleient liom the wiuth anu height ol the winuow. The uimensions ol the
winuow ielei to the size ol the viewpoitthat poition ol the Liowsei that is availaLle
loi uisplaying a uocument. The uimensions ol the uocument ielei to the size ol the
uocument itsell. In most cases, the uocument height will Le tallei than the winuow`s
height. The uocument`s wiuth will always Le at least the winuow`s wiuth Lut may Le
gieatei than the winuow`s wiuth. In Figuie 6-1, jQuery('body').width() < jQuery(docu
ment).width(), anu jQuery(document).width() == jQuery(window).width(). Il the Louy
weie wiuei than the winuow, the uocument wiuth woulu inciease accoiuingly.
Iigurc -1. Thc docuncnt sizc and thc window sizc arc ojtcn dijjcrcnt
The width anu height methous can also accept aiguments il you want to set the
uimensions ol an element. The aigument can Le pioviueu as an integeiin which case
it will Le inteipieteu as a pixel measuiementoi as a stiing, in which case it is intei-
pieteu as a CSS-like measuiement (i.e., $('#foo').width('300px')).
136 | Chapter 6:Dimensions
6.2 Finding the Dimensions of an Element
Problem
You want to ueteimine the space occupieu Ly an element.
Solution
The width anu height methous can Le applieu to any element, anu they aie uselul loi
ueteimining the computeu wiuth oi height ol an element. Howevei, they lall shoit il
you neeu to ueteimine the actual ieal estate that an element is occupying on the scieen.
In auuition to width anu height, jQueiy pioviues the lollowing methous loi ueteimining
moie specilic uimensions ol an element:
innerWidth
Retuins the wiuth cxc|uding the Loiuei anu inc|uding the pauuing
innerHeight
Retuins the height cxc|uding the Loiuei anu inc|uding the pauuing
outerWidth
Retuins the wiuth incluuing both the Loiuei and the pauuing
outerHeight
Retuins the height inc|uding the Loiuei anu inc|uding the pauuing
Foi a visual ieleience, see Figuie 6-2.
Iigurc -2. |||ustration oj an c|cncnt`s hcight, inncrHcight, and outcrHcight
6.2 Finding the Dimensions of an Element | 137
Given the lollowing HTML:
<div id="results"></div>
<div id="myDiv">Some text.</div>
anu the lollowing CSS:
#myDiv {
width:100px;
height:30px;
padding:10px;
border:1px;
}
you coulu expect the lollowing:
jQuery(document).ready(function() {
var $myDiv = jQuery('#myDiv');
var $results = jQuery('#results');
jQuery('<p>Computed width: ' + $myDiv.width() + '</p>')
.appendTo($results); // 100
jQuery('<p>Computed height: ' + $myDiv.height() + '</p>')
.appendTo($results); // 30
jQuery('<p>Inner width: ' + $myDiv.innerWidth() + '</p>')
.appendTo($results); // 120
jQuery('<p>Inner height: ' + $myDiv.innerHeight() + '</p>')
.appendTo($results); // 50
jQuery('<p>Outer width: ' + $myDiv.outerWidth() + '</p>')
.appendTo($results); // 122
jQuery('<p>Outer height: ' + $myDiv.outerHeight() + '</p>')
.appendTo($results); // 52
jQuery('<p>Document outer height: ' + jQuery(document).outerHeight() + '</p>')
.appendTo($results); // NaN
jQuery('<p>Document inner height: ' + jQuery(document).innerHeight() + '</p>')
.appendTo($results); // NaN
jQuery('<p>Window outer height: ' + jQuery(window).outerHeight() + '</p>')
.appendTo($results); // NaN
jQuery('<p>Window inner height: ' + jQuery(window).innerHeight() + '</p>')
.appendTo($results); // NaN
});
Discussion
The innerWidth/innerHeight anu outerWidth/outerHeight methous aie uselul tools loi
ueteimining the actual uimension that you`ie alteithe Lasic wiuth anu height meth-
ous aie ol limiteu use when you aie tiying to measuie the actual ieal estate that an
element with Loiuei anu pauuing occupies on the scieen.
Note that using innerWidth, innerHeight, outerWidth, oi outerHeight methous on
jQuery(document) oi jQuery(window) oLjects will ietuin NaN.
138 | Chapter 6:Dimensions
6.3 Finding the Offset of an Element
Problem
You want to ueteimine the location ol an element in the uocument.
Solution
jQueiy olleis thiee methous that aie uselul in ueteimining an element`s position:
offset
Retuins an oLject containing the position ol the top-lelt coinei ol the element
ielative to the uocument`s top-lelt coinei
position
Retuins an oLject containing the position ol the top-lelt coinei ol the element
ielative to the top-lelt coinei ol the liist positioneu paient ol the element (the
offsetParent)
offsetParent
Retuins a jQueiy oLject containing the offsetParent ol the element
The offset methou is uselul loi ueteimining the location ol an element on the page
loi example, il you want to scioll the winuow to an element. The position methou is
uselul loi iepositioning elements anu loi linuing the position ol an element in a sciolling
containei. Both tasks will Le uiscusseu in suLseguent sections; this section seeks to
seive as an oveiview to the positioning methous.
Given the lollowing HTML wheie the <body> element has 0-pixel maigin anu 10-pixel
pauuing:
<body id="the_offset_parent">
<h1>Finding the Offset of an Element</h1>
<div id="foo">
<div id="bar">Some text inside #bar, which is inside #foo</div>
</div>
<div id="results"></div>
</body>
you can use the lollowing coue to ueteimine the position, ollset, anu ollset paient ol
the two DIVs:
jQuery(document).ready(function() {
var $foo = jQuery('#foo');
var $bar = jQuery('#bar');
var $results = jQuery('#results');
var fooPosition = $foo.position();
var barPosition = $bar.position();
var fooOffset = $foo.offset();
var barOffset = $bar.offset();
6.3 Finding the Offset of an Element | 139
var $fooOffsetParent = $foo.offsetParent();
var $barOffsetParent = $bar.offsetParent();
$results
.append('<p>#foo position.top: ' + fooPosition.top + '</p>') // 10
.append('<p>#foo position.left: ' + fooPosition.left + '</p>') // 10
.append('<p>#bar position.top: ' + barPosition.top + '</p>') // 10
.append('<p>#bar position.left: ' + barPosition.left + '</p>') // 10
.append('<p>#foo offset.top: ' + fooOffset.top + '</p>') // 10
.append('<p>#foo offset.left: ' + fooOffset.left + '</p>') // 10
.append('<p>#bar offset.top: ' + barOffset.top + '</p>') // 10
.append('<p>#bar offset.left: ' + barOffset.left + '</p>') // 10
.append('<p>ID of #foo offsetParent: '
+ $fooOffsetParent.attr('id')) // the_offset_parent
.append('<p>ID of #bar offsetParent: '
+ $barOffsetParent.attr('id')); // the_offset_parent
});
In this case, Loth elements have the same position, anu Loth have the same
offsetParent (the uocument`s <body> element).
Howevei, il #foo is positioneu using CSS:
<body id="the_offset_parent">
<div id="foo" style="position:absolute; top:10px; left:10px;">
<div id="bar">Some text inside #bar, which is inside the
absolutely-positioned #foo</div>
</div>
<div id="results" style="position:absolute; top:60px; left:10px;"></div>
</body>
then the iesults change. The #foo DIV hasn`t actually moveu anu its offsetParent hasn`t
changeu, so its position anu ollset stay the same; the #bar DIV hasn`t moveu eithei, Lut
since its offsetParent has changeu, its position has changeuiememLei, an element`s
position is ielative to its ollset paient.
jQuery(document).ready(function() {
var $foo = jQuery('#foo');
var $bar = jQuery('#bar');
var $results = jQuery('#results');
var fooPosition = $foo.position();
var barPosition = $bar.position();
var fooOffset = $foo.offset();
var barOffset = $bar.offset();
var $fooOffsetParent = $foo.offsetParent();
var $barOffsetParent = $bar.offsetParent();
$results
.append('<p>#foo position.top: ' + fooPosition.top + '</p>') // 10
.append('<p>#foo position.left: ' + fooPosition.left + '</p>') // 10
140 | Chapter 6:Dimensions
.append('<p>#bar position.top: ' + barPosition.top + '</p>') // 0
.append('<p>#bar position.left: ' + barPosition.left + '</p>') // 0
.append('<p>#foo offset.top: ' + fooOffset.top + '</p>') // 10
.append('<p>#foo offset.left: ' + fooOffset.left + '</p>') // 10
.append('<p>#bar offset.top: ' + barOffset.top + '</p>') // 10
.append('<p>#bar offset.left: ' + barOffset.left + '</p>') // 10
.append('<p>ID of #foo offsetParent: '
+ $fooOffsetParent.attr('id')) // the_offset_parent
.append('<p>ID of #bar offsetParent: '
+ $barOffsetParent.attr('id')); // foo
});
Discussion
The impoitant thing to iememLei is this: the offset methou will always give you an
element`s position ielative to the uocument. The ietuin value ol the position methou
nay Le the element`s position ielative to the uocument, uepenuing on whethei the
element has an offsetParent. Il the element has an offsetParentthat is, a paient
element that has positioning applieu to itthen the position methou will pioviue in-
loimation aLout the position ol the element ielative to the offsetParent, not to the
uocument.
jQueiy`s offsetParent methou pioviues a ieplacement loi the stanuaiu
]avaSciipt offsetParent DOM noue piopeity. In ceitain casessuch as
when an element has a lixeu positionsome Liowseis will ietuin null
when askeu loi the offsetParent piopeity ol the element.
6.4 Scrolling an Element into View
Problem
You want to scioll the uocument oi an element to Liing anothei element into view.
Solution: Scrolling the Whole Window
Il you neeu to scioll the whole winuow, you`ll use the offset methou to ueteimine
the location ol the uestination element ielative to the uocument anu then use the
scrollTop methou to scioll the uocument to Liing the element into view.
Foi example, let`s say you want to scioll to the #foo element when the usei clicks the
#bar element:
jQuery('#bar').click(function() {
var fooOffset = jQuery('#foo').offset(),
destination = fooOffset.top;
jQuery(document).scrollTop(destination);
});
6.4 Scrolling an Element into View | 141
Solution: Scrolling Inside an Element
Il youi uestination element is insiue a sciolling containei, you`ll use the position meth-
ou to ueteimine the location ol the uestination element ielative to the containei, auu
it to the cuiient scioll position ol the containei, anu then use the scrollTop methou to
scioll the containei to Liing the element into view. Note that the sciolling containei
must Le positioneuusing position: relative, position: absolute, oi position:
fixedin oiuei loi this to woik.
Foi example, consiuei the lollowing maikup, styleu so that #foo is not laige enough to
show Loth paiagiaphs at once.
<head>
<style>
#foo {
width:300px;
padding:10px;
height:20px;
border:1px solid black;
overflow:auto;
position:relative;
}
</style>
</head>
<body>
<input type="button" id="bar" value="Click to scroll to last paragraph" />
<input type="button" id="bam" value="Click to scroll to last paragraph with
animation" />
<div id="foo">
<p>This is the first paragraph. Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
id est laborum.</p>
<p>This is the second paragraph. Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
id est laborum.</p>
<!-- several more paragraphs -->
</div>
</body>
Sciolling #foo to show the last paiagiaph is simple:
var $foo = jQuery('#foo');
$('#bar').click(function() {
var lastParagraphPosition = jQuery('#foo p:last').position();
var scrollPosition = $foo.scrollTop() + lastParagraphPosition.top;
$foo.scrollTop(scrollPosition);
});
142 | Chapter 6:Dimensions
In Loth ol these examples, the sciolling happens instantaneouslyellicient, Lut not
necessaiily attiactive. The animate methou will animate an element`s scrollTop piop-
eity, so animating the tiansition is tiivial. Heie`s how we woulu uo it loi the sciolling
containei:
var $foo = jQuery('#foo');
$('#bam').click(function() {
var lastParagraphPosition = jQuery('#foo p:last').position();
var scrollPosition = $foo.scrollTop() + lastParagraphPosition.top;
jQuery('#foo').animate({scrollTop: scrollPosition}, 300);
});
jQueiy also incluues a scrollLeft methou, with Lehavioi analogous to
scrollTop.
6.5 Determining Whether an Element Is Within the Viewport
Problem
You want to ueteimine whethei an element is visiLle within the viewpoit; luithei, you
want to ueteimine the peicentage ol the element that is visiLle anu scioll to it il it is
less than 50 peicent visiLle.
Solution
This makes use ol seveial ol the methous uiscusseu in eailiei sections ol this chaptei.
Theie aie seveial steps to this piocess:
1. Deteimine the size ol the viewpoit.
2. Deteimine the scioll position ol the uocument.
3. Figuie out the minimum anu maximum values loi the top anu lelt positions ol the
element il the element is visiLle.
+. Test the position ol the element against those values.
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth,
6.5 Determining Whether an Element Is Within the Viewport | 143
$myElement = jQuery('#myElement'),
elementOffset = $myElement.offset();
if (
(elementOffset.top > minTop && elementOffset.top < maxTop) &&
(elementOffset.left > minLeft &&elementOffset.left < maxLeft)
) {
alert('element is visible');
} else {
alert('element is not visible');
}
});
Vith this solution, we know whethei the top ol the element is visiLle in the viewpoit;
a Lettei solution woulu test whethei the entiie element was containeu in the viewpoit:
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
if (
(elementOffset.top > minTop && elementOffset.top + elementHeight < maxTop) &&
(elementOffset.left > minLeft && elementOffset.left + elementWidth < maxLeft)
) {
alert('entire element is visible');
} else {
alert('entire element is not visible');
}
});
Alteinatively, we coulu look at how much ol the element is visiLleil it is less than a
ceitain amount, then we can scioll to the element:
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
verticalVisible, horizontalVisible,
144 | Chapter 6:Dimensions
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
function scrollToPosition(position) {
jQuery('html,body').animate({
scrollTop : position.top,
scrollLeft : position.left
}, 300);
}
if (
((elementOffset.top > minTop && elementOffset.top < maxTop) ||
(elementOffset.top + elementHeight > minTop && elementOffset.top +
elementHeight < maxTop))
&&
((elementOffset.left > minLeft && elementOffset.left < maxLeft) ||
(elementOffset.left + elementWidth > minLeft && elementOffset.left +
elementWidth < maxLeft))
) {
alert('some portion of the element is visible');
if (elementOffset.top >= minTop && elementOffset.top + elementHeight
<= maxTop) {
verticalVisible = elementHeight;
} else if (elementOffset.top < minTop) {
verticalVisible = elementHeight - (minTop - elementOffset.top);
} else {
verticalVisible = maxTop - elementOffset.top;
}
if (elementOffset.left >= minLeft && elementOffset.left + elementWidth
<= maxLeft) {
horizontalVisible = elementWidth;
} else if (elementOffset.left < minLeft) {
horizontalVisible = elementWidth - (minLeft - elementOffset.left);
} else {
horizontalVisible = maxLeft - elementOffset.left;
}
var percentVerticalVisible = (verticalVisible / elementHeight) * 100;
var percentHorizontalVisible = (horizontalVisible / elementWidth) * 100;
if (percentVerticalVisible < 50 || percentHorizontalVisible < 50) {
alert('less than 50% of element visible; scrolling');
scrollToPosition(elementOffset);
} else {
alert('enough of the element is visible that there is no need to scroll');
}
6.5 Determining Whether an Element Is Within the Viewport | 145
} else {
// element is not visible; scroll to it
alert('element is not visible; scrolling');
scrollToPosition(elementOffset);
}
});
The sciollTo plugin Ly Aiiel Fleslei pioviues excellent shoithanu access
to many ol these methous Ly allowing you to simply wiite
$.scrollTo('#myElement'); it takes caie ol ueteimining the position ol
the uestination element.
6.6 Centering an Element Within the Viewport
Problem
You want to scioll the winuow to centei an element within the viewpoit.
Solution
Get the viewpoit`s uimensions; ueteimine the wiuth, height, anu ollset ol the element;
anu use a little math to centei the element in the viewpoit:
jQuery(document).ready(function() {
jQuery('#bar').click(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
$foo = jQuery('#foo'),
elWidth = $foo.width(),
elHeight = $foo.height(),
elOffset = $foo.offset();
jQuery(window)
.scrollTop(elOffset.top + (elHeight/2) - (viewportHeight/2))
.scrollLeft(elOffset.left + (elWidth/2) - (viewportWidth/2));
});
});
In the linal lines, we auu the top ollset ol the element to hall the element`s height in
oiuei to ueteimine the veitical centei ol the element. Then we suLtiact hall the view-
poit`s height to ueteimine the position to which we want the winuow to scioll. Finally,
we uo an analogous calculation to centei the viewpoit hoiizontally.
146 | Chapter 6:Dimensions
6.7 Absolutely Positioning an Element at Its Current Position
Problem
You want to tuin a static oi ielatively positioneu element into Leing aLsolutely
positioneu.
Solution
To accomplish this, we simply get the position ol the element anu then use it to set the
element`s CSS piopeities accoiuingly:
var $myElement = jQuery('#foo p').eq(0),
elPosition = $myElement.position();
$myElement.css({
position : 'absolute',
top : elPosition.top,
left : elPosition.left
});
Ve can also easily ieposition an element ielative to its cuiient position:
var $myElement = jQuery('#foo p').eq(1),
elPosition = $myElement.position();
$myElement.css({
position : 'absolute',
top : elPosition.top + 20,
left : elPosition.left + 20
});
6.8 Positioning an Element Relative to Another Element
Problem
You want to position a new element ielative to an existing element.
Solution
Get the wiuth, height, anu ollset ol the existing element, anu use the values to position
the new element accoiuingly.
Given the lollowing HTML:
<style>
#foo {
width: 300px;
height: 100px;
border: 1px solid red;
padding: 5px;
}
6.8 Positioning an Element Relative to Another Element | 147
#tooltip {
border: 1px solid black;
padding: 5px;
background-color: #fff;
</style>
<div id="foo">An existing element</div>
the lollowing coue woulu auu an element as a siLling to the existing element Lut posi-
tioneu insiue the element, 10 pixels liom the top anu 10 pixels liom the lelt ol the
existing element`s top-lelt coinei, anu with a wiuth 20 pixels less than that ol the
existing element:
jQuery(document).ready(function() {
var $foo = jQuery('#foo'),
fooPosition = $foo.position(),
$tooltip = $('<div id="tooltip">A new element</div>').insertAfter($foo);
$tooltip.css({
position : 'absolute',
top : fooPosition.top + 10,
left : fooPosition.left + 10,
width : $foo.width() - 20
});
});
Il you wanteu to auu the new element somewheie else in the pagethat is, il you uiun`t
want it to Le a siLling ol the existing elementyou coulu aujust youi coue to look at
the ollset ol the oiiginal element iathei than the position:
jQuery(document).ready(function() {
var $foo = jQuery('#foo'),
fooOffset = $foo.offset(),
$tooltip = $('<div id="tooltip">A new element</div>').appendTo('body');
$tooltip.css({
position : 'absolute',
top : fooOffset.top + 10,
left : fooOffset.left + ($foo.width() / 2),
width : $foo.width() - 20
});
});
6.9 Switching Stylesheets Based on Browser Width
Problem
You want to change the uocument`s CSS Laseu on the wiuth ol the Liowsei.
148 | Chapter 6:Dimensions
Solutions
Theie aie a lew solutions to this pioLlem. One changes the class attiiLute ol the Louy
element, anothei changes the href attiiLute ol the stylesheet you want to change, anu
the thiiu incluues all size-ielateu stylesheets on the page Lut enaLles only one ol them
at a time.
In each case, we`ll cieate a lunction that checks the wiuth ol the Liowsei anu Linu that
lunction to the uocument`s ready event anu to the winuow`s resize event. The
checkWidth lunction will then call the setSize lunction, which we`ll ueline Laseu on the
appioach we`ie taking:
var checkWidth = function() {
var browserWidth = $(window).width();
if (browserWidth < 960) {
setSize('small');
} else {
setSize('large');
}
};
jQuery(document).ready(function() {
checkWidth();
$(window).resize(checkWidth);
});
The uelinition ol the setSize lunction uepenus on how you want to switch styles.
Solution 1: Changing the Class on the Body Element
var setSize = function(size) {
var $body = jQuery('body');
jQuery('body').removeClass('large small').addClass(size);
};
Solution 2: Changing the href Attribute of the Stylesheet Thats Responsible
for Size-Related Styling
Let`s assume you have the lollowing size-ielateu stylesheet in youi uocument:
<link rel="stylesheet" type="text/css" id="css_size" href="size-small.css" />
In this case, you woulu ueline the setSize lunction as lollows:
var setSize = function(size) {
var $css = jQuery('#css_size');
$css.attr('href', 'size-' + size + '.css');
};
Note that in this case, the new CSS lile is ieguesteu liom the seivei, which is likely to
cause a Liiel uelay in the style change occuiiing. Foi this ieason, this is peihaps the
least-pieleiaLle methou.
6.9 Switching Stylesheets Based on Browser Width | 149
Solution 3: Include All Size-Related Stylesheets in the Page, but Enable Only
One at a Time
<link rel="stylesheet" type="text/css" class="css_size small" href="size-small.css" />
<link rel="alternate stylesheet" type="text/css" class="css_size large"
href="size-large.css" disabled=true/>
In this case, you woulu ueline the setSize lunction as lollows:
var setSize = function(size) {
jQuery('link.css_size').each(function() {
var $this = $(this);
if ($this.hasClass(size)) {
$this
.removeAttr('disabled')
.attr('rel', 'stylesheet');
} else {
$this
.attr('disabled', true)
.attr('rel', 'alternate stylesheet');
}
});
};
In this appioach, all stylesheets aie loaueu at page loau, anu nothing new is letcheu
when switching liom one stylesheet to anothei. This eliminates the uelay causeu Ly
solution 2 Lut it also iesults in potentially unnecessaiy HTTP ieguests il youi usei is
unlikely to neeu the alteinate stylesheets.
Discussion
Theie is no uelinitive answei to which ol the thiee style-switching methous is the Lest.
Vhen choosing a methou, you`ll want to consiuei how likely youi useis aie to neeu a
uilleient stylesheet, how Lig youi size-ielateu stylesheets aie, anu how you pielei to
manage youi size-ielateu styles. In many cases, the methou liom the liist solution will
Le Loth sullicient anu pieleiaLle.
150 | Chapter 6:Dimensions
CHAPTER 7
Effects
Rcmy Sharp
7.0 Introduction
Out ol the Lox, jQueiy comes with a numLei ol pieset ellects anu the ioLust low-level
animation methou loi cieating youi own custom ellects.
The pieset ellects incluue the lollowing:
Hiuing anu showing elements in a toggle lashion
Scaling anu simultaneously lauing elements in anu out ol view
Sliuing up anu uown anu toggling
Fauing in anu out anu to a specilic opacity
All ol the pieset ellects suppoit speeus anu callLack lunctions to tiiggei upon
completion.
In auuition to these pieuelineu ellects, theie aie also a numLei ol utilities that can help
you take moie contiol ovei youi animations:
:animated selectoi to assess whethei an element is in the piocess ol Leing animateu
The aLility to tuin oll anu on all ellects acioss the Loaiu
The aLility to auu to the animation gueue with youi own Lespoke lunctions
Function to change the entiie gueue ol animations
It`s woith noting that the canneu animation methous, hide (with a uu-
iation) anu slideUp, ieuuce the maigin anu pauuing on the element as
they appioach zeio height. This may allect how you want to maik up
the page anu CSS loi youi ellect. Also note that jQueiy uoesn`t ojjicia|-
|y suppoit ellects in uocuments using QuiiksMoue.
151
Animate Method
Using the animate methou gives you complete contiol ovei the animation to ioll youi
own Lespoke ellect. Using the animate methou, you can uo the lollowing:
Contiol CSS piopeities (limiteu to numeiical piopeities only)
Contiol scrollTop anu scrollLeft DOM piopeities (il the element has oveillow)
Use any CSS unit ol measuie, e.g., pixels, ems, inches, oi peicentages loi the enu
point values
Specily the enu point ol the ellect as a lixeu value oi a ielative value liom the
element`s cuiient state
Use toggle as a value to llip Letween states, e.g., opacity: toggle
Specily an easing methou to iun the animation ovei
Set callLacks at all points ol the animation: on each step ol the animation anu when
it linishes
Specily whethei the animation shoulu gueue oi iun immeuiately allowing loi
simultaneous animations
Vhen specilying piopeities to animate, they must Le wiitten using
camel case, e.g. marginLeft iathei than margin-left. Il you uon`t uo it
this way, nothing will animate!
Animation Speeds
The speed paiametei can Le specilieu using eithei milliseconus oi a lew pieuelineu
stiings:
slow has a value ol 600 milliseconus.
fast has a value ol 200 milliseconus.
Il a speeu isn`t explicitly passeu in to the animation lunctions, the animation will iun
at a uelault speeu ol +00 milliseconus.
Il you explicitly pass in a speeu ol zeio, then the animation will iun like
the .css() lunction, Lut as ol jQueiy 1.3, the methou call will iun syn-
chronous|y iathei than asynchronous|y like all othei animations woulu
uo.
Effects Template
Unless otheiwise stateu in the iecipe, we will use the lollowing template loi all the
examples, applying a uilleient jQueiy snippet loi each solution:
152 | Chapter 7:Effects
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Chapter 6</title>
<link rel="stylesheet" href="chapter6.css" type="text/css" />
<script src="jquery-latest.js" type="text/javascript"></script>
</head>
<body id="single">
<input type="button" id="animate" value="animate" />
<div class="box">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</body>
</html>
All the inuiviuual examples aie availaLle online at http://jqucry-coo|boo|.con/cxan
p|cs/0/, incluuing a complete amalgamateu veision ol the iecipes.
7.1 Sliding and Fading Elements in and out of View
Problem
Ve want to ieveal oi toggle a Llock ol content into view. This can Le tiiggeieu Ly the
usei clicking some element oi can Le liieu Ly some othei event.
Rathei than just showing anu hiuing, which coulu Le jaiiing visually, we want to cieate
a giauual ellect to ieveal the content into view.
Foi these solutions, I`ve assumeu we want to allow the usei to toggle the ellect.
Solution
Foi ieleience, il we weie just to show the element, oui coue woulu Le as lollows:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').show();
});
);
Il we weie to togg|c the Lox Lut just toggle liom visiLle anu hiuuen, we woulu use the
lollowing insteau ol .show():
$('.box').toggle();
Howevei, oui solution wants to Le a little moie visually engaging than just toggling the
uisplay piopeity. So, let`s look at using the sliue anu laue methous:
7.1 Sliding and Fading Elements in and out of View | 153
Slide
$(document).ready(function () {
$('#animate').click(function () {
$('.box').slideToggle('slow');
});
});
Fade
Because theie`s no opacity toggle lunction, eithei we can use a comLination ol
fadeIn anu fadeOut:
$(document).ready(function () {
$('#animate').click(function () {
var $box = $('.box');
if ($box.is(':visible')) {
$box.fadeOut('slow');
} else {
$box.fadeIn('slow');
}
});
});
oi we can cieate oui own laue toggle animation, using the fadeTo methou:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').fadeTo('slow', 'toggle');
});
});
Howevei, I`m ol the opinion that it ieaus Lettei loi lutuie maintenance il we use the
animate methou:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').animate({ opacity : 'toggle' }, 'slow');
});
});
Both
Il we want to toggle the height anu opacity togethei, we can ieuse the pievious
solution anu auu the height to toggle at the same time. This woulu cause the Lox to
laue out and sliue up at the same time:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').animate({
opacity : 'toggle',
height: 'toggle'
}, 'slow');
});
});
154 | Chapter 7:Effects
Discussion
As we can see liom the pievious solutions, the sliue anu laue methous aie the next step
up liom the stiaight show (anu hiue) anu toggle methous. The sliue methous come in
the lollowing llavois:
slideUp
slideDown
slideToggle
The laue methous uon`t have an explicit toggle leatuie, Lut it can Le achieveu. Fauing
has the lollowing methous:
fadeIn
fadeOut
fadeTo
Vith the exception ol fadeTo, all these methous take speed as the liist paiametei anu
a ca||bac| junction as the seconuLoth ol which aie optional. The callLack lunction
is executeu once the animation is complete, anu the context is set to the element the
animation ian against; i.e., the this vaiiaLle is the cuiient element.
The ieason I woulu choose to use animate ovei fadeTo to toggle opacity is that the
fadeTo paiameteis ieau the wiong way aiounu. Il a new uevelopei weie coming to the
coue, using the animate lunction almost ieaus as plain English, theieloie making it
easiei to skim anu unueistanu what is happening in the coue.
It`s woith also auuing that il you use the show (oi hide) methou using a speeu, it will
animate the height, wiuth, opacity, maigin, anu pauuing all in one animation, as shown
in Figuie 7-1.
Iigurc 7-1. Passing a spccd in to thc show ncthod aninatcs hcight, width, padding, nargin, and
opacity
7.1 Sliding and Fading Elements in and out of View | 155
7.2 Making Elements Visible by Sliding Them Up
Problem
You want to sliue the content Llock into view, Lut the UI uesign uictates that the content
must sliue upward when Leing ievealeu. The slideUp methou woulu hiue the element,
ieuucing the height liom the top position.
To sliue upwaiu, we neeu to use CSS to position the element anu then consiuei the
content that we aie ievealing.
Solution
HTML
Ve neeu to aLsolutely position the element we aie animating to get it to stic| to the
Lottom position so it can animate upwaiu when ievealing.
To achieve this, we neeu to wiap the animating element in anothei <div> (oi the element
that suits youi uesign) anu give it a position: relative style. (This may also Le
position: absolute. Ve just neeu a uelineu position to tiiggei the position: abso
lute on #revealUp to position ielatively to; howevei, since we want the uocument to
llow norna||y, we`ve useu position: relative.)
<div class="box">
<div id="revealUp">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
CSS
Now we neeu to give the box element a ielative position so that we can aLsolutely
position #revealUp ielative to it:
.box {
position: relative;
}
#revealUp {
position: absolute;
overflow: hidden;
display: none;
bottom: 0;
background-color: #c00;
height: 0;
}
156 | Chapter 7:Effects
jQuery
Ve can toggle the #revealUp Laseu on the element`s height. Ve`ie going to longei
lengths to animate the height upwaiu (Ly checking the cuiient height) iathei than just
using slideToggle()Lut we`ll look at why in the uiscussion:
$(document).ready(function () {
$('#animate').click(function () {
var $box = $('#revealUp');
if ($box.height() > 0) {
$box.animate({ height : 0 });
} else {
$box.animate({ height : '100%' });
}
});
});
Discussion
This solution ieguiies that we check the height ol the Lox to then ueteimine how we
pioceeu.
Notice how we uon`t use slideToggle, which Lehinu the scenes is veiy similai, il not
the same as, using .animate({ height: 'toggle' }).
The ieason we`ie not using the toggle is that loi the toggle to woik coiiectly, it neeus
to captuie the rca| height liom somewheie. As the element staits with a height ol zeio,
jQueiy has no way to woik out what the lull height is. Il we useu slideToggle, the
#revealUp element appeais Liielly as a 1-pixel slithei anu then uisappeais again. This
is Lecause theie`s no ieal height to animate to.
Insteau, we ueteimine whethei the height is gieat than zeio anu then animate the
height accoiuingly. Since the element is nesteu within anothei element with
position: relative, we can give it a height ol 100 peicent, anu it will giow to lill the
space.
In the iecipe, I have useu overflow: hidden. Howevei, il the lont size is
incieaseu Ly the usei, my example hiues some ol the content. In youi
ieal solutions, make suie you test that the content is still availaLle when
the lont size is incieaseu, anu consiuei eithei ensuiing that the ievealing
Lox is laige enough loi the content oi using overflow: auto on the
#revealUp element.
7.3 Creating a Horizontal Accordion
Problem
The jQueiy UI liLiaiy suppoits veitical accoiuions out ol the Lox, anu in lact theie aie
a lew simple coue snippets that can Le useu to cieate a iuuimentaiy accoiuion ellect.
7.3 Creating a Horizontal Accordion | 157
Howevei, making the accoiuion iun hoiizontally ieguiies specilic CSS anu a slightly
uilleient take on the jQueiy coue.
Foi this solution we won`t Le using the template, Lecause the maikup is uilleient loi
the hoiizontal accoiuion.
Solution
HTML
<div id="accordionWrapper">
<h3 class="red"><a href="#red">Red</a></h3>
<div id="red" class="box"><p>Lorem ipsum dolor sit amet, consectetur
adipisicing.</p></div>
<h3 class="green"><a href="#green">Green</a></h3>
<div id="green" class="box"><p>Lorem ipsum dolor sit amet, consectetur
adipisicing.</p></div>
<h3 class="blue"><a href="#blue">Blue</a></h3>
<div id="blue" class="box"><p>Lorem ipsum dolor sit amet, consectetur
adipisicing.</p></div>
</div>
CSS
#accordionWrapper {
margin: 10px;
}
#accordionWrapper h3 a {
text-indent: -9999px;
height: 150px;
width: 50px;
float: left;
}
#accordionWrapper .red {
background: #c00 url(images/red.png) no-repeat;
}
#accordionWrapper .green {
background: #0c0 url(images/green.png) no-repeat;
}
#accordionWrapper .blue {
background: #00c url(images/blue.png) no-repeat;
}
#accordionWrapper div.box {
float: left;
height: 150px;
width: 150px;
border: 0;
158 | Chapter 7:Effects
margin: 0;
/* to cancel the image from .red, etc */
background-image: none;
}
jQuery
$.fn.horizontalAccordion = function (speed) {
return this.each(function () {
var $accordionHeaders = $(this).find('h3'),
$open = $accordionHeaders.next().filter(':first'),
width = $open.outerWidth();
// initialize the display
$accordionHeaders.next().filter(':not(:first)').css({ display : 'none', width : 0
});
$accordionHeaders.click(function () {
if ($open.prev().get(0) == this) {
return;
}
$open.animate({ width: 0 }, { duration : speed });
$open = $(this).next().animate({ width : width }, { duration : speed });
});
});
};
$(document).ready(function () {
$('#accordionWrapper').horizontalAccordion(200);
});
Discussion
The HTML anu CSS lay the accoiuion out so that the elements within it aie all lloateu
to the lelt. Il you useu this on a weL page, you woulu pioLaLly expect to have to auu
a cleaiing element uiiectly altei the accoiuion to allow the lollowing content to llow
piopeily.
By lloating the elements to the lelt, oui accoiuion is set up with the h3 > a as the title
to the content panel.
Il CSS anu ]avaSciipt aie uisaLleu, then the content llows coiiectly anu is ieauaLle Ly,
loi instance, Google`s seaich engine.
Il CSS is tuineu on Lut ]avaSciipt isn`t, the uelault view is to see all the content panels.
Using jQueiy, we initialize the uisplay Ly hiuing all the panels except the liist, anu we
hook click hanuleis to the heaueis to sliue the content in anu out ol view.
The hoiizontal accoiuion has Leen wiitten as a jQueiy plugin, in paiticulai to show
that we uon`t neeu to haiu-coue any vaiiaLles within the accoiuion ellect. Ve only
7.3 Creating a Horizontal Accordion | 159
pass the uuiation speeu vaiiaLle in to the plugin, which ueteimines the uuiation ol the
ellect. Ve coulu easily upgiaue this plugin to also take an easing oi callLack.
It`s impoitant to note that thioughout this coue, all the click hanuling anu navigation
ol the DOM happens aiounu the <h3> element, not the <a> element. This still woiks,
keeping the coue ielatively simple (insteau ol having to navigate up anu uown liom the
<a> element to get the paient <h3> then the aujacent <div> element), Lut moie impoi-
tantly, olleis keyLoaiu accessiLility Lecause the <a> elements can Le taLLeu on to anu
tiiggeieu via the keyLoaiu. Ve uon`t have to Linu the click hanulei to the <a> element,
Lecause when the <a> element has the click event tiiggeieu (via clicking oi the key-
Loaiu), it bubb|cs up thiough the DOM anu is caught Ly oui click hanulei on the
<h3> element.
The plugin liist collects the necessaiy paits ol the accoiuion: the heauei, which will Le
clickaLle; the liist visiLle panel, anu the wiuth ol the panels (note that this veision ol
the plugin woiks only loi egual sizeu panels):
var $accordionHeaders = $(this).find('h3'),
this is the cuiient accoiuion wiappei element, typically a <div>.
Fiom the accoiuion wiappei, oui coue collects all the <h3> elements. Note that we will
make use ol next() anu prev() to change oui DOM collection liom the <h3> to the next
noues in the DOM tiee, in paiticulai the accoiuion content panels:
$open = $accordionHeaders.next().filter(':first'),
$open is a tempoiaiy vaiiaLle that will point to the cuiient visiLle panel. Ve can`t
use .is(':visible') Lecause we`ie actually ieuucing the wiuth anu the panel still has
a CSS piopeity ol display: block. So, we will keep tiack ol the cuiient panel thiough
this $open vaiiaLle:
width = $open.outerWidth();
Finally in the initialization, we captuie the wiuth ol the open panel so that we can
animate the wiuth ol the panels coiiectly.
Two tasks aie lelt:
Initialize the view ol panels, showing only the liist panel
Binu the click hanules to show anu hiue the panels
To initialize the view, we must hiue all the panels except the liist. Ve must also set the
wiuth to zeio to allow loi the animate lunction to inciease the wiuth, iathei than making
it pop out when it is shown.
To achieve this, we use an inveise liltei liom the $open vaiiaLle, in paiticu-
lai :not(:first):
$accordionHeaders.next().filter(':not(:first)').css({ display : 'none', width : 0 });
160 | Chapter 7:Effects
Once we have oui selection ol panels that aie not thc jirst, we change the CSS piopeities
to initialize them.
Finally, we attach the click hanulei.
RememLeiing that the $accordionHeaders vaiiaLle contains the h3 elements, the liist
thing we uo is say this: il the <h3> clickeu is the same as the cuiiently open panel, then
uon`t uo anything.
Since the $open vaiiaLle is the panel, we use .prev() to navigate to the pievious <h3>
element anu test whethei it matches the cuiient context ol the clickeu element.
Il the clickeu element is not the cuiient open panel, we animate the $open panel wiuth
to zeio, anu the cuiient clickeu panel to the captuieu wiuth.
Notice the veiy last line ol the click hanulei:
$open = $(this).next().animate({ width : width }, { duration : speed });
Because jQueiy usually ietuins jQueiy (except when getting a value) anu we`ie ani-
mating the panel that will now Le open, we can captuie this at the same time in the
$open vaiiaLle, thus oveiwiiting it with the latest panel.
7.4 Simultaneously Sliding and Fading Elements
Vhen some pait ol the weL page is hiuuen anu is shown to the usei only on a specilic
action, sometimes a simple show/hiue isn`t enough. Ve want to cieate moie pleasing
ellects loi oui visitois.
Depenuing on the layout ol the page, an instant show/hiue ellect may not make it
entiiely cleai to the visitoi what content was ievealeu. This is anothei auvantage ol
sliuing an element into view Lecause it gives a visual cue to the visitoi wheie the page
layout is changing.
Ve coulu use jQueiy`s Luilt-in show methou with a uuiation Lecause this a|nost uoes
the joL, Lut not guite Lecause it also animates the wiuth ol the element, as shown eailiei
in Figuie 7-1. As you also noteu eailiei, the show methou will animate any pauuing
anu maigin aiounu the element, so to solve the pioLlem we will use the animate lunc-
tion to cieate a custom ellect.
Solution
Use the animation lunction to togg|c Loth the height anu the opacity at the same time:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').animate({ opacity: 'toggle', height: 'toggle' });
return false;
});
});
7.4 Simultaneously Sliding and Fading Elements | 161
Discussion
Using the animate methou allows us to specily exactly which CSS piopeities we want
to animate loi the ellect.
Ve aie also using toggle as the enu point value. This way, the animate methou takes
the cuiient height in the initial state anu toggles it to eithei zeio oi 100 peicent ol the
initial state.
In oui example, the initial state ol the Lox is visiLle. Il we want it to sliue anu laue
into view, then we only neeu to set the uisplay piopeity to none in the stylesheet.
Vaining: theie is no neeu to set the height to zeio in the style; in lact, uoing so will
mean the animate won`t expanu to the coiiect height Lecause it will toggle Lack anu
loith Letween zeio height (liom the CSS) anu zeio height anu uisplay none (the linal
point ol slideUp).
7.5 Applying Sequential Effects
Problem
You want an ellect to occui on one set ol elements altei anothei ellect occuis on a
uilleient set ol elements. This is simple to solve il you just have one othei ellect to
execute, Lut il you want to apply the ellect one-Ly-one to any numLei ol elements, the
coue cou|d Lecome uillicult to maintain.
Solution
This solution uses the stanuaiu template outlineu at the Leginning ol this chaptei,
except that we have multiple copies ol the div.box element on the page. This solution
is uesigneu as such that we can Le uealing with any numLei ol div.box elements, liom
just one single element to many, Lecause the automatic seguence solution can hanule
them all.
Manual callback
The Lasic appioach to applying seguential ellects woulu Le to use the callLack. This
woulu also Le useu il the next ellect is uilleient liom the liist:
$(document).ready(function () {
var $boxes = $('.box').hide();
$('#animate').click(function () {
$boxes.eq(0).fadeIn('slow', function () {
$boxes.eq(1).slideDown('slow');
});
});
});
162 | Chapter 7:Effects
Automatic sequence
This alteinative methou, Laseu on Dave Methvin`s solution, will iepeat in seguence the
ellect on any numLei ol elements:
$(document).ready(function () {
var $boxes = $('.box').hide(),
div = 0;
$('#animate').click(function () {
$($boxes[div++] || []).fadeIn('slow', arguments.callee);
});
});
Discussion
The simple solution uses the callLack leatuie to then step in to the next animation in
the seguence. The selectoi we use taigets the liist div.box; howevei, this uoesn`t scale
Lecause it is expecting theie to Le two anu only two animateu elements. Any less anu
the coue Lieaks. Any moie, anu some elements will Le misseu.
Il we have many moie, oi even an unknown numLei ol elements we neeu to animate
in seguence, then Dave Methvin`s solution is peilect.
Theie aie two tiicks to the coue. The liist is the lailovei to an empty aiiay:
$($boxes[div++] || [])
This coue inciements the inuex countei, anu il the element uoesn`t exist, it passes an
empty aiiay to jQueiy.
Vhen the jQueiy iesult set is empty, iunning an animation uoesn`t uo anything. Since
the iesult is empty, jQueiy docsn`t pass any DOM elements to the chaineu call, anu
theieloie any callLacks given to the chaineu methou won`t Le calleu eithei.
Foi example, il we ian the lollowing coue, the aleit Lox woulu nevei appeaiwhich
is a key ingieuient to making this iecipe woik:
$('made-up-element').show(function () {
alert('will never appear');
});
The seconu tiick to this iecipe is the callLack aigument:
arguments.callee
arguments is a keywoiu in ]avaSciipt ieleiiing to a local vaiiaLle that all lunctions have
access to. The arguments oLject is similai to any aiiay Lut uoes not have any ol the aiiay
methous (such as slice) oi piopeities except length.
7.5 Applying Sequential Effects | 163
arguments also contains a ieleience to the cuiiently executing lunction in the
arguments.callee piopeity. This is uselul loi iecuisive lunction calls, which is exactly
how we aie using the piopeity in this solution.
This solution says to keep inciementing thiough the $boxes jQueiy collection anu, on
completion ol the animation, iecuisively execute the lunction. This continues until the
<div> inuex goes Leyonu the length ol the $boxes jQueiy collection ($boxes.length), at
which point an empty aiiay is useu as the jQueiy collection, anu thus the callLack is
not executeu, causing the coue to linish iunning.
7.6 Determining Whether Elements Are Currently Being
Animated
Problem
Vhen an animation is in piogiess, we may want to pievent the usei liom tiiggeiing the
animation to iun again until the initial animation has linisheu.
An example ol this may Le il the usei clicks a Lutton to tiiggei some animation. This
coulu Le to ieveal some piece ol inloimation. Foi oui paiticulai contiiveu example,
when the usei clicks the Lutton, we will shake the Lox Lack anu loith.
Il the usei keeps clicking the Lutton, we won`t want to keep gueuing animations, so
we neeu to test whethei the animation is alieauy iunning anu, il it is, ignoie the ieguest
to animate.
Solution
Foi this solution, I want to incluue some ueLugging inloimation, so I`ve incluueu a
<div> element with the ID ol debug, anu we`ll appenu log messages to this to help us
see what`s happening.
Ve will use the :animated custom jQueiy selectoi to test whethei the animation is
iunning:
$(document).ready(function () {
var speed = 100;
$('#animate').click(function () {
$('.box')
.filter(':not(:animated)')
.animate({ marginLeft: 10 }, speed, function () {
$('#debug').append('<p>Starting animation.<p>');
})
.animate({ marginLeft: 10 }, speed)
.animate({ marginLeft: 10}, speed)
.animate({ marginLeft: 10 }, speed)
.animate({ marginLeft: 10}, speed)
.animate({ marginLeft: 10 }, speed)
164 | Chapter 7:Effects
.animate({ marginLeft: 0}, speed, function () {
$('#debug').append('<p>Finished animation.</p>');
}); // end of our long chain
});
});
Discussion
In this contiiveu example, we use multiple calls to the animate methou to make the Lox
shake Lack anu loith (though il this weie ieguiieu in ieality, it might Le Lettei to use
a Louncing easing insteau!).
This animation is tiiggeieu when the usei clicks the animate Lutton.
I have incluueu two callLack lunctions to show when the animation staits anu linishes.
Note that even though theie aie seveial lines, Lecause ol the way chaining woiks, this
is in lact one single line ol ]avaSciipt staiting liom $('.box') anu enuing on }); // end
of our long chain.
The lollowing line ol jQueiy lilteis out any div.box element that is cuiiently Leing
animateu liom oui collection anu only iunning the suLseguent animations on the ie-
maining elements:
.filter(':not(:animated)')
Since we have a single div.box element in oui example, the animation will iun only il
the element isn`t animating alieauy.
7.7 Stopping and Resetting Animations
Problem
Il an animation is iunning, we may Le ieguiieu to stop it in miullow. A common pioL-
lem is seen when using a mouseovei anu a mouseout to tiiggei an animation to show
anu hiue a paiticulai Llock ol content.
Il the mouse is iun in anu out ol the tiiggei aiea, the animation continuously tiiggeis;
loi example, the content Llock woulu keep sliuing up anu uown until it completeu the
numLei ol times it was tiiggeieu.
One appioach coulu Le to use the :animated selectoi to liltei out the element loi ani-
mation. Howevei, you may want to laue an element Lack out ol view when the usei
moves the mouse away liom the tiiggei iathei than letting it complete. This can Le
solveu with the stop() methou.
7.7 Stopping and Resetting Animations | 165
Solution
Ve have auueu a CSS style to the div.box element to set the opacity to zeio.
Insteau ol having the usei c|ic| the Lutton to tiiggei the ellect, we`ie iunning the ani-
mation when the mouse hovcrs ovei the Lutton. This is just to show that without the
stop() calls, the animation woulu iun out ol contiol:
$(document).ready(function () {
$('#animate').hover(function () {
$('.box').stop().fadeTo(200, 1);
}, function () {
$('.box').stop().fadeTo(200, 0);
});
});
Discussion
Typically this pioLlem woulu Le solveu using a comLination ol fadeIn() anu
fadeOut(). Howevei, il this weie useu, liistly without stop(), then the ellect keeps
iepeating each time the mouse hoveis ovei the Lutton.
To pievent this, we inseit the stop() commanu Leloie gueuing on the next animation.
The Lig auvantage ol this is that it stops the animation miullow. This means il the
opacity ol the element is at 0.5 (oi 50 in IE), it will pioceeu with the next animation
with the staiting point ol 0.5.
Since we aie now stopping in the miuule ol the opacity animation, it also means we
can`t piopeily use fadeIn() anu fadeOut(). Ve have to explicitly state wheie we want
to laue to. So, now we aie using fadeTo(), passing in the uuiation anu then the taiget
opacity.
Now when the usei moves theii mouse Lack anu loith ovei the Lutton, the animation
uoesn`t iepeat Lut laues in anu out in a single smooth tiansition.
7.8 Using Custom Easing Methods for Effects
Problem
jQueiy comes with only two Luilt-in easing lunctions: swing anu linear. The uelault is
swing. Il we want to make oui animations a little moie inteiesting, then we might want
to use a uilleient easing lunctionthis coulu give us a Lounce animation, oi elastic, oi
peihaps just an animation that slows uown as it`s coming to its enu.
Ve can manually auu easing lunctions, Lut we can also incluue a pieuelineu collection
using the jquery.easing plugin, which can Le uownloaueu liom http://jqucry-coo|boo|
.con/go/casing/.
166 | Chapter 7:Effects
Solution
By liist incluuing jquery.easing.1.3.js altei we incluue the jQueiy liLiaiy, we can now
make use ol any one ol the 31 new easing lunctions:
$(document).ready(function () {
$('#animate').click(function () {
$('.box').animate({ scrollTop: '+=100' },
{ duration: 400, easing: 'easeOutElastic' });
});
});
Discussion
By incluuing the easing liLiaiy, we can specily a laige iange ol values in the easing
piopeity in the options paiametei. The animate methou also suppoits passing easing
as the thiiu paiametei, so the pieceuing solution coulu Le wiitten as lollows:
$('.box').animate({ scrollTop: '+=100' }, 400, 'easeOutElastic');
To cieate youi own custom easing lunction, you can extenu the easing oLject using this:
jQuery.extend(jQuery.easing, {
customEasing: function(x, t, b, c, d) {
return c*(t/=d)*t + b;
},
});
The pieceuing example is the eguation loi the easeInQuad easing. All easing lunctions
take live paiameteis:
fraction
The cuiient position ol the animation, as measuieu in time Letween 0 (the Legin-
ning ol the animation) anu 1 (the enu ol the animation)
elapsed
The numLei ol milliseconus that have passeu since the Leginning ol the animation
(seluom useu)
attrStart
The Leginning value ol the CSS attiiLute that is Leing animateu
attrDelta
The uilleience Letween the stait anu enu values ol the CSS attiiLute that is Leing
animateu
duration
The total numLei ol milliseconus that will pass uuiing the animation (seluom useu)
7.8 Using Custom Easing Methods for Effects | 167
7.9 Disabling All Effects
Problem
Youi usei oi weL application may ieguiie that all animations aie uisaLleu, Lut the ellect
ol ievealing inloimation oi sciolling (oi whichevei animation type) may still Le
ieguiieu.
This may Le a peisonal pieleience, the usei may Le using a low-iesolution uevice, oi it
may Le Lecause the usei linus the animations pioLlematic in theii Liowsing.
jQueiy has a way to uisaLle all animations liom one access point Lut still suppoits the
animate methou anu its linal value.
Solution
$.fx.off = true;
$(document).ready(function () {
$('#animate').click(function () {
$('.box').animate({ width: '+=100', height: '+=100' });
});
});
Discussion
By setting fx to off using the lollowing line, all animation calls have the same ellect as
calling css() uiiectly:
$.fx.off = true;
This can Le set at any point anu it will uisaLle the animations, which means it can Le
olleieu as a usei pieleience. To enaLle animations again, you simply set the llag to
false:
$.fx.off = false;
7.10 Using jQuery UI for Advanced Effects
Problem
Il you want to cieate moie complicateu ellects, it is ceitainly possiLle using the
animate methou. This might Le loi a weL application that neeus to animate a whole
iange ol CSS piopeities on an element, oi peihaps theie is a special way a uialog Lox
must uisappeai when closeusay, loi instance, exploue away on the scieen (see Fig-
uie 7-2).
168 | Chapter 7:Effects
Iigurc 7-2. Thc cxp|odc cjjcct running against thc div.box c|cncnt
Solution
Downloau the jQueiy UI liLiaiy liom http://jqucry-coo|boo|.con/go/jqucryui-down
|oad. The liLiaiy can now Le incluueu altei jQueiy is incluueu anu the new ellects
plugin is availaLle.
Foi this solution, I have auueu an extia Lutton to show two ellects anu auueu a new
class to oui CSS.
CSS
.big {
font-size: 400%;
width: 500px;
height: 500px;
line-height: 100%;
}
jQuery
$(document).ready(function () {
$('#animate').click(function () {
$('.box').toggleClass('big', 2000);
});
$('#effect').click(function () {
$('.box').effect('explode', null, 2000);
7.10 Using jQuery UI for Advanced Effects | 169
});
});
Discussion
The jQueiy UI ellects liLiaiy also mouilies the way addClass, removeClass, anu toggle
Class woik; in paiticulai, you can supply a uuiation as the seconu paiametei, anu it
will animate a tiansition liom the cuiient state to the new class, woiking thiough all
new class piopeities.
So, the liist example auus the class big anu sets the animation to iun loi two seconus.
All the CSS piopeities liom the big class aie animateu onto the div.box element. Be-
cause the toggleClass methou has also Leen mouilieu Ly jQueiy UI, we aie aLle to
toggle Lack anu loith to the oiiginal state.
Seconu, we aie using the effect() methou, which is Lespoke to the jQueiy UI liLiaiy.
This methou olleis a collection ol show anu hiue lunctions.
The effect() methou ieguiies the option oLject passeu in as the seconu
vaiiaLle; this can Le null oi it can Le an empty oLject, Lut it must Le
pioviueu to Le aLle to pass in the uuiation.
Using the stiing explode, the div.box will split into nine pieces anu laue oll the page as
shown eailiei in Figuie 7-2.
At the time ol this wiiting, one oi two ellect types have slight siue ellects
in Salaii +. They uo woik in all othei A-giaue Liowseis as outlineu Ly
Yahoo! at http://dcvc|opcr.yahoo.con/yui/artic|cs/gbs/.
To see all the uilleient availaLle ellects, you can visit http://jqucry-coo|boo|.con/go/
jqucryui-cjjccts anu play with all the inteiactive uemos.
170 | Chapter 7:Effects
CHAPTER 8
Events
Aricl Flcslcr
8.0 Introduction
Events aie the main methou ol communication Letween a usei anu a weLsite oi weL
application. Most ol oui ]avaSciipt/jQueiy couing will Le iun in iesponse to a vaiiety
ol usei anu Liowsei events.
By uscr cvcnts, I mean Lasically keyLoaiu anu mouse inteiaction like click, mousedown,
keypress, etc. Browscr cvcnts aie mainly DOM events like document.ready,
window.onload, anu many othei events ielateu to DOM elements.
Vhen couing Ajax applications, we also have custom jQueiy Ajax cvcnts that aie uis-
patcheu uuiing the piocess ol an Ajax ieguest, that is, ajaxSend, ajaxComplete,
ajaxError, anu some moie.
jQueiy`s API is veiy consistent, especially when it comes to events. Attaching a hanulei
to any kinu ol event is uone using the same coue stiuctuie:
jQuery( listener).bind( 'eventName', handlerFunction);
This syntax also applies to a louith categoiy that I haven`t mentioneu yet. jQueiy`s
event system can Le useu loi cvcnt-drivcn progranning
'
in which you can cieate youi
own custon cvcnts that can Le Lounu anu tiiggeieu as iegulai ones.
jQueiy also pioviues a shoitcut methou loi most common Liowsei anu Ajax events. A
mouel call using a shoitcut woulu look like this:
jQuery( listener).eventName( handlerFunction);
Vhen using bind(), eventName will Le a stiing wiappeu in eithei single oi uouLle
guotes. Vhen using the shoitcut, you simply put the event`s name as the jQueiy
methou`s name.
' http://cn.wi|ipcdia.org/wi|i/Evcnt-drivcn_progranning
171
Heie`s an example ol Linuing a click hanulei, with anu without the shoitcut:
// Using bind()
jQuery('div').bind('click',function(e){...});
// Using the shortcut
jQuery('div').click(function(e){...});
Duiing this chaptei, I`ll use the shoitcuts when availaLle, just Lecause they`ie shoitei
anu easiei to ieau, in my opinion. Both woik egually, anu theie`s no auvantage to using
the shoitcut othei than claiity anu Lievity; it`s simply a mattei ol taste.
I`ll assume that you alieauy ieau Chaptei 1, wheie the document.ready event is explaineu
in uetail (Recipe 1.2). Il you have any uouLt aLout its use, uo consult that iecipe.
I also want to claiily that when I use the teim p|ugin, loi most cases I mean plugins,
wiugets, oi simply Llocks ol coue. Most jQueiy useis tenu to oiganize theii coue into
plugin-like stiuctuies, usually auuing names to jQueiy`s namespace.
Finally, jQueiy`s event mouule was highly mouilieu in 1.3. I will always mention when
something neeus to Le uone uilleiently, accoiuing to what jQueiy veision woulu
Le useu.
8.1 Attaching a Handler to Many Events
Problem
In many common situations, one neeus to Linu the same hanulei lunction to moie than
one event (on the same element, that is). You coulu always uo something like this:
jQuery('div').click(function(e){
alert('event');
})
.keydown(function(e){
alert('event');
});
That is not such a pioLlem il the lunction is shoit, Lut loi longei Llocks ol coue, ie-
peating them ovei anu ovei won`t Le that tiivial anu is uelinitely not the Lest appioach.
Solution
Theie`s moie than a single solution to this simple Lut iecuiient pioLlem.
One way to solve it without iepeating youisell too much woulu Le as lollows:
function handler(e){
alert('event');
}
jQuery('div').click(handler)
.keydown(handler);
172 | Chapter 8:Events
Delining a lunction once anu then ieleiiing to it multiple times is not a Lau appioach,
Lut theie`s an even simplei one pioviueu Ly jQueiy.
bind() accepts a list ol events sepaiateu Ly spaces. That means you can solve the pie-
vious pioLlem like this:
jQuery('div').bind'click keydown', function(e){
alert('event');
});
Discussion
You can also apply this Lehavioi to unbind() anu one().
To unLinu a ceitain lunction, you neeu to have a ieleience to it, so even il you aie using
the multievent leatuie, you still neeu to keep a ieleience to the hanulei. Il you uon`t
pass the lunction to unbind(), then any othei event hanulei Lounu to that event will Le
iemoveu as well:
function handler(e){
alert('event');
}
jQuery('div').bind('click keydown', handler);
// ...
jQuery('div').unbind('click keydown', handler);
8.2 Reusing a Handler Function with Different Data
Problem
You`ve come into a situation wheie you have many Linuings, anu the hanulei lunctions
look pietty similai. It uoesn`t mattei whethei these Linuings aie applieu to uilleient
element/event comLinations. The thing is, you uon`t want to iepeat youisell ovei anu
ovei (who uoes?).
Heie`s an example:
jQuery('#button1').click(function(e){
jQuery('div.panel').hide();
jQuery('#panel1').show();
jQuery('#desc').text('You clicked the red button');
});
jQuery('#button2').click(function(e){
jQuery('div.panel').hide();
jQuery('#panel2').show();
jQuery('#desc').text('You clicked the blue button');
});
8.2 Reusing a Handler Function with Different Data | 173
jQuery('#button3').click(function(e){
jQuery('div.panel').hide();
jQuery('#panel3').show();
jQuery('#desc').text('You clicked the green button');
});
As you can see, the only uilleiences noticeu on each hanulei aie the coloi anu the panel
to show. The amount ol coue woulu giow as you auu moie Luttons oi each time the
hanulei lunctions get laigei.
Solution
bind() accepts an optional data aigument to Le Lounu togethei with each specilic han-
ulei lunction. The uata values will Le accessiLle liom within this lunction Ly accessing
event.data

wheie event is the event oLject aigument pioviueu Ly jQueiy.


Note that this value can Le anything...an aiiay, a stiing, a numLei, oi an oLject liteial.
It`s a common appioach to pass an oLject liteial, even il you aie just passing one value,
to make the coue moie ieauaLle. This way, the name you give this single attiiLute within
the oLject will make youi coue a little moie sell-explanatoiy.
Discussion
event.data is useu to pioviue piecomputeu values to a lunction, which means the values
you will Le passing to bind() neeu to Le alieauy availaLle at Linuing time. To hanule
moie uynamic values, theie`s anothei way that we`ll leain aLout in Recipe S.5.
The solution to the pievious pioLlem coulu look something like this:
function buttonClicked(e){
jQuery('div.panel').hide();
jQuery('#panel'+e.data.panel).show();
jQuery('#desc').text('You clicked the '+e.data.color+' button');
}
jQuery('#button1').bind('click',{panel:1, color:'red'}, buttonClicked);
jQuery('#button2').bind('click',{panel:2, color:'blue'}, buttonClicked);
jQuery('#button3').bind('click',{panel:3, color:'green'}, buttonClicked);
Ol couise, you coulu make this even shoitei Ly using a loop. This appioach is calleu a
nacro Ly some coueis, anu it`s a veiy common appioach loi jQueiy coue.
These nacros will suiely ieuuce the coue length anu can sometimes impiove coue
ieauaLility. Some othei times, they`ll just make youi coue completely unieauaLle, so
use them with caution.
Heie`s how you coulu uo it:
jQuery.each(['red','blue','green'], function(num, color){
num++; // it's 0-index based
http://docs.jqucry.con/Evcnts/jQucry.Evcnt=cvcnt.data
174 | Chapter 8:Events
jQuery('#button'+num).bind('click',function(e){
jQuery('div.panel').hide();
jQuery('#panel'+num).show();
jQuery('#desc').text('You clicked the '+color+' button');
});
})
As you can see, I haven`t useu the uata aigument Lecause we uon`t ieally neeu it. The
coue is now somewhat shoitei, Lut not that much, anu it`s not moie ieauaLle.
The conclusion is that Loth appioaches can Le useu on this kinu ol situation. Depenu-
ing on the pioLlem, one coulu Le Lettei (shoitei, moie ieauaLle, easiei to maintain)
than the othei.
8.3 Removing a Whole Set of Event Handlers
Problem
So, you`ve maue a plugin-like Llock ol coue that Linus many event hanuleis to ceitain
DOM elements.
Latei, you want to clean them all up in oiuei to uispose the plugin completely.
This coulu get a little lengthy il you auueu many hanuleis. MayLe you uon`t even have
access to the Lounu hanuleis Lecause they Lelong to anothei local scope.
You can`t unLinu eveiy hanulei loi a ceitain event (oi any existing event), Lecause you
coulu Le ueleting othei hanuleis that you uiun`t take into account.
Solution
Use a unigue namespace loi each plugin you make. Any hanulei Lounu within this
plugin must Le auueu with this namespace.
Latei, when cleaning up, you just neeu to unLinu the whole namespace, anu all the
ielateu event hanuleis will go away with one single line ol coue.
Discussion
How to bind with a namespace?
To auu a namespace to an event type, you simply auu a lolloweu Ly the namespace
name.
Since jQueiy 1.3, you can auu moie than one (namespace) pei event.
This is how you woulu Linu the click anu mousedown lunctions with a namespace:
jQuery.fn.myPlugin = function(){
return this
.bind('click.myPlugin', function(){
8.3 Removing a Whole Set of Event Handlers | 175
// [code]
})
.bind('mousedown.myPlugin', function(){
// [code]
});
};
How to clean up my plugin?
To uispose the Linuings aLove, you woulu uo:
jQuery.fn.disposeMyPlugin = function(){
return this.unbind('.myPlugin');
};
8.4 Triggering Specific Event Handlers
Problem
You neeu to tiiggei an event on a ceitain element (oi many). This element Lelongs to
one oi moie plugins so it may have event hanuleis Lounu to this event.
The pioLlem is that this event is a common one, like click oi mousedown. Simply tiig-
geiing the event coulu iun othei event hanuleis that you uiun`t expect.
Solution
On the same piinciple as the pievious iecipe, namespaces can Le useu loi tiiggeiing as
well. Vhen Linuing, you neeu to make suie you auu a unigue namespace to each set
ol hanuleis.
This can also Le useu loi the opposite situation; il you neeu to tiiggei any event except
those with a namespace, you can use the ! opeiatoi. An example ol this will Le shown
in the uiscussion.
Discussion
How to trigger handlers with a certain namespace?
Now, say you want to piogiammatically tiiggei the click event Lounu Ly the plugin
myPlugin. You coulu simply tiiggei the click event, Lut that woulu Le a Lau appioach,
Lecause any othei hanulei Lounu to the same event woulu get liieu as well.
This is how to uo this piopeily:
jQuery.fn.runMyPlugin = function(){
return this.trigger('click.myPlugin');
};
176 | Chapter 8:Events
How to trigger handlers that do not have a namespace?
On the contiaiy, mayLe you neeu to tiiggei a click (oi any othei event), Lut the taiget
element Lelongs to one oi moie plugins. Tiiggeiing an event coulu iun unuesiieu event
hanuleis, anu that woulu cause pioLlems that will Le pietty haiu to ueLug.
So, assuming all the plugins uiu use a namespace, this is how to tiiggei a click salely:
jQuery('div.panels').trigger('click!');
8.5 Passing Dynamic Data to Event Handlers
Problem
You want to pass ceitain values to an event hanulei, Lut they`ie not known at Linuing
time, anu they woulu change with each call to the hanulei.
Solution
Theie aie two ways ol solving this pioLlem:
Passing extia aiguments to trigger()
Passing a custom event oLject to trigger()
Both appioaches woik, anu neithei is cleaily Lettei than the othei. The seconu ap-
pioach was a little awkwaiu to use Leloie jQueiy 1.3. Since this veision, it has Lecome
pietty stiaightloiwaiu anu less pioLlematic. I`ll explain each option in uetail in the
Discussion section.
Passing uata to the hanulei, insteau ol making the lunction giaL it liom somewheie
(gloLal vaiiaLles, jQueiy namespace, etc.), makes the coue easiei to maintain Lecause
you keep hanulei lunctions simple anu agnostic liom the enviionment.
This also allows you to ieuse the same hanulei loi many situations.
Discussion
Passing extra arguments
trigger() can ieceive one oi moie values that will Le passeu on to the tiiggeieu
hanuleis.
These values can Le ol any type anu any amount. Vhen you have moie than one, you
neeu to wiap them with an aiiay:
jQuery('form').trigger('submit', ['John','Doe', 28, {gender:'M'}]);
8.5 Passing Dynamic Data to Event Handlers | 177
The Lounu lunction loi the pieceuing case woulu Le something like this:
jQuery('form').bind('submit', function(e, name, surname, age, extra){
// Do something with these arguments
});
This appioach is simple anu easy to ieau. The pioLlem is, it looks pietty Lau when you
neeu to ieceive many aiguments; I peisonally woulun`t go Leyonu loui to live.
It`s also kinu ol misleauing il the ieauei is useu to the common function(e){ } kinu ol
lunction.
You stait to wonuei, wheie uo these othei aiguments come liom ?
Useu within a piogiammatic event:
jQuery('#slideshow').bind('add-image', function(e, src){
var $img = jQuery('<img />').attr('src', src);
jQuery(this).append($img);
});
jQuery('#slideshow').trigger('add-image', 'img/dogs4.jpg');
Useu within a ieal event:
jQuery('#button').bind('click', function(e, submit){
if( submit )
// Do something
else
// Do something else
});
jQuery('#button').trigger('click', true);
Passing a custom event object
Il you choose to pass a custom event oLject insteau, each value you pass has to Le
accesseu as an attiiLute on the event oLject ieceiveu Ly the hanulei.
This means that, no mattei how many uata you`ie passing, the hanulei will always have
only a single aigument, the event oLject.
This is alieauy an auvantage ovei the liist appioach, Lecause it makes the lunction
ueclaiation less veiLose.
As mentioneu, this appioach is much nicei to use since jQueiy 1.3. Heie`s how you`u
coue the liist example with a custom oLject:
jQuery('form').bind('submit', function(e){
// Do something with e.name, e.surname, etc.
});
jQuery('form').trigger({
type:'submit',
name:'John',
surname:'Doe',
age: 28,
gender:'M'
});
Some more examples.
178 | Chapter 8:Events
Passing an oLject liteial is actually a shoitcut to cieating an instance ol
jQuery.Event.

This is the alteinative way:


var e = jQuery.Event('submit'); // the new operator can be omitted
e.name = 'John';
e.surname = 'Doe';
e.age = 28;
e.gender = 'M';
jQuery('form').trigger(e);
You can, ol couise, use jQuery.extend insteau ol setting one attiiLute at a time.
You uo neeu to cieate an event oLject youisell il you plan on ietiieving uata liom this
oLject altei the call to trigger(). That`s, Ly the way, a cool technigue to pass inloi-
mation liom the hanulei to the callei (we`ll get into this in the next chaptei).
Whats the difference with event.data?
Using event.data is uselul loi static values that aie accessiLle at the time when the
lunction was Lounu. Vhen the uata you neeu to pass must Le evaluateu latei (oi each
time), event.data won`t uo loi you.
8.6 Accessing an Element ASAP (Before document.ready)
Problem
You neeu to gain access to a ceitain DOM element as soon as possiLle.
Using document.ready isn`t last enough; you ieally want to contiol this element Leloie
the page linishes ienueiing.
Issues like this aie especially noticeaLle on laige pages, wheie the document.ready event
takes longei to Le ieacheu.
Solution
This is a veiy common anu geneiic pioLlem that can Le solveu in many uilleient ways.
Theie`s one appioach that woiks loi all ol them, Lut it ieguiies polling the DOM so it
auus oveiheau to the page-ienueiing piocess (uelinitely unuesiiaLle!).
These aie some ol the usual pioLlems wheie one coulu iely on polling:
Hiue an element iight away, Leloie it is ienueieu (oi anothei style opeiation)
Binu event hanuleis to an element ASAP so that it guickly Lecomes lunctional
Any othei situation
Ve`ll uiscuss what`s the Lettei appioach loi each situation in the Discussion section.
http://docs.jqucry.con/Evcnts/jQucry.Evcnt
8.6 Accessing an Element ASAP (Before document.ready) | 179
Discussion
Hide an element right away (or another style operation)
So, youi pioLlem is uiiectly ielateu to styling, you want to apply a conuitional styling
to an element, anu this conuition neeus to Le evaluateu Ly ]avaSciipt.
The iight way to go aLout this is auuing a specilic CSS class to an element that is guickly
accessiLle, like the <html> element, anu then style the element accoiuingly.
Do something like this:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html.no-message #message{ display:none; }
</style>
<script src="assets/jquery-latest.js"></script>
<script type="text/javascript">
// Bad
jQuery(document).ready(function($){
$('#message').hide();
});
// Correct
jQuery('html').addClass('no-message');
// or...
document.documentElement.className = 'no-message';
</script>
</head>
<body>
<p id="message">I should not be visible</p>
<!--
Many more html elements
-->
</body>
</html>
Bind event handlers to an element ASAP
Veiy olten we have this laige page with inteiactive elements, like Luttons anu links.
You uon`t want those elements to just hang in theie, without any lunctionality attacheu
while the page loaus.
Luckily, theie`s a gieat concept calleu cvcnt dc|cgation that can save the uay. Event
uelegation is easy to implement with one ol seveial jQueiy plugins, anu since jQueiy
1.3, a plugin is no longei neeueu, Lecause it has Leen auueu to the coie jQueiy lile.
180 | Chapter 8:Events
You can now Linu event hanuleis to elements that still uon`t exist Ly using the methou
live().

That way, you uon`t neeu to woiiy aLout waiting loi the element to Le ieauy
in oiuei to Linu the events.
To ieau moie aLout event uelegation, check Recipe S.10.
Any other situation
Youi pioLlem isn`t aLout styling oi aLout events. Then you, my liienu, lall into the
woist gioup.
But uon`t panic! Theie`s a Lettei solution than polling il you`ie conceineu aLout pei-
loimance. I`ll explain it at last.
Polling can Le implementeu with a simple inteival (setInterval) that checks
loi an element, anu once lounu, a ceitain lunction is iun, anu the inteival neeus to Le
cleaieu.
Theie aie two plugins that can aiu you with this. One is LiveQuery,

which has an option


to iegistei a lunction to Le iun loi each newly lounu element that matches a selectoi.
This appioach is pietty slow Lut suppoits the whole set ol selectois.
Theie`s anothei plugin calleu ElementReady
=
that will also hanule this situation
piopeily.
It lets you iegistei paiis ol id/function, anu it will poll the DOM. Once an id is lounu,
the function will Le calleu, anu the id is iemoveu liom the gueue.
This plugin implements, pioLaLly, the lastest appioach to uetect elements, that is,
using document.getElementById. This plugin is pietty last Lut only suppoits ids.
The whole uocument-ieauy concept means altei the html is
paiseu. This means the Liowsei ieacheu the Louy`s closing tag, </body>.
In othei woius, insteau ol using document.ready, you coulu simply put youi sciipts iight
Leloie </body>.
You can apply the same piinciple to othei paits ol the DOM: you can auu a <script>
iight altei the element you want to access, anu you can know, loi ceitain, that it will
Le alieauy accessiLle liom it.
Heie`s an example:
<!DOCTYPE html>
<html>
<head>
<script src="assets/jquery-latest.js"></script>
Polling.
Customly positioned scripts.
http://docs.jqucry.con/Evcnts/|ivc
http://p|ugins.jqucry.con/projcct/LivcQucry
=http://p|ugins.jqucry.con/projcct/E|cncntRcady
8.6 Accessing an Element ASAP (Before document.ready) | 181
</head>
<body>
<p>The time is <span id="time">&nbsp;</span></p>
<script type="text/javascript">
jQuery('#time').text( new Date().toString() );
</script>
<!-- Many more html elements -->
</body>
</html>
As you can see, no polling was neeueu in this case. This is a leasiLle solution il you
uon`t neeu to use it a lot oi you`ll Le auuing tons ol sciipts to the page.
8.7 Stopping the Handler Execution Loop
Problem
You have seveial hanuleis Lounu to the same element/event comLination.
You want to, liom within a hanulei, pievent the iest liom Leing calleu, something like
what event.stopPropagation()
'
uoes. The pioLlem is that event.stopPropagation()
only woiks loi elements that aie Lelow the cuiient element in the DOM hieiaichy.
Solution
Since jQueiy 1.3, event oLjects passeu to hanuleis have a new methou calleu
stopImmediatePropagation().

This methou will uo just that, anu no suLseguent event


hanulei will Le notilieu ol the cuiient event. It will also stop the event`s piopagation,
just like stopPropagation() uoes.
This methou has Leen taken liom ECMASciipt`s DOM level 3 events specilication.

Il you want to consult the event oLject, to know whethei this methou has Leen calleu,
you can uo so Ly calling event.isImmediatePropagationStopped(),

which will ietuin


eithei true oi false.
Discussion
Examples
stopImmediatePropagation() can cancel the actual suLmit Linu-
ing(s) il a ceitain situation is met:
Simple form validation.
' http://docs.jqucry.con/Evcnts/jQucry.Evcnt=cvcnt.stopPropagation.28.29
http://docs.jqucry.con/Evcnts/jQucry.Evcnt=cvcnt.stop|nncdiatcPropagation.28.29
http://www.w3.org/TR/DOM-Lcvc|-3-Evcnts/
http://docs.jqucry.con/Evcnts/jQucry.Evcnt=cvcnt.is|nncdiatcPropagationStoppcd.28.29
182 | Chapter 8:Events
jQuery('form')
.submit(function(e){
e.preventDefault(); // Don't submit for real
if( jQuery('#field').val() == '' )
e.stopImmediatePropagation();
})
.submit(function(e){
// Only executed if the function above
// didn't call e.stopImmediatePropagation
});
It can also Le uselul loi uisaLling elements oi Llocking containeis
tempoiaiily:
(function($){
function checkEnabled(e){
if( jQuery(this).is('.disabled') ){
e.stopImmediatePropagation(); // Stop all handlers
e.preventDefault();
}
};
jQuery.fn.buttonize = function(){
return this.css('cursor','pointer')
.bind('click mousedown mouseup',checkEnabled};
};
})(jQuery);
Disadvantages of this approach
Vhile this new leatuie coulu Le a lilesavei in some situations, you must Le awaie that
Lasing youi logic on this Lehavioi isn`t all that sale. Vhen you iely on this leatuie, you
assume that the hanuleis will Le executeu in the oiuei you expect anu that no othei
hanuleis will get in the way.
Vhile events Lounu with jQueiy aie executeu in the same oiuei they`ie auueu, it`s not
something the API stiongly suppoits, meaning it coulu lail in some Liowseis oi some
special situations. It`s also possiLle that Linuings liom uilleient plugins coulu colliue
Lecause one coulu call stopImmediatePropagation() anu the othei woulun`t get execu-
teu. This coulu cause unexpecteu pioLlems that coulu take a long time to ueLug.
The conclusion is, uon`t Le aliaiu to use stopImmediatePropagation() il it ieally suits
youi pioLlem, Lut uo use it with caution anu uouLle-check all the event hanuleis
involveu.
You shoulu iathei think twice Leloie using it in these situations:
The listenei is a populai DOM element that is also useu Ly othei plugins.
The event is a common one like click oi ready. Theie`s a gieatei chance ol
collisions.
Killing all events.
8.7 Stopping the Handler Execution Loop | 183
On the othei hanu, it shoulu Le pietty sale to use it in these situations:
The listenei is a DOM element that is uynamically cieateu anu useu meiely Ly one
plugin.
The event is a custom event like change-color oi addUser.
You intentionally want to stop any Lounu hanulei (like in the seconu example).
8.8 Getting the Correct Element When Using event.target
Problem
Youi coue is ielying on the event.target

piopeity ol an event oLject, most likely in


comLination with event uelegation, wheie one single event hanulei is Lounu to a con-
tainei anu it manages a vaiiaLle numLei ol uescenuant elements.
In some cases, you uon`t seem to Le getting the expecteu Lehavioi. event.target is
sometimes pointing to an element that is insiue the one you expecteu.
Solution
The event.target piopeity ieleis to the element that got the event, that is, the specilic
element.
This means that il, loi example, you have an image insiue a link anu you click the link,
the event.target will Le the image, not the link.
So, how shoulu you woik aiounu this? Il you`ie not woiking with event uelegation,
then using this (scope ol the lunction) oi event.currentTarget (since jQueiy 1.3)
shoulu uo. It will always point to the element that has the event hanulei Lounu.
Il you`ie inueeu using event uelegation, then you`ll neeu to linu the paient element you
weie expecting.
Since jQueiy 1.3, you can use closest().
=
As specilieu in its uocumentation, it will
ietuin the closest element, Leginning with the cuiient element anu going up thiough
the paients, that matches a ceitain selectoi.
Il you`ie using an oluei veision ol jQueiy, you can simulate closest() with something
like this:
jQuery.fn.closest = function( selector ){
return this.map(function(){
var $parent = jQuery(this).parents();
return jQuery(this).add($parents).filter( selector )[0];
});
}
http://docs.jqucry.con/Evcnts/jQucry.Evcnt=cvcnt.targct
=http://docs.jqucry.con/Travcrsing/c|oscst
184 | Chapter 8:Events
This coulu Le impioveu a little loi peiloimance, Lut this simple veision shoulu uo loi
geneial puiposes.
Heie`s a small example ol a veiy common situation using closest():
jQuery('table').click(function(e){
var $tr = jQuery(e.target).closest('tr');
// Do something with the table row
});
Discussion
event.target is one ol the event oLject`s piopeities noimalizeu Ly jQueiy`s event sys-
tem (event.srcElement on IE).
So, how come an event is tiiggeieu on this taiget element anu youi event hanulei is
calleu even when Lounu to an ancestoi ? The answei is Event LuLLling.
'
Most stanuaiu DOM events uo LuLLle.

This means that, altei the event was tiiggeieu


on the taiget, it will go up to its paient noue anu tiiggei the same event (with all its
hanuleis).
This piocess will continue until eithei it ieaches the document oi event.stopPropaga
tion() is calleu within an event hanulei.
Thanks to event LuLLling, you uon`t neeu to always Linu event hanuleis to specilic
elements; insteau, you can Linu to a common containei once anu hanule them all liom
theie. This is the piinciple ol event uelegation.
8.9 Avoid Multiple hover() Animations in Parallel
Problem
Ve all have lallen loi this at least once. You set up something like this:
jQuery('#something').hover(
function(){
// add some cool animation for jQuery(this)
},
function(){
// Revert the cool animation to its initial state
}
);
Foi example, you coulu Le enlaiging an element each time the mouse iolls ovei it anu
then shiinking it to its initial size once the mouse iolls out.
All goes well until you guickly move the mouse ovei anu out ol the element anu...what?!
' http://www.quir|snodc.org/js/cvcnts_ordcr.htn|
http://cn.wi|ipcdia.org/wi|i/DOM_cvcnts=Connon.2IW3C_cvcnts
8.9 Avoid Multiple hover() Animations in Parallel | 185
The jQuery('#something') element suuuenly gets iesizeu Lack anu loith many times
until it linally stops.
Solution
The solution is inueeu simple, too simple, Lut the pioLlem is so iecuiient that I ieally
consiuei this solution a uselul one.
Vhat you neeu to uo in oiuei to avoiu this nasty ellect is simply kill all existing ani-
mations on the element Leloie you cieate a new one.
To uo so, you have to use jQueiy`s stop() methou. It will (as the name says) stop the
cuiient animation anu, optionally, iemove the lollowing ones as well.
Discussion
Example
I`ll show you an example ol animating the opacity CSS piopeity, Lut it woiks the same
loi any othei piopeity:
jQuery('#something').hover(
function(){
jQuery(this).stop().animate({opacity:1}, 1000);
},
function(){
jQuery(this).stop().animate({opacity:0.8}, 1000);
}
);
This also woiks loi custom jQueiy animations, like slideUp(), slideDown(),
fadeIn(), etc.
This is the loimei example using the laue methous:
jQuery('#something').hover(
function(){
jQuery(this).stop().fadeTo( 1, 1000 );
},
function(){
jQuery(this).stop().fadeTo( 0.8, 1000 );
}
);
Not there yet
Theie`s still anothei ielateu pioLlem that coulu aiise in a situation like this:
jQuery('#something').hover(
function(){
jQuery(this).stop()
.fadeTo( 1, 1000 )
.animate( {height:500}, 1000 );
},
186 | Chapter 8:Events
function(){
jQuery(this).stop()
.fadeTo( 0.8, 1000 )
.animate( {height:200}, 1000 );
}
);
Il you tiy this coue anu move the mouse guickly, the element will get animateu ciazily
again, Lut only its height (not the opacity) will animate.
The ieason is simple; jQueiy animations get gueueu Ly uelault. This means that il you
auu seveial animations, they`ll get executeu in seguence.
stop() Ly uelault only stops (anu iemoves) the cuiient animation. In oui last example,
only the opacity animation will Le iemoveu each time, leaving the height animation in
the gueue, ieauy to iun.
To woik aiounu this, you have to eithei call stop() one moie time oi pass true as the
liist aigument. This will make stop() clean all the gueueu animations as well. Oui
hovei coue shoulu look like this:
jQuery('#something').hover(
function(){
jQuery(this).stop(true)
.fadeTo( 1, 1000 )
.animate( {height:500}, 1000 );
},
function(){
jQuery(this).stop(true)
.fadeTo( 0.8, 1000 )
.animate( {height:200}, 1000 );
}
);
8.10 Making Event Handlers Work for Newly Added Elements
Problem
You`ve Lounu one oi moie event hanuleis, anu they suuuenly stop woiking.
It happens altei new elements aie auueu uynamically Ly an Ajax ieguest oi simple
jQueiy opeiations (append(), wrap(), etc.).
This pioLlem is incieuiLly common, anu we`ve all lallen loi this at
least once.
I`ll explain the theoiy Lehinu it in the Discussion section. Il you leel
you neeu to unueistanu this well Leloie heauing to the solutions, check
Vhy uo event hanuleis get lost ? on page 1SS liist.
8.10 Making Event Handlers Work for Newly Added Elements | 187
Solution
Theie aie two possiLle solutions loi this iecuiiing pioLlem, each with its own pios
anu cons:
Rcbinding
This appioach ieguiies you to call bind() again anu again, eveiy time new elements
aie auueu.
It`s pietty easy to implement anu uoesn`t ieguiie any plugin oi new methou.
You can simply have all the Linuings in a lunction anu call it again altei each upuate.
Evcnt dc|cgation
It ielies on event LuLLling.

This is last anu light Lut ieguiies a little unueistanuing


anu can Le (just) a little tiicky at times.
Since jQueiy 1.3, theie`s Luilt-in suppoit loi event uelegation. Using it is as simple
as using the new live() methou insteau ol bind().
Discussion
Why do event handlers get lost ?
]avaSciipt, as opposeu to CSS, isn`t a ueclaiative language. You uon`t uesciiLe Lehav-
iois, anu they get automagically applieu.
]avaSciipt, like most othei piogiamming languages, is impeiative. The uevelopei speci-
lies a seguence ol actions to peiloim, anu they get applieu as the line ol coue is ieacheu.
Vhen you auu a piece ol coue like this:
function handler(){
alert('got clicked');
}
jQuery('.clickable').bind('click', handler);
this is what you`ie uoing:
1. Look loi all elements with a CSS class clickaLle anu save it to the collection.
2. Binu the hanulei lunction to the click event ol each element in the collection.
Il ]avaSciipt/jQueiy weie inteipieteu ueclaiatively, the pievious coue woulu mean the
lollowing:
1. Each time an element with CSS class clickable is clickeu, iun the lunction handler.
Howevei, Lecause ]avaSciipt/jQueiy is inteipieteu impeiatively, the only elements that
will get Lounu aie those that match the selectoi at the time it is iun. Il you auu new
http://www.quir|snodc.org/js/cvcnts_ordcr.htn|
188 | Chapter 8:Events
elements with a clickable class oi you iemove the class liom an element, the Lehaviois
won`t Le auueu oi iemoveu loi those elements.
A little introduction to event delegation
Event uelegation consists ol Linuing once, at the stait, anu passively listening loi events
to Le tiiggeieu. It ielies on the lact that many events in the Liowsei LuLLle up.
As an example, altei you click a <div>, its paient noue ieceives the click event as well,
anu then it passes to the paient`s paient anu so on, until it ieaches the document element.
Pros and cons of each approach
ReLinuing is simple: you just ie-auu the event hanuleis. It leaus to new pioL-
lems, such as auuing event hanuleis to elements that weie alieauy Lounu. Some auu
CSS classes to woik aiounu this pioLlem (maiking those Lounu with a ceitain class).
All this ieguiies CPU cycles eveiy time the elements aie upuateu anu ieguiies moie anu
moie event hanuleis to Le cieateu.
One way to woik aiounu Loth pioLlems mentioneu is to use nameu lunctions as event
hanuleis. Il you always use the same lunction, then you`ve solveu the uuplication
pioLlem, anu the oveiheau is smallei.
Still, ieLinuing can leau to highei anu highei amounts ol RAM taken as time passes Ly.
Event uelegation just ieguiies an initial Linuing anu theie`s no neeu to
ueal with ieLinuing at all. This is guite a ieliel loi the uevelopei anu makes the coue
shoitei anu cleaiei. The RAM pioLlem mentioneu Leloie uoesn`t apply to event uele-
gation. The content ol the page might change, Lut the active event hanuleis aie always
the same.
Event uelegation has a catch, though. In oiuei loi it to woik, the coue that hanules it
(live(), a plugin oi youi own coue) must take the element that got the event
(event.target) anu go thiough its ancestois to see which ones have event hanuleis to
tiiggei along with some moie piocessing. This means that, while event uelegation ie-
guiies less Linuing, it ieguiies moie piocessing each time an event is tiiggeieu.
Also, event uelegation cannot Le useu with events that uon`t LuLLle, such as focus anu
blur. Foi these events, theie`s a woikaiounu that woiks cioss-Liowsei, using the
focusin anu focusout events in some Liowseis.
Rebinding.
Event delegation.
8.10 Making Event Handlers Work for Newly Added Elements | 189
Conclusion
Event uelegation seems like a nicei appioach, Lut it ieguiies extia piocessing.
My auvice on this mattei is to use live Linuings just when you ieally neeu them. These
aie two common situations:
Dynanic c|cncnts
You have a list ol DOM elements that changes uynamically.
Largc |ists
Event uelegation can woik lastei when you Linu one live Linuing insteau ol, say,
100 liom the iegulai ones. This is lastei at the stait anu takes less memoiy.
Il theie`s no ieason to use live(), then just go loi bind(). Il you then neeu to make it
live, switching shoulu Le just a mattei ol seconus.
190 | Chapter 8:Events
CHAPTER 9
Advanced Events
Aricl Flcslcr
9.0 Introduction
These iecipes will ueal with euge case pioLlems, auvanceu optimizations, anu ceitain
technigues to make youi coue coolei. These iecipes aie mostly loi auvanceu uevelopeis
who want to take theii jQueiy coue one step luithei.
As in Chaptei S, I`ll ielei to coue as p|ugins, Lut that uoesn`t mean it neeus to Le an
actual plugin. Il you uon`t stiuctuie youi coue as jQueiy plugins, then keep my naming
convention in minu.
9.1 Getting jQuery to Work When Loaded Dynamically
Problem
You aie incluuing jQueiy uynamically into the page, Ly eithei auuing a <script> ele-
ment to the DOM oi uoing it some othei way like Ajax.
Once jQueiy is loaueu, you expect eveiything to stait woiking, Lut loi some ieason,
no sciipt staits.
Solution
You neeu to incluue an auuitional sciipt to Le executeu altei jQueiy is loaueu. This
sciipt will simply call jQuery.ready(). Altei you uo this, eveiything will stait woiking
as expecteu.
191
Discussion
What is jQuery.ready()?
The jQuery.ready() lunction is calleu Ly jQueiy`s coie when the uocument is uetecteu
as ieauy. Once calleu, all the document.ready hanuleis aie tiiggeieu automatically.
You uon`t neeu to woiiy aLout whethei this lunction might have Leen
calleu alieauy (loi example, Ly the oiiginal uetection), tiiggeiing all the
document.ready hanuleis again.
jQuery.ready() incluues a check loi uuplicateu executions inteinally.
Fuithei calls will Le ignoieu.
Why was this happening?
The document.ready uetection is mostly Laseu on events. Depenuing on the Liowsei, a
ceitain event is Lounu, anu it`s supposeu to Le tiiggeieu once the uocument is ieauy.
In auuition, the window.onload event is Lounu loi all Liowseis as a lallLack measuie in
case the othei options lail.
Vhat was happening to you is that jQueiy was linally loaueu into the page only altei
the window.onload event; theieloie, all the event hanuleis iemaineu Lounu, anu none
got tiiggeieu.
By calling jQuery.ready(), you`ie announcing the document.ready event manually,
tiiggeiing all the hanuleis anu getting things Lack to noimal.
9.2 Speeding Up Global Event Triggering
Problem
GloLal event tiiggeiing implicates calling all the event hanuleis Lounu loi a ceitain
event, on all availaLle elements.
It is peiloimeu Ly calling jQuery.trigger() without passing any DOM element as con-
text. It is neaily the same as calling trigger() on all the elements that have one oi moie
Linuings to the coiiesponuing event, something like this:
jQuery('#a1,#a2,div.b5').trigger('someEvent');
Tiiggeiing gloLally is oLviously simplei Lecause you uon`t neeu to know all the ele-
ments that neeu to Le tiiggeieu.
It`s guite uselul loi ceitain situations Lut can also Le a slow piocess at times. Although
it`s Leen optimizeu since jQueiy 1.3, it still ieguiies going thiough all the elements
192 | Chapter 9:Advanced Events
iegisteieu to jQueiy`s event system. This can cause shoit (oi not so shoit) hangs eveiy
time an event is tiiggeieu like this.
Solution
One possiLle solution is to have one oi moie gloLal oLjects that will act as event lis-
teneis. These elements can Le DOM elements oi not. All gloLal events will Le Lounu
anu tiiggeieu on one ol these elements.
Insteau ol uoing something like this:
jQuery('#text1').bind('change-page', function(e, title){
jQuery(this).text( 'Page is ' + title );
});
jQuery('#text2').bind('change-page', function(e, title){
jQuery(this).text( 'At ' + title + ' Page' );
});
jQuery.trigger('change-page', 'Inbox');
you`u uo something like this:
jQuery.page = jQuery({}); // Just an empty object
jQuery.page.bind('change', function(e, title){
jQuery('#text1').text( 'Page is ' + title );
});
jQuery.page.bind('change', function(e, title){
jQuery('#text2').text( 'At ' + title + ' Page' );
});
jQuery.page.trigger('change', 'Inbox');
The syntax seems pietty much the same, Lut each call to trigger won`t Le iteiating
jQueiy`s uata iegistiy (aka jQuery.cache).
Even il you ueciue to use a DOM element, the piinciple is the same. DOM elements
can Le moie appiopiiate at times. Il, loi example, you`ie cieating a taLle-ielateu plugin,
then it`u make sense to use each <table> element as an event listenei.
The pioLlem with DOM elements in many Liowseis is that they`ie the main souice ol
memoiy leaks. Memoiy leaks occui when theie aie ceitain amounts ol RAM memoiy
that cannot Le lieeu Ly the ]avaSciipt engine as the usei leaves a page.
You shoulu Le much moie caielul aLout how you save uata into the oLjects when you
use DOM elements. That`s why jQueiy pioviues the data() methou.
Still, I`u peisonally use iegulai ]avaSciipt oLjects in most situations. You can auu at-
tiiLutes anu lunctions to them, anu the likelihoou (anu magnituue) ol memoiy leaks
will Le smallei.
9.2 Speeding Up Global Event Triggering | 193
Discussion
Pros and cons
As stateu Ly the iecipe title, this appioach is lastei. You will Le always tiiggeiing events
on single oLjects, insteau ol the n entiies on jQuery.cache.
The uownsiue ol this appioach is that eveiyone neeus to know the event listenei oLject
(jQuery.page in the example) in oiuei to Linu oi tiiggei one ol its known events.
This can Le negative il you`ie aiming to keep youi coue encapsulateu.
'
The concept ol encapsulation is highly enloiceu in oLject-oiienteu piogiamming,
wheie this is one ol the things you shoulu Le veiy cautious aLout.
This is geneially not such a gieat concein with jQueiy piogiamming, Lecause it is not
oLject oiienteu anu most useis uon`t get too woiiieu aLout coue encapsulation. Still,
it`s woith mentioning.
Making the listeners functional
The listenei oLjects mentioneu uon`t have to Le simple uummy oLjects with nothing
Lut bind(), unbind(), anu trigger() (as lai as we`ie conceineu).
These oLjects coulu actually have methous anu attiiLutes that woulu make them much
moie uselul.
The only pioLlem, though, is that il we uo something like this:
jQuery.page = jQuery({ number:1 });
to access the nunbcr attiiLute, we woulu Le loiceu to uo this:
jQuery.page.number; // undefined
jQuery.page[0].number; // 1
This is how jQueiy woiks on HTML noues anu anything else.
But uon`t give up on me yet! It`s easy to woik aiounu this. Let`s make a small plugin:
(function( $ ){
// These methods will be copied from jQuery.fn to our prototype
var copiedMethods = 'bind unbind one trigger triggerHandler'.split(' ');
// Empty constructor
function Listener(){
};
$.each(copiedMethods, function(i,name){
Listener.prototype[name] = $.fn[name];
});
' http://cn.wi|ipcdia.org/wi|i/Encapsu|ation_(conputcr_scicncc)
194 | Chapter 9:Advanced Events
// Our "jQuery.fn.each" needs to be replaced
Listener.prototype.each = function(fn) {
fn.call(this);
return this;
};
$.listener = function( data ){
return $.extend(new Listener(), data);
};
})( jQuery );
Now we can cieate oLjects that will have all the jQueiy methous we neeu that aie ielateu
to events, Lut the scope ol the lunctions we pass to bind(), unbind(), etc., will Le the
oLject itsell (jQuery.page in oui example).
Note that oui listenei oLjects won`t have all jQueiy methous Lut just the ones we
copieu. Vhile you coulu auu some moie methous, most ol them won`t woik. That
woulu ieguiie a moie complex implementation; we`ll stick to this one, which satislies
oui neeus loi events.
Now that we have this mini plugin, we can uo this:
jQuery.page = jQuery.listener({
title: 'Start',
changeTo: function( title ){
this.title = title;
this.trigger('change');
}
});
jQuery.page.changeTo('Inbox');
Because you can now access the oLject liom within the hanuleis, using the this, you
uon`t neeu to pass ceitain values like the title as aiguments to the hanulei. Insteau, you
can simply use this.title to access the value:
jQuery.page.bind('change', function(e){
jQuery('#text1').text( 'Page is ' + this.title );
});
9.3 Creating Your Own Events
Problem
You want to pioviue ceitain Lehaviois to an element when it`s Lounu to an event.
Solution
Use jQuery.event.special to uo this. This leatuie ieguiies an oLject with, at least, a
lunction that will Le calleu each time youi event is Lounu loi the time on each element
anu anothei lunction to clean up what you uiu in the liist place.
9.3 Creating Your Own Events | 195
The syntax looks something like this:
jQuery.event.special.myEvent = {
// Bind the custom event
setup:function( data, namespaces ){
this; // The element being bound
// return false to get the native binding, otherwise,
// it will be skipped
},
// Clean up
teardown:function( namespaces ){
this; // The element being bound
// Ditto about returning false
}
};
Altei you auu youi event Lehavioi, you can uo something like this:
jQuery('#some_element').bind('myEvent', {foo:'bar'}, function(){...});
Altei this, youi setup() lunction will Le calleu.
Discussion
Handling every binding to your event
As explaineu, youi setup() lunction will Le calleu only when auuing the liist hanulei.
This is enough il the logic you`ie encapsulating on this event uoesn`t ieguiie some
opeiations to Le iun each time a new Linuing is peiloimeu.
This option is pioviueu Ly jQueiy, Lut the appioach has changeu since jQueiy 1.3.3.
Il you`ie using an oluei veision, then you just neeu to use jQuery.event.specialAll
insteau ol jQuery.event.special. It will accept the same kinu ol oLject, anu youi call-
Lacks will ieceive the same aiguments. The only uilleience is that ietuining lalse won`t
Liing any change.
As ol jQueiy 1.3.3, jQuery.event.specialAll is gone. To inteicept all Linuings loi an
event, you neeu to incluue an add() (anu optionally remove()) lunction in youi
jQuery.event.special namespace. The lunctions will ieceive the hanulei that is aLout
to Le Lounu, anu can optionally ietuin a new hanulei lunction to Le useu insteau.
A real-world example
Let`s make suie this is cleai Ly wiiting a simple example; I`ll use the 1.3.3- notation.
Let`s suppose you want to have an event tiiggeieu when an element is selecteu (clickeu)
anu it isn`t uisaLleu. Ve`ll assume that the item is uisaLleu when it has the CSS class
disabled.
196 | Chapter 9:Advanced Events
Heie`s a way ol uoing that:
// Save these to make the code shorter
// Don't do this within the global scope
var event = jQuery.event;
var $selected = event.special.selected = {
setup:function( data ){
event.add(this, 'click', $selected.handler);
return false;
},
teardown:function(){
event.remove(this, 'click', $selected.handler);
return false;
},
handler:function(){
var $elem = jQuery(this);
if( !$elem.hasClass('disabled') )
$elem.triggerHandler('selected');
}
};
As you can see, we pioviue oui own hanulei loi selected. Vithin the hanulei, we useu
triggerHandler() insteau ol trigger() Lecause we uon`t neeu event LuLLling, anu
theie`s no uelault action to pievent, so we save some neeuless piocessing.
Existing uses for this feature
jQuery.event.special is a gieat way ol auuing new Lehaviois without polluting the
jQueiy namespace.
It uoesn`t suit any situation, Lut it usually comes in hanuy when you neeu a custom
event that is Laseu on anothei one (click in oui example). It`s also uselul il you have
a plugin that simply Linus events oi simulates them; then you can mask that plugin
as a iegulai event.
jQueiy`s coie uses jQuery.event.special to hanule events Lounu to the
document.ready event. Actually, they`ie stoieu as iegulai event hanuleis, Lut the liist
time you Linu to this event, you`ie actually activating the (hacky) uetection coue.
It is also useu to tianspaiently hanule mouseenter/mouseleave events (those useu Ly
hover()). All the DOM tiaveisal opeiations neeueu to achieve this aie nicely hiuuen
within the setup() hanuleis.
Theie aie also plugins that take auvantage ol jQuery.event.special. Some ol these aie
as lollows:
mousewheel
Pioviues suppoit loi mouse wheel changes.

http://p|ugins.jqucry.con/projcct/nouscwhcc|
9.3 Creating Your Own Events | 197
drag, drop
Diag anu uiop suppoit maskeu as simple events.

focusin, focusout
This snippet (not an actual plugin) oiiginally wiitten Ly ]oin Zaelleiei was latei
auueu via plugins to achieve event uelegation ol focus anu blur events.
Checking these plugins can Le a goou stait il you`ie planning on auuing new events to
jQueiy.
9.4 Letting Event Handlers Provide Needed Data
Problem
You neeu to allow othei plugins (oi just simple jQueiy coue) to chime in anu mouily
ceitain vaiiaLles Leloie you peiloim the ieguesteu action.
Solution
Use events to notily othei sciipts aLout the action that is aLout to Le caiiieu out.
It is possiLle to get uata that is gatheieu liom the actioneu event hanuleis.
Il none is pioviueu, you coulu then use some uelault option ol youi choice.
You`ll see how to uo this accoiuing to what jQueiy veision you aie using.
Discussion
How can we do this with jQuery 1.3+?
Since jQueiy 1.3, with the auuition ol jQuery.Event, this can Le achieveu in a nicei way.
The olu way still woiks loi triggerHandler() Lut not loi jQuery.trigger().
Foi the coue we`ll see now, we will neeu to cieate a jQuery.Event:
var e = jQuery.Event('updateName');
Now, to call the hanuleis anu ietiieve the value, we`ll pass the event oLject to
trigger() anu then letch the uata liom the event oLject:
jQuery('#element').trigger(e);
alert( e.result ); // Charles
As I saiu at the Leginning, this uoesn`t woik nicely when many hanuleis aie Lounu anu
is, in geneial teims, a little unieliaLle anu liagile.
So, how can we communicate event hanuleis anu the lunction tiiggeiing the event?
http://p|ugins.jqucry.con/projcct/drag, http://p|ugins.jqucry.con/projcct/drop
198 | Chapter 9:Advanced Events
The answei is, thiough the event oLject that we`ie passing.
The jQuery.Event oLject passeu to trigger() will Le the same that is ieceiveu Ly each
hanulei as its liist aigument.
This means that we can uo this:
jQuery('#name').bind('updateName', function(e){
e.name = this.value;
});
var e = jQuery.Event('updateName');
jQuery('#name').trigger(e);
alert( e.name );
This example uoesn`t uillei much liom simply accessing e.result, Lut what aLout
multiple event hanuleis that opeiate on the same event oLject?
jQuery('#first').bind('update', function(e){
e.firstName = this.value;
});
jQuery('#last').bind('update', function(e){
e.lastName = this.value;
});
var e = jQuery.Event('update');
jQuery('#first, #last').trigger(e);
alert( e.firstName );
alert( e.lastName );
Ve now have a way ol allowing any numLei ol event hanuleis to pioviue neeueu in-
loimation loi a lunction to iun. Neeuless to say, you can call trigger() seveial times,
passing the same event oLject.
As saiu Leloie, it`u Le wise to pieset the event oLject with uelault values (il applicaLle).
Youi coue shoulun`t iely on the lact that otheis uiu suLsciiLe to a ceitain event.
Il no uelault value can Le useu, then you can always aLoit the call oi thiow an eiioi.
How this was achieved before jQuery 1.3
Oluei veisions ol jQueiy only alloweu the useis to get a single value, which woulu Le
ietuineu when calling jQuery.trigger() anu/oi triggerHandler().
It lookeu something like this:
jQuery('#element').bind('updateName', function(){
return 'Charles';
});
var name = jQuery('#element').triggerHandler('updateName');
alert( name ); // Charles
This was OK until you hau moie than one event hanulei ietuining uata. At that point,
it was a mattei ol who comes last to ueciue which one`s uata woulu Le ietuineu.
9.4 Letting Event Handlers Provide Needed Data | 199
Allowing event handlers to prevent actions
This is ieally a specialization ol what we just saw. Event oLjects, Ly uesign, have a
methou calleu preventDefault(). This methou is useu on native events to aLoit com-
mon actions like clicks on links, Lut it has no ieal use on custom events.
Ve coulu take auvantage ol this anu use this methou to allow othei sciipts to pievent
actions that aie aLout to Le peiloimeu.
I`ll now show you an example ol an action. I`ll use the mini plugin intiouuceu on
Recipe 9.2, Lut that is ceitainly not a ieguiiement to use this:
var remote = jQuery.listener({
request:function( url, callback ){
jQuery.ajax({ url:url, success:callback });
}
});
// Do a request
remote.request('contact.html', function( html ){
alert( html );
});
Now suppose we want to allow an exteinal sciipt to aLoit ceitain ieguests when
neeueu. Ve neeu to mouily remote.request like this:
var remote = jQuery.listener({
request:function( url, callback ){
var e = jQuery.Event('beforeRequest');
e.url = url;
this.trigger(e);
if( !e.isDefaultPrevented() )
jQuery.ajax({ url:url, success:callback });
}
});
e.isDefaultPrevented() will ietuin whethei e.preventDefault() was evei calleu on this
oLject.
Any exteinal sciipt can now uo something like this:
remote.bind('beforeRequest', function(e){
if( e.url == 'contact.html' )
e.preventDefault();
});
Retuining lalse (within the lunction) woulu have neaily the same ellect as calling
e.preventDefault(). It will also stop the event piopagation, which coulu Le uesiiaLle.
Neeuless to say, in a situation like this, we coulu use what we leaineu Leloie to allow
the URL (oi post uata il auueu) to Le mouilieu Ly hanuleis.
200 | Chapter 9:Advanced Events
9.5 Creating Event-Driven Plugins
Problem
You want youi plugin to Le contiollaLle liom the outsiue. One shoulu Le aLle to tell
the plugin to uo something at any time. Theie coulu Le many instances (calls) ol a
plugin, Lut oui action shoulu only Le executeu in the context we pioviue.
Solution
One way to uo this is inueeu using events.
Vhen a plugin is calleu, it Linus lunctions on each matcheu element that once tiiggeieu,
anu it will peiloim the uesiieu actions.
As a possiLle siue solution, each time the plugin is calleu, insteau ol iespecting the
chaining, it coulu ietuin an oLject that contains the Linuings anu allows exteinal ma-
nipulation (use the plugin liom Recipe 9.2).
This allows you to call the plugin many times on the same element without messing up
the events.
Discussion
An example
Ve`ll now cieate a simple sliueshow plugin. I`ll Lase this plugin on an existing plugin
ol mine calleu jQuery.SerialScroll.

I liist thought ol this appioach when couing this


plugin, anu, I must say, it woikeu pietty well.
Ve`ll name oui plugin slideshow. It will ieceive an <img> element anu an aiiay ol URLs,
anu it will cycle the images. It will allow pievious anu next movement, jumping to a
ceitain image, anu also autocycling.
Let`s stait with the Lasics:
(function( $ ){
$.fn.slideshow = function(options){
return this.each(function(){
var $img = $(this),
current = 0;
// Add slideshow behavior...
});
};
})( jQuery );
http://j|cs|cr.b|ogspot.con/2008/02/jqucryscria|scro||.htn|
9.5 Creating Event-Driven Plugins | 201
Now we`ll auu a lew local lunctions that will allow us to move to uilleient images
(URLs) in the collection:
function show( index ){
var total = options.images.length;
while( index < 0 )
index += total;
while( index >= total )
index = total;
current = index;
$img.attr('src', options.images[index]);
}
function prev(){
show( current 1 );
}
function next(){
show( current + 1 );
}
Ve can now expose this lunctionality with events:
$img.bind('prev', prev).bind('next', next).bind('goto',function(e, index){
show( index );
});
Vhat aLout autocycling? Let`s auu a lew moie lunctions:
var auto = false, id;
function start(){
stop();
auto = true;
id = setTimeout(next, options.interval || 2000);
}
function stop(){
auto = false;
clearTimeout(id);
}
Heie aie the events:
$img.bind('start', start).bind('stop', stop);
Ve now neeu to auu a lew lines to show() to keep autocycling il neeueu:
function show( index ){
// Same as before...
if( auto )
start();
}
202 | Chapter 9:Advanced Events
Anu that`s it! Ve now have a lull sliueshow with prev, next, anu autocycling.
In oiuei to make the example cleai, I maue this plugin completely uepenuent on the
outsiue manipulation.
Heie`s a mouel implementation:
<ul>
<li><img id="prev" src="prev.png" /></li>
<li><img id="slideshow" /></li>
<li><img id="next" src="next.png" /></li>
</ul>
...
(function( $ ){
var $image = $('#slideshow');
$image.slideshow({
images: ['1.jpg', '2.jpg', '3.jpg', '4.jpg'],
interval: 3000
});
$('#prev').click(function(){
$image.trigger('prev');
});
$('#next').click(function(){
$image.trigger('next');
});
$image.trigger('goto', 0); // Initialize on 0
$image.trigger('start'); // We want auto cycling
})( jQuery );
I useu trigger() Lecause it`s nice anu shoit, Lut the tiuth is that it woulu
Le lastei il you useu triggerHandler() Lecause trigger() will geneiate
event LuLLling (since jQueiy 1.3) anu you pioLaLly uon`t neeu it.
What happens if an element already has one of these events?
It coulu happen (although it`s stiange) that the #slideshow element coulu alieauy have
a Linuing on an event Ly the name ol prev, next, goto, start, oi stop.
Il this is the case, check Recipe S.+ loi a solution.
9.5 Creating Event-Driven Plugins | 203
How can I allow others to clean up the added event handlers?
Because I uiun`t expose the Lounu lunctions, any othei exteinal coue won`t Le aLle to
unLinu them.
In most cases, you coulu simply unLinu the whole events liom the element, something
like this:
jQuery('#slideshow').unbind('prev next goto start stop'); // Enumerate each event
// or
jQuery('#slideshow').unbind(); // Blindly remove them all
Il you neeu a cautious unLinuing oi il you simply want to unLinu all ielateu events,
check Recipe S.3.
Whats the difference with other approaches?
Theie aie othei existing technigues to allow exteinal manipulation. I`ll compaie some:
This pattein is useu Ly jQueiy UI (among otheis).
It consists ol executing actions when the plugin is passeu a stiing as the liist aigument,
loi example:
jQuery('#image').slideshow('goto', 1);
This is a little shoitei than using events, Lut the whole appioach ieguiies you to save
all the neeueu uata (the cuiient inuex in oui case) in a puLlic way, so it can Le ietiieveu
alteiwaiu. People who use this pattein also tenu to use data() to stoie the vaiiaLles.
Il you use events, you can simply use local vaiiaLles Lecause youi event hanuleis have
access to the plugin`s local scope.
This pattein is useu Ly the validate plugin liom ]oin
Zaelleiei (anu otheis too).
Depenuing on how it is coueu, the oLject`s methous coulu Le aLle to access local vai-
iaLles. To uo so, it must use closuies,

which aien`t a nice thing to aLuse. Also, you


neeu to stoie this oLject somewheie (gloLally). This also ieguiies you to uo pseuuo-
oLject-oiienteu coue (which you may like oi not).
You coulu cieate some kinu ol hyLiiu Letween this appioach anu the one I explaineu.
Insteau ol Linuing the events (prev, next, etc.) to the DOM element, you coulu cieate
an oLject (using jQuery.listener) anu Linu the events to it; then it coulu Le ietuineu.
As we saw in Recipe 9.2, this listenei oLject woulun`t Le iestiicteu to events. It coulu
have methous anu even uata saveu into its attiiLutes.
Allowing the plugin to accept commands.
Returning an object with methods.
http://cn.wi|ipcdia.org/wi|i/C|osurc_(conputcr_scicncc)
204 | Chapter 9:Advanced Events
9.6 Getting Notified When jQuery Methods Are Called
Problem
You want to peiloim a ceitain action when a DOM element gets mouilieu using jQueiy.
This coulu involve changing an attiiLute such as a CSS piopeity, iemoving it liom the
uocument, etc.
Some Liowseis alieauy suppoit mutation events,
=
which woulu seive this neeu, Lut
they`ie not something you can use in a cioss-Liowsei lashion yet, anu they aien`t
integiateu with jQueiy.
Anothei thing you might evei neeu is to mouily the aiguments passeu to jQueiy meth-
ous Leloie they`ie executeu. On the same piinciple, you coulu neeu to altei the uata
ietuineu Ly a methou altei the executing ol the lunction itsell.
Solution
This is somehow ielateu to aspect-oiienteu piogiamming,
'
Lut heie we won`t Le nesting
lunctions; insteau, we`ll oveiloau the uesiieu methou once anu tiiggei events eveiy time
the methou is calleu.
Ve`ll neeu one event to Le tiiggeieu bcjorc the lunction is iun to allow the aiguments
to Le changeu. Ve`ll also neeu an event ajtcr the lunction is iun so we can ietiieve the
ietuineu uata anu even change it il necessaiy.
Let`s see how to coue this as a plugin. I`ll show you each step sepaiately.
Discussion
Overloading the desired method
Fiist, let`s cieate a lunction that ieplaces jQueiy methous with oui own lunction. I`ll
name it jQuery.broadcast(); you can change its name il you pielei something else:
(function($){
$.broadcast = function(name){
// Save the original method
var old = $.fn[name];
$.fn[name] = function(){
// Broadcast
};
};
=http://www.w3.org/TR/DOM-Lcvc|-2-Evcnts/cvcnts.htn|=Evcnts-cvcntgroupings-nutationcvcnts
' http://cn.wi|ipcdia.org/wi|i/Aspcct_oricntcd_progranning
9.6 Getting Notified When jQuery Methods Are Called | 205
})(jQuery);
name neeus to Le the methou name we want to oveiiiue, loi example:
jQuery.broadcast('addClass');
Triggering an event prior to the execution
Now that we have put oui own lunction as the jQueiy methou, let`s see how to tiiggei
an event that will allow us to change the incoming aiguments:
// Create an event object
var e = $.Event('before-'+name);
// Save the arguments into the object
e.args = $.makeArray(arguments);
// Trigger the event
this.trigger(e);
Assuming you`ie Lioaucasting addClass(), we can now uo this:
jQuery('body').bind('before-addClass',function(e){
e.args[0]; // The CSS class
});
Executing the original method
An event is now tiiggeieu, Lut we still have to call the olu addClass(). Ve`ll save the
ietuineu uata into the event oLject as well so we can expose it latei when we tiiggei
the othei event.
e.ret = old.apply(this, e.args);
As you can see, we uon`t pass the oiiginal arguments aiiay; insteau, we use the one we
exposeu in case it was mouilieu in some way.
Triggering an event after the execution
Ve now have the ietuineu uata saveu in oui event oLject. Ve can now tiiggei the linal
event, allowing exteinal mouilication ol the ietuineu uata.
Ve`ll ieuse the same event oLject, Lut we`ll change the event`s name.
e.type = 'after-'+name;
this.trigger(e);
Returning the result
All what`s lelt now is to ietuin the iesulting uata anu continue with the noimal exe-
cution. Ve`ll give out what we saveu on e.ret that coulu have Leen mouilieu Ly an
event hanulei:
return e.ret;
206 | Chapter 9:Advanced Events
Putting it all together
This is the completeu coue we`ve uevelopeu:
(function($){
$.broadcast = function(name){
var old = $.fn[name];
$.fn[name] = function(){
var e = $.Event('before-'+name);
e.args = $.makeArray(arguments);
this.trigger(e);
e.ret = old.apply(this, e.args);
e.type = 'after-'+name;
this.trigger(e);
return e.ret;
};
};
})(jQuery);
Where to go from here?
I tiieu to keep the example shoit to illustiate the point. Theie aie a couple ol things
you can uo to impiove it; heie aie a lew iueas:
Use triggerHandler() insteau ol trigger(): il you uon`t neeu the events to LuLLle,
you coulu simply use triggerHandler(). This will make the whole piocess lastei;
note that triggerHandler() only tiiggeis the event on the liist element ol the
collection.
Run the piocess on each element sepaiately: in the pievious example, trigger() is
calleu on the whole collection at once. That will Le OK loi most cases Lut can yielu
unexpecteu iesults when useu on collections with multiple elements.
You coulu wiap what we put insiue the lunction with a call to map(). That shoulu
make the coue woik once pei element.
The uownsiue is that it will Le slightly slowei anu will also geneiate an (unexpecteu)
stack entiy (pushStack()) uue to the call to map().
Allow exteinal coue to pievent noimal execution: il you`ie using jQueiy 1.3 oi
highei, you coulu take auvantage ol the methous loi jQuery.Event.
You can ask the event oLject whethei someone calleu its preventDefault() meth-
ou using e.isDefaultPrevented().
Il this ietuins true, then you uon`t call the oiiginal lunction.
9.6 Getting Notified When jQuery Methods Are Called | 207
Avoiu multiple oveiloaus ol the same jQueiy methou: this one is pietty simple;
just cieate an inteinal oLject liteial wheie you keep tiack ol which methous weie
oveiloaueu. Then you just ignoie iepeateu calls.
Integiate this with jQuery.event.special: this one will save you liom calling
jQuery.broadcast() loi each methou you want to oveiloau.
Insteau, you auu an entiy to jQuery.event.special loi each methou, anu you in-
teinally call jQuery.broadcast() when someone Linus an event. This shoulu Le
comLineu with the check loi uuplicateu calls.
9.7 Using Objects Methods as Event Listeners
Problem
You have oLjects with methous anu attiiLutes, anu you want to pass those methous
(lunctions) as event hanuleis. The pioLlem is that once you uo this, the methou will
lose the ieleience to the oLject, anu you have no way ol ieleiencing the oLject within
the event hanuleis.
Solution
This useu to Le guite complicateu to achieve. It ieguiieu you to geneiate closuies that
woulu encapsulate the oLject anu then pass them to bind().
Since jQueiy 1.3.3, a new paiametei has Leen auueu to bind(). It allows you to specily
an oLject as the scope oi this ol the event hanulei without using lunction closuies.
This makes the ieguiieu coue Loth shoitei anu lastei. You can now pass the oLject`s
methou as the lunction anu the oLject itsell as the scope.
Discussion
Where did the node go?
You will suiely wonuei this soonei oi latei. I saiu Leloie that when you pass a scope
oLject to bind(), the this ol the event hanulei will Le oveiiiuuen. This means we can`t
ietiieve the noue as we always uo...Lut the noue is not lost.
Vhen you pass a scope oLject to the Linu() methou, events will Le ueliveieu with the
this ol the event hanulei set to the scope oLject. You can still ueteimine the element
Leing ueliveieu to the event Ly using the event.currentTarget piopeity, which contains
a ieleience to the DOM element.
It`s usually not neeueu Lecause using the this is shoitei, Lut in situations like this, it`s
the only way aiounu.
208 | Chapter 9:Advanced Events
The example
I`ll cieate a small example that shoulu illustiate how to use the scope paiametei anu
also show you a situation wheie it is uselul.
Foi the example, we`ll neeu two oLjects. Each will have a methou that we
want to Linu as an event hanulei.
These aie the oLjects:
function Person(name){
this.name = name;
this.married = false;
}
jQuery.extend( Person.prototype, {
whatIsYourName: function(){
alert(this.name);
},
updateMarriedState: function(e){
var checkbox = e.currentTarget;
this.married = checkbox.checked;
}
});
var peter = new Person('Peter');
var susan = new Person('Susan');
Let`s suppose we have some soit ol loim anu it has two checkLoxes
(#c1 anu #c2). Each will manipulate the narricd state ol one ol oui pievious oLjects.
jQuery('#c1').bind('change', peter.updateMarriedState, peter);
jQuery('#c2').bind('change', susan.updateMarriedState, susan);
Thanks to the scope attiiLute, we uon`t neeu to cieate new lunctions loi each Linuing;
we can use the oLjects` methous insteau.
The methous uon`t even neeu to Le attacheu to the oLjects in the liist place. You coulu
uo something like this:
function updatePersonMarriedState(e){
var checkbox = e.currentTarget;
this.married = checkbox.checked;
}
jQuery('#c1').bind('change', updatePersonMarriedState, peter);
jQuery('#c2').bind('change', updatePersonMarriedState, susan);
As you can see, you`ie not ieally loiceu to put those lunctions into the oLjects` pioto-
type, anu it coulu actually make moie sense to keep them sepaiateu. Vhy shoulu a
methou Lelonging to Person know aLout checkLoxes anu the noue? It`s pioLaLly nicei
to keep all the specilic DOM manipulation apait liom the uata.
In some cases, the oLject`s methou won`t neeu to know aLout the noue oi the event
oLject at all. Vhen this happens, we can Linu a methou uiiectly, anu we won`t Le
mixing DOM anu uata at all.
The objects.
Binding the methods.
9.7 Using Objects Methods as Event Listeners | 209
Il we hau to have make two Luttons (#b1 anu #b2) to uisplay the name ol one peison
when clickeu, then it`u Le as simple as this:
jQuery('#b1').bind('click', peter.whatIsYourName, peter);
jQuery('#b2').bind('click', susan.whatIsYourName, susan);
It`s woith mentioning that Loth methous aie actually the same:
peter.whatIsYourName == susan.whatIsYourName; // true
The lunction is cieateu only once anu saveu into Person.prototype.
210 | Chapter 9:Advanced Events
CHAPTER 10
HTML Form Enhancements
from Scratch
Brian Chcrnc
10.0 Introduction
Vhethei you`ie tiying to leain moie aLout ]avaSciipt anu jQueiy oi you just want to
coue the most uiiect solution loi youi immeuiate pioLlem, sometimes wiiting coue
liom sciatch is the Lest appioach. This chaptei aims to pioviue you with simple, geneiic
solutions that will help you get staiteu wiiting youi own coue.
It is impoitant to note that while theie aie gieat Lenelits to staiting liom sciatch, some
ol the moie common pioLlems you`ll encountei, such as iemaining chaiactei count,
autoiesizing textaieas, anu loim valiuation (just to name a lew), have alieauy Leen
auuiesseu Ly otheis. Please see Chaptei 11 oi visit the jQueiy loiums anu Llogs online
loi moie inloimation on how community-ciitigueu anu community-testeu plugins can
help you. Sometimes it helps to look at someone else`s coue to linu out what you coulu
uo Lettei with youis.
Vhen necessaiy, I pioviue some sample HTML unuei the PioLlem heauing ol each
iecipe. This isn`t a philosophical statementtheie isn`t anything wiong oi pioLlematic
with nakeu HTML. I am, howevei, tiying to ieinloice the minu-set that ]avaSciipt
shoulu Le useu loi enhancing existing HTML anu impioving usei inteiaction. ]ava-
Sciipt is, anu shoulu Le consiueieu, completely sepaiate liom youi HTML.
211
In the lollowing iecipes I am only showing XHTML coue snippets iel-
evant to the pioLlem. Please make suie that youi coue is a complete
XHTML uocument anu that it passes valiuation.
Also, I am only incluuing $(document).ready(function(){...}) in the
iecipes wheie that is pait ol the uiscussion. All othei solutions assume
you will place the ]avaSciipt in the coiiect location loi youi coue stiuc-
tuieeithei in the .ready() hanulei oi at the Lottom ol youi lile altei
the XHTML coue in guestion. Please see Chaptei 1 loi moie
inloimation.
10.1 Focusing a Text Input on Page Load
Problem
You have a login loim on youi home page, anu you`u like the useiname text input to
Le locuseu on page loau.
Solution
Use the jQueiy $(selector).focus() methou:
// when the HTML DOM is ready
$(document).ready(function(){
// focus the <input id="username" type="text" ...>
$('#username').focus();
});
Discussion
Using $(document).ready() shoulu Le last enough. Howevei, in situations like ietiiev-
ing a huge HTML lile ovei a slow connection, the cuisoi might locus latei than
uesiieuthe usei coulu have alieauy enteieu hei useiname anu coulu Le in the piocess
ol typing hei passwoiu when $(document).ready() executes anu puts hei cuisoi Lack
in the useiname text input. How annoying! In this case you coulu use inline ]avaSciipt
altei the <input> tag to make locus immeuiate:
<input name="username" id="username" type="text" />
<script type="text/javascript">
$('#username').focus();
</script>
Oi, il you pielei to keep youi coue togethei in the $(document).ready() Llock, you can
check to see whethei the text input has any text in it Leloie giving it locus:
// when the HTML DOM is ready
$(document).ready(function(){
var $inputTxt = $('#username');
if( $inputTxt.val() == '' ) {
// focus the username input by default
212 | Chapter 10:HTML Form Enhancements from Scratch
$inputTxt.focus();
}
});
Vhat will happen when ]avaSciipt is uisaLleu? The usei will have to manually click
into the text input to stait typing.
10.2 Disabling and Enabling Form Elements
Problem
Youi oiuei loim has lielus loi Loth shipping anu Lilling contact inloimation. You`ve
ueciueu to Le nice anu supply the usei with a checkLox that inuicates the usei`s shipping
inloimation anu Lilling inloimation aie the same. Vhen checkeu, the Lilling text lielus
shoulu Le uisaLleu:
<fieldset id="shippingInfo">
<legend>Shipping Address</legend>
<label for="shipName">Name</label>
<input name="shipName" id="shipName" type="text" />
<label for="shipAddress">Address</label>
<input name="shipAddress" id="shipAddress" type="text" />
</fieldset>
<fieldset id="billingInfo">
<legend>Billing Address</legend>
<label for="sameAsShipping">Same as Shipping</label>
<input name="sameAsShipping" id="sameAsShipping" type="checkbox"
value="sameAsShipping" />
<label for="billName">Name</label>
<input name="billName" id="billName" type="text" />
<label for="billAddress">Address</label>
<input name="billAddress" id="billAddress" type="text" />
</fieldset>
Solution 1
Il all you want to uo is uisaLle the Lilling lielus, it`s as simple as using the
jQueiy .attr() anu .removeAttr() methous when the change event is tiiggeieu:
// find the "sameAsShipping" checkbox and listen for the change event
$('#sameAsShipping').change(function(){
if( this.checked ){
// find all text inputs inside billingInfo and disable them
$('#billingInfo input:text').attr('disabled','disabled');
10.2 Disabling and Enabling Form Elements | 213
} else {
// find all text inputs inside billingInfo and enable them
$('#billingInfo input:text').removeAttr('disabled');
}
}).trigger('change'); // close change() then trigger it once
Solution 2
Vhile selecting a checkLox anu uisaLling the loim lielus might Le enough to get the
point acioss to the usei, you coulu go the extia mile anu piepopulate the Lilling text
lielus with uata liom shipping inloimation.
The liist pait ol this solution is the same in stiuctuie as the solution shown pieviously.
Howevei, in auuition to uisaLling the Lilling lielus, we aie also piepopulating them
with uata liom the shipping lielus. The lollowing coue assumes the shipping anu Lilling
<fieldset> elements contain the same numLei ol text inputs anu that they aie in the
same oiuei:
// find the "sameAsShipping" checkbox and listen for the change event
$('#sameAsShipping').change(function(){
if( this.checked ){
// find all text inputs inside billingInfo, disable them, then cycle
through each one
$('#billingInfo input:text').attr('disabled',
'disabled').each(function(i){
// find the shipping input that corresponds to this billing input
var valueFromShippingInput =
$('#shippingInfo input:text:eq('+i+')').val();
// set the billing value with the shipping text value
$(this).val( valueFromShippingInput );
}); // close each()
} else {
// find all text inputs inside billingInfo and enable them
$('#billingInfo input:text').removeAttr('disabled');
}
}).trigger('change'); // close change() then trigger it
The seconu pait ol this solution upuates the Lilling lielus automatically when the usei
enteis inloimation into the shipping lielus, Lut only il the Lilling lielus aie otheiwise
uisaLleu:
// find the shippingInfo text inputs and listen for the keyup and change event
$('#shippingInfo input:text').bind('keyup change',function(){
// if "sameAsShipping" checkbox is checked
if ( $('#sameAsShipping:checked').length ){
// find out what text input this is
var i = $('#shippingInfo input:text').index( this );
var valueFromShippingInput = $(this).val();
214 | Chapter 10:HTML Form Enhancements from Scratch
$('#billingInfo input:text:eq('+i+')').val( valueFromShippingInput );
}
}); // close bind()
Discussion
In the pieceuing solution I`m using the input:text selectoi to avoiu uisaLling the
checkLox itsell.
Using .trigger('change') immeuiately executes the .change() event. This will check
the state ol the checkLox initially, in case it is checkeu Ly uelault. Also, this piotects
against Fiielox anu othei Liowseis that holu on to iauio Lutton anu checkLox states
when the page is ieliesheu.
Vhat will happen when ]avaSciipt is uisaLleu? You shoulu hiue the checkLox Ly ue-
lault in CSS. Then use ]avaSciipt to auu a class name to a paient element that woulu
oveiiiue the pievious CSS iule. In the lollowing example coue I`ve auueu an extia
<div> suiiounuing the checkLox anu laLel so they can Le easily hiuuen:
<style type="text/css" title="text/css">
#sameAsShippingWrapper { display:none; }
.jsEnabled #sameAsShippingWrapper { display:block }
</style>
...
// when the HTML DOM is ready
$(document).ready(function(){
$('form').addClass('jsEnabled');
});
...
<form>
...
<div id="sameAsShippingWrapper">
<label for="sameAsShipping">Same as Shipping</label>
<input name="sameAsShipping" id="sameAsShipping" type="checkbox" ... />
</div>
....
</form>
As an alteinative to hiuing the checkLox in CSS anu showing it using ]avaSciipt, you
coulu auu the checkLox to the DOM using ]avaSciipt. I pielei to keep my HTML, CSS,
anu ]avaSciipt sepaiate, Lut sometimes this is the Lettei solution:
var html_label = '<label for="sameAsShipping">Same as Shipping</label>';
var html_input = '<input name="sameAsShipping" id="sameAsShipping" type="checkbox"
value="sameAsShipping" />';
$( html_label + html_input ).prependTo('#billingInfo").change( ... ).trigger( ... );
10.2 Disabling and Enabling Form Elements | 215
10.3 Selecting Radio Buttons Automatically
Problem
You have a seiies ol iauio Luttons. The last iauio Lutton is laLeleu Othei anu has a
text input lielu associateu with it. Natuially you`u want that iauio Lutton to Le selecteu
il the usei has enteieu text in the Othei lielu:
<p>How did you hear about us?</p>
<ul id="chooseSource">
<li>
<input name="source" id="source1" type="radio" value="www" />
<label for="source1">Website or Blog</label>
</li>
<li>
<input name="source" id="source2" type="radio" value="mag" />
<label for="source2">Magazine</label>
</li>
<li>
<input name="source" id="source3" type="radio" value="per" />
<label for="source3">Friend</label>
</li>
<li>
<input name="source" id="source4" type="radio" value="oth" />
<label for="source4">Other</label>
<input name="source4txt" id="source4txt" type="text" />
</li>
</ul>
Solution 1
In the HTML coue you`ll notice the iauio Lutton, laLel, anu associateu text input ele-
ments aie wiappeu in an <li> tag. You uon`t necessaiily neeu this stiuctuie, Lut it
makes linuing the coiiect iauio Lutton much easieiyou`ie guaianteeu theie`s only
one iauio Lutton siLling:
// find any text input in chooseSource list, and listen for blur
$('#chooseSource input:text').blur(function(){
// if text input has text
if ( $(this).val() != '' ) {
// find the radio button sibling and set it be selected
$(this).siblings('input:radio').attr('checked',true);
}
});
Solution 2
To take the concept one step luithei, when the iauio Lutton is selecteu, we
can .focus() the text lielu. It`s impoitant to note that the lollowing coue completely
ieplaces the pievious solution. Insteau ol using the .blur() methou anu then chaining
216 | Chapter 10:HTML Form Enhancements from Scratch
a .each() methou, just use the .each() methou since that gives us access to all the
oLjects we neeu:
$('#chooseSource input:text').each(function(){
// these are both used twice, let's store them to be more efficient
// the text input
var $inputTxt = $(this);
// the associated radio button
var $radioBtn = $inputTxt.siblings('input:radio');
// listen for the blur event on the text input
$inputTxt.blur(function(){
// if text input has text
if ( $inputTxt.val() != '' ) {
// select radio button
$radioBtn.attr('checked',true);
}
});
// listen for the change event on the radio button
$radioBtn.change(function(){
// if it is checked, focus on text input
if ( this.checked ) { $inputTxt.focus(); }
});
}); // close each()
Discussion
The jQueiy .sibling() methou only ietuins siLlings, not the HTML element you`ie
attempting to linu siLlings ol. So, the coue $(this).siblings('input:radio') coulu Le
iewiitten $(this).siblings('input') Lecause theie is only one othei input that is a
siLling. I pielei incluuing the :radio selectoi Lecause it is moie explicit anu cieates sell-
commenting coue.
It woulu have Leen veiy easy to taiget the Othei text input uiiectly using
$('#source5txt').focus(...) anu have it uiiectly taiget the iauio Lutton using its id
attiiLute. Vhile that`s a peilectly lunctional appioach, the coue as shown pieviously
is moie llexiLle. Vhat il someone ueciueu to change the id ol the Othei iauio Lutton?
Vhat il each iauio Lutton hau a text input? The aLstiact solution hanules these cases
without auuitional woik.
Vhy use .blur() insteau ol .focus() on the text input? Vhile .focus() woulu Le moie
immeuiate loi selecting the associateu iauio Lutton, il the usei weie simply taLLing
thiough the loim elements, .focus() woulu acciuentally select the iauio Lutton. Us-
ing .blur() anu then checking loi a value avoius this pioLlem.
Vhat will happen when ]avaSciipt is uisaLleu? The usei will have to manually click
into the text input to stait typing anu manually select the iauio Lutton. You aie lelt to
10.3 Selecting Radio Buttons Automatically | 217
ueciue how to valiuate anu piocess suLmitteu uata shoulu the usei entei text anu select
a uilleient iauio Lutton.
10.4 (De)selecting All Checkboxes Using Dedicated Links
Problem
You neeu to select all checkLoxes anu ueselect all checkLoxes using ueuicateu Select
All anu Deselect All links:
<fieldset>
<legend>Reasons to be happy</legend>
<a class="selectAll" href="#">Select All</a>
<a class="deselectAll" href="#">Deselect All</a>
<input name="reasons" id="iwokeup" type="checkbox" value="iwokeup" />
<label for="iwokeup">I woke up</label>
<input name="reasons" id="health" type="checkbox" value="health" />
<label for="health">My health</label>
<input name="reasons" id="family" type="checkbox" value="family" />
<label for="family">My family</label>
<input name="reasons" id="sunshine" type="checkbox" value="sunshine" />
<label for="sunshine">The sun is shining</label>
</fieldset>
Solution
Taiget the Select All anu Deselect All links uiiectly using theii class attiiLutes. Then
attach the appiopiiate .click() hanulei:
// find the "Select All" link in a fieldset and list for the click event
$('fieldset .selectAll').click(function(event){
event.preventDefault();
// find all the checkboxes and select them
$(this).siblings('input:checkbox').attr('checked','checked');
});
// find the "Deselect All" link in a fieldset and list for the click event
$('fieldset .deselectAll').click(function(event){
event.preventDefault();
// find all the checkboxes and deselect them
$(this).siblings('input:checkbox').removeAttr('checked');
});
218 | Chapter 10:HTML Form Enhancements from Scratch
Discussion
Il you aie inteiesteu in activating anu ueactivating the ueuicateu links, you shoulu see
Recipe 10.5 in this chaptei. In that solution, the inuiviuual checkLoxes upuate the
toggle state, anu you will neeu this logic to activate anu ueactivate the ueuicateu links
appiopiiately.
Vhat will happen when ]avaSciipt is uisaLleu? You shoulu hiue the links Ly uelault in
CSS. Then use ]avaSciipt to auu a class name to a paient element that will oveiiiue the
pievious CSS iule:
<style type="text/css" title="text/css">
.selectAll, .deselectAll { display:none; }
.jsEnabled .selectAll, .jsEnabled .deselectAll { display:inline; }
</style>
...
// when the HTML DOM is ready
$(document).ready(function(){
$('form').addClass('jsEnabled');
});
10.5 (De)selecting All Checkboxes Using a Single Toggle
Problem
You neeu to select anu ueselect all checkLoxes using a single toggle, in this case anothei
checkLox. Auuitionally, that toggle shoulu automatically switch states il some (oi all)
ol the checkLoxes aie selecteu inuiviuually:
<fieldset>
<legend>Reasons to be happy</legend>
<input name="reasons" id="toggleAllReasons" type="checkbox" class="toggle" />
<label for="toggleAllReasons" class="toggle">Select All</label>
<input name="reasons" id="iwokeup" type="checkbox" value="iwokeup" />
<label for="iwokeup">I woke up</label>
<input name="reasons" id="health" type="checkbox" value="health" />
<label for="health">My health</label>
<input name="reasons" id="family" type="checkbox" value="family" />
<label for="family">My family</label>
<input name="reasons" id="sunshine" type="checkbox" value="sunshine" />
<label for="sunshine">The sun is shining</label>
</fieldset>
10.5 (De)selecting All Checkboxes Using a Single Toggle | 219
Solution
Taiget the toggle uiiectly using its class attiiLute anu the :checkbox selectoi. Then
cycle thiough each toggle lounu, ueteimine the associateu checkLoxes us-
ing .siblings(), anu attach the change event listeneis:
// find the "Select All" toggle in a fieldset, cycle through each one you find
$('fieldset .toggle:checkbox').each(function(){
// these are used more than once, let's store them to be more efficient
// the toggle checkbox
var $toggle = $(this);
// the other checkboxes
var $checkboxes = $toggle.siblings('input:checkbox');
// listen for the change event on the toggle
$toggle.change(function(){
if ( this.checked ) {
// if checked, select all the checkboxes
$checkboxes.attr('checked','checked');
} else {
// if not checked, deselect all the checkboxes
$checkboxes.removeAttr('checked');
}
});
// listen for the change event on each individual checkbox (not toggle)
$checkboxes.change(function(){
if ( this.checked ) {
// if this is checked and all others are checked, select the toggle
if ( $checkboxes.length == $checkboxes.filter(':checked').length ) {
$toggle.attr('checked','checked');
}
} else {
// if not checked, deselect the toggle
$toggle.removeAttr('checked');
}
}).eq(0).trigger('change'); // close change() then trigger change on first
checkbox only
}); // close each()
Discussion
Using .eq(0).trigger('change') immeuiately executes the .change() event loi the liist
checkLox. This sets the state ol the toggle anu piotects against Fiielox anu othei
Liowseis that holu on to iauio anu checkLox states when the page is ieliesheu.
The .eq(0) is useu to only tiiggei the liist checkLox`s change event. Vithout .eq(0),
the .trigger('change') woulu Le executeu loi eveiy checkLox, Lut since they all shaie
the same toggle, you only neeu to iun it once.
Vhat will happen when ]avaSciipt is uisaLleu? You shoulu hiue the toggle checkLox
anu laLel Ly uelault in CSS. Then use ]avaSciipt to auu a class name to a paient element
that woulu oveiiiue the pievious CSS iule:
220 | Chapter 10:HTML Form Enhancements from Scratch
<style type="text/css" title="text/css">
.toggle { visibility:hidden; }
.jsEnabled .toggle { visibility:visible; }
</style>
...
// when the HTML DOM is ready
$(document).ready(function(){
$('form').addClass('jsEnabled');
});
10.6 Adding and Removing Select Options
Problem
You have a uiop-uown Lox loi colois anu want to auu new colois to it, as well as iemove
options liom it.
<label for="colors">Colors</label>
<select id="colors" multiple="multiple">
<option>Black</options>
<option>Blue</options>
<option>Brown</options>
</select>
<button id="remove">Remove Selected Color(s)</button>
<label for="newColorName">New Color Name</label>
<input id="newColorName" type="text" />
<label for="newColorValue">New Color Value</label>
<input id="newColorValue" type="text" />
<button id="add">Add New Color</button>
Solution
To auu a new option to the uiop-uown Lox, use the .appendTo() methou:
// find the "Add New Color" button
$('#add').click(function(event){
event.preventDefault();
var optionName = $('#newColorName').val();
var optionValue = $('#newColorValue').val();
$('<option/>').attr('value',optionValue).text(optionName).appendTo('#colors');
});
10.6 Adding and Removing Select Options | 221
To iemove an option, use the .remove() methou:
// find the "Remove Selected Color(s)" button
$('#remove').click(function(event){
event.preventDefault();
var $select = $('#colors');
$('option:selected',$select).remove();
});
Discussion
I use the .attr() anu .text() methous to populate the <option> element:
$('<option/>').attr("value",optionValue).text(optionName).appendTo('#colors');
Howevei, the same line coulu Le iewiitten so that the <option> element is Luilt in one
step, without using the methous:
$('<option value="'+optionValue+'">'+optionName+'</option>').appendTo('#colors');
Concatenating all the <option> uata like that woulu Le a liaction ol a milliseconu lastei,
Lut not in any way noticeaLle Ly a human. I pielei using the .attr() anu .text()
methous to populate the <option> element Lecause I think that it is moie ieauaLle anu
easiei to ueLug anu maintain. Vith the peiloimance issue Leing negligiLle, using one
appioach oi the othei is the uevelopei`s pieleience.
Vhat woulu happen with ]avaSciipt uisaLleu? You woulu neeu to pioviue a seivei-siue
alteinative that piocesses the Lutton clicks, anu the usei woulu have to wait loi the
iesulting page ieloaus.
10.7 Autotabbing Based on Character Count
Problem
You have a loim loi allowing useis to iegistei a piouuct online, anu you ieguiie the
usei to entei a seiial numLei piinteu on the installation uiscs. This numLei is 16 uigits
long anu sepaiateu acioss loui input lielus. Iueally, to speeu the usei along in theii uata
entiy, as each input lielu is lilleu up, you`u like to automatically locus the next input
lielu until they`ie linisheu typing the numLei:
<fieldset class="autotab">
<legend>Product Serial Number</legend>
<input type="text" maxlength="4" />
<input type="text" maxlength="4" />
<input type="text" maxlength="4" />
<input type="text" maxlength="4" />
</fieldset>
222 | Chapter 10:HTML Form Enhancements from Scratch
Solution
Insiue <fieldset class="autotab">, linu all the <input> elements. Use
jQueiy`s .bind() methou to listen loi the keydown anu keyup events. Ve exit the Lounu
lunction loi a hanulul ol keys that we want to ignoie, Lecause they aien`t meaninglul
loi automatically taLLing loiwaiu oi Lackwaiu. Vhen an <input> element is lull, Laseu
on the maxlength attiiLute, we .focus() the next <input> element. Conveisely, when
using the Backspace key, il an <input> element is maue empty, we .focus() the pievious
<input> element:
$('fieldset.autotab input').bind('keydown keyup',function(event){
// the keycode for the key evoking the event
var keyCode = event.which;
// we want to ignore the following keys:
// 9 Tab, 16 Shift, 17 Ctrl, 18 Alt, 19 Pause Break, 20 Caps Lock
// 27 Esc, 33 Page Up, 34 Page Down, 35 End, 36 Home
// 37 Left Arrow, 38 Up Arrow, 39 Right Arrow, 40 Down Arrow
// 45 Insert, 46 Forward Delete, 144 Num Lock, 145 Scroll Lock
var ignoreKeyCodes =
',9,16,17,18,19,20,27,33,34,35,36,37,38,39,40,45,46,144,145,';
if ( ignoreKeyCodes.indexOf(',' + keyCode + ',') > 1 ) { return; }
// we want to ignore the backspace on keydown only
// let it do its job, but otherwise don't change focus
if ( keyCode == 8 && event.type == 'keydown' ) { return; }
var $this = $(this);
var currentLength = $this.val().length;
var maximumLength = $this.attr('maxlength');
// if backspace key and there are no more characters, go back
if ( keyCode == 8 && currentLength == 0 ) {
$this.prev().focus();
}
// if we've filled up this input, go to the next
if ( currentLength == maximumLength ) {
$this.next().focus();
}
});
Discussion
Vhy uo we Linu Loth keydown anu keyup events?
You coulu use just the keydown event. Howevei, when the usei is uone lilling out the
liist input, theie woulu Le no visual inuication that theii next keystioke woulu locus
the seconu input. By using the keyup event, altei the liist input is lilleu, the seconu input
gains locus, the cuisoi is placeu at the Leginning ol the input, anu most Liowseis in-
uicate that locus with a Loiuei oi some othei highlight state. Also, the keyup event is
10.7 Autotabbing Based on Character Count | 223
ieguiieu loi the Backspace key to locus the pievious input altei the cuiient input is
empty.
You coulu use just the keyup event. Howevei, il youi cuisoi was in the seconu input
anu you weie using the Backspace key to cleai it, once you iemoveu all chaiacteis, the
locus woulu Le shilteu into the liist input. Unloitunately, the liist is alieauy lull, so the
next keystioke woulu Le lost, Lecause ol the maxlength attiiLute, anu then the keyup
event woulu locus the seconu input. Losing a keystioke is a Lau thing, so we peiloim
the same check on keydown, which moves the cuisoi to the next input Leloie the chai-
actei is lost.
Because the logic isn`t CPU intensive, we can get away with Linuing Loth the keydown
anu keyup events. In anothei situation, you may want to Le moie selective.
You`ll notice that the ignoreKeyCodes vaiiaLle is a stiing. Il we weie Luiluing it uynam-
ically, it woulu Le lastei to cieate an aiiay anu then use .join(',') oi .toString()
]avaSciipt methous. But since the value is always the same, it`s easiei to simply coue it
as a stiing liom the veiy Leginning. I also stait anu enu the ignoreKeyCodes vaiiaLle
with commas, Lecause I am paianoiu aLout lalse positives. This way, when seaiching
loi a keyCode llankeu Ly commas, you aie guaianteeu to linu only the numLei you`ie
looking loiil you look loi 9, it won`t linu 19, oi 39.
Notice theie is no coue to pievent $this.next().focus() liom executing when on the
last <input> element. I`m taking auvantage ol the jQueiy chain heie. Il $this.next()
linus nothing, then the chain stopsit can`t .focus() what it can`t linu. In a uilleient
scenaiio, it might make sense to piecache any known .prev() anu .next() elements.
Vhat will happen when ]avaSciipt is uisaLleu? Nothing. The usei will have to manually
click liom one text input lielu to the next.
10.8 Displaying Remaining Character Count
Problem
Youi company has a contact loim on its weLsite. This loim has a <textarea> element
to allow useis to expiess themselves lieely. Howevei, you know time is money, anu
you uon`t want youi stall ieauing shoit novels, so you woulu like to limit the length ol
the messages they have to ieau. In the piocess, you`u also like to show the enu usei
how many chaiacteis aie iemaining:
<textarea></textarea>
<div class="remaining">Characters remaining: <span class="count">300</span></div>
224 | Chapter 10:HTML Form Enhancements from Scratch
Solution
Taiget all .remaining messages, anu loi each linu the associateu <textarea> element
anu the maximum numLei ol chaiacteis as listeu in the .count chilu element. Binu an
update lunction to the <textarea> to captuie when the usei enteis text:
// for each "Characters remaining: ###" element found
$('.remaining').each(function(){
// find and store the count readout and the related textarea/input field
var $count = $('.count',this);
var $input = $(this).prev();
// .text() returns a string, multiply by 1 to make it a number (for math)
var maximumCount = $count.text()*1;
// update function is called on keyup, paste and input events
var update = function(){
var before = $count.text()*1;
var now = maximumCount - $input.val().length;
// check to make sure users haven't exceeded their limit
if ( now < 0 ){
var str = $input.val();
$input.val( str.substr(0,maximumCount) );
now = 0;
}
// only alter the DOM if necessary
if ( before != now ){
$count.text( now );
}
};
// listen for change (see discussion below)
$input.bind('input keyup paste', function(){setTimeout(update,0)} );
// call update initially, in case input is pre-filled
update();
}); // close .each()
Discussion
The pieceuing coue is geneiic enough to allow loi any numLei ol Chaiactei iemain-
ing messages anu <textarea> elements on a given page. This coulu Le uselul il you
weie Luiluing a content management oi uata entiy system.
To piotect against when the usei attempts to copy anu paste uata into the <textarea>
using a mouse, we neeu to Linu Loth the input anu paste events. The mouseup event
cannot Le useu Lecause it is not tiiggeieu when selecting an item liom the Liowsei`s
contextual menu. The input event is pait ol HTML5 (Voiking Dialt) anu alieauy
10.8 Displaying Remaining Character Count | 225
implementeu Ly Fiielox, Opeia, anu Salaii. It liies on usei input, iegaiuless ol input
uevice (mouse oi keyLoaiu). Salaii, at the time ol this wiiting, has a Lug anu uoes not
liie the input event on <textarea> elements. Both Salaii anu Inteinet Exploiei unuei-
stanu the paste event on <textarea> elements anu unueistanu keyup to captuie key-
stiokes. Attaching keyup, input, anu paste is ieuunuant Lut, in this case, Lenign. The
update lunction is simple enough that theie aien`t any peiloimance issues, anu it only
manipulates the DOM when neeueu, so any ieuunuant update calls altei the liist woulu
uo nothing.
An alteinative to ieuunuant events woulu Le to use setInterval when the <textarea>
element has locus. The same update lunction coulu Le calleu liom the inteival, anu il
it is paiieu with the keyup event, you`u get the immeuiate upuating on key piesses anu
an aiLitiaiy upuate inteival, say 300 milliseconus, loi when inloimation is pasteu into
the <textarea> element. Il the update lunction weie moie complex oi costly, this might
Le a Lettei alteinative.
Vhen Linuing events to loim elements, it is sometimes impoitant to use a timeout to
slightly uelay a lunction call. In the pievious example, Inteinet Exploiei tiiggeis the
paste event Leloie the text liom the clipLoaiu is actually auueu to the <textarea> ele-
ment. Thus, the calculation loi chaiacteis iemaining woulu Le incoiiect until the usei
clicks oi piesses anothei key. By using setTimeout(update,0), the upuate lunction is
placeu at the enu ol the call stack anu will liie altei that Liowsei has auueu the text:
$input.bind('input keyup paste', function(){setTimeout(update,0)} );
Vhat will happen when ]avaSciipt is uisaLleu? You shoulu hiue the Chaiacteis ie-
maining message Ly uelault in CSS. Then use ]avaSciipt to auu a class name to a paient
element that woulu oveiiiue the pievious CSS iule. Also, it`s impoitant to check the
length ol the message again on the seivei siue:
<style type="text/css" title="text/css">
.remaining { display:none; }
.jsEnabled .remaining { display:block; }
</style>
...
// when the HTML DOM is ready
$(document).ready(function(){
$('form').addClass('jsEnabled');
});
10.9 Constraining Text Input to Specific Characters
Problem
Youi shopping cait page has a guantity lielu, anu you want to make suie useis can only
entei numLeis into that lielu:
226 | Chapter 10:HTML Form Enhancements from Scratch
<input type="text" class="onlyNumbers" />
Solution
Finu all elements with the onlyNumbers class, anu listen loi keydown anu blur events.
The keydown event hanulei will pievent useis liom typing non-numeiic chaiacteis into
the lielu. The blur event hanulei is a piecautionaiy measuie that cleans any uata enteieu
via Paste liom the contextual menu oi the Liowsei`s Euit menu:
$('.onlyNumbers').bind('keydown',function(event){
// the keycode for the key pressed
var keyCode = event.which;
// 48-57 Standard Keyboard Numbers
var isStandard = (keyCode > 47 && keyCode < 58);
// 96-105 Extended Keyboard Numbers (aka Keypad)
var isExtended = (keyCode > 95 && keyCode < 106);
// 8 Backspace, 46 Forward Delete
// 37 Left Arrow, 38 Up Arrow, 39 Right Arrow, 40 Down Arrow
var validKeyCodes = ',8,37,38,39,40,46,';
var isOther = ( validKeyCodes.indexOf(',' + keyCode + ',') > 1 );
if ( isStandard || isExtended || isOther ){
return true;
} else {
return false;
}
}).bind('blur',function(){
// regular expression that matches everything that is not a number
var pattern = new RegExp('[^0-9]+', 'g');
var $input = $(this);
var value = $input.val();
// clean the value using the regular expression
value = value.replace(pattern, '');
$input.val( value )
});
Discussion
The keydown event is immeuiate anu pievents useis liom typing non-numeiic chaiacteis
into the lielu. This coulu Le ieplaceu with a keyup event that shaies the same hanulei
as the blur event. Howevei, useis woulu see a non-numeial appeai anu then guickly
uisappeai. I pielei just to pievent them liom enteiing the chaiactei in the liist place
anu avoiu the llickeiing.
10.9 Constraining Text Input to Specific Characters | 227
The blur event piotects against copying anu pasting non-numeiic chaiacteis into the
text lielu. In the pievious scenaiio, I`m assuming the usei is eithei tiying to test the
limits ol the ]avaSciipt (something that I woulu uo) oi tiying to copy anu paste uata
liom a spieausheet. Neithei situation ieguiies immeuiate coiiection in my opinion.
Howevei, il youi situation ieguiies moie immeuiate coiiection, please see the
Discussion section ol Recipe 10.S loi moie inloimation aLout captuiing changes
liom the paste event.
Il youi situation is uilleient anu you expect useis to Le copying anu pasting uata liom
a spieausheet, keep in minu that the iegulai expiession I use uoes not account loi a
uecimal point. So, a numLei like 1,000 woulu Le cleaneu to 1000 anu the numLei
10.00 woulu also Le cleaneu to 1000 as well.
You`ll notice that the validKeyCodes vaiiaLle is a stiing that staits anu enus with com-
mas. As I mentioneu in Recipe 10.7, I uiu this Lecause I am paianoiu aLout lalse pos-
itiveswhen seaiching loi a keyCode llankeu Ly commas, you aie guaianteeu to linu
only the numLei you`ie looking loi.
Vhat will happen when ]avaSciipt is uisaLleu? The usei will Le aLle to entei any chai-
acteis they please. Always Le suie to valiuate coue on the seivei. Don`t iely on ]avaSciipt
to pioviue clean uata.
10.10 Submitting a Form Using Ajax
Problem
You have a loim that you woulu like to suLmit using Ajax:
<form action="process.php">
<!-- value changed via JavaScript -->
<input type="hidden" name="usingAJAX" value="false" />
<label for="favoriteFood">What is your favorite food?</label>
<input type="text" name="favoriteFood" id="favoriteFood" />
<input type="submit" value="Tell Us" />
</form>
Solution
Finu the <form> element, anu hijack the submit event:
$('form').submit(function(event){
// we want to submit the form using Ajax (prevent page refresh)
event.preventDefault();
// this is where your validation code (if any) would go
228 | Chapter 10:HTML Form Enhancements from Scratch
// ...
// this tells the server-side process that Ajax was used
$('input[name="usingAJAX"]',this).val( 'true' );
// store reference to the form
var $this = $(this);
// grab the url from the form element
var url = $this.attr('action');
// prepare the form data to send
var dataToSend = $this.serialize();
// the callback function that tells us what the server-side process had to say
var callback = function(dataReceived){
// hide the form (thankfully we stored a reference to it)
$this.hide();
// in our case the server returned an HTML snippet so just append it to
// the DOM
// expecting: <div id="result">Your favorite food is pizza! Thanks for
// telling us!</div>
$('body').append(dataReceived)
};
// type of data to receive (in our case we're expecting an HTML snippet)
var typeOfDataToReceive = 'html';
// now send the form and wait to hear back
$.get( url, dataToSend, callback, typeOfDataToReceive )
}); // close .submit()
Discussion
Vhat will happen when ]avaSciipt is uisaLleu? The loim will Le suLmitteu, anu the
entiie page will ieliesh with the iesults liom the seivei-siue sciipt. I use ]avaSciipt to
altei the value ol the <input type="hidden" name="usingAJAX" /> element liom false
to true. This allows the seivei-siue sciipt to know what to senu Lack as a iesponse
eithei a lull HTML page oi whatevei uata is expecteu loi the Ajax iesponse.
10.11 Validating Forms
Problem
You have a loim that you woulu like to valiuate. To get staiteu, you`ll want to set up
some Lasic CSS. The only styles that aie ieally impoitant loi this enhancement aie the
display:none ueclaiation ol the div.errorMessage selectoi anu the display:block
10.11 Validating Forms | 229
ueclaiation ol the div.showErrorMessage selectoi. The iest aie just to make things look
Lettei:
<style type="text/css" title="text/css">
div.question {
padding: 1em;
}
div.errorMessage {
display: none;
}
div.showErrorMessage {
display: block;
color: #f00;
font-weight: bold;
font-style: italic;
}
label.error {
color: #f00;
font-style: italic;
}
</style>
The lollowing HTML snippet is one example ol how you might stiuctuie this loim.
The <div class="question> element is puiely loi layout anu not impoitant loi the val-
iuation coue. Each <label> element`s for attiiLute associates it with the loim element
with that iuentical id attiiLute. That is stanuaiu HTML, Lut I wanteu to call it out
Lecause the ]avaSciipt will also Le using that (in ieveise) to linu the coiiect <label> loi
a given loim element. Similaily, you`ll notice the eiioi messages have an id attiiLute
ol errorMessage_ plus the name attiiLute ol the associateu loim element. This stiuctuie
may seem ieuunuant, Lut iauio Luttons anu checkLoxes aie gioupeu Ly the name at-
tiiLute anu you`u only want to have one eiioi message pei such gioup:
<form action="process.php">
<!-- TEXT -->
<div class="question">
<label for="t">Username</label>
<input id="t" name="user" type="text" class="required" />
<div id="errorMessage_user" class="errorMessage">Please enter your username.</div>
</div>
<!-- PASSWORD -->
<div class="question">
<label for="p">Password</label>
<input id="p" name="pass" type="password" class="required" />
<div id="errorMessage_pass" class="errorMessage">Please enter your password.</div>
</div>
<!-- SELECT ONE -->
<div class="question">
<label for="so">Favorite Color</label>
<select id="so" name="color" class="required">
<option value="">Select a Color</option>
<option value="ff0000">Red</option>
230 | Chapter 10:HTML Form Enhancements from Scratch
<option value="00ff00">Green</option>
<option value="0000ff">Blue</option>
</select>
<div id="errorMessage_color" class="errorMessage">Please select your favorite
color.</div>
</div>
<!-- SELECT MULTIPLE -->
<div class="question">
<label for="sm">Favorite Foods</label>
<select id="sm" size="3" name="foods" multiple="multiple" class="required">
<option value="pizza">Pizza</option>
<option value="burger">Burger</option>
<option value="salad">Salad</option>
</select>
<div id="errorMessage_foods" class="errorMessage">Please choose your favorite
foods.</div>
</div>
<!-- RADIO BUTTONS -->
<div class="question">
<span>Writing Hand:</span>
<input id="r1" type="radio" name="hand" class="required"/>
<label for="r1">Left</label>
<input id="r2" type="radio" name="hand" class="required" />
<label for="r2">Right</label>
<div id="errorMessage_hand" class="errorMessage">Please select what hand you
write with.</div>
</div>
<!-- TEXTAREA -->
<div class="question">
<label for="tt">Comments</label>
<textarea id="tt" name="comments" class="required"></textarea>
<div id="errorMessage_comments" class="errorMessage">Please tell us what you
think.</div>
</div>
<!-- CHECKBOX -->
<div class="question">
<input id="c" type="checkbox" name="legal" class="required" />
<label for="c">I agree with the terms and conditions</label>
<div id="errorMessage_legal" class="errorMessage">Please check the box!</div>
</div>
<input type="submit" value="Continue" />
</form>
Solution
The liist pait ol the solution is laiily stiaightloiwaiu. Finu the <form> element, anu
hijack the submit event. Vhen the loim is suLmitteu, iteiate thiough the ieguiieu loim
10.11 Validating Forms | 231
elements, anu check to see whethei the ieguiieu elements aie valiu. Il the loim is eiioi
liee, then (anu only then) tiiggei the submit event:
$('form').submit(function(event){
var isErrorFree = true;
// iterate through required form elements and check to see if they are valid
$('input.required, select.required, textarea.required',this).each(function(){
if ( validateElement.isValid(this) == false ){
isErrorFree = false;
};
});
// Ajax alternatives:
// event.preventDefault();
// if (isErrorFree){ $.get( url, data, callback, type ) }
// if (isErrorFree){ $.post( url, data, callback, type ) }
// if (isErrorFree){ $.ajax( options ) }
return isErrorFree;
}); // close .submit()
The seconu pait ol this solution is wheie all the ieal valiuation happens. The
isValid() methou staits Ly stoiing lieguently useu uata liom the element we`ie vali-
uating. Then, in the switch() statement, the element is valiuateu. Finally, class names
aie auueu to oi iemoveu liom the <label> anu div.errorMessage elements.
var validateElement = {
isValid:function(element){
var isValid = true;
var $element = $(element);
var id = $element.attr('id');
var name = $element.attr('name');
var value = $element.val();
// <input> uses type attribute as written in tag
// <textarea> has intrinsic type of 'textarea'
// <select> has intrinsic type of 'select-one' or 'select-multiple'
var type = $element[0].type.toLowerCase();
switch(type){
case 'text':
case 'textarea':
case 'password':
if ( value.length == 0 ||
value.replace(/\s/g,'').length == 0 ){ isValid = false; }
break;
case 'select-one':
case 'select-multiple':
if( !value ){ isValid = false; }
break;
232 | Chapter 10:HTML Form Enhancements from Scratch
case 'checkbox':
case 'radio':
if( $('input[name="' + name +
'"]:checked').length == 0 ){ isValid = false; };
break;
} // close switch()
// instead of $(selector).method we are going to use $(selector)[method]
// choose the right method, but choose wisely
var method = isValid ? 'removeClass' : 'addClass';
// show error message [addClass]
// hide error message [removeClass]
$('#errorMessage_' + name)[method]('showErrorMessage');
$('label[for="' + id + '"]')[method]('error');
return isValid;
} // close validateElement.isValid()
}; // close validateElement object
Discussion
The valiuation in this solution is guite simple. It checks the lollowing:
<input type="text">, <input type="password">, anu <textarea> elements have
some uata othei than whitespace.
<select> elements have something othei than the uelault option selecteu. Please
note that theie aie two types ol <select> element: select-one anu select-
multiple (see the seconu coue snippet in this section loi HTML coue anu the
pievious coue snippet loi ]avaSciipt valiuation). The liist <option> element ol the
select-one <select> must have a value="" in oiuei loi valiuation to woik. The
select-multiple <select> is immune liom this ieguiiement Lecause its <option>
elements can Le ueselecteu.
<input type="radio"> anu <input type="checkbox"> elements have at least one el-
ement checkeu in theii iespective name gioups.
The switch(){} statement is useu Lecause it is moie ellicient than multiple if(){}else
if(){} statements. It also allows loi elements with shaieu valiuation to Le gioupeu
togethei, letting the break; statement sepaiate these gioups.
The validateElement oLject is in the gloLal scope with the intention that it might Le
ieuseu on othei loims. It also keeps the gloLal scope less clutteieu Ly containing the
valiuation methousin the lutuie, helpei methous coulu Le auueu to the
validateElement oLject without woiiying aLout gloLal naming collisions. Foi instance,
a stripWhitespace() methou coulu Le implementeu like this:
var validateElement = {
stripWhitespace : function(str){
return str.replace(/\s/g,'');
10.11 Validating Forms | 233
},
isValid : function(element){
//... snipped code ...//
case 'text':
case 'textarea':
case 'password':
// if text length is zero after stripping whitespace, it's not valid
if ( this.stripWhitespace(value).length == 0 ){ isValid = false; }
break;
//... snipped code ...//
} // close validateElement.isValid()
}; // close validateElement object
Vhen showing anu hiuing eiioi messages, I useu the Liacket notation loi calling
the .addClass() anu .removeClass() jQueiy methous:
// instead of $(selector).method we are going to use $(selector)[method]
// choose the right method, but choose wisely
var method = isValid ? 'removeClass' : 'addClass';
// show error message [addClass]
// hide error message [removeClass]
$('#errorMessage_' + name)[method]('showErrorMessage');
$('label[for="' + id + '"]')[method]('error');
The pievious coue in Liacket notation is lunctionally iuentical to the uot notation:
if (isValid) {
$('#errorMessage_' + name).removeClass('showErrorMessage');
$('label[for="' + id + '"]').removeClass('error');
} else {
$('#errorMessage_' + name).addClass('showErrorMessage');
$('label[for="' + id + '"]').addClass('error');
}
Vhen we valiuate on suLmit, the uot notation is cleanei anu moie ieauaLle. Howevei,
let`s extenu the Liacket-notation solution to allow elements to ievaliuate (altei an initial
valiuation) using the change event. This woulu give the usei immeuiate leeuLack that
theii new answeis aie in lact valiu, without ieguiiing them to click the suLmit Lutton.
The lollowing coue uoes not woik as expecteu (see the next paiagiaph loi the ieal
solution), Lut it illustiates wheie to .unbind() anu .bind() the change event:
// instead of $(selector).method we are going to use $(selector)[method]
// choose the right method, but choose wisely
var method = isValid ? 'removeClass' : 'addClass';
// show error message [addClass]
// hide error message [removeClass]
$('#errorMessage_' + name)[method]('showErrorMessage');
$('label[for="' + id + '"]')[method]('error');
234 | Chapter 10:HTML Form Enhancements from Scratch
// after initial validation, allow elements to re-validate on change
$element
.unbind('change.isValid')
.bind('change.isValid',function(){ validateElement.isValid(this); });
Because we aie unLinuing anu Linuing the change event with each val-
iuation, I auueu the .isValid event namespace to taiget it moie uiiectly.
This way, il a loim element has othei change events Lounu, they will
iemain.
The pioLlem with the pievious coue isn`t syntax Lut logic. You`ll note that the iauio
Luttons in the HTML have the class="required" attiiLute. This means that when the
entiie loim is valiuateu, each iauio Lutton is valiuateu, anu (moie impoitantly) each
iauio Lutton`s <label> has a class auueu oi iemoveu to inuicate the eiioi. Howevei, il
we allow loi a ievaliuation to occui using the element-specilic change event, only that
paiticulai iauio Lutton`s <label> will Le upuateuthe otheis woulu iemain in an eiioi
state. To account loi this, a single change event woulu have to look at all iauio Luttons
anu checkLoxes in that name gioup to allect all the <label> classes simultaneously:
// instead of $(selector).method we are going to use $(selector)[method]
// choose the right method, but choose wisely
var method = isValid ? 'removeClass' : 'addClass';
// show error message [addClass]
// hide error message [removeClass]
$('#errorMessage_' + name)[method]('showErrorMessage');
if ( type == 'checkbox' || type == 'radio' ) {
// if radio button or checkbox, find all inputs with the same name
$('input[name="' + name + '"]').each(function(){
// update each input elements <label> tag, (this==<input>)
$('label[for="' + this.id + '"]')[method]('error');
});
} else {
// all other elements just update one <label>
$('label[for="' + id + '"]')[method]('error');
}
// after initial validation, allow elements to re-validate on change
$element
.unbind('change.isValid')
.bind('change.isValid',function(){ validateElement.isValid(this); });
Il the pieceuing coue weie to Le iewiitten using uot-notation syntax, it woulu have
twice again as many lines. Anu on a sepaiate note, with this new logic in place, only
one iauio Lutton (oi checkLox) in a name gioup woulu neeu to have the
10.11 Validating Forms | 235
class="required" in oiuei loi all the othei elements in that gioup to Le aujusteu
coiiectly.
Vhat will happen when ]avaSciipt is uisaLleu? The loim will Le suLmitteu without
client-siue valiuation. Always Le suie to valiuate coue on the seivei. Don`t iely on
]avaSciipt to pioviue clean uata. Il the seivei-siue coue ietuins the loim with eiiois, it
can use the same classes, on the same elements, in the same way. Theie is no neeu to
use inline style tags oi wiite custom coue to hanule the seivei-siue eiiois uilleiently.
236 | Chapter 10:HTML Form Enhancements from Scratch
CHAPTER 11
HTML Form Enhancements
with Plugins
]orn Zacjjcrcr
11.0 Introduction
Foims aie a veiy common inteiaction loi useis ol weL applications; impioving this
inteiaction impioves the Lusiness ol the application.
jQueiy anu vaiious plugins ollei out-ol-the-Lox anu customizaLle solutions loi Lettei
inteiactions, with piogiessive enhancement at heait.
Each pioLlem coulu Le solveu with a jQueiy solution liom sciatch, Lut using a plugin
yielus a lot ol Lenelits:
Avoius ieinventing the wheel
Pioviues lunctionality that is well testeu among uilleient Liowseis
Saves a lot ol woik that hiues in the uetails
Pioviues lunctionality that is tuneu to woik unuei extieme conuitions
Each iecipe will uiscuss the stiengths anu weaknesses ol the plugin, highlighting wheie
it may make sense to stait liom sciatch insteau.
Basic Approach
The Lasic appioach to using jQueiy plugins is always the same. Fiist you incluue jQueiy
itsell, anu then you incluue the plugin lile on youi page. Some plugins also neeu a
stylesheet. Most plugins ieguiie some maikup to woik with anu a line ol coue that
selects this maikup element anu uoes something with it. Because ol common naming
conventions, a plugin sliueshow woulu Le useu like this:
<!DOCTYPE html>
<html>
<head>
237
<link rel="stylesheet" href="jquery.slideshow.css"/>
<script src="assets/jquery-latest.js"></script>
<script src="assets/jquery.slideshow.js"></script>
<script type="text/javascript">
jQuery(document).ready(function($){
$("#slideshow").slideshow();
});
</script>
</head>
<body>
<div id="slideshow">...</div>
</body>
</html>
The specilic maikup necessaiy loi a sliueshow is guite uilleient loi a sliuei oi loim
valiuation, so that`s something to look out loi in the uocumentation anu examples ol
each plugin, anu that will Le coveieu in the lollowing iecipes.
11.1 Validating Forms
Problem
Most iegistiation loims ieguiie input ol email auuiess, a passwoiu (two times), a usei-
name, anu some othei inloimation, like a Liith uate. This applies to email seivices, weL
shops, oi loiums.
It`s easy to imagine ]ohn Doe, who wants to Luy a new monitoi at some weL shop
wheie the iegistiation also ieguiies the input ol a captcha (a Laiely legiLle gioup ol
ianuom chaiacteis to tell the uilleience Letween a human anu a Lot). He lills out the
complete loim, which takes some time, anu then suLmits the loim. Altei aLout live
seconus, the loim is uisplayeu again, with some eiioi message at the top: he loigot to
lill out the stieet lielu. He lixes that anu suLmits again. Anothei live seconus pass: now
he misseu the passwoiu anu captcha lielu! Huh? He uiu lill those in, Lut he hau to lill
them in again altei the laileu liist attempt.
Such late leeuLack can Le veiy liustiating anu can iuin an expeiience that was otheiwise
goou, especially when secuiity conceins limit lunctionalityheie causing the empty
passwoiu anu captcha lielus.
Solution
One way to impiove the situation is to auu client-siue valiuation. The Lasic iuea is to
give the usei leeuLack as eaily as possiLle, without annoying him. It shoulun`t Le pos-
siLle to suLmit an invaliu loim, avoiuing the issue ol lilling in passwoius oi captchas
again.
It also makes sense to highlight eiiois on lielus altei they aie lilleu in, as in the case ol
an invaliu email auuiess like john.docgnai|,con. Highlighting lielus as wiong uoesn`t
help when it happens Leloie the usei even has the chance to lill out a lielu coiiectly: to
238 | Chapter 11:HTML Form Enhancements with Plugins
uisplay too shoit on a lielu that ieguiies at least two chaiacteis, altei the usei types
the liist chaiactei, isn`t helping at all.
A plugin coveiing these ieguiiements guite well is the valiuation plugin.
To get staiteu, uownloau the plugin, extiact the liles, anu copy jquery.validate.js to
youi pioject. The lollowing example shows a comment loim with lielus loi name,
email, URL, anu actual comment. A call to the plugin methou validate() sets up the
valiuation loi the loim. Valiuation iules aie specilieu inline using classes anu attiiLutes:
<!DOCTYPE html>
<html>
<head>
<script src="assets/jquery-latest.js"></script>
<script src="assets/jquery.validate.js"></script>
<style type="text/css">
* { font-family: Verdana; font-size: 96%; }
label { width: 10em; float: left; }
label.error { float: none; color: red; padding-left: .5em; vertical-align: top; }
div { clear: both; }
input, textarea { width: 15em; }
.submit { margin-left: 10em; }
</style>
<script type="text/javascript">
jQuery(document).ready(function($){
$("#commentForm").validate();
});
</script>
</head>
<body>
<form id="commentForm" method="get" action="">
<fieldset>
<legend>A simple comment form with submit validation and default messages</legend>
<div>
<label for="cname">Name</label>
<input id="cname" name="name" class="required" minlength="2" />
</div>
<div>
<label for="cemail">E-Mail</label>
<input id="cemail" name="email" class="required email" />
</div>
<div>
<label for="curl">URL (optional)</label>
<input id="curl" name="url" class="url" value="" />
</div>
<div>
<label for="ccomment">Your comment</label>
<textarea id="ccomment" name="comment" class="required"></textarea>
</div>
<div>
<input class="submit" type="submit" value="Submit"/>
</div>
</fieldset>
</form>
11.1 Validating Forms | 239
</body>
</html>
Any lielu with the class required is checkeu to have any content at all. Othei methous
in this example incluue the lollowing:
email
Checks that the lielu contains a valiu email auuiess
url
Checks that the lielu contains a valiu URL
minlength
Checks that the lielu contains at least x chaiacteis; heie x is specilieu via an
attiiLute: minlength="2"
Discussion
The valiuation plugin piomotes one specilic appioach to client-siue valiuation: peiloim
as much woik as possiLle in the Liowsei, anu ask the seivei loi help only in special
cases, which aie coveieu Ly the iemote methou, loi example, to check whethei a usei-
name is still availaLle.
A uilleient appioach woulu avoiu ieplicating valiuation iules anu methous on Loth the
client anu seivei siues, insteau senuing the whole loim via Ajax to the seivei, usually
on suLmit ol the loim. It coulu then use the same logic on the seivei siue that is in place
alieauy. The uiawLack is that usei leeuLack is slowei, Lecause it is impiactical to senu
a ieguest loi eveiy keypiess. It`s also not veiy likely that the seivei valiuation was wiitten
with Ajax valiuation in minu, making it impiactical to ieuse it. In that case, you`u have
to plan up liont to use it that way.
The valiuation plugin can Le auueu to a loim latei, anu apait liom iemote valiuation,
theie is no neeu to auapt the application in any way. This makes it uselul loi a simple
comment loim on a Llog, as well as moie complex loims on some intianet application
anu anything in Letween.
The most impoitant Luiluing Llocks loi the plugin aie iules anu methous. Methous
contain valiuation logic, like the email methou that uses a iegulai expiession to uetei-
mine whethei a value is a valiu email auuiess. Rules wiie input lielus togethei with
methous, wheie a single iule is a paii ol an input lielu anu a methou. The email lielu
then has one iule loi making it ieguiieu anu one loi making it an email auuiess.
Methods
The plugin has aLout 19 Luilt-in methous. The essential methou is requiredwhen
specilieu, the lielu has to Le lilleu out. Vhen lelt out, most othei methous will Le
ignoieu on an empty lielu. The only exception to that is the equalTo methou, which
checks that the content ol a lielu is exactly the same as some othei lielu, which even
240 | Chapter 11:HTML Form Enhancements with Plugins
applies loi an empty lielu. The iule itsell is most commonly useu loi Conliim pass-
woiu lielus.
The email, url, date, dateISO, dateDE, number, numberDE, digits, anu creditcard meth-
ous all check loi ceitain uata types, with simple vaiiations loi uilleient locales. Foi
example, number ieguiies a U.S. numLei loimat like 1,000.00, anu numberDE ieguiies
the Geiman numLei loimat 1.000,00.
The min anu max anu range methous check the value ol a numLei, while minlength,
maxlength, anu rangelength check the numLei ol chaiacteis.
In case ol a select input oi checkLoxes, min, max, anu range valiuate the numLei ol
selecteu options oi checkeu checkLoxes.
In case ol lile inputs, the accept methou comes in hanuy anu checks the lile extension,
Ly uelault looking loi .gif, .png, .jpg, oi .jpeg.
The remote methou is the only methou that uelegates the actual valiuation logic else-
wheie, to the seivei siue. It gets a URL as the paiametei, pointing at some seivei-siue
iesouice. This coulu Le a sciipt that uoes a uataLase gueiy, loi example, loi checking
il a useiname is alieauy taken oi il a specilieu email auuiess is alieauy iegisteieu. An
example ol a iegistiation loim using the iemote methou loi Loth useiname anu email
lielus can Le lounu at http://jqucry-coo|boo|.con/go/p|ugin-va|idation-rcnotc-dcno.
Custom methous aie a goou way to extenu the plugin with application-
specilic ieguiiements. You may have a loim wheie useis entei URLs that have to stait
with a ceitain coipoiate uomain. A custom methou coulu encapsulate the necessaiy
valiuation:
jQuery.validator.addMethod("domain", function(value, element) {
return this.optional(element) || /^http:\/\/mycorporatedomain.com/.test(value);
}, "Please specify the correct domain for your documents");
The liist aigument to jQuery.validator.addMethod is the name ol the custom methou,
anu it must Le a valiu ]avaSciipt iuentiliei. The seconu aigument is a lunction that
implements the actual valiuation. Il it ietuins tiue, the input is consiueieu valiu. It uses
this.optional(element) to ueteimine whethei that input has no value anu shoulu
theieloie Le skippeuall uelault methous use the same call. The thiiu aigument speci-
lies the uelault message loi the new methou.
Viiting methous that accept a paiametei woiks veiy similaily:
jQuery.validator.addMethod("math", function(value, element, params) {
return this.optional(element) || value == params[0] + params[1];
}, jQuery.format("Please enter the correct value for {0} + {1}"));
In this case, the uelault message is specilieu with the help ol jQuery.format, a templating
helpei the plugin pioviues. The inuexeu cuily-Liaceu placeholueis aie ieplaceu with
the actual paiameteis when the valiuation is iun.
Custom methods.
11.1 Validating Forms | 241
Custom methous can also ieuse existing methous, which is uselul to specily uilleient
uelault messages loi a single methou. In this example, the required methou is aliaseu
to customerRequired with a uilleient uelault message:
$.validator.addMethod("customerRequired", $.validator.methods.required,
"Customer name required");
A collection ol ieauy-to-use custom methous aie Lunuleu with the plugin in
additionalMethods.js.
Rules
Theie aie loui uistinct ways to specily iules: two in coue anu two inline as metauata.
The pievious example uses classes anu attiiLutes as metauata, which the plugin sup-
poits Ly uelault. Vhen the metauata plugin is availaLle, iules can Le emLeuueu in
vaiious ways, loi example, insiue the class attiiLute:
<input type="text" name="email" class="{required:true, email:true}" />
Heie the class contains ]avaSciipt liteials insiue cuily Liaces, which is veiy similai in
syntax to specilying iules in coue via the rules option:
$("#myform").validate({
rules: {
name: {
required: true,
minlength: 2
},
email: {
required: true,
email: true
},
url: "url",
comment: "required"
}
});
The oLject keys like name, email, url, anu comment always ielei to the name ol the ele-
ment, not the ID.
Note the shoitcuts useu loi url anu comment, wheie only a single iule is necessaiy. This
isn`t availaLle when specilying iules with paiameteis, like minlength.
Some iules neeu to Le auueu latei, which is possiLle using the louith way, the rules
plugin methou:
// initialize the validation first
$("#myform").validate();
// some time later, add more rules
$("#username").rules("add", { minlength: 2});
Rules can also Le iemoveu that way:
$("#username").rules("remove", "required");
242 | Chapter 11:HTML Form Enhancements with Plugins
This can come in hanuy when implementing a Foigot passwoiu link on a login loim:
$("#loginform").validate({
username: "required",
password: "required"
});
$("a#forgotPassword").click(function(e) {
$("#password").rules("remove", "required");
$("#loginform").submit();
$("#password").rules("add", "required");
return false;
});
That click event coue iemoves the ieguiieu iule liom the passwoiu, tiies to suLmit the
loim (tiiggeiing the valiuation), anu auus the iule Lack. That way, the useiname lielu
is still Leing valiuateu, anu il the valiuation lails, the passwoiu lielu will Le ieguiieu
again (in case ol a noimal loim suLmit).
Olten the valiuation Lehavioi ol a lielu uepenus on some moie lactois
than just a link Leing clickeu. Those can Le hanuleu using paiameteis loi the
required methou. The paiametei can Le a selectoi oi a callLack. The selectoi is uselul
when the uepenuency can Le wiitten in a simple expiession. An email lielu may Le
ieguiieu only when the newslettei checkLox is selecteu:
email: {
required: "#newsletter:checked"
}
A callLack can Le useu loi expiessions ol any complexity, loi example, when the lielu
uepenus on the state ol multiple othei lielus:
email: {
required: function(element) {
return $("#newsletter:checked").length && $("#telephone:blank");
}
}
The pievious example useu the :blank expiession to select an element
only when it has no value at all oi only whitespace. The plugin also pioviues
the :filled expiession, the inveision ol :blank. jQueiy itsell pioviues :checked, anu
the valiuation plugin auus the inveision :unchecked. Both aie uselul when specilying
uepenuencies on iauio Luttons oi checkLoxes.
Vhile you coulu use the :not expiession to inveise :filled oi :checked, :blank
anu :unchecked make the selectoi moie ieauaLle anu theieloie easiei to unueistanu at
a glance.
Error messages
Similai to iules, theie aie a lew ways to specily messages, Loth in coue anu inline. Inline
messages aie ieau liom the title attiiLute:
Dependencies.
Custom expressions.
11.1 Validating Forms | 243
<input name="email" class="required email" title="A valid email address is
required" />
That will piouuce a single eiioi message loi each iule. An alteinative inline appioach
is to use the metauata plugin (see Rules on page 2+2):
<input name="email" class="{required:true, email:true, messages:{required:"Required",
email: "Not a valid email address"}}"/>
Vith this appioach, you can specily a message loi each iule, which is also possiLle
when using the messages option:
$("#myform").validate({
messages: {
email: {
required: "Required",
email: "Not a valid email address"
}
}
});
Again, the keysheie, emailielei to the name ol the input, not the ID, just the same
as specilying iules.
Foi moie uynamic scenaiios, the rules plugin methou can Le useu:
$("#myform").validate();
// sometime later
$("#email").rules("add", {
messages: {
email: "A valid email address, please!"
}
});
Il you use some ol the alteinatives to the title attiiLute while using a iegulai title, you
can suppiess the plugin liom checking the attiiLute loi messages:
$("#myform").validate({
ignoreTitle: true
});
The uelault messages aie in English (with the exception ol dateDE anu
numberDE). In auuition, the plugin pioviues (at the time ol this wiiting) 17 localizations.
Usage is plain anu simple: just copy the messages_xx.js lile you neeu to youi pioject,
anu incluue it altei the valiuation plugin. Foi example, heie`s the coue loi the Sweuish
localization:
<script src="assets/jquery-latest.js"></script>
<script src="assets/jquery.validate.js"></script>
<script src="assets/messages_se.js.js"></script>
Vith that in place, insteau ol Please entei a valiu email auuiess. you`ll get Ange en
koiiekt e-postauiess.
By uelault eiioi messages aie inseiteu into the DOM next to the element
that they aie ieleiiing to. An eiioi message is inseiteu as a laLel element, with the for
Localization.
Error element.
244 | Chapter 11:HTML Form Enhancements with Plugins
attiiLute set to the id ol the valiuateu element. Using a laLel with the for attiiLute
leveiages the Liowsei leatuie wheie a click on the laLel gives locus to the input lielu.
So Ly uelault, the usei can click the eiioi message to give the invaliu lielu locus.
Il you neeu a uilleient element type, use the errorElement option:
$("#myform").validate({
errorElement: "em"
});
The plugin will still use the for attiiLute then, Lut the auto linking the Liowsei pioviues
won`t woik.
Il you want to customize the position wheie eiioi messages aie inseiteu, the
errorPlacement option is uselul. Ve may have a loim that uses a taLle loi layout, wheie
the liist column contains the iegulai laLel, the seconu the input, anu the thiiu the
messages:
<form id="signupform" method="get" action="">
<table>
<tr>
<td class="label">
<label id="lfirstname" for="firstname">First Name</label>
</td>
<td class="field">
<input id="firstname" name="firstname" type="text" value=""
maxlength="100" />
</td>
<td class="status"></td>
</tr>
<!-- more fields -->
</table>
</form>
$("#signupform").validate({
errorPlacement: function(error, element) {
error.appendTo( element.parent("td").next("td") );
}
});
Anothei common ieguiiement is to uisplay a geneial message aLove the loim. The
errorContainer option helps with that:
$("#myform").validate({
errorContainer: "#messageBox1"
});
In this example, an element with the ID messageBox1 woulu Le shown when the loim
is invaliu anu woulu Le hiuuen when valiu.
This can also Le comLineu with the errorLabelContainer option. Vhen specilieu, eiioi
laLels aien`t placeu next to theii input elements Lut insteau auueu to a single element
aLove oi Lelow the loim. ComLineu with the errorContainer anu wrapper options,
messages aie auueu to a list ol eiiois aLove the loim:
Layout.
11.1 Validating Forms | 245
<div class="container">
<h4>There are a few problems, please see below for details.</h4>
<ul></ul>
</div>
<form id="myform" action="">
<!-- form content -->
</form>
var container = $('div.container');
// validate the form when it is submitted
$("#myform").validate({
errorContainer: container,
errorLabelContainer: $("ul", container),
wrapper: 'li'
});
Handling the submit
Once the loim is valiu, it has to Le suLmitteu. By uelault that just woiks as any othei
loim suLmit. To suLmit the loim via Ajax, the submitHandler option can Le useu, to-
gethei with the loim plugin (see Recipe 11.6 loi moie uetails):
$(".selector").validate({
submitHandler: function(form) {
$(form).ajaxSubmit();
}
});
The invalidHandler callLack is uselul loi iunning coue on an invaliu suLmit. The lol-
lowing example uisplays a summaiy ol the missing lielus:
$("#myform").validate({
invalidHandler: function(e, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
var message = errors == 1
? 'You missed 1 field. It has been highlighted below'
: 'You missed ' + errors + ' fields. They have been highlighted below';
$("div.error span").html(message);
$("div.error").show();
} else {
$("div.error").hide();
}
}
});
The Maiketo uemo shows this Lehavioi in action (http://jqucry-coo|boo|.con/go/p|u
gin-va|idation-nar|cto-dcno).
Limitations
So, when uoes it make sense to not use the plugin anu wiite a valiuation solution liom
sciatch? Theie aie ceitain limitations: loims wheie gioups ol inputs, like checkLoxes,
have uilleient name attiiLutes aie haiu to valiuate as a gioup. Lists ol inputs that all have
246 | Chapter 11:HTML Form Enhancements with Plugins
the same name can`t Le valiuateu, Lecause each inuiviuual input neeus its own unigue
name. Il you stick with the naming convention ol unigue names loi inuiviuual inputs
anu one name loi gioups ol checkLoxes oi iauio Luttons, the plugin woiks line.
Il youi application has only a login loim, the plugin is pioLaLly oveikill, anu it woulu
Le uillicult to justily the lile size; howevei, il you use the plugin somewheie else on a
site, it can Le useu loi the login loim as well.
11.2 Creating Masked Input Fields
Problem
Theie aie ceitain input types that aie guite eiioi pione, like a cieuit caiu numLei. A
simple typo that goes unnoticeu at liist can cause weiiu eiiois much latei. That also
applies to uates oi phone numLeis. These have a lew leatuies in common:
A lixeu length
Mostly numLeis
Delimiting chaiacteis at ceitain positions
Solution
A jQueiy plugin that can impiove the leeuLack is the maskeu input plugin. It is applieu
to one oi moie inputs to iestiict what can Le enteieu while inseiting uelimiteis auto-
matically.
In this example, a phone input is maskeu:
<!DOCTYPE html>
<html>
<head>
<script src="assets/jquery-latest.js"></script>
<script src="assets/jquery.maskedinput.js"></script>
<script>
jQuery(document).ready(function($) {
$("#phone").mask("(999) 999-9999");
});
</script>
</head>
<body>
<form>
<label for="phone">Phone</label>
<input type="text" name="phone" id="phone" />
</form>
</body>
</html>
The plugin lile is incluueu in auuition to jQueiy itsell. In the uocument-ieauy callLack,
the input with ID phone is selecteu, anu the mask methou is calleu. The only aigument
specilies the mask to use, heie uesciiLing the loimat ol a U.S. phone numLei.
11.2 Creating Masked Input Fields | 247
Discussion
Theie aie loui chaiacteis with a special meaning availaLle when specilying the mask:
a
Any alpha chaiactei liom a-z anu A-Z
9
Any uigit liom 09
*
Any alphanumeiic chaiactei, that is, az, AZ, anu 09
?
Anything altei this is optional
Any othei chaiactei, like the paientheses oi hyphen in the phone mask, aie consiueieu
liteials, which the plugin automatically inseits into the input anu which the usei can`t
iemove.
By uelault, the plugin inseits an unueiscoie ( ) loi each vaiiaLle chaiactei. Foi the
phone example, the input woulu uisplay the lollowing value once locuseu:
(___) ___-____
Vhen the usei staits typing, the liist unueiscoie gets ieplaceu il it is a valiu chaiactei,
heie a uigit. The othei liteials aie skippeu as well.
The unueiscoie placeholuei can Le customizeu Ly passing an auuitional aigument:
$("#phone").mask("(999) 999-9999", {placeholder: " "});
In this case, whitespace woulu Le uisplayeu insteau ol the unueiscoie.
It`s also possiLle to ueline new mask chaiacteis:
$.mask.definitions['~'] = '[+]';
$("#eyescript").mask("~9.99 ~9.99 999");
Heie the new mask chaiactei is a tilue, anu alloweu values loi it aie - anu -, specilieu
as a iegulai expiession chaiactei class. The tilue can then Le useu in a mask.
The guotation maik enaLles masks with a lixeu pait anu an optional pait. A phone
numLei with an optional extension coulu Le uelineu like this:
$("#phone").mask("(999) 999-9999? x99999");
Vhen a maskeu input is comLineu with the valiuation plugin (Recipe 11.1), it`s im-
poitant the lielu piopei iules aie uelineu loi it. Otheiwise, the valiuation plugin may
accept the placeholuei chaiacteis ol the mask plugin as valiu input, iiiitating the usei
when an invaliu lielu is maikeu as valiu while he just inseiteu the liist chaiactei.
248 | Chapter 11:HTML Form Enhancements with Plugins
Limitations
The signilicant limitation ol the plugin is the lixeu-length ieguiiement. It can`t Le useu
loi anything with a vaiiaLle length, like cuiiency value. Foi example, $ 999,999.99
woulu ieguiie a value Letween 100,000.00 anu 999,999.99 anu can`t accept anything
aLove oi Lelow.
11.3 Autocompleting Text Fields
Problem
Theie aie two HTML input types that allow a usei to select one value out ol a list ol
existing values: iauio Luttons anu selects. Rauio Luttons woik well loi lists with up to
eight items, anu selects woik well with up to 30 to 150, uepenuing on the type ol uata.
Both lall shoit when the usei can entei a new value as wellin this case they aie usually
accompanieu Ly an Othei lielu. Both Lecome useless when the list is Lig, mayLe 500
oi 500,000 items.
Solution
The jQueiy UI autocomplete wiuget can solve the vaiious situations wheie a select isn`t
enough. In the simplest case, the uata to uisplay is availaLle in a ]avaSciipt aiiay:
<label for="month">Select a month:</label>
<input id="month" name="month" />
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December'];
$("#month").autocomplete({
source: months
});
Heie we apply the autocomplete plugin to a month input, with the uata Leing a plain
]avaSciipt aiiay.
Vhen the uata isn`t alieauy availaLle on the client siue, the plugin can get it liom a
seivei-siue iesouice:
$("#month").autocomplete({
source: "addresses.php"
});
The plugin then senus a GET ieguest to that iesouice, with the usei-enteieu value
appenueu as the q paiametei, e.g., addresses.php?q=ma. As a iesponse, the plugin ex-
pects a list ol newline sepaiateu values:
Mainstreet
Mallstreet
Marketstreet
11.3 Autocompleting Text Fields | 249
Discussion
The liist uecision to make when using the plugin is ueciuing on local oi iemote uata.
Vith local uata, the complete uata set is alieauy piesent in the Liowsei`s memoiy. It
coulu have Leen loaueu as pait ol the page oi via a sepaiate Ajax ieguest. In any case,
it`s loaueu just once. This moue is piactical when the uata is small anu staticless than
500 iows ol uataanu uoesn`t change while selecting a value. The Lig auvantage ol
local uata is that it`s extiemely last to linu matching values.
Remote uata is loaueu liom the seivei in small chunks (up to 100 iows pei chunk makes
sense). This woiks with Loth small uata sets as well as veiy Lig uata sets (say, moie
than hall a million iows). As the uata is loaueu liom the seivei, linuing matching values
is slowei when compaieu to local uata. This is mitigateu Ly loauing Lig enough chunks,
which can then Le lilteieu uown on the client siue without auuitional ieguests.
11.4 Selecting a Range of Values
Problem
Imagine a cai seaich inteilace: the usei inputs the piice iange that`s acceptaLle loi him,
anu while changing the value, the list ol availaLle cais in that iange is upuateu. The
HTML loim elements loi that type ol inputplain text input, iauio Luttons, selects
aien`t goou enough. On the one hanu, each ieguiies an exact value. On the othei, they
lail to visualize the piice iange. It`s also not possiLle to move the entiie iange; insteau,
the usei has to upuate Loth the stait anu enu values, one Ly one.
Solution
The jQueiy UI sliuei wiuget can tiansloim two text inputs into a iange sliuei. The stait
anu enu values ol the iange can Le uiaggeu using the mouse oi using the cuisoi keys.
The uelault sliuei is applieu to a simple <div>, with no options necessaiy:
<div id="slider"></div>
$("#slider").slider();
Foi that to woik, jQueiy, jQueiy UI coie, anu the sliuei .js liles must Le incluueu, in
auuition to a UI theme:
<link rel="stylesheet" href="ui.core.css" />
<link rel="stylesheet" href="ui.slider.css" />
<link rel="stylesheet" href="ui.theme.css" />
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="ui.core.js"></script>
<script type="text/javascript" src="ui.slider.js"></script>
Vhile this auus a nice-looking sliuei to the page, it uoesn`t yet ieally uo anything uselul.
250 | Chapter 11:HTML Form Enhancements with Plugins
In the case ol the cai seaich, we want to put the selecteu values into an input lielu anu
uisplay them to the usei:
<p>
<label for="amount">Price range:</label>
<input type="text" id="amount" style="border:0; color:#f6931f;
font-weight:bold;" />
</p>
<div id="slider-range"></div>
Baseu on that maikup, we can cieate a iange sliuei:
var slider = $("#slider-range").slider({
range: true,
min: 0,
max: 500,
values: [75, 300],
slide: function(event, ui) {
$("#amount").val('$' + ui.values[0] + ' $' + ui.values[1]);
}
});
$("#amount").val('$' + slider.slider("values", 0) + ' $' + slider.slider("values",
1));
Setting the range option to true instiucts the plugin to cieate two hanules insteau ol
just one. The min anu max options specily the total iange availaLle; the values option
the staiting positions.
The slide callLack is tiiggeieu when a hanule is moveu. Heie it upuates the amount
input to uisplay the selecteu piice iange.
Discussion
Binuing a sliuei to a text input is one option; Linuing it to a select, anu using the options
ol the select as values, is anothei.
Let`s take the example ol a ioom ieseivation loim wheie the usei enteis the minimum
numLei ol Leus. The maximum numLei ol Leus is six; theieloie, a sliuei isn`t a Lau
choice to stait with. Using piogiessive enhancement, we can enhance the select with a
sliuei anu leeu changes to the sliuei Lack to the <select> element:
<select name="minbeds" id="minbeds">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
</select>
var select = $("#minbeds");
var slider = $('<div id="slider"></div>').insertAfter(select).slider({
min: 1,
max: 6,
11.4 Selecting a Range of Values | 251
range: "min",
value: select[0].selectedIndex + 1,
slide: function(event, ui) {
select[0].selectedIndex = ui.value 1;
}
});
$("#minbeds").click(function() {
slider.slider("value", this.selectedIndex + 1);
});
Insteau ol using existing maikup, which uoesn`t have any semantic meaning, we gen-
eiate the <div> on the lly anu inseit it into the DOM, iight altei the <select>.
Ve have a single value, so we use the value option insteau ol the values option. Ve
initialize it with the selectedIndex ol the select, using the DOM piopeity uiiectly. The
piopeity staits at zeio, so we auu one.
Vhen the sliuei is upuateu, on keypiesses oi while uiagging the hanule with the mouse,
the select is upuateu Ly setting its selectedIndex to the value ieau liom the ui oLject
passeu to eveiy ui event. The ollset ol one, which we auueu uuiing initialization, is
now suLtiacteu.
Ve also set the range option, even though we have only one hanule. It accepts a stiing
paiametei in auuition to the Boolean: setting it to min uisplays the iange liom the stait
ol the sliuei to the hanule; setting it to max uisplays it liom the enu ol the sliuei to the
hanule. This helps to visualize the minimum numLei ol Leus the hotel ioom shoulu
have.
Finally, we Linu a click event to the select to upuate the sliuei when the select itsell is
changeu uiiectly Ly the usei. Ve coulu also hiue the select Lut woulu then neeu to auu
anothei loim ol laLel to uisplay the selecteu numeiical value.
The plugin also suppoits two moie options, which weien`t coveieu in the example:
Setting animate: true animates the hanule to move to the uestination when clicking
somewheie on the sliuei.
Setting orientation: vertical uisplays a veitical sliuei, insteau ol the hoiizontal
uelault.
Theie aie also moie events with moie line-giaineu contiol:
start is calleu whenevei sliuing Legins.
stop is calleu when sliuing stops.
change is calleu when sliuing stops anu the sliuei value changes; this is especially
uselul when a change to the sliuei tiiggeis an expensive opeiation, such as senuing
a ieguest to the seivei, oi upuating a giaph. Ol couise, it makes the sliuei Lehavioi
less oLvious, Lecause theie isn`t instant leeuLack while sliuing.
252 | Chapter 11:HTML Form Enhancements with Plugins
11.5 Entering a Range-Constrained Value
Problem
A sliuei is goou at hanuling iough inputs anu visualizing them Lut Lau loi gatheiing
exact values. An example woulu Le a pixel value in a layout component, wheie the
value has to Le tuneu in veiy small inciements, pixel Ly pixel. Vith a stanuaiu input,
the keyLoaiu has to Le useu: click the lielu, iemove the cuiient value anu entei a new
value, iepeat loi each inciement.
Solution
The jQueiy UI spinnei wiuget can solve this pioLlem Ly auuing up anu uown Luttons
to the input to enaLle mouse inteiaction as well as hanule keyLoaiu events like cuisoi
up anu uown.
All you neeu is a iegulai text input:
<input id="value" name="value" />
to which you then apply the spinnei plugin:
$("#value").spinner();
This will cieate anu position the up/uown Luttons anu auu the necessaiy keyLoaiu
hanuling events.
Use the spinnei plugin to auu Luttons to in- anu ueciement the value, eithei Ly clicking
the Luttons oi giving the input locus anu using the cuisoi keys.
It also iestiicts the input to numeiic valueswhen enteiing abc into the spinnei, it`ll
get ieplaceu with the uelault value on Llui. Unless specilieu otheiwise, it`s a zeio.
Discussion
The plugin olleis a lew options to iestiict the input luithei:
min sets the lowei limit, e.g., -10 oi 100.
max sets the uppei limit, e.g., 10 oi 200.
stepping iestiicts the value to ceitain inciements, e.g., 5; the uelault is 1.
Vhen the spinnei is useu to input a cuiiency value, the currency option can Le useu
to uisplay the appiopiiate symLol insiue the input.
The lollowing example puts these all togethei anu cieates a loim loi uonating money:
<label for="currency">Currency</label>
<select id="currency" name="currency">
<option value="$">US $</option>
<option value="">EUR </option>
<option value="">YEN </option>
</select>
11.5 Entering a Range-Constrained Value | 253
<br/>
<label for="amount">Select the amount to donate:</label>
<input id="amount" name="amount" value="5" />
Ve have a select loi the cuiiency anu a text input loi the amount:
var currency = $("#currency").change(function() {
$("#amount").spinner("option", "currency", $(this).val()).blur();
});
$("#amount").spinner({
currency: currency.val(),
min: 5,
max: 1000,
step: 5
});
Ve Linu a change event to the cuiiency select to upuate the currency option ol the
spinnei whenevei the selection changes.
The spinnei itsell is initializeu with the cuiient value, as well as limits loi min, max, anu
step, iestiicting the value somewheie Letween 5 anu 1,000, with inciements ol 5, e.g.,
10, 15, 20, anu so on.
Google Maps integration
The value may also Le a uecimal numLei; in that case, the decimal option can Le useu
to specily the numLei ol alloweu uigits altei the uecimal point. In the lollowing exam-
ple, we uisplay a Google map anu use spinneis to specily the latituue anu longituue
values.
To stait with, we incluue the Google Maps API sciipts:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?
sensor=false"></script>
Vith that in place, we can auu maikup loi the spinneis anu the actual map, along with
some minimal styles:
<style>
#map { width:500px; height:500px; }
</style>
<label for="lat">Latitude</label>
<input id="lat" name="lat" value="44.797916" />
<br/>
<label for="lng">Longitude</label>
<input id="lng" name="lng" value="-93.278046" />
<div id="map"></div>
Baseu on that, we can initialize the map anu link it with the spinneis:
function latlong() {
return new google.maps.LatLng($("#lat").val(),$("#lng").val());
}
function position() {
254 | Chapter 11:HTML Form Enhancements with Plugins
map.set_center(latlong());
}
$("#lat, #lng").spinner({
precision: 6,
change: position
});
var map = new google.maps.Map($("#map")[0], {
zoom: 8,
center: latlong(),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
The position lunction sets the centei ol the map to the latituue anu longituue values
oLtaineu liom the spinneis. They aie initializeu with the decimal option set to 6, anu
passing the position lunction loi the change option. Vith that, the map is upuateu
whenevei one ol the spinneis changes. Then the map itsell is initializeu, using the
Google Maps API.
The uiawLack ol the spinnei in this case is that inciements anu ueciements allect only
the uigits Leloie the uecimal point, so sciolling is iathei iough. The increment option
iounus any value Lelow one up to one, so it can`t help heie.
11.6 Uploading Files in the Background
Problem
File uploau is pait ol many weL applications Lut Lauly suppoiteu Ly Liowseis. The
Liggest pioLlem is the lack ol leeuLack ol the uploau status, while any action ol the
useis uisiupts the uploau. A simple piogiess Lai coulu impiove the leeuLack Lut ie-
guiies guite some woik on the seivei siue, while the pioLlem ol uisiuptive actions
iemains.
Solution
To impiove the situation, lile uploaus shoulu Le peiloimeu in the Lackgiounu. This
allows the application to continue accepting othei usei input.
The jQueiy loim plugin makes it tiivial to switch liom the native Liowsei uploau to
Ajax Lackgiounu uploauing. Vith this loim:
<form id="uploadform">
<input type="file" id="fileupload" name="fileupload" />
<input type="submit" value="Upload!" />
</form>
all you neeu to auu is a call to ajaxForm:
$("#uploadform").ajaxForm();
11.6 Uploading Files in the Background | 255
Howevei, just uoing the uploau in the Lackgiounu without any leeuLack ol the com-
pleteu uploau isn`t enough, so we use the success option to uisplay an aleit aLout the
successlul uploau:
$("#uploadform").ajaxForm({
success: function() {
alert("Upload completed!");
}
});
Discussion
The ajaxForm methou Linus itsell to the suLmit event ol the loim, which allows it to
also incluue the Lutton useu to suLmit the loim in the Ajax ieguest. The lattei isn`t
availaLle when using ajaxSubmit. The ajaxSubmit methou is uselul on its own when the
loim suLmit is hanuleu elsewheie, loi example, Ly the valiuation plugin. To integiate
valiuation anu Ajax suLmit, ajaxSubmit shoulu Le useu in the submitHandler option:
$("#commentform").validate({
submitHandler: function(form) {
$(form).ajaxSubmit({
success: function() {
$(form).clearForm();
alert("Thanks for your comment!");
}
});
}
});
In auuition to the alert, the clearForm methou, also pioviueu Ly the loim plugin,
iemoves all values liom the loim. This makes it easy loi the usei to uploau anothei lile.
11.7 Limiting the Length of Text Inputs
Problem
It is common to limit the amount ol chaiacteis in a textaiea, like the 1+0 chaiacteis loi
Twittei oi the 500 chaiacteis loi a YouTuLe comment. Inloiming the usei that he
enteieu too much, altei he suLmitteu a loim, is liustiating, so it makes sense to uisplay
an inuicatoi ol the availaLle chaiacteis lelt.
Solution
The maxlength plugin solves this Ly auuing a Chaiacteis lelt: x inuicatoi in liont oi
altei the textaiea. The plugin, altei Leing applieu on a text input oi textaiea, looks loi
an element with the class charsLeft to upuate with the count:
<form action="/comment">
<p>Characters left: <span class="charsLeft">10</span></p>
<textarea name="commentbody" maxlength="10"></textarea>
256 | Chapter 11:HTML Form Enhancements with Plugins
</form>
$('textarea').maxlength();
To make this less intiusive, we can cieate the necessaiy elements with jQueiy, iesulting
in a simplei loim maikup:
<form action="/comment">
<textarea name="commentbody" maxlength="10"></textarea>
</form>
var textarea = $('textarea');
$('<p>Characters left: <span class="charsLeft">10</span></p>').insertBefore(textarea);
textarea.maxlength();
Discussion
In the case ol Twittei, the textaiea allows you to go ovei the 1+0-chaiactei limit, Lut
you can`t suLmit. This helps a lot when pasting longei text that woulun`t lit into the
1+0-chaiactei limit anu euiting it alteiwaiu. To get a similai ellect with the maxlength
plugin, we can set the hardLimit option to false. Howevei, that uoesn`t allect the actual
suLmit Lut coulu Le hanuleu elsewheie, e.g., Ly the valiuation plugin (see Recipe 11.1).
The plugin also suppoits counting woius insteau ol chaiacteis, Ly setting the words
option to true.
Insteau ol having the plugin look loi the uelault .charsLeft selectoi, we can also set
the feedback option.
Heie is anothei example using all thiee ol these options:
<form action="/comment">
<textarea name="commentbody" maxlength="10"></textarea>
<p><span>x</span> characters left</p>
</form>
$('textarea').maxlength({
feedback: "p>span",
hardLimit: false,
words: true
});
11.8 Displaying Labels Above Input Fields
Problem
A page layout uoesn`t have enough space in liont ol an input element to uisplay a laLel,
the lunction ol the input is oLscuieu, anu a title alone isn`t visiLle enough.
Seaich anu login loims aie olten suLject to space constiaints. Theie just isn`t enough
visual space to uisplay a laLel in liont ol the input lielu. Though without the laLel, the
lunction ol the input is oLscuieu. A title attiiLute isn`t enough to lix the pioLlem,
11.8 Displaying Labels Above Input Fields | 257
Lecause it`s iathei haiu to spot, ieguiiing the usei to mouse ovei the input anu iest
theie.
Solution
The most common example, the seaich lielu, can Le solveu Ly uisplaying seaich
insiue the lielu with a light giay to emphasize that it`s just a laLel, not the actual text
to seaich loi. Vhen locusing the lielu, the text is iemoveu. Vhen Lluiiing the lielu,
the text is ietuineu, unless something else was enteieu.
The less common example is a space-constiaineu login loim, consisting ol useiname
anu passwoiu lielus. The passwoiu lielu neeus to uisplay the wateimaik as plain text,
while the passwoiu to Le enteieu (oi pielilleu Ly the Liowsei) must still Le oLluscateu.
In Loth cases, the wateimaik shoulun`t Le suLmitteu as a value.
The wateimaik plugin solves this pioLlem Ly uisplaying a laLel element aLove the
actual input, hiuing the laLel when the input gets locus, anu uisplaying it again when
the empty lielu is Lluiieu.
Using a laLel aLove the lielu, insteau ol mouilying the text insiue the lielu, makes this
solution also woik with passwoiu lielus anu avoius having to cleai wateimaik values
on suLmit.
The uelault usage calls the wateimaik plugin methou anu passes the value to uisplay:
$("#search").watermark("Search");
Discussion
Insteau ol passing the value to the plugin, it can also Le specilieu as metauata, using
the metauata plugin, in the maikup, which is moie piactical when seveial wateimaiks
aie useu oi when those aie geneiateu on the seivei siue:
<form id="loginform">
<input type="text" id="email" name="email"
class="{watermark:'E-Mail Address'}" />
<input type="password" id="password" name="password"
class="{watermark:'Your password'}" />
</form>
$("#loginform input").watermark();
Metauata has the uiawLack that it uoesn`t Luilu on piogiessive enhancement. To
impiove that, laLel elements shoulu Le useu as loi a noimal loim, with the plugin
positioning the laLels at the iight position:
<form id="loginform">
<div>
<label for="email">E-Mail Address</label>
<input type="text" id="email" name="email" />
</div>
<div>
258 | Chapter 11:HTML Form Enhancements with Plugins
<label for="password">Your password</label>
<input type="password" id="password" name="password" />
</div>
</form>
In this case, the plugin is applieu to the laLels insteau ol the inputs:
$("#loginform label").watermark();
The plugin then uses the for attiiLute ol each laLel to linu the associateu input anu
position it aLove the input.
11.9 Growing an Input with Its Content
Problem
A textaiea is pait ol an inteilace anu is olten too laige oi too small, uepenuing on the
usei`s input. Eithei it`s too Lig anu othei impoitant elements get out ol sight, oi it`s too
small anu the usei has to scioll too much.
Solution
Use the elastic plugin to stait with a small uelault height anu have the height autogiow
when the usei enteis a ceitain amount ol text.
Usage is plain anu simple. Stait with a textaiea:
<textarea id="commentbody"></textarea>
Anu apply the plugin to it:
$("#commentbody").elastic();
Discussion
The plugin Linus Loth a timei anu a Llui event to the textaiea to look loi changes.
Vhen the content changes, it copies the content into a hiuuen textaiea with the same
styles applieu to it as the oiiginal, calculates the new height loi that, anu il it exceeus
the cuiient height ol the oiiginal, staits an animation to auapt. This allows the textaiea
to Loth giow anu shiink as content is auueu oi iemoveu.
An alteinative is to let the usei iesize the textaiea. Salaii olleis that Ly uelault loi any
textaiea. The jQueiy UI iesizaLle plugin can auu that to othei Liowseis as well. Staiting
with the same textaiea, we apply the iesizaLle plugin, customizing the hanule option
to uisplay only one hanule on the Lottom iight:
$("#resizable").resizable({
handles: "se"
});
11.9 Growing an Input with Its Content | 259
Vith that anu the jQueiy UI Lase theme incluueu, the hanule gets uisplayeu Lelow the
textaiea. To move it into the Lottom-iight coinei ol the textaiea, we have to auu
some CSS:
.ui-resizable-handle {
bottom: 17px;
}
11.10 Choosing a Date
Problem
Date inputs aie necessaiy loi seaiching loi events, llights, oi hotels, oi enteiing a Liith
uate in a iegistiation loim. A common solution is to use thiee selects, loi the uay,
month, anu yeai components. Vhile that woiks OK loi a uate ol Liith, it can get veiy
cumLeisome when seaiching loi a llight in a ceitain time peiiou.
Solution
The jQueiy UI uatepickei can solve the pioLlem Ly olleiing a calenuai togethei with
a lot ol customization options to optimize loi vaiious applications.
The uelault uatepickei woiks Ly simply applying it to an input:
<label for="startAt">Start at:</label>
<input type="text" name="startAt" id="startAt" />
$("#startAt").datepicker();
This will Linu the events necessaiy to show the uatepickei when the input gets locuseu,
staiting with the cuiient uate. Next anu pievious Luttons can Le useu to select the next
oi pievious month, anu a calenuai can Le useu to select a uay.
To make the uatepickei moie uselul, we neeu to auapt it to the application wheie it`s
useu. Foi the llight-seaich example, we can assume that the usei looks loi a llight
sometime in the next thiee months, anu theieloie it uisplays thiee months at once,
staiting with the next week liom the cuiient uate:
<label for="from">From</label>
<input type="text" id="from" name="from"/>
<label for="to">to</label>
<input type="text" id="to" name="to"/>
Ve stait with two inputs, each associateu with an appiopiiate laLel, anu then apply
the uatepickei to Loth:
var dates = $('#from, #to').datepicker({
defaultDate: "+1w",
changeMonth: true,
numberOfMonths: 3,
onSelect: function(selectedDate) {
var option = this.id == "from" ? "minDate" : "maxDate";
260 | Chapter 11:HTML Form Enhancements with Plugins
dates.not(this).datepicker("option", option, new Date(selectedDate));
}
});
The uelault uate loi the uatepickei is the cuiient uate plus one week, specilieu using
the defaultDate option. A select loi changing the months is uisplayeu as well, via
changeMonth: true. The option numberOfMonths: 3 inuicates that thiee calenuais shoulu
Le uisplayeu at once.
The onSelect option is an event tiiggeieu whenevei the usei selects a uate. Vhen the
liom uate is selecteu, the minDate option loi the to uate is set to the liom uate, anu
when the to uate is selecteu, the maxDate option loi the liom uate is set.
Vith that in place, the usei can stait selecting any ol the two uates, anu when he
continues to select the othei, the input is iestiicteu to a positive iange alieauy.
Discussion
By uelault, the uatepickei is shown when the input lielu ieceives locus. Using the
showOn option, we can conliguie the calenuai to appeai only when clicking a calenuai
icon next to the input:
$("#datepicker").datepicker({
showOn: 'button',
buttonImage: 'images/calendar.gif',
buttonImageOnly: true
});
The buttonImage option specilies the path to an image to use as the Lutton, wheie
buttonImageOnly specilies to use only that image, insteau ol a Lutton element with an
emLeuueu image.
The showOn option also suppoits both as a value, uisplaying the uatepickei on locus ol
the input anu on clicks on the Lutton.
Localization
The jQueiy UI uatepickei suppoits +1 locales, pioviueu as ui.datepicker-xx.js liles,
wheie xx is the locale. Each lile auus a piopeity to $.datepicker.regional. The ui.date
picker-ar.js lile auus these:
$.datepicker.regional['ar'] = {
closeText: '
prevText: '&#x3c;
nextText: '&#x3e;',
currentText: '
dayNames: ['
@
dayNamesShort: ['
@
dayNamesMin: ['
@
dateFormat: 'dd/mm/yy',
11.10 Choosing a Date | 261
firstDay: 0,
isRTL: true
};
To initialize a uatepickei with the AiaLic locale, we ielei to that piopeity:
$("#datepicker").datepicker($.datepicker.regional.ar);
To mix in othei options as well, we use $.extend:
$("#datepicker").datepicker($.extend({}, $.datepicker.regional.ar, {
changeMonth: true,
changeYear: true
});
Ve cieate an empty oLject liteial via {} anu then use $.extend to copy the iegional
options as well as values loi changeMonth anu changeYear into the empty oLject, which
is then useu to initialize the uatepickei.
262 | Chapter 11:HTML Form Enhancements with Plugins
CHAPTER 12
jQuery Plugins
Mikc Hostctlcr
12.0 Introduction
A piimaiy goal ol the jQueiy ]avaSciipt liLiaiy is to iemain a last anu concise alteinative
to othei ]avaSciipt liLiaiies that aie availaLle in the open souice woilu. A key piinciple
towaiu this goal is ensuiing that the jQueiy coie auuiesses the neeus ol most uevelopeis,
while iemaining last anu concise. Developeis may have neeus that aien`t completely
satislieu Ly the jQueiy coie. Oi, a uevelopei may wiite an extension to coie jQueiy
lunctionality that may Le uselul to a signilicant segment ol jQueiy useis Lut shoulun`t
Le incluueu in the jQueiy coie.
jQueiy was uesigneu to Le extensiLle in a vaiiety ol ways. The iecipes in this chaptei
aie intenueu to intiouuce the ieauei to the woilu ol jQueiy plugins.
12.1 Where Do You Find jQuery Plugins?
Problem
You`ie tiying to Luilu something with jQueiy that ieguiies lunctionality that uoesn`t
exist in the jQueiy coie. The pioLlem is one that othei uevelopeis have likely iun into
Leloie, anu you think a plugin may exist. Vheie shoulu you stait looking to linu plu-
gins, anu how shoulu you evaluate the plugins that you linu?
Solution
Seaich thiough the lollowing iepositoiies loi jQueiy plugins:
jQucry P|ugin Rcpository
http://p|ugins.jqucry.con
Goog|c Codc
http://codc.goog|c.con
263
GitHub
http://github.con
Goog|c with spccia| qucrics
http://goog|c.con
SourccIorgc
http://sourccjorgc.nct
Discussion
Theie aie a lew places aiounu the VeL that jQueiy plugins may Le lounu. Because ol
the natuie ol jQueiy plugins, theie aie ceitain open souice hosting sites that tenu to
attiact jQueiy plugins moie than otheis. Auuitionally, the jQueiy pioject hosts a cential
iepositoiy loi jQueiy plugins at http://p|ugins.jqucry.con.
It`s Lest to look thiough all ol the availaLle iesouices anu collect seveial potential
plugins, il they aie availaLle, loi youi ieview. Plugins that aie Luilt to solve the same
pioLlem olten take veiy uilleient appioaches oi weie Luilt loi alteinate veisions ol the
jQueiy coie liLiaiy.
Vhen looking loi a jQueiy plugin, the lollowing aie the Lest steps to linu the most
upuateu anu iecent veisions ol plugins.
Search through the jQuery Plugin Repository
The jQueiy Pioject hosts a plugin iepositoiy that cuiiently Loasts moie than 1,200
plugins at the time ol this wiiting. Most authois who host theii own plugins will post
theii plugins heie.
Plugins hosteu in the jQueiy Plugin Repositoiy aie oiganizeu into a numLei ol cate-
goiies, which can assist with naiiowing youi seaich. Plugins may Le oiganizeu into
multiple categoiies. Plugins aie also ieguiieu to Le listeu Ly API compatiLility, ensuiing
that any plugins you linu aie likely to woik with a paiticulai veision ol the jQueiy coie
liLiaiy. Lastly, you may also Liowse plugins Ly ielease uate, allowing you to keep up
with youi lavoiite plugins as new veisions aie ieleaseu.
Search through Google Code
Google Coue hosting olleis a veiy iich iepositoiy ol jQueiy plugins. Moie olten than
not, il you can`t linu a plugin hosteu on the main Plugin Repositoiy, theie`s a goou
chance it coulu Le on Google Coue.
Search through GitHub
GitHuL is a iising stai in the coue hosting woilu that many jQueiy plugin authois aie
tuining towaiu. Moie anu moie plugins enu up heie, anu it is ceitainly a site that
waiiants a seaich when looking loi a specilic plugin. One ol the most compelling lea-
tuies ol GitHuL is the aLility to loik a iepositoiy in a liienuly way Ly utilizing the
264 | Chapter 12:jQuery Plugins
leatuies ol the Git souice coue management system. In the event that you neeu to
mouily an existing plugin, utilizing the leatuies ol GitHuL aie a compelling way to keep
tiack with upstieam upuates.
The Lest way to linu a plugin on GitHuL is to utilize GitHuL`s excellent seaich. GitHuL
suppoits a numLei ol auvanceu opeiatois when seaiching. All ol these options may Le
vieweu in gieatei uetail at http://github.con/scarch. Vhen looking specilically loi a
jQueiy plugin, seaiching loi iepositoiies using ]avaSciipt will ietuin the Lest iesults.
Perform a Google search
Vhile the pievious suggestions aie known souices ol plugins, seaiching thioughout
the entiie VeL via Google is uselul as well. Because the Louy ol seaich mateiial tenus
to Le laigei, so uoes the numLei ol potential iesults to silt thiough. Using a lew ol the
suggesteu seaiches can iesult in linuing plugins guickei:
{searchterm} "jquery*.js" - Best practice plugin naming is jquery-{myplugin}.js or
jquery.{myplugin}.js
{searchterm} "*jquery.js" - Alternate best practice plugin naming
Search through SourceForge
Theie tenus to Le veiy lew actual jQueiy plugins hosteu on SouiceFoige. Howevei, a
numLei ol piojects on this site ollei jQueiy suppoit tools, such as IDE coue completion
extensions. Il you`ie out ol options, oi aie looking loi something unigue, SouiceFoige
is a goou place to uo a guick seaich.
12.2 When Should You Write a jQuery Plugin?
Problem
Altei seaiching loi an existing jQueiy plugin to lit youi neeus, the plugins that weie
lounu eithei uon`t meet youi neeus oi aie not constiucteu in a way that you can take
auvantage ol them piopeily. Is it woith wiiting a new jQueiy plugin that can Le shaieu
with otheis who have the same neeu?
Solution
Theie`s no cut anu uiieu solution to this pioLlem. The numLei ol availaLle jQueiy
plugins is laige, Lut theie aie valiu cases wheie plugins uon`t exist to meet a
paiticulai neeu.
In my opinion, the uecision to wiite anu puLlish youi own jQueiy plugin comes uown
to thiee things:
Is it likely theie aie otheis who have the same pioLlem?
12.2 When Should You Write a jQuery Plugin? | 265
Vhat level ol suppoit aie you willing to pioviue?
Vhat level ol community paiticipation uo you uesiie?
Discussion
Build a plugin if there is a potential audience
Il you`ie lacing a pioLlem that iemains unsolveu, theie aie likely othei uevelopeis who
have encounteieu the same issue. How otheis Leloie you have solveu the issue is the
key guestion. It`s assumeu that you`ve uone some homewoik at this point, seaiching
loi a solution. Duiing that seaich, clues that may suilace that point towaiu a neeu loi
a plugin can Le lounu in loium posts oi mailing list guestions that have gone unan-
sweieu. Theie`s no easy way to ueciue whethei a plugin is woith Luiluing, anu the
uecision ultimately comes uown to the peison who is planning to Luilu the plugin.
Howevei, a geneial leel ol whethei theie is a potential auuience is woith exploiing.
The othei potential ieason to Luilu anu puLlish youi own plugin is il a plugin exists to
meet youi neeus Lut uoes not lully uo what you want. Il this is the case, it is woith
consiueiing the potential loi wiiting a patch anu suLmitting that patch Lack to the
oiiginal authoi loi inclusion in the plugin. Paiticipating in the open souice piocess Ly
suLmitting a patch to an existing pioject tenus to Le a much moie ellicient application
ol a uevelopei`s most piecious iesouice: time.
Know and communicate the level of support you are willing to provide
Il wiiting youi own plugin is the Lest option, a Lit ol loiethought anu planning will
help make suie the piocess ol hanging out youi own open souice shingle goes well.
Vhenevei you ueciue to puLlish youi coue, the liist anu Liggest consiueiation is li-
censing. The jQueiy coie pioject is uual-licenseu as MIT anu GPL, Lut many othei
open souice licenses aie woithy ol consiueiation. A moie thoiough uiscussion on the
intiicacies ol open souice licensing can Le lounu at Vikipeuia.
Seconu, it is impoitant to consiuei anu communicate the level ol suppoit that you, the
plugin authoi, aie willing to pioviue to otheis who may uownloau anu use youi coue.
Choosing to simply puLlish youi coue anu pioviue no suppoit is a completely valiu
option anu is much Lettei than keeping youi coue to youisell loi leai ol the potential
suppoit issues. The key is communication; wiiting a guick note aLout youi suppoit
plan into the comments ol youi plugin will go a long way.
Il you aie willing to pioviue ueepei suppoit loi a plugin that you want to puLlish, theie
aie seveial gieat souice coue hosting sites that ollei seveial leatuies to assist in sup-
poiting youi plugin. See Recipe 12.1 loi a list ol the Lest places to host anu suppoit
youi plugin.
266 | Chapter 12:jQuery Plugins
Plan for participation from others
Lastly, think thiough anu gauge youi willingness to accept paiticipation liom otheis.
Paiticipation is a key component ol the open souice ecosystem, anu it is wise to com-
municate youi intention liom the moment you puLlish youi plugin. The attiaction ol
allowing paiticipation is that you can Lenelit liom the woik ol otheis. Plugins that
accept paiticipation liom otheis tenu to attiact auuitional useis, paitly Lecause ol
the appeaiance ol activity anu paitly Lecause active coue tenus to Le moie
tiustwoithy coue.
Communicating the path to paiticipation is key. Vhethei you intenu to oi not, any
piece ol coue that is puLlisheu tenus to attiact some soit ol paiticipation once useis
linu it. Having a plan to engage that paiticipation in an open anu puLlic way is essential.
One last woiu ol auvice: engaging paiticipation simply Ly puLlishing youi email au-
uiess anu allowing people to email you with comments anu guestions is geneially a Lau
iuea loi a couple ieasons. Fiist, email isn`t a puLlic loium that uisplays activity to
potential useis, anu seconu, it intiouuces you, the plugin authoi, as a Lottleneck to
integiating that activity Lack into the plugin.
12.3 Writing Your First jQuery Plugin
Problem
You`ve ueciueu that you want to wiite a jQueiy plugin. How uo you wiite a plugin in
jQueiy? Vhat Lest piactices shoulu you lollow?
Solution
jQueiy is uesigneu to make wiiting a plugin veiy simple anu stiaightloiwaiu. You can
extenu the existing jQueiy oLject Ly wiiting eithei methous oi lunctions. Simply ue-
claiing the lollowing ]avaSciipt altei inclusion ol the jQueiy coie liLiaiy will allow youi
coue to use youi new custom methou oi lunction.
Writing a custom jQuery method
jQueiy methous aie availaLle to Le chaineu anu thus can take auvantage ol jQueiy
selectois. jQueiy methous aie uelineu Ly extenuing the jQuery.fn oLject with youi
methou name. Because the jQueiy oLject must Le aLle to hanule multiple iesults, you
must wiap youi custom lunctionality insiue a call to the each() lunction to apply youi
coue to all ol the iesults:
jQuery.fn.goShop = function() {
return this.each(function() {
jQuery('body').append('<div>Purchase: ' + this.innerHTML + '</div>');
});
};
12.3 Writing Your First jQuery Plugin | 267
Accessing this new plugin is as simple as calling jQueiy like you noimally woulu anu
utilizing youi new methou name:
jQuery('p').goShop();
Writing a custom jQuery function
Functions aie attacheu to the main jQueiy oLject. Functions aie uesigneu to Le calleu
outsiue ol a jQueiy selection:
jQuery.checkout = function() {
jQuery('body').append('<h1>Checkout Successful</h1>');
};
This new lunction can Le manipulateu anu calleu noimally:
jQuery.checkout();
Discussion
Attaching new methous anu lunctions to the main jQueiy oLject aie a poweilul leatuie
ol jQueiy. Many ol the coie methous aie Luilt into the liLiaiy using this same technigue.
By leveiaging this existing lounuation in jQueiy, useis ol jQueiy anu useis ol youi
plugin have a last anu concise way to auu new lunctionality, extenu existing lunction-
ality, anu molu the jQueiy coue into whatevei loim suits them Lest. This llexiLility is
a key leatuie anu enaLles jQueiy anu its plugins to Le useu Ly a wiuei auuience.
The choice to extenu jQueiy via a new methou oi a lunction mainly uepenus on the
neeus ol the uevelopei. In geneial, locusing on extenuing jQueiy via auuing a new
methou is Lest Lecause this allows that new methou to Le chaineu along with othei
methous, anu it allows the coue in the methou to take auvantage ol jQueiy`s selectoi
engine.
12.4 Passing Options into Your Plugin
Problem
Youi liist plugin auus a methou to jQueiy. Howevei, theie aie a lew options that woulu
Le helplul to otheis il they weie exposeu piopeily. Vhat is the Lest methou ol passing
options into a custom methou?
Solution
Options aie Lest passeu into youi custom plugin methou via an options oLject. Using
a single options oLject to pass in paiameteis piomotes cleanei coue, is easiei to woik
with, anu pioviues llexiLility uown the ioau.
Vhen allowing options to Le utilizeu in youi plugin, it`s wise to pioviue sensiLle ue-
laults. Altei pioviuing sensiLle uelault options, it`s also impoitant that youi plugin
268 | Chapter 12:jQuery Plugins
pioviue a methou loi the usei ol the plugin to oveiiiue the uelaults. Both ol these goals
aie easily accomplisheu Ly ueclaiing a uelault options oLject, oveiiiuing the uelault
options with usei-supplieu options anu the jQueiy extend() methou, anu then utilizing
the options in youi coue:
jQuery.fn.pulse = function(options) {
// Merge passed options with defaults
var opts = jQuery.extend({}, jQuery.fn.pulse.defaults, options);
return this.each(function() {
// Pulse!
for(var i = 0;i<opts.pulses;i++) {
jQuery(this).fadeTo(opts.speed,opts.fadeLow).fadeTo(opts.speed,opts.fadeHigh);
}
// Reset to normal
jQuery(this).fadeTo(opts.speed,1);
});
};
// Pulse plugin default options
jQuery.fn.pulse.defaults = {
speed: "slow",
pulses: 2,
fadeLow: 0.2,
fadeHigh: 1
};
By specilying option uelaults, uevelopeis using youi plugin have the aLility to pioviue
as many oi as lew options when they call youi lunction. It is impoitant to place youi
options` uelaults altei you`ve uelineu youi plugin entiy methou; otheiwise, you will
encountei an eiioi:
// Override only one option
jQuery('p').pulse({pulses: 6});
// Override all options
jQuery('p').pulse({speed: "fast", pulses: 10, fadeLow: 0.3, fadeHigh: 0.8});
Lastly, Ly specilying youi options as an oLject attacheu as a chilu to youi plugin lunc-
tion, the uelault options may Le oveiiiuuen only once in a pioject. A uevelopei then
has the aLility to specily theii own set ol uelault options, minimizing the amount ol
coue ieguiieu to piouuce the uesiieu Lehavioi:
// Plugin code included above
// Reset pulse default options
jQuery.fn.pulse.defaults = {
speed: "fast",
pulses: 4,
fadeLow: 0.2,
fadeHigh: 1
};
12.4 Passing Options into Your Plugin | 269
// This call will use the new defaults
jQuery('p').pulse();
Discussion
Suppoiting options in youi plugin is a poweilul way to auu tiemenuous llexiLility to
the plugin. Plugins that suppoit a iich set ol options aie moie likely to lit the neeus ol
a wiuei auuience, peiloim a wiuei vaiiety ol tasks, anu geneially gain moie populaiity
than plugins that uon`t suppoit options.
Incluuing a set ol uelault options with youi plugin is anothei way to give uevelopeis
who use youi plugin llexiLility anu choice in how the plugin is implementeu. A hanuy
siue Lenelit is that the plugin can always iely on ceitain options Leing uelineu, ieuucing
the amount ol coue ieguiieu to check whethei an option has Leen passeu. This leaves
plugin useis with the aLility to oveiiiue a single option, multiple options, oi even all ol
the options eveiy time they call youi plugin. Lastly, Ly attaching the uelault options to
the jQueiy oLject, the options can Le oveiiiuuen gloLally, giving youi useis anothei
tool to leveiage in new anu cieative ways.
12.5 Using the $ Shortcut in Your Plugin
Problem
Othei ]avaSciipt liLiaiies make use ol the $ shoitcut. jQueiy itsell uses $ only as a
shoitcut, with the main oLject Leing nameu jQuery. How can you ensuie that youi
plugin maintains compatiLility with othei plugins anu liLiaiies?
Solution
jQueiy itsell uses the $ lunction as a custom alias loi the jQueiy oLject. Vhen jQueiy
is set into compatiLility moue, it passes Lack contiol ol the $ alias to the oiiginal liLiaiy
that uelineu it. Plugins can Le cialteu to use the same technigue.
By wiapping youi plugin in an anonymous lunction anu immeuiately executing that
lunction, the $ shoitcut is kept insiue the plugin. Coue outsiue ol the plugin can use
$ noimally. Insiue the plugin, $ will ieleience the jQueiy oLject as noimal:
;(function($) {
$.fn.pulse = function(options) {
// Merge passed options with defaults
var opts = $.extend({}, $.fn.pulse.defaults, options);
return this.each(function() {
// Pulse!
for(var i = 0;i<opts.pulses;i++) {
$(this).fadeTo(opts.speed,opts.fadeLow).fadeTo(opts.speed,opts.fadeHigh);
}
// Reset to normal
270 | Chapter 12:jQuery Plugins
$(this).fadeTo(opts.speed,1);
});
};
// Pulse plugin default options
$.fn.pulse.defaults = {
speed: "slow",
pulses: 2,
fadeLow: 0.2,
fadeHigh: 1
};
})(jQuery);
Discussion
Viapping youi uistiiLuteu coue in an anonymous lunction is a veiy stiaightloiwaiu
anu simple step that auus seveial leatuies anu ensuies that youi plugin coue can play
nicei in the wiuei woilu that youi useis may live within.
Auuing a semicolon at the Leginning ol youi lunction uelinition helps piotect against
anothei uevelopei who may have loigotten to incluue an enuing semicolon in theii
liLiaiy. The ]avaSciipt language Lieaks statements on newline Ly uelault, Lut many
useis take auvantage ol minimization tools that compiess the entiie set ol ]avaSciipt
in theii piojects into a single lile. This piocess iemoves the line enuings anu can cause
eiiois il youi coue lollows immeuiately altei. Auuing the initial semicolon is a guick
anu easy tiick to piotect against that possiLility.
The open paienthesis immeuiately Legins the anonymous lunction uelinition. Vithin
oui anonymous lunction, we ueline a lunction that passes the vaiiaLle that we want to
use in place ol the lully nameu jQueiy oLject. In this case, we want to take auvantage
ol using $ as the vaiiaLle. Delining an auuitional lunction is ieguiieu Lecause ol the
way the ]avaSciipt language hanules scoping. In moie tiauitional languages such as
]ava anu C--, scope is limiteu to the Llock statement. In ]avaSciipt, scope is wiappeu
in lunctions. Theieloie, the ieason loi using a lunction heie is ieally to set up a scope
Lounuaiy that we can ueline oui plugin within.
Vhat lollows is a new veision ol oui plugin, with the sole change ol swapping out the
way we utilize the jQueiy oLject. Because we`ve wiappeu this plugin anonymously anu
limiteu the scope ol the $ vaiiaLle, we can now use $ lieely without conllict liom any
othei coue.
The last line wiaps up the scoping lunction anu anonymous lunction with a close
Liacket anu close paienthesis, iespectively. The last Lit is what actually calls oui anon-
ymous lunction immeuiately altei it has Leen uelineu. This is wheie we tell oui lunction
to pass in the jQueiy oLject, which is what gets ienameu to $ within oui lunction.
Lastly, we close oll oui new statement with a semicolon to piotect against ]avaSciipt
minimization anu compiession eiiois.
12.5 Using the $ Shortcut in Your Plugin | 271
The $ shoitcut can Le incieuiLly uselul in wiiting ]avaSciipt coue. It cuts uown on coue
size, piomotes goou coue uesign, anu has Lecome extiemely populai anu well known.
Thus, many liLiaiies take auvantage ol the $ shoitcut, tying it into theii own context.
Vith each liLiaiy suppoiting theii own veision ol the $ shoitcut, conllicts can easily
aiise. By wiapping youi plugin coue within an anonymous lunction, you can ensuie
that youi plugin maintains a level ol scope aiounu usage ol the $ shoitcut that will
ieuuce the potential loi conllicts with othei ]avaSciipt liLiaiies.
One auuitional siue ellect ol wiapping youi plugin in an anonymous lunction, as
uesciiLeu eailiei, is that a closuie is cieateu. Utilizing a closuie in ]avaSciipt aius in
piopeily namespacing any methous oi vaiiaLles that you may neeu to ueline, luithei
ieuucing the chance loi vaiiaLle names oi lunction names to conllict with othei coue.
12.6 Including Private Functions in Your Plugin
Problem
Youi plugin coue is giowing anu neeus to Le oiganizeu. How can you implement a
piivate methou that`s unavailaLle to coue outsiue youi plugin?
Solution
By utilizing the plugin uesign pattein staiteu in Recipe 12.+, piivate lunctions may Le
uelineu noimally within the anonymous lunction that we`ve wiappeu oui plugin in.
Because the lunction is encloseu in an anonymous lunction, outsiue coue won`t see oui
piivate methou. Coue outsiue will only Le aLle to see lunctions oi methous that aie
attacheu to the jQueiy oLject.
;(function($) {
$.fn.pulse = function(options) {
// Merge passed options with defaults
var opts = $.extend({}, $.fn.pulse.defaults, options);
return this.each(function() {
doPulse($(this),opts);
});
};
function doPulse($obj,opts) {
for(var i = 0;i<opts.pulses;i++) {
$obj.fadeTo(opts.speed,opts.fadeLow).fadeTo(opts.speed,opts.fadeHigh);
}
// Reset to normal
$obj.fadeTo(opts.speed,1);
}
272 | Chapter 12:jQuery Plugins
// Pulse plugin default options
$.fn.pulse.defaults = {
speed: "slow",
pulses: 2,
fadeLow: 0.2,
fadeHigh: 1
};
})(jQuery);
Discussion
Because we now have oui plugin wiappeu in an anonymous lunction, uelining piivate
lunctions within oui plugin is as simple as auuing a new lunction as you noimally
woulu.
Giouping anu oiganizing youi plugin with puLlic anu piivate methous olleis many
auvantages to youi useis anu to the plugin authoi. As youi plugin matuies anu you
ieceive leeuLack liom the community, you can leveiage the use ol puLlic anu piivate
methous to pioviue a consistent API Letween plugin veisions. The consistency ol youi
API can Le a majoi lactoi in youi plugin`s success.
The aLility to Lieak coue uown into piivate anu puLlic messages also has signilicant
auvantages in coue oiganization as youi plugin giows. Vell-oiganizeu coue is easiei to
ieau, to maintain, anu to test. Vell-testeu, clean coue can leau to less eiioi-pione coue.
12.7 Supporting the Metadata Plugin
Problem
Seveial plugins utilize the metauata plugin to pass custom options into theii methous.
How can integiation with the metauata plugin Le constiucteu?
Solution
Leveiaging the metauata plugin is as simple as checking whethei the plugin is availaLle
anu then extenuing youi plugin options with the metauata paiameteis. Using this
technigue, you can supply uelault options when making the call to youi plugin anu
oveiiiue those uelault options loi each oLject to Le opeiateu on thiough the metauata
wiitten into the maikup:
<!-- Include the metadata plugin -->
<script type="text/javascript" src="metadata/jquery.metadata.js"></script>
<!-- Example of markup containing metadata -->
<p class="{pulses: 8, speed: 'slow'}">Starship Enterprise</p>
<p>Battlestar Galactica</p>
<p class="{speed: 100}">Serenity</p>
;(function($) {
12.7 Supporting the Metadata Plugin | 273
$.fn.pulse = function(options) {
// Merge passed options with defaults
var opts = $.extend({}, $.fn.pulse.defaults, options);
return this.each(function() {
// Merge in the metadata elements for this specific node
var o = $.metadata ? $.extend({}, opts, $.metadata.get(this)) : opts;
doPulse($(this),o);
});
};
function doPulse($obj,opts) {
for(var i = 0;i<opts.pulses;i++) {
$obj.fadeTo(opts.speed,opts.fadeLow).fadeTo(opts.speed,opts.fadeHigh);
}
// Reset to normal
$obj.fadeTo(opts.speed,1);
}
// Pulse plugin default options
$.fn.pulse.defaults = {
speed: "slow",
pulses: 2,
fadeLow: 0.2,
fadeHigh: 1
};
})(jQuery);
Discussion
Incluuing the metauata plugin is a gieat example ol how jQueiy plugins can Luilu oll
ol one anothei. The jQueiy plugin ecosystem is vast, anu chances aie theie aie othei
plugins that you can utilize.
To incluue anu use the metauata plugin, you liist must actually incluue it into youi
sciipt. The metauata plugin is hosteu along with jQueiy at Google Coue. The metauata
plugin woiks Ly allowing you to emLeu auuitional uata into youi HTML, while still
piouucing valiu HTML. Ve take auvantage ol this Ly allowing useis to emLeu element-
specilic options into the class element ol the items we can opeiate on.
The options aie emLeuueu into the HTML using stanuaiu ]SON. All ol the options
may Le emLeuueu, oi none may Le emLeuueu; it`s up to youi useis. Theie aie seveial
othei methous anu options loi using the metauata plugin that aie uesciiLeu on its
uocumentation page.
Vithin oui plugin, we liist check to see whethei a usei has incluueu the metauata
plugin. This is uone to ensuie that we keep this auuitional leatuie optional anu to
pioviue Lackwaiu compatiLility, il necessaiy. Because the metauata plugin opeiates on
a single element, we split up how we hanule options. The liist step is to use the options
274 | Chapter 12:jQuery Plugins
pioviueu when the plugin was calleu. These options aie extenueu with oui uelault
options, cieating oui staiting point loi this liist instantiation ol oui plugin. The seconu
step is to extenu those locally uelault options with the metauata that may Le uelineu
loi each element. All that is ieguiieu is loi us to extenu oui locally uelault options with
the metauata options, il the metauata plugin exists.
The metauata plugin pioviues anothei option loi useis ol youi plugin to pass in options.
Pioviuing options to potential useis is a gieat way to show that you aie committeu to
youi plugin, Leing a goou citizen ol the jQueiy ecosystem. The metauata plugin is also
a gieat way to ollei youi useis the aLility to wiite less coue Ly emLeuuing custom
options into the HTML elements.
12.8 Adding a Static Function to Your Plugin
Problem
In auuition to making youi plugin availaLle thiough the jQueiy lunction, you want to
expose a static lunction. How can you auu a static lunction to youi jQueiy plugin?
Solution
Auuing a static methou to youi plugin ieguiies extenuing the jQueiy oLject in much
the same way you woulu auu a methou. The uilleience is simply that lunctions aie
calleu without using jQueiy selectois:
;(function($) {
$.fn.pulse = function(options) {
// Merge passed options with defaults
var opts = $.extend({}, $.fn.pulse.defaults, options);
return this.each(function() {
// Merge in the metadata elements for this specific node
var o = $.metadata ? $.extend({}, opts, $.metadata.get(this)) : opts;
doPulse($(this),o);
});
};
function doPulse($obj,opts) {
for(var i = 0;i<opts.pulses;i++) {
$obj.fadeTo(opts.speed,opts.fadeLow).fadeTo(opts.speed,opts.fadeHigh);
}
// Reset to normal
$obj.fadeTo(opts.speed,1);
}
// Define our base to add to
$.pulse = {};
12.8 Adding a Static Function to Your Plugin | 275
// Static Function
$.pulse.impulse = function($obj) {
var opts = {
speed: 2500,
pulses: 10,
fadeLow: 0.2,
fadeHigh: 0.8
};
doPulse($obj,opts);
}
// Static Function
$.pulse.warpspeed = function($obj) {
var opts = {
speed: 25,
pulses: 100,
fadeLow: 0.2,
fadeHigh: 0.8
};
doPulse($obj,opts);
}
// Pulse plugin default options
$.fn.pulse.defaults = {
speed: "slow",
pulses: 2,
fadeLow: 0.2,
fadeHigh: 1
};
})(jQuery);
Calling the static methous availaLle in youi plugin is veiy stiaightloiwaiu, ieguiiing
only that you explicitly pass a valiu oLject to opeiate on:
// Call the impulse method on the first element returned
jQuery.pulse.impulse(jQuery('p:first'));
// Call the warpspeed method on the first element returned
jQuery.pulse.impulse(jQuery('p:first'));
Discussion
Auuing a static lunction within the scope ol youi plugin only ieguiies auuing a way loi
coue outsiue ol youi plugin to call it. This is accomplisheu Ly attaching the lunctions
to the jQueiy oLject.
In the pievious example, we`ve auueu a namespace oLject to aiu in oiganizing oui coue
Lettei. Il all that youi plugin ieguiieu was a single static lunction, it woulu Le com-
pletely appiopiiate to expose youi static lunction without auuing a namespacing oL-
ject. Altei auuing oui namespace oLject, we simply ueline oui lunctions like noimal
anu attach them to the namespace oLject we cieateu. Doing this exposes oui lunction
276 | Chapter 12:jQuery Plugins
to the gloLal namespace, while allowing the contents ol the lunctions to access piivate
lunctions anu vaiiaLles.
Taking auvantage ol the static lunction is as simple as calling it using the jQueiy oLject
we attacheu it to. This lunction is calleu without utilizing jQueiy selectois, so in oiuei
to opeiate on a DOM element, that element must Le explicitly passeu to the lunction.
A static lunction attacheu to the jQueiy oLject is anothei example ol the llexiLility ol
the jQueiy liLiaiy. Youi entiie plugin coulu Le maue up ol auuing static lunctions that
simply extenu the jQueiy coie in inteiesting new ways. A static lunction coulu Le the
entiy point you pioviue to youi plugin, oi it coulu Le a simple shoitcut methou you`ve
lounu uselul that`s packageu in youi plugin in a way that makes it easiei to shaie with
othei uevelopeis. Vhatevei the neeu, static lunctions can Le a uselul anu poweilul tool
when Luiluing youi own jQueiy plugin.
12.9 Unit Testing Your Plugin with QUnit
Problem
You want to iaise the guality anu ieliaLility ol youi jQueiy plugin Ly cieating unit tests
loi it. How uo you wiite anu ship tests with youi jQueiy plugin?
Solution
The easiest methou to wiite unit tests loi a jQueiy plugin is to utilize QUnit, the same
unit testing liamewoik that the jQueiy pioject uses. Vith QUnit, you can wiite youi
tests iight in ]avaSciipt anu ship them with youi plugin loi youi useis to iun in theii
own Liowseis:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="metadata/jquery.metadata.js"></script>
<script type="text/javascript" src="jquery.pulse.js"></script>
<link rel="stylesheet"
href="http://jqueryjs.googlecode.com/svn/trunk/qunit/testsuite.css" type="text/css"
media="screen" />
<script type="text/javascript"
src="http://jqueryjs.googlecode.com/svn/trunk/qunit/testrunner.js"></script>
</head>
<body>
<script type="text/javascript">
module("Testing the jQuery Pulse Plugin");
test("Test Pulse with basic options", function() {
$("div.starship").pulse();
12.9 Unit Testing Your Plugin with QUnit | 277
equals($("#enterprise").css("opacity"),1,"The element should be visible");
equals($("#galactica").css("opacity"),1,"The element should be visible");
});
test("Test Impulse", function() {
$.pulse.impulse($("#galactica"));
equals($("#galactica").css("opacity"),1,"The element should be visible");
});
test("Test Warp Speed", function() {
$.pulse.warpspeed($("#enterprise"));
equals($("#enterprise").css("opacity"),1,"The element should be visible");
});
</script>
<div id="main">
<div class="starship" id="enterprise">USS Enterprise - NC-1701-A</div>
<div class="starship" id="galactica">Battlestar Galactica</div>
</div>
</body>
</html>
Discussion
Leaining how to ellectively test coue is Leyonu the scope ol this chaptei. The tests
wiitten in the pievious example aie intenueu to simply show an example ol what can
Le uone with unit testing. Chaptei 1S goes into gieat uetail aLout unit testing anu
specilically the QUnit liamewoik. Foi a uiscussion on how to use QUnit, what types
ol things you can test, anu how to ellectively test youi coue, please ielei to that chaptei.
Shipping unit tests with youi plugin is anothei gieat way to show uevelopeis you aie
committeu to the success anu staLility ol the coue that you puLlish. This Luilus tiust
with youi usei Lase anu shows that youi plugin is a goou memLei ol the jQueiy plugin
ecosystem. Tests also make it easy loi useis ol youi plugins to linu Lugs that can cieep
up in anothei iuntime enviionment, such as a uilleient Liowsei. This allows you, the
plugin authoi, to Lettei auuiess the Lug that was lounu Ly having a woiking test Leu,
allowing you, the plugin uevelopei, to uiiectly auuiess the Lug that was lounu.
278 | Chapter 12:jQuery Plugins
CHAPTER 13
Interface Components from Scratch
Nathan Smith
13.0 Introduction
Vhile the ollicial jQueiy UI wiuget collection olleis a wealth ol ieauy-maue lunction-
ality, liom time to time you might choose to cieate a customizeu element that meets a
specilic neeu. Peihaps you uesiie gieatei contiol ovei the HTML maikup oi simply
want to keep youi ]avaSciipt coue Lase lightei. MayLe you aie looking to Luilu some-
thing not alieauy coveieu Ly existing solutions. Vhatevei the ieason, this chaptei will
show you how to teisely wiite customizeu components loi youi piojects. These iecipes
have Leen wiitten with ease ol use in minu, lavoiing simplicity ovei conliguiation.
Recipe 13.1 will show you how to cieate custom tool tips, loi occasions wheie you neeu
to uiiect the usei`s attention via pioviuing auuitional content oi instiuction. Rec-
ipe 13.2 will explain how to Luilu a lile tieestyle menu, allowing the usei to uiill uown
anu exploie the uepth ol a site hieiaichy. In Recipe 13.3 you will leain how to cieate a
veitically loluing accoiuion. Recipe 13.+ will explain how to use inteipage links anu
theii iespective taigets to cieate uocument taLs. Recipe 13.5 shows how to cieate a
Lasic moual winuow via appiopiiate action. Recipe 13.6 explains how to Luilu a simple
uiop-uown menu. Recipe 13.7 uelves into the cieation ol an image iotatoi that can Le
contiolleu via Luttons, ieusing the inteipage link technigue liom Recipe 13.+. Rec-
ipe 13.S takes lessons leaineu liom Recipe 13.3, cieating hoiizontal panels insteau ol
a veitical accoiuion.
The lollowing paiauigms aie useu thioughout this chaptei anu will not
Le calleu out specilically loi each example.
Each iecipe Legins Ly checking whethei the necessaiy element actually exists in the
uocument. Il not, then we exit the lunction. Theie is no neeu to go any luithei il that
ciiteiion is not met, anu this keeps coue liom executing unnecessaiily:
279
// Does element exist?
if (!$('#foobar').length) {
// If not, exit.
return;
}
A snippet ol geneiic coue is useu thioughout to cancel the lollowing links that only
seive to tiiggei ]avaSciipt events. The blur() methou is applieu to get iiu ol uotteu
Loiueis that woulu otheiwise Le peimanent (until the usei clickeu something new),
anu return false tells the Liowsei not to lollow the link`s href:
// Nofollow.
this.blur();
return false;
To actually kick oll the uynamic lunctionality, each iecipe enus with a call to jQueiy`s
document.ready() lunction, ensuiing that the DOM has linisheu loauing (Lut not nec-
essaiily all image assets) Leloie attempting to apply event listeneis anu so loith:
// Kick things off.
$(document).ready(function() {
init_foobar();
});
Some ol the iecipes have the lollowing Lit ol coue in the <head> ol the HTML uocument.
Foi the most pait, document.write() is consiueieu an antiguateu piactice in ]avaSciipt,
Lecause it loices the Liowsei to pause, ienueiing the page when it encounteis such a
commanu. Howevei, when piehiuing content with CSS that will latei Le shown via
]avaSciipt, this is cxact|y the outcome we want:
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
Essentially, Leloie the page even Legins to ienuei, a CSS lile is wiitten to the <head>
that piehiues all the content that will latei Le shown as the usei inteiacts with the page.
The ieason we wiite the CSS ieleience with ]avaSciipt is that with ]avaSciipt oll, all
the content is visiLle anu lully accessiLle. Foi moie on that technigue, ieau Petei-Paul
Koch`s Thiee ]avaSciipt aiticles anu one Lest piactice.
13.1 Creating Custom Tool Tips
Problem
Fiom time to time, a giaphical element oi inteilace aspect may neeu luithei claiilica-
tion, Lut Lecause ol iestiaints on space (oi loi the sake ol aesthetics), a uesignei might
not want to take up piecious scieen ieal estate Ly auuing explanatoiy text. In such a
case, theie is a neeu to pioviue a Lit ol guiuance to the usei, who woulu neeu it initially
280 | Chapter 13:Interface Components from Scratch
Lut whose neeu woulu uiminish as lamiliaiity with the inteilace giew. In such cases, a
tool tip makes loi an iueal solution. Howevei, HTML leaves us with scaice iesouices
to cieate a tool tip, anu olten the title="..." attiiLute uoes not cut it.
Tool tips can Le a goou solution loi usei inteilace claiilication, especially il tieu to some
soit ol uismissiLle usei pieleience (i.e., Don`t show me this again). Howevei, uy-
namic tool tips have olten Leen aLuseu, most notaLly on Llogs, wheie eveiy single
element on a page with a title="..." attiiLute causes a tool tip to appeai when the
mouse passes ovei it. Such cases shoulu Le avoiueu, Lecause il eveiything is tieateu as
a special case via a tool tip, then the impoitance is uiminisheu, anu in ieality nothing
on the page is emphasizeu. It is the eguivalent ol shouting eveiy single woiu in a
sentence. ]ust as with any weL pioject, the context ol the content shoulu uictate the
appioach, not vice veisa.
Solution
To solve this pioLlem, we can use jQueiy to get the mouse position within oui aiea ol
inteiest on the page anu then uynamically place a <div> element ollset liom the point
ol oiigin, which coulu contain instiuctions, auuitional inloimation (in the case ol
e-commeice), oi just aLout anything the uevelopei neeus to appeai. This woulu Le
uone Ly cieating a uynamically geneiateu <div> Leloie the close ol the </body> tag,
allowing it to have a highei z-inuex than the iest ol the page, which woulu look like
Figuie 13-1. Auuitionally, just to Le suie the tool tip takes pieceuence, it is explicitly
given an extiemely high z-inuex ol 9999.
Iigurc 13-1. A too| tip gcncratcd with jQucry
Tool tipHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Creating Custom Tooltips</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="tooltip.css" />
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="tooltip.js"></script>
</head>
13.1 Creating Custom Tool Tips | 281
<body>
<div id="container">
<p>
<span class="tooltip" title="This is my title. There are many like it, but
this one is mine. You will see it as you hover your mouse over me.">
Mouse over me to read my title in a tooltip!
</span>
</p>
<p>
<span class="tooltip" title="This is more content that will appear in a
tooltip. Don't be alarmed, because this is only a test of a tooltip.">
Guess what? I have a tooltip too. Please read it.
</span>
</p>
</div>
</body>
</html>
Tool tipjQuery code
// Initialize.
function init_tooltip() {
// Does element exist?
if (!$('.tooltip').length) {
// If not, exit.
return;
}
// Insert tool tip (hidden).
$('body').append('<div id="tooltip_outer"><div id="tooltip_inner"></div></div>');
// Empty variables.
var $tt_title, $tt_alt;
var $tt = $('#tooltip_outer');
var $tt_i = $('#tooltip_inner');
// Watch for hover.
$('.tooltip').hover(function() {
// Store title, empty it.
if ($(this).attr('title')) {
$tt_title = $(this).attr('title');
$(this).attr('title', '');
}
// Store alt, empty it.
if ($(this).attr('alt')) {
$tt_alt = $(this).attr('alt');
$(this).attr('alt', '');
}
// Insert text.
282 | Chapter 13:Interface Components from Scratch
$tt_i.html($tt_title);
// Show tool tip.
$tt.show();
},
function() {
// Hide tool tip.
$tt.hide();
// Empty text.
$tt_i.html('');
// Fix title.
if ($tt_title) {
$(this).attr('title', $tt_title);
}
// Fix alt.
if ($tt_alt) {
$(this).attr('alt', $tt_alt);
}
// Watch for movement.
}).mousemove(function(ev) {
// Event coordinates.
var $ev_x = ev.pageX;
var $ev_y = ev.pageY;
// Tool tip coordinates.
var $tt_x = $tt.outerWidth();
var $tt_y = $tt.outerHeight();
// Body coordinates.
var $bd_x = $('body').outerWidth();
var $bd_y = $('body').outerHeight();
// Move tool tip.
$tt.css({
'top': $ev_y + $tt_y > $bd_y ? $ev_y $tt_y : $ev_y,
'left': $ev_x + $tt_x + 20 > $bd_x ? $ev_x $tt_x 10 : $ev_x + 15
});
});
}
// Kick things off.
$(document).ready(function() {
init_tooltip();
});
13.1 Creating Custom Tool Tips | 283
Discussion
It is woith mentioning that $('.tooltip') is not the most peiloimant way to ietiieve
elements. Foi the sake ol this uemo, all tags on the page aie Leing paiseu, which is the
eguivalent ol document.getElementsByTagName('*'). Depenuing on the size ol the uocu-
ment, anu uepenuing on the Liowsei, this can Le guite slow. So, when actually em-
ploying this coue, Le suie to specily which tags you aie looking loi. Foi example, you
woulu use $('a.tooltip, span.tooltip') insteau ol just $('.tooltip'). Vhile moie
mouein Liowseis will map such class selectois to getElementsByClassName oi
querySelectorAll (il availaLle), oluei Liowseis have to liist iteiate thiough tag names
anu then ueteimine whethei the ielevant class is piesent.
Assuming that one oi moie elements exist that match class="tooltip", we appenu the
uynamic maikup at the enu ol the page, iight Leloie the close ol the Louy. It uoes not
yet appeai anywheie visiLly, Lecause in the CSS lile we have applieu display: none to
the #tooltip_outer ID.
Next, we cieate empty vaiiaLles calleu $tt_title anu $tt_alt. These will Le useu to
tempoiaiily stoie the title anu alt (il it exists) attiiLutes ol oui matcheu class="tool
tip" elements. The astute ieauei might wonuei, Aien`t we just inteiesteu in the
title attiiLute? Vhy woiiy aLout alt? Goou guestion. Ve stoie the alt attiiLute in
auuition to the title, just in case class="tooltip" is useu on an image. Inteinet Ex-
ploiei causes its own tool tip to appeai showing the alt contents, anu we uon`t
want that.
The iest ol the coue ueals with class="tooltip" elements. Vhen one such element is
hoveieu ovei with the mouse, we stoie the contents ol the title anu (possiLly) alt
attiiLutes anu then zeio them out Ly setting each one egual to an empty text stiing.
This way, theie is no Liowsei uelault tool tip inteileiing with oui custom one. The
contents ol the title attiiLute aie copieu to #tooltip_inner, anu then the
#tooltip_outer is shown.
Likewise, when the mouse leaves the taiget element, we want to unuo what happeneu
when it was it liist enteieu. The #tooltip is hiuuen, the #tooltip_inner content is set
to an empty stiing, anu the title anu alt attiiLutes aie iestoieu to theii oiiginal values.
Lastly, the .mousemove() methou monitois mouse movement once it has enteieu the
Lounuaiies ol a class="tooltip" element. The tool tip is ollset ielative to the mouse
position, appeaiing to the iight siue ol the cuisoi; that is, unless the tool tip is uangei-
ously close to extenuing Leyonu the wiuth ol the Liowsei. In such a case, a hoiizontal
scioll Lai woulu appeai, anu we uo not want that. To solve this snalu, we have a Lit ol
logic that llips the tool tip to the lelt siue ol the cuisoi. The same is tiue veitically. Il
the tool tip is too lai at the Lottom ol a page, it will llip itsell to Le aLove the mouse
cuisoi.
284 | Chapter 13:Interface Components from Scratch
13.2 Navigating with a File-Tree Expander
Problem
On content-heavy sites with multiple tieis ol inloimation aichitectuie, occasionally a
neeu aiises to piesent seveial levels ol nesteu uata. Il all ol the inlo was piesenteu in its
entiiety, it woulu Le too unwieluy to Le uselul anu woulu take up too much veitical
space on a page. Entei the lile-tiee paiauigm. This lunctionality, seen most notaLly in
the uesktop UI ol Vinuows Exploiei (not to Le conluseu with Inteinet Exploiei), al-
lows a usei to expanu anu compact layeis ol uiiectoiies.
Solution
By using jQueiy`s uescenuant selectois on nesteu unoiueieu lists, we can hiue/show
auuitional poitions ol a tiee stiuctuie, as neeueu. This is uone Ly auuing
class="tree" to the top-level unoiueieu list anu using a comLination ol CSS anu ]ava-
Sciipt to unveil its suLlevels, piouucing a tiee like that in Figuie 13-2. Auuitionally, we
make use ol event uelegation to suppoit numeious tieis without the oveiheau ol at-
taching event listeneis to multiple elements. Insteau, the event is captuieu at the top
level ol the <ul class="tree"> via jQueiy`s .live() methou.
Iigurc 13-2. Prcscnting nu|tip|c |cvc|s oj data through a ji|c trcc
File treeHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
13.2 Navigating with a File-Tree Expander | 285
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Navigating a File Tree Expander</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="tree.css" />
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="tree.js"></script>
</head>
<body>
<div id="container">
<p class="tree_controls">
<a href="#" class="expand_all">Expand all</a> ~
<a href="#" class="collapse_all">Collapse all</a>
</p>
<ul class="tree">
<li>
<a href="#" class="tree_trigger">&nbsp;</a> Primary
<ul class="tree_expanded">
<li>
<a href="#" class="tree_trigger">&nbsp;</a> Secondary
<ul class="tree_expanded">
<li>
<a href="#" class="tree_trigger">&nbsp;</a> Tertiary
<ul>
<li>
<span class="tree_slug">&nbsp;</span> Quaternary
</li>
<li>
<span class="tree_slug">&nbsp;</span> Quaternary
</li>
<li>
<span class="tree_slug">&nbsp;</span> Quaternary
</li>
<li>
<span class="tree_slug">&nbsp;</span> Quaternary
</li>
<li>
<span class="tree_slug">&nbsp;</span> Quaternary
</li>
</ul>
...
</li>
...
</ul>
...
</li>
...
</ul>
...
286 | Chapter 13:Interface Components from Scratch
</li>
...
</ul>
</div>
...
</body>
</html>
File treejQuery code
// Initialize.
function init_tree() {
// Does element exist?
if (!$('ul.tree').length) {
// If not, exit.
return;
}
// Expand and collapse.
$('p.tree_controls a.expand_all, p.tree_controls a.collapse_all').click(function() {
// Look at the class.
if ($(this).hasClass('expand_all')) {
$(this).parent('p').next('ul').find('a.tree_trigger')
.addClass('trigger_expanded')
.end().find('ul').addClass('tree_expanded');
return false;
} else {
$(this).parent('p').next('ul').find('a.tree_trigger')
.removeClass('trigger_expanded')
.end().find('ul').removeClass('tree_expanded');
}
// Nofollow.
this.blur();
return false;
});
// Listen for tree clicks.
$('ul.tree a.tree_trigger').live('click', function() {
// Is the next <ul> hidden?
if ($(this).next('ul').is(':hidden')) {
$(this).addClass('trigger_expanded').next('ul')
.addClass('tree_expanded');
} else {
$(this).removeClass('trigger_expanded').next('ul')
.removeClass('tree_expanded');
}
// Nofollow.
this.blur();
return false;
13.2 Navigating with a File-Tree Expander | 287
});
// Add class for last <li>.
$('ul.tree li:last-child').addClass('last');
// Change state of trigger.
$('ul.tree_expanded').prev('a').addClass('trigger_expanded');
}
// Kick things off.
$(document).ready(function() {
init_tree();
});
Discussion
The tiee coue Legins Ly attaching event hanuleis to links with class names ol
expand_all anu collapse_all. Il eithei link is clickeu, then we tiaveise the DOM up-
waiu to the paient <p>, ovei to the next <ul>, anu then uown into its chiluien. Each
chilu link with class="tree_trigger" ieceives the class ol trigger_expanded, anu each
suLseguent <ul> ieceives the class tree_expanded. These class names coiiesponu to the
CSS iules that change theii visual appeaiance. In the case ol the tiiggei links, they have
an expanueu icon. As loi the lists, they aie now display: block insteau ol
display: none.
The live event listenei listens loi clicks anywheie within the tiee. Basically, this listens
loi clicks anywheie within the <ul class="tree"> anu then ueteimines whethei the
click happeneu on a link with class="trigger". Il so, it executes the associateu coue.
The Lenelit ol using .live(), as opposeu to auuing a click hanulei uiiectly to each link,
is that the coue is associateu with all existing anu lutuie elements that match the ciiteiia.
The Lenelit ol this is twololu: you uon`t waste time attaching event listeneis to nu-
meious elements, anu il uynamic content is inseiteu via Ajax, it is allecteu Ly the live
event listenei as well.
Next, we auu a style hook ol class="last" via ]avaSciipt to each <li> that is the :last-
child ol its paient. This allows us to position a Lackgiounu image that simulates con-
nectivity thioughout the tiee, via a light giay line. Finally, il any chilu <ul> has Leen
haiu-coueu to Le visiLle when the page loaus via class="tree_expanded", we tiaveise
the DOM anu auu class="tree_trigger_expanded" to the neaiest tiiggei link.
13.3 Expanding an Accordion
Problem
The situation in which one might use an accoiuion coulu Le somewhat akin to when
a lile tiee might Le uselul. The paiauigms aie similai in that each one allows loi auui-
tional inloimation to Le initially oLscuieu liom view anu then ievealeu as the usei
288 | Chapter 13:Interface Components from Scratch
inteiacts luithei. They uillei, howevei, in that an accoiuion is not meant to contain an
entiie taxonomy ol uata Lut iathei is useu moie as a novelty to uiaw attention to seveial
lacets ol a site oi piouuct. One such accoiuion example can Le seen at http://www.app|c
.con/iphonc. This allows loi panels ol inlo to Le expanueu at the usei`s leisuie, without
completely uominating the veitical space allotteu to the siueLai. It conseives space not
unlike high-uensity shelving oi movaLle Lookcases in a liLiaiy, allowing one aisle to
seive seveial iacks ol stoiage veisus having an evei-piesent aisle Letween each one.
It is woith noting that theie is a jQueiy UI accoiuion wiuget that is highly customizaLle
anu can Le given a theme/skin to match the iest ol the UI wiugets. You can see it in
action at http://jqucryui.con/dcnos/accordion. The Lenelit ol using the ollicial wiuget
is that it is ollicially suppoiteu Ly the jQueiy UI community anu will continue to evolve
anu Lecome moie ioLust. The potential uiawLack is the amount ol extia coue ieguiieu,
il all you neeu is a simple accoiuion. On the llip siue, the ieason one might choose to
Luilu a custom accoiuion component is loi a smallei coue lootpiint. This comes at the
uisauvantages ol having the animation not Le pixel-peilect anu having to set the height
in pixels ol each accoiuion panel. It is auviseu that you consiuei Loth options anu uo
what Lest lits the pioject at hanu.
Solution
Using jQueiy`s excellent DOM tiaveisal capaLilities, namely, aujacent siLling selectois,
it is possiLle to wiite a sciipt geneiically enough to hanule multiple accoiuion elements.
Auuitionally, this sciipt is aLle to hanule moie elements Leing auueu to the accoiuion,
il neeu Le. Figuie 13-3 shows an accoiuion that hasn`t yet expanueu, while Fig-
uie 13-+ shows its contents, ievealeu Ly expanuing it.
Iigurc 13-3. Accordion, waiting jor thc uscr to cxpand
13.3 Expanding an Accordion | 289
Iigurc 13-1. Thc cxpandcd accordion
AccordionHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Expanding an Accordion</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="accordion.css" />
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="accordion.js"></script>
</head>
<body>
<div id="container">
<dl class="accordion">
<dt>
<a href="#"><span></span> Title goes here</a>
</dt>
<dd>
<p>
Lorem ipsum...
</p>
</dd>
<dt>
290 | Chapter 13:Interface Components from Scratch
<a href="#"><span></span> Title goes here</a>
</dt>
<dd>
<p>
Lorem ipsum...
</p>
</dd>
<dt>
<a href="#"><span></span> Title goes here</a>
</dt>
<dd>
<p>
Lorem ipsum...
</p>
</dd>
</dl>
...
</div>
</body>
</html>
AccordionjQuery code
// Initialize.
function init_accordion() {
// Does element exist?
if (!$('dl.accordion').length) {
// If not, exit.
return;
}
// Gather all accordions.
$('dl.accordion').each(function() {
// Reveal first accordion item.
$(this).find('dt:first a').addClass('accordion_expanded')
.end().find('dd:first').show();
// Added to round corners via CSS.
$(this).find('dt:last').addClass('last');
});
// Event listener for click.
$('dl.accordion dt a').click(function() {
// Get parent <dl>.
var $dl = $(this).parents('dl:first');
// Get the next <dd>.
var $dd = $(this).parent('dt').next('dd');
// Class final <dt>.
function findLast() {
13.3 Expanding an Accordion | 291
if ($dl.find('dd:last').is(':hidden')) {
$dl.find('dt:last').addClass('last');
}
}
// Is it visible?
if ($dd.is(':hidden')) {
// Expand the <dd>, hide others.
$dd.slideDown('fast').siblings('dd:visible').slideUp('fast', findLast);
// Change arrow state, remove class="last" from <dt>.
$(this).addClass('accordion_expanded').parent('dt')
.removeClass('last').siblings('dt').find('a')
.removeClass('accordion_expanded');
}
// Nofollow.
this.blur();
return false;
});
}
// Kick things off.
$(document).ready(function() {
init_accordion();
});
Discussion
This lunction Legins Ly linuing all uelinition lists with the class ol accordion anu ap-
plying jQueiy`s .each() methou to them. Insiue each one, the liist <dt> link is given
the class accordion_expanded, anu the liist <dd> is shown (the iest iemain hiuuen Le-
cause ol CSS display: none). Auuitionally, the last <dt> is given class="last", allowing
us to style it uniguely with iounueu coineis loi those Liowseis that suppoit it. This
uilleis liom the lile-tiee example, in which we patcheu Liowseis that lackeu :last-
child. In the case ol the accoiuion, class="last" will Le iemoveu anu ieapplieu Laseu
on usei inteiaction.
The seconu pait ol the coue hanules the ciux ol the accoiuion. All links that iesiue
insiue the accoiuion`s <dt> aie given a click event listenei. Vhen any ol these links is
clickeu, we tiaveise the DOM upwaiu to the paient <dt> anu then ovei to the next
<dd>. Il that <dd> is hiuuen, then we animate it into place via jQueiy`s .slideDown()
methou, while simultaneously calling .slideUp() on all the othei siLling <dd>. Vhen
this is completeu, the callLack lunction findLast is executeu, which ueteimines wheth-
ei to assign class="last" to the last visiLle <dt>, uepenuing on whethei its accompa-
nying <dd> is hiuuen.
Il that last <dd> is visiLle, then no action is taken, Lecause the <dd> itsell is Leing iounueu
via CSS, taigeteu via :last-child. Again, the astute ieauei may wonuei, Vhy aie we
not patching Inteinet Exploiei 6 anu 7, since they uon`t unueistanu :last-child? The
292 | Chapter 13:Interface Components from Scratch
ieason is, while IE 6 anu 7 uon`t suppoit :last-child, neithei uo they suppoit iounueu
coineis via CSS, so in this case theie is nothing to Le gaineu.
Finally, the class ol accordion_expanded is auueu to the <dt> link that was clickeu, anu
that class is iemoveu liom all othei <dt> links. This causes the aiiows in each <dt> to
all point to the iight, inuicating that they aie collapseu, with the exception ol the most
iecently clickeu <dt> link.
13.4 Tabbing Through a Document
Problem
You might have a page that has guite a Lit ol uata that all Lelongs togethei Lecause ol
site aichitectuie, as opposeu to sepaiating it into uistinct pages. In such a case, insteau
ol simply having a lengthy uocument with heauings anu paiagiaphs, a taLLeu inteilace
olten makes Lettei sense. In this case, the taLs woik as one might expect a uesktop
application to lunction. Insteau ol leaving the page that you aie on, the ielevant inloi-
mation associateu with each taL is Liought to the loieliont, as shown in Figuie 13-5.
One such example ol this type ol lunctionality is the Yahoo! home page.
Solution
By giaLLing the href="..." ol an inteipage anchoi link, we can use jQueiy to then linu
the ID ol the taiget, hiue its siLlings, anu Liing the taiget element into the loiegiounu.
This is Ly lai one ol the simplei applications ol jQueiy yet can Le useu to gieat ellect.
Iigurc 13-5. Using tabs to hc|p uscrs navigatc injornation
TabsHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
13.4 Tabbing Through a Document | 293
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Tabbing Through a Document</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="tabs.css" />
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="tabs.js"></script>
</head>
<body>
<div id="container">
<ul class="tabs">
<li>
<a href="#tab_content_primary_01" class="current">Tab Link 01</a>
</li>
<li>
<a href="#tab_content_primary_02">Tab Link 02</a>
</li>
<li>
<a href="#tab_content_primary_03">Tab Link 03</a>
</li>
<li>
<a href="#tab_content_primary_04">Tab Link 04</a>
</li>
<li>
<a href="#tab_content_primary_05">Tab Link 05</a>
</li>
</ul>
<div class="tab_content_wrap">
<div id="tab_content_primary_01" class="tab_content">
<p>
<strong>Content Area 01</strong>
</p>
<p>
Lorem ipsum...
</p>
</div>
<div id="tab_content_primary_02" class="tab_content">
<p>
<strong>Content Area 02</strong>
</p>
<p>
Duis ultricies ante...
</p>
</div>
<div id="tab_content_primary_03" class="tab_content">
<p>
<strong>Content Area 03</strong>
</p>
<p>
Morbi fringilla...
294 | Chapter 13:Interface Components from Scratch
</p>
</div>
<div id="tab_content_primary_04" class="tab_content">
<p>
<strong>Content Area 04</strong>
</p>
<p>
Sed tempor...
</p>
</div>
<div id="tab_content_primary_05" class="tab_content">
<p>
<strong>Content Area 05</strong>
</p>
<p>
Nulla facilisi...
</p>
</div>
</div>
...
</div>
</body>
</html>
TabsjQuery code
// Initialize.
function init_tabs() {
// Does element exist?
if (!$('ul.tabs').length) {
// If not, exit.
return;
}
// Reveal initial content area(s).
$('div.tab_content_wrap').each(function() {
$(this).find('div.tab_content:first').show();
});
// Listen for click on tabs.
$('ul.tabs a').click(function() {
// If not current tab.
if (!$(this).hasClass('current')) {
// Change the current indicator.
$(this).addClass('current').parent('li').siblings('li')
.find('a.current').removeClass('current');
// Show target, hide others.
$($(this).attr('href')).show().siblings('div.tab_content').hide();
}
13.4 Tabbing Through a Document | 295
// Nofollow.
this.blur();
return false;
});
}
// Kick things off.
$(document).ready(function() {
init_tabs();
});
Discussion
Vhen the lunction iuns initially, the liist taLLeu content aiea is ievealeu, while the iest
iemain hiuuen Lecause ol the display: none style iule in oui preload.css lile.
Beyonu that, all we have to uo is listen loi any link within <ul class="tabs"> to Le
clickeu. Il it uoesn`t alieauy have class="current", then we know its content is oL-
scuieu, so we auu class="current" to the clickeu link anu iemove it liom any siLling
taLs that might have it. Next, we giaL the href="..." oi the clickeu link, which points
to an ID in the same page, anu we ieveal that element via jQueiy`s .show() methou,
while simultaneously hiuing any siLling taLLeu content aieas that might Le visiLle.
Note that il you want enhanceu lunctionality, such as liiing custom events when taL
states change oi loauing iemote content via Ajax, Le suie to check out the ollicial jQueiy
UI TaL wiuget.
13.5 Displaying a Simple Modal Window
Problem
Vith the pievalence ol pop-up Llocking leatuies Leing incluueu in most Liowseis, gone
aie the uays ol Leing aLle to ieliaLly use window.open() to cieate a uialog Lox. Insteau,
a much moie populai anu usaLle solution is to cieate a moual oveilay within the cuiient
page, which will take visual pieceuence until the usei inteiacts with oi uismisses it.
It is woith noting that theie is a jQueiy UI uialog wiuget that is highly customizaLle
anu can Le given a theme/skin to match the iest ol the UI wiugets. You can see it in
action at http://jqucryui.con/dcnos/dia|og.The Lenelit ol using the ollicial wiuget is that
it is ollicially suppoiteu Ly the jQueiy UI community anu will continue to evolve anu
Lecome moie ioLust. The potential uiawLack is the amount ol extia coue ieguiieu, il
all you neeu is a simple moual. On the llip siue, the ieason one might choose to Luilu
a custom moual component is loi a smallei coue lootpiint. It is auviseu that you con-
siuei Loth options anu uo what Lest lits the pioject at hanu.
296 | Chapter 13:Interface Components from Scratch
Il you want an even moie ioLust solution, one paiticulaily geaieu to-
waiu showing a wiue vaiiety ol content anu paiticulaily well suiteu to
image galleiies, look no luithei than ThickBox. It is a populai jQueiy
auu-on wiitten Ly Couy Linuley (one ol the coauthois ol this Look).
You can see it in action at http://jqucry.con/dcno/thic|box/.
Solution
Using jQueiy, we can easily linu the wiuth anu height ol the Liowsei viewpoit anu
cieate a uimmeu layei to sit atop the entiie site uesign. Using CSS positioning, we can
then place oui moual winuow (which in lact is simply a <div> layei) liont anu centei
to uiaw the usei`s attention to it, as shown in Figuie 13-6. Vaiious types ol content can
Le uisplayeu, incluuing images, Ajax-loaueu HTML liagments, anu in-page maikup.
Iigurc 13-. A noda| window, crcatcd with jQucry
ModalHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
13.5 Displaying a Simple Modal Window | 297
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Displaying a Simple Modal Window</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="modal.css" />
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="modal.js"></script>
</head>
<body>
<div id="container">
<a href="#modal_anchor" class="modal">In-page</a>
| <a href="modal_markup.html#load_me" class="modal">Remote markup</a>
| <a href="modal_text.txt" class="modal">Remote text</a>
| <a href="../_common/photo_1.jpg" class="modal" title="Baltic Sea - Estonia">Image
file</a>.
<br />
<br />
<select><option>-- SHOULD BE OVERLAPPED IN IE6 --</option></select>
<br />
<br />
<div id="modal_anchor">
<p>
This content will be copied into the modal window, if its #anchor is targeted.
</p>
</div>
Lots of line breaks, to simulate scrolling content...
<br />
It's the end of the world, as we know it, and I feel fine.
</div>
</body>
</html>
ModaljQuery code
// Initialize.
function init_modal() {
// Does element exist?
if (!$('a.modal').length) {
// If not, exit.
return;
}
// Detect IE6 (boolean).
var $IE6 = typeof document.addEventListener !== 'function' && !window.XMLHttpRequest;
// Do some math.
function sizeModal() {
// Modal dimensions.
var $modal = $('#modal_window');
var $modal_width = $modal.outerWidth();
var $modal_height = $modal.outerHeight();
var $modal_top = '-' + Math.floor($modal_height / 2) + 'px';
298 | Chapter 13:Interface Components from Scratch
var $modal_left = '-' + Math.floor($modal_width / 2) + 'px';
// Set modal.
$('#modal_window').css('margin-top', $modal_top)
.css('margin-left', $modal_left);
}
/* For IE6. */
function positionModal() {
// Force modal into place.
$('#modal_wrapper').css('top', $(document).scrollTop() + 'px');
}
// Reveal the modal.
function showModal() {
if ($IE6) {
positionModal();
}
// Unveil the wrapper.
$('#modal_wrapper').show();
// Size it.
sizeModal();
// Reveal modal window.
$('#modal_window').css('visibility', 'visible').show();
// Resize as images load.
$('#modal_content img').each(function() {
$(this).load(function() {
$(this).removeClass('modal_placeholder').show();
sizeModal();
});
});
}
// Insert modal at end of </body>.
$('body').append('
<div id="modal_wrapper">
<!--[if IE 6]>
<iframe id="modal_iframe"></iframe>
<![endif]-->
<div id="modal_overlay"></div>
<div id="modal_window">
<div id="modal_bar">
<strong>Modal window</strong>
<a href="#" id="modal_close">Close</a>
</div>
<div id="modal_content"></div>
</div>
');
// Look for modal links.
$('a.modal').click(function() {
13.5 Displaying a Simple Modal Window | 299
// Check the href="..."
var $the_link = $(this).attr('href');
// Determine link target.
if ($the_link.match(/^#./)) {
// Assume #anchor content.
$('#modal_content').html($($(this).attr('href')).html());
showModal();
} else if ($the_link.match(/.jpg$/) ||
$the_link.match(/.png$/) ||
$the_link.match(/.gif$/)) {
// Assume image content.
$('#modal_content').html('
<p id="modal_image_wrapper">
<img src="' + $the_link + '" class="modal_placeholder" />
</p>
');
showModal();
} else {
// Assume external Ajax content.
$('#modal_content').load($(this).attr('href')
.replace('#', ' #'), '', showModal);
}
// Determine modal title.
if ($(this).attr('title')) {
// Insert title.
$('#modal_bar strong').html($(this).attr('title'));
} else if ($(this).html() !== '') {
// Insert link text.
$('#modal_bar strong').html($(this).html());
}
// Nofollow.
this.blur();
return false;
});
// Hide modal elements.
$('#modal_overlay, #modal_close').click(function() {
// Hide the modal.
$('#modal_wrapper').hide();
// Hide, because images might load later.
$('#modal_window').css('visibility', 'hidden');
300 | Chapter 13:Interface Components from Scratch
// Unbind image listeners.
$('#modal_content img').each(function() {
$(this).unbind();
});
// Destroy modal content.
$('#modal_content').html('');
// Reset modal title.
$('#modal_bar strong').html('Modal window');
// Nofollow.
this.blur();
return false;
});
// Listen for browser scroll, if IE6.
if ($IE6) {
$(window).scroll(function() {
if ($('#modal_wrapper').is(':visible')) {
positionModal();
}
});
}
}
// Kick things off.
$(document).ready(function() {
init_modal();
});
Discussion
Oui moual solution Legins Ly uelining a vaiiaLle that acts as a Boolean value, iepie-
senting whethei the Liowsei is Inteinet Exploiei 6. To ueteimine this, we peiloim two
guick evaluations. Once we know il we aie laceu with IE 6, we can use that knowleuge
to patch lunctionality. You will also notice that theie is a conuitional comment incluueu
in the maikup liagment that we uynamically cieate:
<!--[if IE 6]><iframe id="modal_iframe"></iframe><![endif]-->
At liist glance, this might Le conlusing Lecause il the Liowsei is Inteinet Exploiei 6,
an empty iframe is inseiteu that uoes not ieleience any incluueu page content. The
ieason we uo this is to tiick IE 6 into allowing oui moual to oveilap any <select> loim
elements that might Le in the page. Il we uo not use this woikaiounu, then all
<select> elements on the page will essentially poke thiough the moual oveilay, mak-
ing loi a guite uisoiienting usei expeiience.
Next, we cieate a lunction to house all the calculations that neeu to Le peiloimeu in
oiuei to centei the moual winuow insiue the viewpoit. Vhile we coulu have uone this
all in CSS anu simply haiu-coueu the wiuth anu height, this allows loi gieatei llexiLility.
13.5 Displaying a Simple Modal Window | 301
The uevelopei implementing this ]avaSciipt neeu only set the wiuth ol the moual in
CSS, anu oui lunction takes caie ol the iest, even allowing loi content ol vaiying height.
The next lunction exists loi, anu is only evei calleu Ly, Inteinet Exploiei 6. This patches
IE 6`s lack ol CSS suppoit loi position: fixed. Foi all othei Liowseis, oui moual will
iemain centeieu veitically anu hoiizontally as the usei sciolls a long uocument. In IE
6, howevei, we neeu to specilically tell the moual to aujust its position as the usei sciolls.
Ve will uo so Ly calling this lunction latei in the lile.
Actually ievealing the moual winuow is simple enough. Ve have Lunuleu all the nec-
essaiy coue loi that into showModal(). It contains a call to positionModal() il the Liowsei
is IE 6. It shows the moual wiappei <div> anu calls sizeModal() to centei the moual
anu size it accoiuing to its content`s height. Once sizeu coiiectly, the moual winuow
itsell is shown. An onload lunction is also attacheu to any uynamically inseiteu images.
This is to account loi Liowseis not knowing the uimensions ol an image until it is lully
cacheu. Note that showModal() isn`t actually calleu until latei in the lile.
Vhen the uocument loaus, we attach the moual maikup iight Leloie the close ol the
</body>.
Click listeneis aie attacheu to all links with class="modal". Vhen a moual link is
clickeu, theie is a seiies ol evaluations uone in oiuei to ueteimine what type ol content
is to Le loaueu. Fiist il the link Legins with a hash (#) anu is lolloweu Ly one oi moie
chaiacteis, we know that theie is in-page content Leing linkeu to. In such cases, the
HTML content is copieu liom that ID into the moual. The seconu case involves images.
Il the href enus in .jpg, .png, oi .gif, then an <img> tag is cieateu, anu the href is copieu
into the src. Thiiuly, il none ol the pievious ciiteiia is met, we aie most likely uealing
with an exteinal page. In this case, jQueiy`s .load() methou is calleu, ietiieving the
HTML liom that page (anu liom a specilic ID il a hash exists) anu inseiting it into the
moual.
The next chunk ol coue auus click event listeneis to the moual oveilay (the giay Lack-
giounu) anu the close Lutton. Il eithei ol these is clickeu, the moual will Le hiuuen, all
moual images will Le stiippeu ol theii event listeneis, the moual content will Le set to
an empty stiing, anu the text in the moual winuow`s title Lai will Le ieset.
Last is an event listenei specilically loi IE 6 that watches loi the winuow to scioll. Il
the moual winuow wiappei is visiLle (anu implicitly eveiything else associateu with
the moual winuow), then positionModal() is calleu continuously as the usei sciolls the
page. This ensuies that the moual winuow stays in place via mimicking position:
fixed.
302 | Chapter 13:Interface Components from Scratch
13.6 Building Drop-Down Menus
Problem
InevitaLly, theie will Le a client oi Loss who wants eveiything one click away in a
site navigation stiuctuie. Vhile this is not an altogethei ignoLle aspiiation, placing
links to eveiy single section ol a site on a single page coulu auu signilicant cluttei to a
page. Entei the uiop-uown menu.
Solution
In uesktop piogiams anu opeiating systems, these menus aie olten activateu Ly clicking
a teim, altei which you see a vaiiety ol suLteims anu categoiies. On the VeL, howevei,
the paiauigm seems to Le that uiop-uown menus appeai when the usei hoveis ovei a
top-level link, as shown in Figuies 13-7 anu 13-S. By using a comLination ol
CSS :hover iules anu positioning technigues, most ol the heavy lilting can Le uone
without much ]avaSciipt at all. jQueiy can simply ollei minoi enhancements loi IE 6.
A milu waining loi uevelopeis: take into account the accessiLility implications ol useis
who uo not have the manual uexteiity to use a mouse. It`s like the olu auage: Il all you
have is a hammei, eveiything looks like a nail. Beloie iesoiting to uiop-uowns as an
easy oll-the-shell solution, check that the inloimation aichitectuie ol the pioject has
Leen well thought thiough. Be suie that a uiop-uown paiauigm is the Lest choice. Foi
example, Miciosolt Voiu, long known loi its iiuiculous levels ol uiop-uowns anu
toggleaLle options (most ol which the aveiage usei nevei toucheu), was ieuesigneu in
Ollice 2007 with a taLLeu UI uuLLeu the iiLLon. Suuuenly, once oLscuie options
aie Leing useu iegulaily, Lecause ol a Lettei executeu inteilace.
Iigurc 13-7. Drop-down ncnu rcady jor usc
Iigurc 13-8. Drop-down ncnu in action
13.6 Building Drop-Down Menus | 303
Drop-downHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Building Drop-Down Menus</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="dropdown.css" />
<!--[if IE 6]>
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="dropdown.js"></script>
<![endif]-->
</head>
<body>
<div id="container">
<ul class="dropdown">
<li class="dropdown_trigger">
<a href="#">Nav Item</a>
<ul>
<li>
<a href="#">Subitem</a>
</li>
<li>
<a href="#">Subitem</a>
</li>
<li>
<a href="#">Subitem</a>
</li>
<li>
<a href="#">Subitem</a>
</li>
<li>
<a href="#">Subitem</a>
</li>
</ul>
</li>
...
</ul>
<p>
This text is just here to show that the menu overlaps the content below it.
</p>
...
</div>
</body>
</html>
Drop-downjQuery code
// Initialize.
function init_dropdown() {
// Does element exist?
304 | Chapter 13:Interface Components from Scratch
if (!$('ul.dropdown').length) {
// If not, exit.
return;
}
// Add listener for hover.
$('ul.dropdown li.dropdown_trigger').hover(function() {
// Show subsequent <ul>.
$(this).find('ul').fadeIn(1);
},
function() {
// Hide subsequent <ul>.
$(this).find('ul').hide();
});
}
// Kick things off.
$(document).ready(function() {
init_dropdown();
});
Discussion
In this example, jQueiy is only employeu il the Liowsei is IE 6. You might Le wonueiing,
Vhy is fadeIn Leing calleu with only a one-milliseconu animation? This lixes a Lug
in IE 6, which has tiouLle ienueiing veitical CSS Loiueis. Visually, it is the same
as .show() Lut without any Loiuei issues. Asiue liom that, eveiything else is pietty
simple. Vhen a list item with class="dropdown_trigger" is hoveieu ovei, the suLse-
guent <ul> is shown. Vhen the mouse leaves that aiea, the <ul> is hiuuen. That`s all
theie is to it! Note that we aie conuitionally incluuing the jQueiy liLiaiy only loi IE 6.
Chances aie, il you aie ieauing this Look, you will want to use jQueiy loi moie than
just this one paiticulai uemo. In that case, move youi inclusion ol jQueiy outsidc ol the
conuitional comments.
13.7 Cross-Fading Rotating Images
Problem
On pages that contain a laige mastheau oi heio image, olten seen on e-commeice
sites, many uilleient piouucts anu/oi uepaitments aie vying loi that top spot. Olten,
the compiomise is to simply have a seiies ol images laue in anu out, iepeating on a
loop. This is all well anu goou Lut can olten Le liustiating to use, Lecause lai too many
sites oveilook the neeu to pause the iotation in oiuei to glean the veiy inloimation that
is attempting to Le conveyeu.
13.7 Cross-Fading Rotating Images | 305
The implications ol a constant animation shoulu Le consiueieu. Most useis have
leaineu to ignoie annoying aus that contain a lot ol motion. The uesignei/uevelopei
must take into account those useis who might not want to see the animation, while
also tiying to ieau the iest ol the page. Voise yet is when a usei attempts to ieau one
ol the iotating sliues, only to have it continue to animate. Theieloie, play/pause
lunctionality is Le incluueu in this iecipe, lest oui useis Le caught in an enuless, ani-
mateu loop.
Solution
Using jQueiy`s .fadeIn() anu .fadeOut() methous, we can cieate a nice cioss-laue
animation that will iteiate thiough an aiiay, changing each image`s opacity Laseu on
a set timei. By implementing what we leaineu liom the taLLeu uocument poition ol
this chaptei, we can cieate links to each image, which not only will cause the taiget
image to come to the loieliont Lut also sets a llaggeu vaiiaLle ol pause to eithei tiue oi
lalse, which will stait oi stop the animation. This makes loi a tiuly usaLle image iotatoi
veisus puie eye canuy.
RotatorHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Cross-fading Rotating Images</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="rotator.css" />
<script type="text/javascript">
/* <![CDATA[ */
document.write('<link rel="stylesheet" type="text/css" href="preload.css" />');
/* ]]> */
</script>
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="rotator.js"></script>
</head>
<body>
<div id="container">
<div id="rotator_wrapper">
<ul id="rotator">
<li id="photo_1">
<img src="../_common/photo_1.jpg" alt="Photo" />
</li>
<li id="photo_2">
<img src="../_common/photo_2.jpg" alt="Photo" />
</li>
<li id="photo_3">
<img src="../_common/photo_3.jpg" alt="Photo" />
</li>
<li id="photo_4">
306 | Chapter 13:Interface Components from Scratch
<img src="../_common/photo_4.jpg" alt="Photo" />
</li>
<li id="photo_5">
<img src="../_common/photo_5.jpg" alt="Photo" />
</li>
</ul>
<ul id="rotator_controls">
<li>
<a href="#photo_1" class="current">1</a>
</li>
<li>
<a href="#photo_2">2</a>
</li>
<li>
<a href="#photo_3">3</a>
</li>
<li>
<a href="#photo_4">4</a>
</li>
<li>
<a href="#photo_5">5</a>
</li>
</ul>
<a href="#" id="rotator_play_pause">PAUSE</a>
</div>
</div>
</body>
</html>
RotatorjQuery code
// Initialize.
function init_rotator() {
// Does element exist?
if (!$('#rotator').length) {
// If not, exit.
return;
}
// Rotate speed.
var speed = 2000;
// Pause setting.
var pause = false;
// Rotator function.
function rotate(element) {
// Stop, if user has interacted.
if (pause) {
return;
}
13.7 Cross-Fading Rotating Images | 307
// Either the next /first <li>.
var $next_li = $(element).next('li').length ?
$(element).next('li') :
$('#rotator li:first');
// Either next / first control link.
var $next_a = $('#rotator_controls a.current').parent('li').next('li').length ?
$('#rotator_controls a.current').parent('li').next('li').find('a') :
$('#rotator_controls a:first');
// Animate.
$('#rotator_controls a.current').removeClass('current');
$next_a.addClass('current');
// Continue.
function doIt() {
rotate($next_li);
}
// Fade out <li>.
$(element).fadeOut(speed);
// Show next <li>.
$($next_li).fadeIn(speed, function() {
// Slight delay.
setTimeout(doIt, speed);
});
}
// Add click listeners for controls.
$('#rotator_controls a').click(function() {
// Change button text.
$('#rotator_play_pause').html('PLAY');
// Show target, hide other <li>.
$($(this).attr('href')).show().siblings('li').hide();
// Add class="current" and remove from all others.
$(this).addClass('current').parent('li').siblings('li')
.find('a').removeClass('current');;
// Pause animation.
pause = true;
// Nofollow.
this.blur();
return false;
});
308 | Chapter 13:Interface Components from Scratch
// Pause / Play the animation.
$('#rotator_play_pause').click(function() {
// What does the button say?
if ($(this).html() === 'PAUSE') {
// Stop rotation.
pause = true;
// Change the text.
$(this).html('PLAY');
} else {
// Remove class="pause".
pause = false;
// Start the rotation.
rotate('#rotator li:visible:first');
// Change the text.
$(this).html('PAUSE');
}
// Nofollow.
this.blur();
return false;
});
// Hide all but first <li>.
$('#rotator li:first').siblings('li').hide();
// Wait for page load.
$(window).load(function() {
// Begin rotation.
rotate($('#rotator li:visible:first'));
});
}
// Kick things off.
$(document).ready(function() {
init_rotator();
});
Discussion
This iecipe staits oll Ly uelining two key vaiiaLles: speed (a numeiic value in
milliseconus) anu pause (a Boolean to tell the iotatoi whethei to play). Initially, speed
has Leen set to two seconus, anu pause is set to false, allowing the iotatoi to autoplay
when the page loaus.
13.7 Cross-Fading Rotating Images | 309
Insiue the rotate() lunction, a vaiiaLle has Leen set calleu $next_li, which will
coiiesponu eithei to the next <li> altei the one cuiiently Leing animateu oi to the liist
<li> in the aiiay (in the case ol ieaching the enu ol the aiiay anu neeuing to Legin
anew). Likewise, the same piemise is Leing applieu to links within <ul id="rotator_con
trols"> in oiuei to auu a visual inuicatoi ol which image`s Lutton is cuiiently active.
Altei a slight uelay ol two seconus, the whole seguence is kickeu oll again.
Il that weie wheie this uemo enueu, it coulu get pietty tiiesome seeing images iotate
uncontiollaLly. Luckily, we can ieuse the in-page anchoi link technigue liom the
taLLeu uocument iecipe. Ve simply assign click listeneis to each ol the links in
<ul id="rotator_controls"> anu then ieveal the taiget image while hiuing the iest. Ve
also auu a play/pause Lutton that will stait anu/oi stop the iotatoi liom animating.
Last is the coue that sets eveiything into motion. All Lut the liist <li> within
<ul id="rotator"> aie hiuuen, anu then when the winuow has linisheu loauing, the
animation Legins. Note that $(window).load() uilleis liom $(document).ready() Le-
cause the loimei waits loi all assets to loau completely, incluuing images, which is
especially impoitant loi the case ol an image iotatoi. The lattei simply waits loi the
HTML stiuctuie to Le intact, which is impoitant loi applying lunctionality even as the
iest ol the images on a page aie loauing. Both aie impoitant, anu each one has its place.
13.8 Sliding Panels
Problem
Occasionally, you might neeu to uisplay a vaiiety ol choices hoiizontally, anu uo so
with a Lit ol panache, Lut might have moie choices than the wiuth ol a layout will
allow. Oi, peihaps the appioach simply uictates that theie Le some lancy usei intei-
action. Eithei way, the sliuing panels appioach (sometimes calleu a horizonta| accor-
dion) is one possiLle way to piesent such inloimation. Figuie 13-9 shows a closeu panel,
while Figuie 13-10 shows a panel that has sliu out to Lecome visiLle.
Solution
In this iecipe, we will ievisit some ol the concepts applieu in the accoiuion uemo, Lut
insteau ol expanuing anu collapsing content panels veitically, we will Le animating
them hoiizontally. Ve will also use a CSS positioning tiick to woik aiounu the slight
miscalculation ol simultaneously animating panels. Rathei than woiiy aLout synchio-
nization Letween each panel, animating with pixel-peilect piecision at exact liactions
ol a seconu, we simply take the last <li> in the <ul class="panels"> anu position it
aLsolutely to the top iight ol the <ul>. That way, when the sum wiuth ol all the panels
occasionally auus up to gieatei than 100 peicent ol the <ul> as they animate, the last
<li> nevei Lieaks to the next line.
310 | Chapter 13:Interface Components from Scratch
Iigurc 13-9. Horizonta| panc|, sti|| c|oscd
Iigurc 13-10. Horizonta| panc|, opcncd
PanelsHTML code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="imagetoolbar" content="false" />
<title>jQuery Cookbook - Ch.13 - Sliding Panels</title>
<link rel="stylesheet" type="text/css" href="../_common/basic.css" />
<link rel="stylesheet" type="text/css" href="panels.css" />
<script type="text/javascript" src="../_common/jquery.js"></script>
<script type="text/javascript" src="panels.js"></script>
</head>
<body>
<div id="container">
<ul class="panels">
<li>
<a href="#">1</a>
</li>
<li>
<a href="#">2</a>
</li>
<li>
<a href="#">3</a>
</li>
<li>
<a href="#">4</a>
</li>
<li>
13.8 Sliding Panels | 311
<a href="#">5</a>
</li>
</ul>
<ul class="panels">
<li>
<a href="#">A</a>
</li>
<li>
<a href="#">B</a>
</li>
<li>
<a href="#">C</a>
</li>
<li>
<a href="#">D</a>
</li>
<li>
<a href="#">E</a>
</li>
</ul>
</div>
</body>
</html>
PanelsjQuery code
// Initialize.
function init_panels() {
// Does element exist?
if (!$('ul.panels').length) {
// If not, exit.
return;
}
// Animation speed.
var speed = 200;
// Add class for last <li>.
$('ul.panels li:last-child').addClass('last');
// Begin with mouseover.
$('ul.panels li').hover(function() {
// Alter target <li>.
$(this).stop().animate({
width: '360px',
fontSize: '150px'
// Speed.
}, speed)
// Alter sibling <li>.
.siblings('li').stop().animate({
312 | Chapter 13:Interface Components from Scratch
width: '135px',
fontSize: '50px'
// Speed.
}, speed);
},
// End with mouseout.
function() {
// Restore target <li>.
$(this).stop().animate({
width: '180px',
fontSize: '100px'
// Speed.
}, speed)
// Restore sibling <li>.
.siblings('li').stop().animate({
width: '180px',
fontSize: '100px'
// Speed.
}, speed);
});
}
// Kick things off.
$(document).ready(function() {
init_panels();
});
Discussion
The iecipe Legins Ly uelining a vaiiaLle loi speed. In this case, it is set to 200
milliseconus. Ve then auu class="last" to each enuing <li>. Ve then attach a hovei
event listenei (in ieality, this maps to Loth a mouseovei anu mouseout, Lut let`s not
get technical). Vhen an <li> is hoveieu ovei with the mouse, its wiuth is animateu to
40% anu lont size to 150px, while the othei <li> aie each animateu to 15% wiue with a
lont size ol 50px. Likewise, when the mouse exits the <li>, the wiuths ol all <li> ele-
ments aie set to 20%, anu theii lont sizes aie set to 100px.
13.8 Sliding Panels | 313
CHAPTER 14
User Interfaces with jQuery UI
Richard D. Worth
14.0 Introduction
A couple yeais Lack, theie was a set ol guite populai jQueiy plugins Lunuleu in a
package calleu Inteilace, wiitten Ly Stelan Petie. These olleieu ieally gieat inteiactions,
such as uiagging-anu-uiopping, selecting, soiting, anu iesizing, anu gieat wiugets such
as a tool tip, an autocomplete, anu an accoiuion. The 1.2 ielease ol jQueiy hau some
API changes that woulu`ve ieguiieu changes to Inteilace loi it to Le compatiLle, Lut
Inteilace was nevei upuateu.
jQueiy UI, staiteu Ly Paul Bakaus, pickeu up wheie Inteilace lelt oll. jQueiy UI is a
suite ol plugins with a consistent API anu complete uocumentation that has Leen testeu
in all majoi Liowseis. Vith it, you can cieate iich weL inteilaces anu iich Inteinet
applications (RIAs). Oh yeah, anu the plugins woik well togethei anu aie easy to use,
accessiLle, extensiLle, anu themeaLle.
jQueiy UI is a sistei pioject ol jQueiy. Veision 1.0 ol jQueiy UI was ieleaseu in Sep-
temLei 2007. Veision 1.5 was ieleaseu in ]une 200S. ALout hallway thiough the ue-
velopment ol 1.6, the team changeu uiiections anu enueu up ieleasing 1.7 with some
majoi changes, most specilically the intiouuction ol the jQueiy UI CSS Fiamewoik.
jQueiy UI 1.6 was ieleaseu latei loi legacy compatiLility. The latest staLle ielease is
1.7.2 anu incluues the lollowing inteiactions, wiugets, anu ellects.
Interactions
DiaggaLle (uiag)
DioppaLle (anu uiop)
ResizaLle
SelectaLle
SoitaLle
315
Widgets
Accoiuion
Datepickei
Dialog
PiogiessLai
Sliuei
TaLs
Effects
Blinu, Lounce, clip, uiop uown/up/lelt/iight, exploue, lolu, highlight, pulsate,
pull, scale, shake, sliue uown/up/lelt/iight, tianslei
Coloi animations
Class animations (addClass/removeClass/toggleClass with inteival)
Basic Usage
This chaptei will loigo coveiing some ol the moie common ways to use these inteiac-
tions, wiugets, anu ellects, Lecause they aie well coveieu in uemos on the jQueiy UI
weLsite. These same uemos, with lull souice coue anu uesciiptions, aie incluueu in
eveiy uownloau ol jQueiy UI, along with lull uocumentation.
How This Chapter Is Organized
The liist two iecipes get you staiteu Ly helping you to uownloau jQueiy UI, oi ieleience
it on a content ueliveiy netwoik (CDN), anu incluue it on youi page loi use.
The next seven iecipes ol this chaptei covei the jQueiy UI API. This API liist Luilt on
top ol the jQueiy plugin pattein Lut has giown to incluue what is neeueu Ly jQueiy
UI wiugets, which aie a unigue style ol jQueiy plugin. Namely, they`ie state anu methou
calls. So, in auuition to specilying options on init, you can mouily options altei init.
You can also call methous on jQueiy UI plugins to change the state anu piogiammat-
ically tiiggei custom events.
The iemainuei ol the chaptei locuses on a pioject wheie multiple jQueiy UI wiugets
aie comLineu to cieate a single usei inteilace that incluues llexiLle anu themeaLle con-
tiols loi a music playei.
316 | Chapter 14:User Interfaces with jQuery UI
14.1 Including the Entire jQuery UI Suite
Problem
You want to incluue the entiie jQueiy UI suite. This might Le Lecause you uon`t know
yet what paits you`ll use anu what paits you won`t. Oi it might Le Lecause you`ll use
enough ol the suite that it`s easiei oi moie ellicient to incluue the whole suite, iathei
than each inuiviuual piece you`ll use.
Solution
Link to a jQueiy UI theme, then a compatiLle veision ol the jQueiy sciipt, anu then
the jQueiy UI sciipt:
<link rel="stylesheet" type="text/css" href="themename/jquery-ui.css" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery-ui.js"></script>
Discussion
This chaptei coveis the latest staLle veision ol jQueiy UI: 1.7.2. It ieguiies at a mini-
mum jQueiy 1.3. Vhen you uownloau jQueiy UI, incluueu in the ZIP package is the
latest staLle veision ol jQueiy that is compatiLle.
Rathei than host youi own veision ol jQueiy anu jQueiy UI, you can use Google`s
A]AX LiLiaiies API. Simply change youi sciipt URLs like so:
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
Google also hosts the 20 oi so themes that aie in the jQueiy UI ThemeRollei galleiy.
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/
jqueryui/1.7.2/themes/{themename}/jquery-ui.css" />
This incluues the 13 images pei theme that aie ieleienceu Ly ielative URLs in the
theme CSS.
You can ieplace {themename} with base, black-tie, blitzer, cupertino, dark-hive,
dot-luv, eggplant, excite-bike, flick, hot-sneaks, humanity, le-frog, mint-choc,
overcast, pepper-grinder, redmond, smoothness, south-street, start, sunny, swanky-
purse, trontastic, ui-darkness, ui-lightness, oi vader. Foi a pieview ol each ol these,
see the jQueiy UI ThemeRollei galleiy.
Theming with jQueiy UI is well coveieu in the next chaptei. Foi oui puiposes, we`ll
just Le suie to incluue one ol these themes, Lecause a theme is ieguiieu.
14.1 Including the Entire jQuery UI Suite | 317
14.2 Including an Individual jQuery UI Plugin or Two
Problem
You only want to use one oi two jQueiy UI wiugets. You uon`t want to impoit the
whole liLiaiy anu an entiie theme`s CSS. You just want the minimum ieguiieu to use
the plugins you neeu.
Solution
So, you only want SoitaLle anu TaLs. You have two options loi incluuing inuiviuual
jQueiy UI components iathei than the entiie suite:
Use the jQueiy UI Downloau Builuei to cieate a custom Luilu ol jQueiy UI con-
taining only those plugins you aie inteiesteu in. Foi this example, select SoitaLle
anu TaLs. The Downloau Builuei will automatically select any uepenuencies, in
this case, UI Coie. The ZIP you uownloau incluues a single .js lile with UI Coie,
SoitaLle, anu TaLs:
js/jquery-ui-1.7.2.custom.min.js
Incluue this lile on youi page altei the jQueiy sciipt, which is pioviueu in the same
loluei:
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
Downloau the jQueiy UI uevelopment Lunule, ieleience the dcvc|opncnt-bund|c
loluei in a custom Downloau Builuei ZIP, oi use SVN. Each inuiviuual plugin lile
is in the ui suLloluei. Releience each lile inuiviuually:
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="ui/ui.core.js"></script>
<script type="text/javascript" src="ui/ui.sortable.js"></script>
<script type="text/javascript" src="ui/ui.tabs.js"></script>
The CSS loi each inuiviuual plugin is also availaLle in sepaiate liles, il you go with the
seconu option (dcvc|opncnt-bund|c). You`ll neeu to incluue the coie CSS, each plugin-
specilic CSS, anu the theme CSS:
<link rel="stylesheet" type="text/css" href="themes/base/ui.core.css" />
<link rel="stylesheet" type="text/css" href="themes/base/ui.tabs.css" />
<link rel="stylesheet" type="text/css" href="themes/base/ui.theme.css" />
In this case, one ol the plugins we`ve selecteu, SoitaLle, uoesn`t have any plugin-
specilic CSS.
Discussion
Vhethei using ]avaSciipt oi CSS, theie aie tiaue-olls Letween using a single laige in-
cluue anu multiple smallei (oveiall) incluues. It`s not always cleai-cut, like Use inui-
318 | Chapter 14:User Interfaces with jQuery UI
viuual plugin liles in uevelopment. Use one laige lile in piouuction. Foi example, it
may Le simplei in uevelopment to point to the whole suite, wheie peiloimance testing
isn`t a Lig consiueiation. But then in piouuction you might neeu to incluue only the
liles loi the plugins useu on each page to minimize loau.
On the othei hanu, loi ueLugging puiposes, it may Le Lenelicial to have a sciipt anu
CSS ieleience to each plugin lile uuiing uevelopment, anu in piouuction you may use
the Google A]AX LiLiaiies API anu the visitoi`s cache to make up loi the lile size, even
il the lile incluues lunctions that aie not evei useu. The iueal setup will uepenu on youi
aichitectuie, how many anu which ol the plugins you use, anu the specilic neeus ol
youi uevelopment anu piouuction enviionments.
14.3 Initializing a jQuery UI Plugin with Default Options
Problem
You want to stait using a jQueiy UI plugin as guickly anu easily as possiLle, accepting
the Luilt-in uelault options.
Solution
All jQueiy UI plugins aie calleu like tiauitional jQueiy plugins, so altei you get a
matcheu set ol elements, simply call the plugin name as a lunction on the jQueiy oLject:
<script type="text/javascript">
$(function() {
$('#topnav').tabs();
});
</script>
Discussion
Because ]avaSciipt is case sensitive, caie is taken in the naming ol jQueiy UI plugins.
All jQueiy UI plugins stait loweicase, anu, like the jQueiy API, most aie only one woiu.
Il moie than one woiu is neeueu, any altei the liist will stait uppeicase. Theie aien`t
cuiiently any jQueiy UI plugins with moie than one woiu, so heie`s a maue-up
example:
$('p.long').succinct();
$('.short').longerPluginName();
The initializeu element gets a class ol ui-pluginname. Foi example, heie`s the Leloie
anu altei HTML il you call $('div').draggable();:
<div>A simple DIV</div>
<div class="ui-draggable">A simple DIV</div>
14.3 Initializing a jQuery UI Plugin with Default Options | 319
Theie aie some exceptions to this. The element on which you call .dialog() gets the
class ol ui-dialog-content anu is wiappeu in a geneiateu element with a class ol
ui-dialog. Anothei exception is il you call .datepicker() on a text input. The input
will not get the ui-datepicker, Lut the <div> that appeais when the input is locuseu
has the ui-datepicker class.
Heie aie a lew points to keep in minu when initializing a jQueiy UI plugin:
Il you call a jQueiy UI plugin init methou on a set containing moie than one
element, it will Le calleu as a sepaiate init on each element inuiviuually. So, the
lollowing:
$('img').draggable();
is eguivalent to this:
$('img').each(function() {
$(this).draggable();
});
Each DOMElement can Le initializeu Ly each jQueiy UI plugin only once. Any lutuie
init calls, whethei with options specilieu oi not, will Le ignoieu. See latei in this
chaptei loi iecipes on changing options altei init as well as uestioying a plugin,
which unuoes an init. Il you ieally want to, you can call init again altei that.
All options aie optional. You can always salely initialize a jQueiy UI plugin Ly
simply calling the plugin name methou. Not only is it sale, Lut it shoulu Le
supiemely uselul. Each has Leen uesigneu to have the most common options as
uelaults. Il they uon`t make you happy, see the next two iecipes.
14.4 Initializing a jQuery UI Plugin with Custom Options
Problem
You want to use a jQueiy UI plugin Lut with options othei than those selecteu Ly the
plugin authoi to Le the Luilt-in uelaults.
Solution
Specily uelault option oveiiiues in an options hash as the liist aigument to the plugin
init methou call:
$('#myDiv').dialog({
height: 100, // overrides default: 'auto'
width: 350 // overrides default: 300
});
320 | Chapter 14:User Interfaces with jQuery UI
Discussion
Any option values you specily on init will oveiiiue the uelault value. All unspecilieu
options values will maintain the uelault.
The options hash, whethei all uelaults oi some uelaults plus some custom options, is
the Lasis loi the initial state ol the plugin. That state is specilic to the comLination ol
that DOMElement with that jQueiy UI plugin. Foi example, you might initialize a single
element with two uilleient jQueiy UI plugins that each has a coloi option:
$('#myDiv').foo({ color: 'black' });
$('#myDiv').bar({ color: 'green' });
Now, #myDiv, what`s youi foo coloi? Black. Vhat`s youi bar coloi? Gieen. Both aie
sepaiate liom the CSS coloi. In some latei iecipes, we`ll get into how to ask elements
what theii plugin values aie, as well as how to give them new values.
Also impoitant to note is now that #myDiv is initializeu as a foo anu a bar, it is no longei
allecteu Ly those plugin uelaults. The uelaults aie only useu on init as a template loi
the plugin`s initial state.
14.5 Creating Your Very Own jQuery UI Plugin Defaults
Problem
Eveiy time you cieate a jQueiy UI uialog, you linu youisell specilying the same lew
options, among otheis:
$('#msg').dialog({
height: 300,
width: 400,
draggable: false,
modal: true,
buttons: {
'OK': function(event, ui) {
$(this).dialog('close');
}
}
...
});
You long loi youi coue to Le as succinct as it once was. Vhat happeneu to the simple
Leauty ol $('#msg').dialog();?
Solution
Oveiiiue the plugin uelaults Leloie init Ly extenuing $.ui.pluginname.defaults:
$.extend($.ui.dialog.defaults, {
height: 300,
width: 400,
draggable: false,
14.5 Creating Your Very Own jQuery UI Plugin Defaults | 321
modal: true,
buttons: {
'OK': function(event, ui) {
$(this).dialog('close');
}
}
});
...
$('#msg').dialog();
...
$('#note').dialog();
Discussion
Il you weie only looking to impiove the ieauaLility a Lit, you coulu simply put the
options in a vaiiaLle anu pass them to the plugin init:
var options = {
height: 300,
width: 400,
draggable: false,
modal: true,
buttons: {
'OK': function(event, ui) {
$(this).dialog('close');
}
}
};
$('#msg').dialog(options);
But this iecipe is aLout moie than just ieauaLility anu coue Leauty. It`s aLout changing
the uelault Lehavioi ol a plugin you uiun`t wiite. Plus, it makes it so you can get Lack
to the simple no-options init:
$('#msg').dialog();
As Dave Methvin lamously saiu, It coulun`t get any shoitei unless it ieau youi minu.
Ol couise, you still have the option ol oveiiiuing even these custom uelaults Ly passing
custom options to the plugin init, as in the pievious iecipe.
Don`t loiget that plugin options aie cloneu anu extenueu liom the uelaults at the time
ol init. So, extenuing $.ui.dialog.defaults altei a <div> has alieauy Leen initializeu
as a uialog will have no ellect on that uialog, even il that init was uone with no custom
options. The ellect will Le on any uialogs initializeu altei the uelaults weie oveiiiuuen.
322 | Chapter 14:User Interfaces with jQuery UI
14.6 Getting and Setting jQuery UI Plugin Options
Problem
You neeu to check oi change the value ol a jQueiy UI plugin option altei it has Leen
initializeu.
Solution 1: Getting the Value
Call the plugin`s option methou, passing the name ol the option:
var active = $('#myDiv').accordion('option', 'active');
Vhen calleu with only an option name, the option methou gets anu ietuins the value,
so it`s not chainaLle.
Solution 2: Setting the Value
Call the plugin`s option methou, passing the name ol the option anu the new value:
$('#myDiv').accordion('option', 'active', 3);
Vhen calleu with an option name anu value, the option methou sets the value anu
ietuins the jQueiy oLject, so it`s chainaLle.
Discussion
The option methou get/set lollows the same pattein as jQueiy getteis anu setteis such
as .css() anu .attr(). Il you pioviue a value, it`s a settei; il you omit the value, it`s a
gettei.
As with othei jQueiy setteis, you can set multiple options at once Ly passing a hash to
the option methou:
$('#myDiv').accordion('option', {
active: 2,
collapsible: true
});
14.7 Calling jQuery UI Plugin Methods
Problem
You neeu to make a jQueiy UI plugin uo something piogiammatically.
Solution
Call the jQueiy UI plugin name methou, anu pass the name ol the plugin methou you
want to call as the liist aigument. Foi example, to close a uialog, use this:
14.7 Calling jQuery UI Plugin Methods | 323
$('#msg').dialog('close');
Il the methou takes aiguments, pass them altei the name ol the methou. Foi example,
to select the thiiu taL, use this:
$('#nav').tabs('select', 2); // tabs method select accepts a 0-based index
Discussion
Eveiy jQueiy UI plugin pioviues at least loui common Lase methous:
option
enable
disable
destroy
The option methou was coveieu in the pievious iecipe. The destroy methou is coveieu
in a latei iecipe. The enable anu disable methous aie pietty sell-explanatoiy. These
woik Ly setting the disabled option loi that plugin, which uelaults to lalse:
$('img').draggable('disable');
$('#mySlider').slider('enable');
Calling these methous also toggles the ui-pluginname-disabled class on the element,
which can Le useu loi styling oi selecting.
To see whethei a plugin is cuiiently uisaLleu, use the option methou to get the value
ol the disabled option:
var isDisabled = $('#tempature').slider('option', 'disabled');
14.8 Handling jQuery UI Plugin Events
Problem
You neeu to ieact to, oi Le notilieu ol, an event that occuis on a jQueiy UI plugin. This
coulu Le a uialog opening, an accoiuion panel closing, oi a taL Leing selecteu.
In this iecipe, we`ie going to hanule a uiaggaLle Leing uioppeu onto a uioppaLle, which
tiiggeis the drop event on the uioppaLle element.
Solution 1: Pass a Callback Function to the Event Name Option
On init, oi latei using the option methou, you can ueclaie a callLack lunction to Le
calleu when that event occuis:
// Declaring an event callback option on init
$('#shopping-cart').droppable({
drop: function(event, ui) {
addProduct(ui.draggable);
324 | Chapter 14:User Interfaces with jQuery UI
}
});
// Declaring an event callback after init using the option method
$('#shopping-cart').droppable();
...
$('#shopping-cart').droppable('option', 'drop', function(event, ui) {
addProduct(ui.draggable);
});
Note that this solution allows loi only one lunction to Le calleu at each event tiiggei.
You can call multiple hanuling lunctions Ly using a pioxy methou oi Ly using the Linu
solution, shown next.
Solution 2: Bind to the Custom Event Using the Event Type
Use the jQueiy .bind() methou, anu Linu to the type ol the event:
// Declaring an event callback option on init
$('#shopping-cart').bind('drop', function(event, ui) {
addProduct(ui.draggable);
});
This Linuing can Le uone on the plugin element itsell, oi some containei, taking au-
vantage ol custom event LuLLling anu uelegation.
Discussion
Eveiy jQueiy UI event ieceives two aiguments, event anu ui. The event aigument is
similai to the event aigument passeu to all Liowsei events, such as click anu
keypress. The uilleience is that this is a custom event oLject. As with Liowsei events,
the type can Le lounu in event.type.
Many jQueiy UI plugin events have coiiesponuing Liowsei events that will typically
tiiggei them. Foi example, the uiaggaLle seguence, dragstart, drag, dragstop, is most
likely tiiggeieu Ly the Liowsei events mousedown, mousemove, anu mouseup. Il the custom
event was tiiggeieu Ly a Liowsei event, that Liowsei event will Le in the
event.originalEvent piopeity. This can Le ieally uselul il you neeu to ueteimine
whethei something was uone via the keyLoaiu, the mouse, oi piogiammatically. Oi it
can Le helplul il you neeu to linu out whethei a mouiliei key was helu while the mouse
was clickeu oi moveu.
The ui aigument is a hash that contains any values that aie paiticulaily applicaLle to
that event at that time, as well as ones that coulun`t Le hau Ly calling the option oi
some othei methou on the plugin. Foi example, when a uioppaLle gets a uiaggaLle
uioppeu on it, that uiaggaLle element is passeu to the uiop event in ui.draggable. The
contents ol this ui hash aie unigue to each plugin event.
Note that the event name is most olten uilleient liom the event type. Foi example, Loth
DiaggaLle anu Sliuei have a start event. This is the event name. The types ol the same
14.8 Handling jQuery UI Plugin Events | 325
aie dragstart anu slidestart. Since each plugin has its own option namespace, each
can have the same option name, simply, start:
$('img').draggable({
start: function(event, ui) {
//event.type == 'dragstart'
}
});
$('#mySlider').slider({
start: function(event, ui) {
//event.type == 'slidestart'
}
});
But since events aie Lounu anu tiiggeieu in the same namespace, a pielix is ieguiieu
to make the event types unigue:
$('img').bind('dragstart', function(event, ui) {
//event.type == 'dragstart'
}
});
$('#mySlider').bind('slidestart', function(event, ui) {
//event.type == 'slidestart'
}
});
This pielix is most commonly the name ol the plugin, yieluing event types such as
dialogfocus, tabsadd, anu progressbarchange. In some cases, a custom veiL pielix is
useu insteau, il it`s a Lettei lit. So, you use dragstart insteau ol draggablestart, anu
you use slidestart insteau ol sliderstart.
Il the event type pielix happens to match the event name exactly, it is uioppeu to avoiu
a uouLling up like dragdrag oi slideslide. In these cases, the event type will match the
event name, like drag anu slide.
14.9 Destroying a jQuery UI Plugin
Problem
You`ie uone with a paiticulai plugin, anu you want youi element Lack the way it was.
This is Liggei than disable; this is un-init.
Solution
Call the uestioy methou:
$('#queue').sortable('destroy');
326 | Chapter 14:User Interfaces with jQuery UI
Discussion
Calling the destroy methou will completely uninitialize that element as that plugin. It
will iemove any classes auueu Ly the init oi any latei methou call oi event. Il the
init causeu the element to Le wiappeu, it will unwiap. It`s like a Lig unuo.
Destioying a jQueiy UI plugin uoesn`t iemove the element liom the DOM. It simply
iemoves that plugin state saveu on that element, putting the element Lack as close as
possiLle to its pie-init state. Altei a jQueiy UI plugin is uestioyeu, it can Le initializeu
as the same again.
Il you want to Loth uestioy anu iemove a plugin element, you can simply
call .remove(). The destroy methou will Le calleu automatically Ly jQueiy UI as it`s
iemoveu. This is tiue even il the element has Leen initializeu as moie than one jQueiy
UI plugin.
14.10 Creating a jQuery UI Music Player
Problem
You neeu a music playei that suppoits a common set ol inteilace contiols whethei the
music is Leing playeu Ly Flash Playei oi HTML5 auuio oi some othei Liowsei auuio
capaLility. You neeu the contiols to Le accessiLle, llexiLle, anu themeaLle. A lew Lasic
leatuies will uo:
Play
Pause
A tiack Lai to show anu contiol the cuiient point in the playLack
A piogiess metei to show how much ol the song is Lulleieu
Volume
In auuition to these Lasic leatuies, you want one moie leatuie. This music playei neeus
to Le scalaLle. The same inteilace shoulu woik at any size, whethei iesizeu Ly the
Liowsei, the usei, oi the applicationall the way up to lull scieen.
Solution
Let`s Luilu a music playei using jQueiy UI. Ve`ie going to cieate the play anu pause
Luttons using jQueiy UI CSS Fiamewoik icons, anu we`ie going to cieate the tiack Lai
using the jQueiy UI Sliuei plugin. The piogiess metei will Le a jQueiy UI PiogiessLai.
Finally, the volume contiol will Le one moie jQueiy UI Sliuei. Ve`ll wiap these ele-
ments in a common containei to pioviue loi some nice wiuget theming so that not only
will each ol oui contiols Le themeu Lut also oui music playei as a whole will Le themeu.
14.10 Creating a jQuery UI Music Player | 327
Ve will not Le Luiluing this music playei as a ieusaLle plugin. Ve`ie
simply going to wiie togethei some jQueiy UI wiugets to woik as some-
thing that will appeai to the usei as one component. But the music playei
itsell won`t Le a jQueiy plugin oi a jQueiy UI plugin. Foi this iecipe,
it`s just a collection ol HTML, ]avaSciipt, anu CSS. That way, we can
locus on how to use the jQueiy UI plugins unueineath, without the
auuitional complexity ol Luiluing a new plugin out ol existing plugins.
HTML5 audio
To keep things simple, we`ie going to use a minimal suLset ol the HTML5 Meuia
Element API. This is availaLle in a numLei ol iecent Liowseis, such as Fiielox 3.5. Ve`ll
implement it as a compatiLility layei so that anothei playLack mechanism, such as
Flash Playei, coulu Le suLstituteu easily. Foi this iecipe, we neeu the lollowing liom
oui auuio API:
Stait oi iesume playLack (play)
Pause the playLack (pause)
Get the length ol the song (duration)
Get the cuiient point that the playLack is at (timeupdate)
Change to a ceitain point in the song (currentTime)
Get the volume the song is Leing playeu at (volumechange)
Change to a ceitain volume (volume)
Assuming an HTML5 audio element exists in the uocument, heie`s the compatiLility
layei coue:
var $audio = $('audio'), audioEl = $audio[0];
var audio = {
currentTime: 0,
duration: secondsTotal,
volume: 0.5,
set: function(key, value) {
this[key] = value;
try { audioEl[key] = value; } catch(e) {}
if (key == 'currentTime') {
$audio.trigger('timeupdate');
}
if (key == 'volume') {
$audio.trigger('volumechange');
}
},
play: function() {
audioEl.play && audioEl.play();
},
pause: function() {
audioEl.pause && audioEl.pause();
}
};
328 | Chapter 14:User Interfaces with jQuery UI
$audio.bind('timeupdate', function() {
audio.currentTime = audioEl.currentTime;
});
audio.set('currentTime', 0);
audio.set('volume', 0.5);
The music player
Let`s use the CSS class mplayer loi oui music playei. This will Le the class loi oui main
<div>, anu will Le useu as a pielix in all oui CSS iules anu jQueiy selectois. Heie`s the
CSS anu HTML loi oui Laie playei:
.mplayer { position: relative; width: 40%; height: 2.5em; margin: 50px 0 100px 0; }
<div class="mplayer ui-widget"></div>
I`ve set the wiuth to +0 peicent so that we can see we have a llexiLle playei liom the
giounu up. ]ust iesize youi Liowsei anu watch the playei iesize. This will Le even easiei
to see when the playei isn`t empty.
In auuition to the mplayer class, oui main <div> gets a ui-widget class. This is to ensuie
elements within it get styleu appiopiiately. See the next chaptei loi moie on theming
with jQueiy UI CSS Fiamewoik classes.
An empty <div> anu no ]avaSciipt make loi an invisiLle anu guiet music playei. Let`s
auu a play Lutton anu get oui music on.
Play and pause button
Theie`s not yet a Lutton plugin in jQueiy UI. Ve can make uo in the meantime with
an a element anu some semantically nameu jQueiy UI CSS Fiamewoik icon classes:
Heie`s the CSS:
.mplayer .buttons-container { position: absolute; top: 10px; left: 10px; }
.mplayer .buttons-container .playpause { height: 1.2em; width: 1.2em; display: block;
position: relative; top: 2px; left: 2px; }
.mplayer .buttons-container .playpause .ui-icon { margin: 1px 0 0 1px; }
.mplayer .playpause .ui-icon-play, .paused .playpause .ui-icon-pause { display: none; }
.paused .playpause .ui-icon-play { display: block; }
Heie`s the HTML:
<div class="mplayer ui-widget">
<div class="buttons-container">
<a class="playpause ui-state-default ui-corner-all" href="#">
<span class="ui-icon ui-icon-play"></span>
<span class="ui-icon ui-icon-pause"></span>
</a>
</div>
</div>
14.10 Creating a jQuery UI Music Player | 329
Vith a couple CSS iules, we`ie aLle to have one Lutton seive as Loth the pause anu the
play Lutton. Vith the pievious CSS, only one icon, play oi pause, will Le visiLle at
once, uepenuing on whethei oui div.mplayer has the paused class. But the same HTML
allows loi a uilleient uesignei to ueciue that Loth icons will Le visiLle at once, Lut
peihaps with uilleient colois anu opacity, uepenuing on whethei the song is playing.
Heie`s the ]avaSciipt:
$('.mplayer .playpause').click(function() {
var player = $(this).parents('.mplayer');
if (player.is('.paused')) {
$('.mplayer').removeClass('paused');
audio.play();
} else {
$('.mplayer').addClass('paused');
audio.pause();
}
return false;
})
.hover(function() { $(this).addClass('ui-state-hover'); },
function() { $(this).removeClass('ui-state-hover'); })
.focus(function() { $(this).addClass('ui-state-focus'); })
.blur(function() { $(this).removeClass('ui-state-focus'); });
$('.mplayer').addClass('paused');
Oui Lutton neeus ]avaSciipt to uo the lollowing:
Call the audio.play() oi audio.pause() lunction, uepenuing on whethei the
paused class is on div.mplayer when clickeu.
Toggle the paused class on the .mplayer.
React to mouse anu keyLoaiu focus, hover, anu blur. This is wheie a Lutton plugin
might come in hanuy (theie`s one Leing Luilt), Lut loi a simple icon Lutton like
this, it`s not too much coue.
Don`t loiget the return false; since oui Lutton is an <a> with an hiel ol #.
Vith jQueiy, jQueiy UI, anu the UI Lightness theme loaueu, Figuie 1+-1 shows what
oui music playei looks like with just the play/pause Lutton.
Iigurc 11-1. P|ay and pausc button
Il you click the play Lutton, it shoulu change to a pause Lutton. Il you click again, it
shoulu change Lack. Also notice that you get a hovei ellect, as well as a visual cue, when
taLLing in anu out ol the Lutton with the keyLoaiu. Il you`ie in a Liowsei that suppoits
the audio element anu it has a src attiiLute that points to a suppoiteu music lile, you
shoulu even heai something when you click play.
330 | Chapter 14:User Interfaces with jQuery UI
Current and total time labels
The next step is to auu two laLels, one that shows the cuiient point we`ie at in the song
anu anothei that shows the total time in the song. These aie pietty stiaightloiwaiu.
Heie`s the CSS:
.mplayer .currenttime { position: absolute; top: 0.6em; left: 2.2em;
width: 3em; text-align: center; background: none; border: none; }
.mplayer .duration { position: absolute; top: 0.6em; right: 2.2em;
width: 3em; text-align: center; background: none; border: none; }
Heie`s the HTML:
<div class="mplayer ui-widget">
<div class="buttons-container">
<a class="playpause ui-state-default ui-corner-all" href="#">
<span class="ui-icon ui-icon-play"></span>
<span class="ui-icon ui-icon-pause"></span>
</a>
</div>
<span class="currenttime ui-state-default"></span>
<span class="duration ui-state-default"></span>
</div>
Heie`s the ]avaSciipt:
function minAndSec(sec) {
sec = parseInt(sec);
return Math.floor(sec / 60) + ":" + (sec % 60 < 10 ? '0' : '') +
Math.floor(sec % 60);
}
$('.mplayer .currenttime').text(minAndSec(audio.currentTime));
$('.mplayer .duration').text(minAndSec(secondsTotal));
$audio
.bind('timeupdate', function(event) {
$('.mplayer .currenttime').text(minAndSec(audio.currentTime));
});
Ve`ve put the cuiient time on the lelt anu total time on the iight, leaving ioom in the
miuule loi the tiack Lai (see Figuie 1+-2). Ve want the cuiient time to always iellect
wheie we aie in the song, so we Linu to auuio`s timeupdate notilication event. The event
itsell uoesn`t give us the currentTime. Foi that, we go to the audio.currentTime piopeity.
Ve neeu a small lunction to loimat it as minutes:seconus, since times in the auuio layei
aie in seconus.
Iigurc 11-2. Currcnt and tota| tinc |abc|s
14.10 Creating a jQuery UI Music Player | 331
Slider track for song position
Now we`ie getting somewheie. Next is oui tiack Lai. It consists ol a simple <div>, Lut
we`ie going to give it a tiack anu hanule Ly calling .slider() on it. Ve`ll use Sliuei`s
range: 'min' option so that the iegion Letween 0:00 anu the cuiient time will Le
shaueu. Oh yeah, anu we have to set max to the uuiation ol the song, in seconus. So il
it`s a 3.5-minute song, we`ll set max to 210. No calculations aie neeueu, Lecause
audio.duration alieauy gives us the total numLei ol seconus in the song. The othei
uelaults loi Sliuei woik loi us heie: max: 0, step: 1.
Heie`s the CSS:
.mplayer .track { top: 11px; margin: 0 5.2em; margin-top: 2px;
border-style: none; }
.mplayer .track .ui-slider-handle { border-left-width: 0; height: 1.1em;
top: 0.24em; width: 2px; margin-left: 3px; }
Heie`s the HTML:
<div class="mplayer ui-widget">
<div class="buttons-container">
<a class="playpause ui-state-default ui-corner-all" href="#">
<span class="ui-icon ui-icon-play"></span>
<span class="ui-icon ui-icon-pause"></span>
</a>
</div>
<span class="currenttime ui-state-default"></span>
<div class="track"></div>
<span class="duration ui-state-default"></span>
</div>
Heie`s the ]avaSciipt:
$('.mplayer .track')
.slider({
range: 'min',
max: audio.duration,
slide: function(event, ui) {
$('.ui-slider-handle', this).css('margin-left',
(ui.value < 3) ? (1 - ui.value) + 'px' : '');
if (ui.value >= 0 && ui.value <= audio.duration) {
audio.set('currentTime', ui.value);
}
},
change: function(event, ui) {
$('.ui-slider-handle', this).css('margin-left',
(ui.value < 3) ? (1 - ui.value) + 'px' : '');
}
})
.find('.ui-slider-handle').css('margin-left', '0').end()
.find('.ui-slider-range').addClass('ui-corner-left').end();
$audio
.bind('timeupdate', function(event) {
$('.mplayer .track').each(function() {
332 | Chapter 14:User Interfaces with jQuery UI
if ($(this).slider('value') != audio.currentTime) {
$(this).slider('value', audio.currentTime);
}
});
$('.mplayer .currenttime').text(minAndSec(audio.currentTime));
});
Sliuei hanules aie centei aligneu, meaning at the min value, the lelt hall ol the hanule
goes Leyonu the lelt ol the sliuei, anu when at the max point, the iight hall ol the hanule
goes Leyonu the iight ol the sliuei. Ve alieauy maue the hanule skinniei than noimal
anu got iiu ol the lelt Loiuei so it sticks to the iange a little Lettei. But we still neeu a
little Lit ol aujustment when neai the min. That`s what these lines aie loi:
slide: function(event, ui) {
$('.ui-slider-handle', this).css('margin-left',
(ui.value < 3) ? (1 - ui.value) + 'px' : '');
if (ui.value >= 0 && ui.value <= audio.duration) {
audio.set('currentTime', ui.value);
}
},
change: function(event, ui) {
$('.ui-slider-handle', this).css('margin-left',
(ui.value < 3) ? (1 - ui.value) + 'px' : '');
}
Also, in the slide callLack, we`ie checking whethei the value is valiu Leloie telling the
auuio to go to that point. This is a case wheie the usei is uiagging the sliuei aiounu,
anu we neeu to move aiounu the playLack point in the song. This allows loi sciuL-
Ling. Il we only hanuleu this in the change callLack, the auuio woulun`t change until
the usei let go ol the mouse, altei clicking oi uiagging the sliuei hanule to a new point.
Figuie 1+-3 shows the sliuei we`ve cieateu.
Iigurc 11-3. S|idcr trac| jor song position
Progress bar in track to show buffering
Get ieauy loi some lun. Vhat il I tolu you we can call two uilleient jQueiy UI plugins
on the same element? It woiks ieally well in this case. Ve alieauy have a tiack Lai,
which we cieateu as a <div>, calling .slider() on it. In auuition to auuing a ui-
slider class to oui .track element, the jQueiy UI Sliuei plugin cieateu anu appenueu
a couple elements to oui tiack, a sliuei hanule (.ui-slider-handle) anu a sliuei iange
(.ui-slider-range), since we specilieu range: 'min'. Foitunately, that`s as much as it
uiu to oui <div>. It`s still a <div>, anu it`s still oui <div>. So, let`s uual-puipose it anu
call .progressbar() on it. This will make it so oui Lullei uisplay iuns Lehinu the iange
uisplay that shows oui cuiient time. Check this out.
14.10 Creating a jQuery UI Music Player | 333
Heie`s the CSS:
.mplayer .ui-progressbar .ui-progressbar-value { border-style: none; }
Heie`s the ]avaSciipt:
var secondsCached = 0, cacheInterval;
$('.mplayer .track')
.progressbar({
value: secondsCached / secondsTotal * 100
})
.find('.ui-progressbar-value').css('opacity', 0.2).end();
cacheInterval = setInterval(function() {
secondsCached += 2;
if (secondsCached > secondsTotal) clearInterval(cacheInterval);
$('.mplayer .track.ui-progressbar')
.progressbar('value', secondsCached / secondsTotal * 100);
}, 30);
Theie`s no HTML, since we`ie ieusing the .track element liom the pievious section.
Oh, anu in case you haun`t noticeu, that Lulleiing coue is totally Logus. Vell, it woiks;
it just isn`t iepiesenting a song Leing Lulleieu, only simulating it. But it woiks gieat! Il
you ieally hau a music iesouice that was coming in anu Lulleiing anu youi auuio API
suppoiteu notilying you ol that, you`u Linu to the event anu set the piogiess Lai value
as shown eailiei, Letween 0 anu 100. Unlike Sliuei, you can`t specily a custom max loi
piogiess. But that makes sense, iight? Piogiess goes liom 0 peicent to 100 peicent.
OK, so we have got some piool-ol-concept coue heie. Vhen the page loaus, the Lullei
piogiess will iace away as il the lile is llying in, Lut not guite as il it`s local. It`s lun to
watch. Figuie 1+-+ shows the piogiess Lai we`ve cieateu. The othei thing that`s Logus
aLout oui Lullei piogiess inuicatoi? Since it isn`t a ieal Lullei piogiess, you can jump
Leyonu it. Vhat will happen? That uepenus on youi auuio API anu Lackenu. So, il you
uon`t have a Lullei piogiess oi uon`t want oi neeu one, skip this. Oi leave it in loi looks.
Iigurc 11-1. Progrcss bar in trac| to show bujjcring
Volume slider
So, we neeu to auu a volume contiol. Sliuei is a goou lit. Diag liom volume: 0 to volume:
1 anu set step to 0.01:
$('.mplayer .volume').slider({
max: 1,
step: 0.01,
value: audio.volume,
slide: fnSlide,
change: fnChange
});
334 | Chapter 14:User Interfaces with jQuery UI
Bam. Vhy not? Vell, that woulu ceitainly woik. But it woulu take up a Lit ol space.
Anu oiientation may Le an issue. Il we lay it out hoiizontally, which is the uelault loi
Sliuei, we`ie competing with the tiack loi hoiizontal space. Not to mention we`ie
lopsiuing oui playei. OK, so shoulu we auu orientation: 'vertical' to the sliuei
options? Vell, that too woulu woik, Lut it woulu mean oui playei is now 100 pixels
tall anu only in oiuei to lit the volume contiol. The iest ol the contiols neeu just ovei
30 pixels. Theie has to Le a Lettei way.
Theie is. Keep the volume sliuei`s Lai hiuuen when not in use. Ve`ll keep the sliuei
hanule visiLle anu auu a little speakei icon to it. Then we`ll hiue the iest Ly setting the
height ol the contiol to 0. Vhen the usei hoveis ovei the hanule, we`ll set the height
to 100 pixels. On mouseout, we`ll iemove that, anu it will go Lack to 0 height. Also,
with its containei positioneu aLsolutely in a ielative wiappei, it won`t allect the oveiall
height ol the playei when it is lully visiLle.
Theie`s one pioLlem. Vhen the Lai appeais, let`s say the volume is at 0.10, oi 10
peicent. That woulu mean the hanule is neai the Lottom. Shoulu the hanule jump
uown? Oi the Lai up? Anu what aLout while the usei sliues it? Vhat il they uiag liom
10 peicent up to 90 peicent anu then let go? It woulu jump Lack uown when the Lai
hiues again. Yuck.
So, heie`s what we`ie going to uo. Ve`ie going to keep the hanule lixeu the whole time.
The usei will uiag up loi inciease anu uown loi ueciease. The Lai, incluuing the range:
"min" shaueu poition Lelow the hanule, will move uown anu up accoiuingly.
Heie`s the CSS:
.mplayer .volume-container { position: absolute; top: 12px; right: 12px; }
.mplayer .volume { height: 0; margin-top: 5px; }
Heie`s the HTML:
<div class="mplayer ui-widget">
<div class="buttons-container">
<a class="playpause ui-state-default ui-corner-all" href="#">
<span class="ui-icon ui-icon-play"></span>
<span class="ui-icon ui-icon-pause"></span>
</a>
</div>
<span class="currenttime ui-state-default"></span>
<div class="track"></div>
<span class="duration ui-state-default"></span>
<div class="volume-container">
<div class="volume">
<a href="#" class="ui-state-default ui-corner-all
ui-slider-handle">
<span class="ui-icon ui-icon-volume-on"></span>
</a>
</div>
</div>
</div>
14.10 Creating a jQuery UI Music Player | 335
Heie`s the ]avaSciipt:
$('.mplayer .volume')
.slider({
max: 1,
orientation: 'vertical',
range: 'min',
step: 0.01,
value: audio.volume,
start: function(event, ui) {
$(this).addClass('ui-slider-sliding');
$(this).parents('.ui-slider').css({
'margin-top': (((1 - audio.volume) * 100) + 5) + 'px',
'height': '100px'
}).find('.ui-slider-range').show();
},
slide: function(event, ui) {
if (ui.value >= 0 && ui.value <= 1) {
audio.set('volume', ui.value);
}
$(this).css({
'margin-top': (((1 - audio.volume) * 100) + 5) + 'px',
'height': '100px'
}).find('.ui-slider-range').show();
},
stop: function(event, ui) {
$(this).removeClass('ui-slider-sliding');
var overHandle = $(event.originalEvent.target)
.closest('.ui-slider-handle').length > 0;
if (!overHandle) {
$(this).css({
'margin-top': '',
'height': ''
}).find('.ui-slider-range').hide();
}
},
change: function(event, ui) {
if (ui.value >= 0 && ui.value <= 1) {
if (ui.value != audio.volume) {
audio.set('volume', ui.value);
}
}
}
})
.mouseenter(function(event) {
if ($('.ui-slider-handle.ui-state-active').length) {
return;
}
$(this).css({
'margin-top': (((1 - audio.volume) * 100) + 5) + 'px',
'height': '100px'
}).find('.ui-slider-range').show();
})
336 | Chapter 14:User Interfaces with jQuery UI
.mouseleave(function() {
$(this).not('.ui-slider-sliding').css({
'margin-top': '',
'height': ''
}).find('.ui-slider-range').hide();
})
.find('.ui-slider-range').addClass('ui-corner-bottom').hide().end();
Vhile it`s Leing uiaggeu, we`ie aujusting the negative margin-top ol the Lai in inveise
piopoition to the cuiient value, keeping the hanule static. This happens heie:
$(this).parents('.ui-slider').css({
'margin-top': (((1 - audio.volume) * 100) + 5) + 'px',
'height': '100px'
})
Figuie 1+-5 shows the volume sliuei in oui playei.
Iigurc 11-5. \o|unc s|idcr
This inteiaction ieguiies iecognizing that you`ie not uiagging the Lai, which is what`s
moving, in the opposite uiiection ol youi mouse. But meanwhile, youi mouse, the size
ol the shaueu iange, anu youi volume uo move in logical conceit: uown loi uown, up
loi up. Also, il you pielei, you can hovei so that the Lai appeais, move youi mouse to
the position on the Lai wheie you want to set the volume, anu click.
Widget background and top styling
OK, let`s auu a couple elements with jQueiy UI CSS Fiamewoik classes to style the
playei in a way that matches the contiols within it:
Heie`s the CSS:
.mplayer .bg { position: absolute; width: 100%; height: 100%; top: 0;
bottom: 0; left: 0; right: 0; border: none; }
.mplayer .rod { position: absolute; top: 2px; left: 0.4%; right: 0.4%;
width: 100.8%; height: 3px; overflow: hidden; border: none; }
.mplayer .hl { position: absolute; top: 2px; left: 1%; right: 1%; width: 98%;
height: 1px; overflow: hidden; border: none; }
.mplayer .hl2 { position: absolute; top: 2px; left: 2%; right: 2%; width: 96%;
height: 3px; overflow: hidden; border: none; }
14.10 Creating a jQuery UI Music Player | 337
Heie`s the ]avaSciipt:
$('.mplayer').each(function() {
$('.bg:first', this).css('opacity', 0.7);
$('.bg:last', this).css('opacity', 0.3);
})
$('.mplayer .rod').css('opacity', 0.4);
$('.mplayer .hl').css('opacity', 0.25);
$('.mplayer .hl2').css('opacity', 0.15);
Heie`s the HTML:
<div class="mplayer ui-widget">
<div class="bg ui-widget-header ui-corner-bottom"></div>
<div class="bg ui-widget-content ui-corner-bottom"></div>
<div class="rod ui-widget-header"></div>
<div class="hl ui-widget-content"></div>
<div class="hl2 ui-widget-content"></div>
<div class="buttons-container">
<a class="playpause ui-state-default ui-corner-all" href="#">
<span class="ui-icon ui-icon-play"></span>
<span class="ui-icon ui-icon-pause"></span>
</a>
</div>
<span class="currenttime ui-state-default"></span>
<div class="track"></div>
<span class="duration ui-state-default"></span>
<div class="volume-container">
<div class="volume">
<a href="#" class="ui-state-default ui-corner-all
ui-slider-handle">
<span class="ui-icon ui-icon-volume-on"></span>
</a>
</div>
</div>
</div>
Heie we`ie using opacity anu layeiing to sgueeze a couple moie shaues out ol any
jQueiy UI theme. Figuie 1+-6 shows the linisheu piouuct:
Iigurc 11-. Widgct bac|ground and top sty|ing
338 | Chapter 14:User Interfaces with jQuery UI
Finally, Figuie 1+-7 shows a sampling ol the jQueiy UI music playei in a lew pieLuilt
jQueiy UI themes.
Iigurc 11-7. jQucry U| ncdia p|aycr in a jcw dijjcrcnt ThcncRo||cr thcncs
14.10 Creating a jQuery UI Music Player | 339
CHAPTER 15
jQuery UI Theming
Maggic Wachs, Scott ]chl, Todd Parkcr, and Patty Toland
(Filamcnt Group, Inc.)
15.0 Introduction
One ol the auvantages ol jQueiy UI is its ease ol integiation into such a wiue iange ol
weLsites anu applications. Anu a majoi lactoi loi successlul integiation is the aLility
to apply a look anu leel to jQueiy UI wiugets that`s consistent with a laigei site oi
system uesign.
jQueiy UI is expiessly uesigneu to make custom theming easy. You can cieate highly
customizeu visual styles loi youi wiugetsthat automatically incluue not only colois
anu textuies Lut a lull complement ol inteiaction statesusing the lollowing:
The jQueiy UI CSS Fiamewoik, a compiehensive set ol CSS classes loi applying
consistent styles anu Lehaviois acioss wiugets
ThemeRollei, jQueiy UI`s tool loi theme cieation
Togethei, they pioviue ways to easily anu consistently change the look anu leel ol Loth
ollicial jQueiy UI wiugets anu youi own custom components so they Llenu seamlessly
with youi site oi application.
This chaptei locuses how to get the most out ol these tools, whethei you`ie using them
to customize an ollicial jQueiy UI wiuget oi incoipoiating them into youi own custom
uevelopment woikllow. Ve`ll stait with a summaiy ol the jQueiy UI CSS anu how it
woiks with ThemeRollei, anu then we`ll piesent loui theming iecipes in this oiuei:
1. Styling jQueiy UI wiugets with ThemeRollei
2. Oveiiiuing jQueiy UI layout anu theme styles
3. Applying a ThemeRollei theme to non-jQueiy UI components
+. Releiencing multiple themes on a single page
341
Each iecipe staits with a Lasic sample uesign challenge anu piogiessively applies tech-
nigues to customize the theme. Foi that ieason, you`ll lieguently see ieleiences liom
one iecipe to anothei in this chaptei.
Beloie we uive into styling the wiugets, it`s impoitant to unueistanu how all ol the
jQueiy UI classes aie stiuctuieu anu how they woik with ThemeRollei.
Understanding the Components of jQuery UI CSS
Oui piimaiy goal when cieating the jQueiy UI CSS was to simplily the setup piocess
so that uevelopeis coulu ueploy wiugets guickly anu seamlessly in theii coue without
having to silt thiough complex maikup oi CSS.
In oui eaily expeiience integiating thiiu-paity ]avaSciipt wiugets into oui own piojects,
customizing the appeaiance ol liLiaiy wiugets was signilicantly haiuei than setting up
the sciipts to iun piopeily. Unlike the sciipts, which weie uesigneu to Le customizeu
coie anu wiuget plugin sciipts hanule complex tasks Lehinu the scenes anu conliguiaLle
options aie maue easily accessiLle loi customizationwiuget styles weie geneially
keyeu oll ol a single class oi Lakeu into the maikup. Ve hau to iuentily classes in the
maikup anu ueconstiuct theii style iules Leloie we coulu mouily them, which usually
involveu seveial houis ol silting thiough the coue anu CSS, using FiieLug to liguie out
wheie classes aie assigneu oi linu inline styles, ietiolitting Lackgiounu images, anu
then ieplacing style iules oi euiting classes in the maikup to make the appeaiance
appioximate oui pioject`s uesign. (Anu that was only when the coue anu CSS weie
ieasonaLly oiganizeu anu consistent.)
To us, this lelt Lackwaiu; it woulu Le much easiei to auu a custom look anu leel to a
mostly unstyleu wiuget than to pick apait the CSS ol an alieauy-styleu wiuget anu tiy
to liguie out which iules can salely Le ieplaceu. Ve iesolveu to uevelop a Lettei way
to apply styles consistently so they woulu woik coheiently acioss a gioup ol wiugets
anu within a laigei site oi application uesign system.
To solve this pioLlem loi jQueiy UI, we uiviueu the jQueiy UI CSS into logical com-
ponents, similaily to how the sciipts aie stiuctuieu, anu sepaiateu coie stiuctuial styles
ieguiieu loi a wiuget to lunction piopeily (positioning, lloats, anu pauuing) liom the
customizaLle theme styles (colois anu Lackgiounu images). So, the classes that uevel-
opeis can mouily to make the wiugets match theii pioject aie now gioupeu into two
Lasic categoiies:
Viuget-specilic classes incluue all styles ieguiieu to loimat a paiticulai wiuget`s
stiuctuie anu layout, incluuing positioning, spacing anu uimensions, anu othei
layout-ielateu styles to help it lunction coiiectly. Foi instance, Viuget classes loi
the taLs incluue styles that lloat taLs so they appeai in a hoiizontal iow anu selec-
tively hiue the associateu taL content panels.
Viuget-specilic classes aie incluueu in the accompanying CSS when you uownloau
one oi moie jQueiy UI wiugets (see Recipe 15.1 to leain how to uownloau anu
342 | Chapter 15:jQuery UI Theming
ieleience jQueiy UI CSS). Classes aie nameu loi the specilic wiuget they contiol,
anu the class name always Legins with the pielix ui-[widgetname], e.g., ui-tabs.
Fiamewoik classes apply a customizeu theme look anu leelincluuing a Lase lont,
Lackgiounu colois anu textuies, lont anu icon colois, shape (coinei iauius), anu
inteiaction state leeuLackacioss all wiugets. Fiamewoik classes aie nameu
accoiuing to theii Lasic puiposeloi example, some pioviue state leeuLack
(ui-state-default, ui-state-hover) oi apply iounueu coineis (ui-corner-all,
ui-corner-top)anu aie intenueu loi ieuse thioughout a weLsite oi application.
In lact, they can Le applieu to any wiuget, incluuing those cieateu Ly jQueiy UI oi
anothei ]avaSciipt liLiaiy oi youi custom wiugets.
In piactice, we style jQueiy UI wiugets Ly assigning a comLination ol these classes
one oi moie uesciiptive Viuget-specilic classes along with a seiies ol geneiic Fiame-
woik classesthat woik togethei to cieate the linal appeaiance. Foi example, look at
the maikup loi the accoiuion heauei:
<h3 class="ui-accordion-header ui-state-active ui-corner-top">code</h3>
Thiee classes aie applieu that assign veiy specilic styles:
ui-accordion-header is a Viuget-specilic class unigue to this component; it sets
stiuctuial style iules (positioning, uimensions, maigin, pauuing) Lut uoes not ap-
ply any colois oi images.
ui-state-active is a Fiamewoik class that auus the theme colois anu Lackgiounu
images to show its active state.
ui-corner-top, anothei Fiamewoik class, specilies that the heauei shoulu have
iounueu top coineis.
Although this appioach means that multiple classes aie assigneu to some elements, it`s
a poweilul system that makes it easy to apply a veiy lightweight theme to an unlimiteu
numLei ol wiugets, even youi own custom components. The caielul sepaiation ol the
stiuctuial styles liom the theme also means that you can uiop in a new theme at any
time without woiiying aLout it Lieaking youi existing wiugets.
Ve also wanteu to make it easy to cieate a new look anu leel, oi accuiately match an
existing uesign, without ueep expeitise in CSS oi photo-euiting tools like AuoLe
Photoshop. ThemeRollei lets uevelopeis euit style iules set Ly the Fiamewoik classes
without having to touch the CSS oi uo any manual image piouuction.
ThemeRollei is a weL application that olleis a lun anu intuitive inteilace loi uesigning
anu uownloauing custom themes loi jQueiy UI. ThemeRollei pioviues leveis to change
the lollowing theme styles:
Basc jont jor a|| widgcts: The Lase lont sets a stanuaiu typelace, size, anu weight
(noimal oi Lolu) that will Le useu thioughout all the wiugets in the theme. By
uelault, lont size is specilieu in em units. Ve iecommenu using ems ovei pixels
so text will scale with the wiuget containeis when the usei manipulates Liowsei
15.0 Introduction | 343
text size, Lut you can specily pixels il you like. As with stanuaiu CSS, it`s goou
piactice to pioviue a iange ol lonts in case youi liist lont ol choice is not installeu
on a usei`s computei anu to enu the lont stiing with the geneiic lont style like
seiil oi sans-seiil.
Corncr radius: A coinei iauius can Le applieu consistently acioss all wiugets in the
theme to give them a iounueu appeaiance. Each iauius value must Le lolloweu Ly
a unit: pixels loi a lixeu iauius, ems loi a iauius that iesponus to text size changes,
oi a value ol zeio loi peilectly sguaie coineis. Smallei pixel values make the coineis
ol wiugets moie sguaie, while laigei values make the coineis moie iounu.
As ol this wiiting, coineis set in CSS3 as we uo in the Fiamewoik aie
not suppoiteu in some mouein Liowseis, incluuing Inteinet Exploiei.
Please see the siueLai in Recipe 15.1 to leain how to Liing iounueu
coinei suppoit to these Liowseis.
Hcadcrs, too|bars, and contcnt arcas: Each ol these leveis sets a Lackgiounu coloi
with a semitianspaient textuie anu colois loi Loiuei, text, anu icons. Foi example,
the heauei style is useu loi the title Lai ol a uialog oi uatepickei anu the selecteu
iange ol a sliuei oi piogiess Lai, while the content style is useu loi the content aiea
ol a selecteu accoiuion oi taL.
Dcjau|t, activc, and hovcr statcs jor c|ic|ab|c c|cncnts: Theie aie thiee states that
iepiesent uilleient points in the usei inteiaction: default is the stanuaiu clickaLle
state, hover is useu to pioviue visual leeuLack when the mouse is placeu ovei the
item, anu active is useu when the item is cuiiently selecteu. Each clickaLle state
is uelineu Ly a Lackgiounu coloi with a semitianspaient textuie anu Ly colois loi
Loiuei, text, anu icons. Keep in minu that each state shoulu Le uilleient enough
to pioviue aueguate leeuLack to the usei.
High|ight and crror statcs: These aie special styles loi communicating states in a
system. The highlight state is useu on text messages to uiaw a usei`s attention, as
well as to inuicate touay`s uate in the calenuai wiuget, anu is also uselul loi high-
lighting when an Ajax scieen upuate has occuiieu. The eiioi state can Le useu to
inuicate that theie is a pioLlem that ieguiies the usei`s attention such as uisplaying
a loim valiuation issue oi aleiting the usei to a system lailuie. Both aie uelineu Ly
a Lackgiounu coloi with a semitianspaient textuie anu Ly colois loi Loiuei, text,
anu icons. These states shoulu contiast with the stanuaiu content text anu Lack-
giounu colois in youi theme anu shoulu also Le uilleient enough liom each othei
so that it`s cleai which one is meant to uiaw attention veisus communicate an aleit
oi waining message.
Moda| scrccn jor ovcr|ays: The moual scieen is a layei that sits Letween a moual
uialog anu the page content Leneath it anu is commonly useu to make page content
appeai tempoiaiily uisaLleu while the moual is showing. This levei styles the moual
344 | Chapter 15:jQuery UI Theming
scieen`s Lackgiounu coloi anu opacity. Il you uon`t want a moual oveilay at all loi
a paiticulai wiuget, that can Le toggleu thiough the wiuget`s modal option.
Drop shadow sty|cs: As with the highlight anu eiioi states, a uiopshauow style can
Le optionally applieu to oveilays. Diop shauows have Lackgiounu coloi, textuie,
anu opacity (like heaueis anu clickaLle elements), anu also have a shauow thickness
specilying how lai the shauow shoulu Le ollset liom the top-lelt coinei ol its com-
ponent anu a coinei iauius. To make the shauow appeai evenly aiounu the com-
ponent, the top anu lelt ollset values shoulu Le negative anu egual to the shauow
thickness. As with stanuaiu coinei iauius, you can set a shauow coinei iauius in
pixels oi ems oi entei zeio to make coineis sguaie.
The ThemeRollei inteilace lets you uiiectly euit all ol the pievious Fiamewoik class
styles anu pieview youi uesign changes in lunctioning jQueiy UI wiugets. Once you`ve
cieateu a theme, ThemeRollei automatically geneiates anu packages all ieguiieu CSS
anu Lackgiounu imagesyou simply uownloau the iesulting theme stylesheet anu
ieleience it in youi pioject. (You`ll linu ThemeRollei in the Themes section ol the
jQueiy UI site oi at http://thcncro||cr.con.)
Now that we`ve ievieweu the jQueiy UI CSS anu ThemeRollei, we`ll look at loui iecipes
that use them to customize themes. Fiist, we`ll stait with the simple step ol cieating a
theme anu styling wiugets with ThemeRollei (Recipe 15.1); then we`ll move thiough
slightly moie complex steps ol oveiiiuing Fiamewoik classes loi moie customizeu
themes (Recipe 15.2), using Fiamewoik classes thioughout youi pioject (Rec-
ipe 15.3), anu linally looking at multiple themes on a single page loi complex inteilaces
(Recipe 15.+).
Foi uesigneis anu uevelopeis who aie inteiesteu in euiting anu
pieviewing themes loi jQueiy UI anu custom ThemeRollei-ieauy com-
ponents in place in youi weLsite oi application, we uevelopeu a uown-
loauaLle ThemeRollei Lookmaiklet tool. To leain moie aLout anu
uownloau the Lookmaiklet, go to ui.jgueiy.com/themeiollei.
15.1 Styling jQuery UI Widgets with ThemeRoller
Problem
jQueiy UI wiugets useu in youi weLsite oi application must match an estaLlisheu
uesign.
Solution
Use ThemeRollei, a simple weL application loi euiting the jQueiy UI CSS Fiamewoik
classes to customize the look anu leel ol the jQueiy UI wiugets.
15.1 Styling jQuery UI Widgets with ThemeRoller | 345
This iecipe makes the lollowing assumptions:
You have a Lasic knowleuge ol how CSS woiks anu, specilically,
how styles cascaue, take pieceuence, anu can Le scopeu using se-
lectoi classes, ius, oi elements. (Foi oui iecommenueu iesouices,
please ielei to the Appenuix at the enu ol this chaptei.)
You`ie alieauy lamiliai with jQueiy UI CSS classes. (Il not, just
ieview Unueistanuing the Components ol jQueiy UI
CSS on page 3+2.)
Let`s walk thiough an example.
Ve`ie woiking on a new weLsite loi Looking tiavel ieseivations, anu specilically, we`ie
Luiluing out the pait ol the inteilace loi Looking a llight. The uesign consists ol a set
ol taLs loi selecting the type ol ieseivation (llight, cai iental, oi package ueal), anu the
Book a Flight taL incluues a loim loi enteiing the numLei ol passengeis, selects loi the
uepaituie anu aiiival cities, calenuais to set uepaituie anu ietuin tiavel uates, anu a
suLmit Lutton (see Figuie 15-1).
Iigurc 15-1. Iina| targct dcsign jor travc| app|ication
346 | Chapter 15:jQuery UI Theming
Foi this iecipe, we`ll use the jQueiy UI wiugets loi the taLs anu uatepickeis, anu style
them with a custom theme cieateu in ThemeRollei. (You can also mouily the theme
stylesheet Leyonu the stanuaiu ThemeRollei output to moie closely match youi
uesignyou`ll see how in Recipes 15.215.+).
Step 1. Open ThemeRoller
Open the jQueiy UI weLsite at http://jqucryui.con anu choose Themes liom the top
navigation Lai, oi go uiiectly to http://thcncro||cr.con.
The inteilace loi ThemeRollei is gioupeu into two main sections, as shown in Fig-
uie 15-2:
ThcncRo||cr too|bar panc in thc |cjt co|unn, which pioviues tools to set anu change
all style settings in a theme
Sanp|c widgcts prcvicw panc on thc right loi pieviewing youi style selectionseach
wiuget is inteiactive to show the lull iange ol styles (use youi mouse to see hovei
anu active styles, loi example) anu upuates in ieal time when you euit styles using
the toolLai
Iigurc 15-2. Thc dcjau|t vicw oj ThcncRo||cr, with thc too|bar panc on thc |cjt and widgcts prcvicw
panc on thc right
15.1 Styling jQuery UI Widgets with ThemeRoller | 347
The ThemeRollei toolLai pioviues two uistinct ways to customize themes, accessiLle
with the taLs at the top ol the toolLai column:
Thc Ro|| Your Own tab (Figuie 15-3) is the woikspace wheie you cieate custom
styles loi youi theme. CustomizaLle settings aie gioupeu into sections with inputs
anu tools loi guick style selection, incluuing setting the Lase lont anu coinei iauius
acioss all wiugets anu setting Lackgiounu colois anu textuies, text coloi, anu icon
coloi.
Each section is closeu Ly uelault anu uisplays cuiient styles in the loim ol a small
icon to the iight ol the laLel. Open/close sections as neeueu while you euit, anu
pieview sample wiugets to the iight, which upuate to iellect youi changes in
ieal time.
]avaSciipt is not ieguiieu to use ThemeRollei. Il ]avaSciipt is uis-
aLleu, a Pieview Lutton appeais that may Le clickeu to view
changes.
Thc Ga||cry tab (Figuie 15-3) olleis a iange ol pieconliguieu themes that can Le
uownloaueu as is oi useu as a staiting point loi a moie customizeu theme.
Iigurc 15-3. ThcncRo||cr`s Ro|| Your Own tab (A) providcs contro|s to changc thc jont, corncr radius,
and co|ors jor a rangc oj intcraction statcs, thc Ga||cry tab (B) providcs onc-c|ic| acccss to a varicty
oj prcbui|t thcncs
348 | Chapter 15:jQuery UI Theming
Step 2. Create and preview a theme
Foi oui tiavel ieseivations app, we`ll select a galleiy theme calleu Sunny that`s close to
oui linal uesign (as shown in Figuie 15-+).
Iigurc 15-1. ThcncRo||cr`s ga||cry thcncs ojjcr a widc rangc oj starting points jor custonizing
dcsigns, Sunny (A) sharcs nany sty|cs with our targct dcsign (B)
Sunny specilies similai oveiall Lackgiounu, lont lace, anu lont colois to oui linal uesign,
Lut a couple ol styles will neeu to Le euiteu to moie closely match oui uesignloi
instance, Sunny`s taLs aie yellow with a giay Lackgiounu, while oui taLs aie uaik giay
with a white Lackgiounu.
Ve can easily change those settings Ly eithei clicking the Euit Lutton Lelow the Sunny
image in the galleiy (which will move you ovei to the Roll Youi Own view) oi clicking
the Sunny image in the galleiy to activate it anu then clicking ovei to the Roll Youi
Own taL at the top ol the toolLai.
Once you have the Sunny settings in the Roll Youi Own taL, the toolLai pielills with
all the theme`s settings, anu you can stait euiting. Let`s tweak the lollowing settings to
make the Sunny theme match oui uesign:
Sct thc basc jont jor a|| widgcts: The uelault lont in the Sunny theme anu oui taiget
uesign seem veiy similai, Lut we can simply open the Font Settings section (as
shown in Figuie 15-5) anu eithei conliim that they aie coiiect oi lill in alteinate
values loi lont lamily, weight, anu size. The lont lamily accepts multiple comma-
sepaiateu lont names (as in stanuaiu CSS notation). Heie aie some uesign notes
anu tips:
15.1 Styling jQuery UI Widgets with ThemeRoller | 349
By uelault, the lont size is specilieu in em units. Ve iecommenu using ems
in lavoi ol pixel text sizes so wiuget text will scale with the wiuget containeis
when the usei manipulates Liowsei text size.
Pioviue a iange ol lonts in case youi liist lont ol choice is not installeu on a
usei`s computei. It`s goou piactice to enu a lont stiing with the geneiic lont style
like seiil oi sans-seiil.
Iigurc 15-5. Thc Iont Scttings and Corncr Radius scctions
App|y a corncr radius: Oui uesign incluues iounueu coineis on the uatepickei anu
taLs. You can set a coinei iauius on jQueiy UI wiugets in ThemeRollei Ly opening
the Coinei Rauius section (as shown in Figuie 15-5) anu enteiing a value lolloweu
Ly a unit: pixels loi a lixeu iauius, oi ems loi a iauius that iesponus to text size.
Smallei pixel values make the coineis ol wiugets moie sguaie, while laigei values
make the coineis moie iounu. Foi peilectly sguaie coineis, set the value to zeio.
350 | Chapter 15:jQuery UI Theming
At the time ol wiiting ol this euition, some mouein Liowseis, most
notaLly Inteinet Exploiei, uo not suppoit the CSS3 border-
radius piopeity anu as a iesult uo not ienuei the iounueu coinei
styles applieu Ly Fiamewoik classes. Coineis appeai sguaie in-
steau. Il youi uesign incluues iounueu coineis anu must ienuei
consistently acioss all Liowseis, you may want to use a coinei-
iounuing ]avaSciipt liLiaiy like uuRounuies.
Ve`ve wiitten a Lasic tutoiial on oui Filament Gioup laL explain-
ing how to incoipoiate uuRounuies into youi pioject: Achieving
Rounueu Coineis in Inteinet Exploiei loi jQueiy UI with
DDiounuies.
Ma|c thc dcjau|t tabs and buttons gray. Unselecteu taLs, like accoiuion section
heaueis oi uatepickei Luttons, aie clickaLle elements, anu each is assigneu a class
that iepiesents its cuiient clickaLle state: uelault, hovei, oi active. In this case we`ll
change the uelault state Lackgiounu coloi liom giay to yellow anu upuate text anu
Loiuei coloi to match oui uesign (Figuie 15-6):
1. Open the ClickaLle: uelault state section.
2. Focus youi cuisoi on the Lackgiounu coloi lielu (it contains a hexauecimal
value pieceueu Ly #), anu pick a new uaik giay coloi oi entei a hexauecimal
value; in this case we`ll entei the value #333333.
3. The text coloi is uaik giay anu now Llenus with oui Lackgiounu, so we`ll also
upuate the uelault state text coloi to contiast with the Lackgiounu. Ve`ll
change the text coloi value to #FFFFFF.
+. As with the text, the icons that appeai in the heauei aie giay anu neeu to Le
upuateu so they uon`t uisappeai against the giay Lackgiounu. Let`s give them
a value ol #EEEEEE, a coloi that will complement Lut won`t appeai highei con-
tiast than the text.
5. Finally, let`s change the Loiuei coloi liom yellow to light giay; entei value
#D2D2D2.
6. Hit the TaL oi Entei key, oi click elsewheie on the page, to pieview the changes
in the wiugets on the iight.
15.1 Styling jQuery UI Widgets with ThemeRoller | 351
Iigurc 15-. ThcncRo||cr`s scction jor thc C|ic|ab|c: dcjau|t statc
Updatc thc hovcr statc to natch thc ncw tab co|or: The clickaLle hovei state style is
intenueu to Le shown whenevei you mouse ovei a clickaLle component like a taL,
accoiuion section, oi uatepickei Lutton. Now that the uelault state is giay, we`ll
aujust the hovei state`s Lackgiounu anu text colois to cooiuinate anu use a com-
plementaiy uaikei shaue ol giay loi the Lackgiounu with white text anu icons:
1. Open the ClickaLle: hovei state section.
2. In the Lackgiounu coloi lielu entei the value #111111.
3. Upuate the text anu icon colois to #FFFFFF.
+. Let`s also make the Loiuei coloi Lettei match oui uesign Ly setting it to a
slightly uaikei giay than the uelault Loiuei, #888888.
Changc thc tabs and datcpic|cr hcadcr bac|grounds to whitc: The heauei style ap-
peais in seveial jQueiy UI wiugets: Lehinu the taLs, at the top ol uatepickei`s
month/yeai leeuLack anu navigation Luttons, as the sliuei iange, anu as the pio-
giess Lai completion inuicatoi. In oui uesign the heauei is a llat white coloi with
giay text anu uaik yellow icons:
1. Open the Heauei/ToolLai section.
2. In the Lackgiounu coloi lielu entei a hexauecimal value ol #FFFFFF.
3. Click the textuie icon next to the Lackgiounu input, anu choose the liist op-
tion, llat. (Hovei ovei any textuie image to see the name.) Doing this ie-
moves the Lackgiounu image so that the style only sets a llat Lackgiounu coloi.
+. Set the Lackgiounu opacity to 100 peicent to ensuie that the heauei is lully
opague.
352 | Chapter 15:jQuery UI Theming
5. The text coloi is white anu uoesn`t show up on oui new Lackgiounu, so let`s
change it to uaik giay to match oui uelault clickaLle state, #333333.
6. Finally, change the Loiuei anu icon colois to #EDAA12, anu the text coloi to
white, #FFFFFF.
Changc thc contcnt containcr bordcr co|or to yc||ow: Content Loiueis appeai aiounu
accoiuion sections, anu ueline the taLs, uialog, sliuei, uatepickei, anu piogiess Lai
containeis. In the uesign the Loiuei is the same light yellow we useu loi the heauei
Loiuei:
1. Open the Content section.
2. Focus on the Loiuei coloi lielu, anu entei the value #EDAA12.
Updatc thc activc statc bordcr co|or to b|cnd with thc containcr: Altei upuating
the containei Loiuei coloi, you`ll see that the selecteu accoiuion section anu se-
lecteu taL still have uaik giay Loiueis. This coloi is set with the clickaLle active
state class:
1. Open the ClickaLle: active state section.
2. Focus on the Loiuei coloi lielu, anu entei the value #EDAA12.
You can save a theme at any point simply Ly Lookmaiking the page;
ThemeRollei upuates the URL with all ielevant styles each time the
pieview pane ielieshes. Bookmaik youi custom themeeven Look-
maik multiple themes to compaie them siue Ly siueanu ieloau any
theme liom its Lookmaik to mouily anu ieline it loi uownloau.
Also, loi any theme uownloaueu liom ThemeRollei, a complete theme
URL is incluueu in the stylesheet. Open the stylesheet (e.g., jquery-
ui-1.7.1.custom.css), anu seaich loi the comment that staits with this:
To view anu mouily this theme, visit http://jgueiyui.com/
themeiollei/...
At this point, we have maue oui ThemeRollei theme match the uesign ol oui tiavel
ieseivations app as closely as we can (see Figuie 15-7). It`s now ieauy loi uownloau.
15.1 Styling jQuery UI Widgets with ThemeRoller | 353
Iigurc 15-7. Our jina| custonizcd ThcncRo||cr thcnc that c|osc|y natchcs our dcsign
Step 3. Download the jQuery UI widgets and theme
Click the Downloau theme Lutton at the top ol the ThemeRollei toolLai`s Roll Youi
Own taL, which navigates you to the jQueiy UI uownloau Luiluei (see Figuie 15-S).
In the iight column unuei Theme, you`ll see Custom Theme pie-selecteu in the uiop-
uown.
Il you chose a uelault theme liom the galleiy anu maue no changes to
it, you`ll see the name ol that theme, e.g., Smoothness.
Next, we`ll select which jQueiy UI components to uownloau with oui theme. All aie
selecteu Ly uelault; simply uncheck those you uon`t want to uownloau, oi click De-
select all components at the top ol the Components section to uownloau only the
theme stylesheet. Foi oui tiavel ieseivations app, we neeu the jQueiy UI coie sciipts
anu those loi taLs anu the uatepickei.
354 | Chapter 15:jQuery UI Theming
Finally, select which veision ol jQueiy UI you`u like to use; the latest staLle veision is
selecteu Ly uelault. Click Downloau, anu save the ZIP lile locally. The uownloaueu ZIP
lile will Le nameu like jqucry-ui-1.7.1.custon.zip.
(The Auvanceu Theme Settings section in the uownloau Luiluei`s Theme section allows
you to uownloau a scopeu themewe`ll get to that in uetail in Recipe 15.+.)
Iigurc 15-8. Thc jQucry down|oadcr conbincs U| corc, any intcractions and widgcts you sc|cct, and
your thcnc into a sing|c zippcd ji|c
15.1 Styling jQuery UI Widgets with ThemeRoller | 355
The jQueiy UI CSS is upuateu with each new veision ol jQueiy UI
e.g., new ieleases will incluue not only upuateu sciipts Lut may also
incluue mouilications anu upuates to the CSS as well.
At the time ol this wiiting, the veision ol jQueiy UI is 1.7, anu iecipes
anu technigues in this chaptei aie applicaLle only to theming leatuies
in that veision.
Step 4. Merge files into your project directory
Next, we`ll open the ZIP lile we uownloaueu in the pievious step anu ieview its con-
tents. jQueiy UI liles aie aiiangeu into the lollowing uiiectoiy stiuctuie; the oiuei ol
the lolueis anu liles may vaiy uepenuing on youi opeiating system (Figuie 15-9 shows
the loluei openeu on Mac OS X).
Iigurc 15-9. jQucry down|oad jo|dcr structurc
indcx.htn|
Sample maikup loi the UI components you selecteu.
Il you chose not to uownloau any components, this lile will not Le
incluueu in the uownloau.
/css
Contains a theme loluei (e.g., custon-thcnc) with the lollowing liles:
An images uiiectoiy with liamewoik icons anu Lackgiounu textuies.
356 | Chapter 15:jQuery UI Theming
Youi theme stylesheet, e.g., jquery-ui-1.7.1.custom.css, which incluues the
styles you just euiteu anu, il uownloaueu, the wiuget-specilic styles necessaiy
loi the wiugets to lunction piopeily.
/js
Compileu jQueiy UI ]avaSciipt liles.
/dcvc|opncnt-bund|c
Inuiviuual component sciipts anu CSS useu to cieate the compileu veisions lounu
in the css anu js lolueis, open souice license text, anu ielateu iesouices necessaiy
loi auvanceu uevelopment with jQueiy UI.
Vhen woiking on youi own pioject, Le suie to ieview the maikup in indcx.htn| anu
use it as a guiue along with the Demos e Documentation at http://jqucryui.con to
integiate the component maikup anu sciipts into youi pioject.
Foi oui tiavel application, we`ll copy the theme loluei in the css uiiectoiy anu paste it
to the styles uiiectoiy in oui pioject; to keep it simple, we nameu the styles loluei css
to match.
It`s impoitant to maintain the estaLlisheu uiiectoiy stiuctuie within the
theme loluei so that the icon images aie ieleienceu piopeily Ly the
theme classes. Il you uo change the theme uiiectoiy stiuctuie, you will
likely have to ieplicate those changes il latei you ueciue to upgiaue to a
newei veision ol the jQueiy UI sciipts anu CSS.
Step 5. Reference the theme stylesheet in your project
Finally, we`ll incluue a ieleience to the theme stylesheet in the <head> ol oui page.
Keep in minu that thc sty|cshcct rcjcrcncc shou|d a|ways appcar bcjorc any rcjcrcnccs to
jQucry U| scripts so that the CSS loaus liist; this is necessaiy Lecause some wiugets
uepenu on the CSS to lunction piopeily.
Ve`ll ieleience the theme stylesheet (in Lolu) Leloie all sciipts in oui tiavel
ieseivations app:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>travel application | Book a Flight, Rent a Car, or Find Package
Deals</title>
<!-- jQuery UI styles -->
<link rel="stylesheet" type="text/css" href="css/custom-theme/jquery-ui-
1.7.1.custom.css" />
<!-- jQuery core & UI scripts -->
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.1.custom.min.js"></script>
<script type="text/javascript">
15.1 Styling jQuery UI Widgets with ThemeRoller | 357
$(function(){
$('#travel').tabs();
$("#departure-date-picker").datepicker({altField: '#departure-date',
altFormat: 'MM d, yy'});
$("#arrival-date-picker").datepicker({altField: '#arrival-date',
altFormat: 'MM d, yy'});
});
</script>
</head>
Vhen the jQueiy UI wiuget maikup anu styles aie in place loi youi pioject, pieview
youi page in a Liowsei to conliim that the styles aie Leing applieu coiiectly. Pieviewing
oui tiavel application ieveals that the theme is applieu coiiectlyas you can see in
Figuie 15-10, oui uelault taLs aie giay, the heaueis aie white, anu the text anu icon
colois match oui selections.
Iigurc 15-10. Our dcsign intcrjacc with custonizcd ThcncRo||cr thcnc app|icd (A) and our targct
jina| dcsign (B)
But oui inteilace cleaily neeus moie woik to match oui taiget uesign (Figuie 15-10):
the taLs aie too small anu aie missing theii custom icons, anu the uatepickei heauei is
encloseu within the uatepickei wiuget when it shoulu appeai on top. In Recipe 15.2
we`ll ieview how to make small aujustments to theme styles so that these elements
Lettei match oui uesign.
358 | Chapter 15:jQuery UI Theming
Il the jQueiy UI wiugets in youi page aie not picking up the theme
stylesheet, uouLle-check the uiiectoiy path to the theme stylesheet
against the ieleience in youi page, anu coiiect any typos. Il that uoesn`t
solve the issue, tempoiaiily uisaLle any non-jQueiy styles oi sciipts to
test whethei they`ie inteileiing with how the theme stylesheet is loaueu
oi ienueieu, anu lix any ielateu Lugs.
Discussion
Since ThemeRollei themes aie stiuctuieu to uelivei a holistic expeiience anu apply
acioss multiple wiugets, it helps to think aLout how the vaiious Fiamewoik classes
inteiact with one anothei. Il you choose to cieate youi own theme liom sciatch, oi
suLstantially mouily an existing theme, heie aie some points you might want to
consiuei:
To cieate uniloim Lackgiounus loi heaueis anu toolLais anu content aieas to make
the on state taL appeai seamlessly connecteu to the visiLle content panel, anu match
the content aiea Lackgiounu anu Loiueis to youi clickaLle active state Lackgiounu anu
Loiueis.
Foi clickaLle elements, states shoulu Le cleaily uilleient enough to pioviue aueguate
leeuLack to the usei. Heie aie a couple ol ways to make suie the states woik togethei
to uelivei uistinctive visual uilleientiation:
Use miiioi image textuies loi the uelault anu active clickaLle states to achieve a
thiee-uimensional look anu leel. Foi instance, a highlight textuie loi the uelault
Lutton state paiis well with an inset textuie loi the active Lutton state. The
Lutton will look like it physically uepiesses on click.
Il you uo use the same textuie loi clickaLle anu hovei, make suie the Lackgiounu
coloi anu image opacity aie uilleient enough (geneially at least a 10 peicent shilt)
to pioviue a cleai visual change.
Optimize youi theme loi speeu Ly using the same image loi multiple styles. Foi
example:
Vhen you use the same icon coloi loi multiple states, the stylesheet will make
lewei HTTP ieguests, impioving page peiloimance.
You can also use the same Lackgiounu image (coloi plus textuie opacity) loi
multiple states as well. Il you uo this, it`s impoitant to make suie that the othei
style elementsLoiuei, text, anu icon coloisaie uistinct enough to make a cleai
uilleientiation.
15.1 Styling jQuery UI Widgets with ThemeRoller | 359
To make changes to youi custom theme without having to stait liom
sciatch, open the oiiginal theme stylesheet, seaich loi the comment that
staits with To view anu mouily this theme, visit http://jgueiyui.com/
themeiollei/..., anu copy anu paste the theme URL into a Liowsei`s
auuiess Lai to open ThemeRollei with that theme`s settings pieloaueu.
15.2 Overriding jQuery UI Layout and Theme Styles
Problem
The customizeu (oi stanuaiu galleiy) theme you cieateu in ThemeRollei, uownloaueu,
anu ieleienceu in youi pioject is a paitial match to youi taiget uesign Lut uoesn`t match
exactly. You neeu to mouily the styles, Lut at the same time you want to ensuie that
euits to these styles uon`t make it uillicult loi you to upgiaue to newei veisions ol
jQueiy UI sciipts anu CSS.
Solution
Cieate custom oveiiiue styles, scopeu to the components that neeu auuitional non-
ThemeRollei styling, anu stiuctuie them so that they uon`t conllict with oi oveiwiite
any stanuaiu jQueiy UI CSS liles.
The lollowing iecipe makes the lollowing assumptions:
You have a Lasic knowleuge ol how CSS woiks anu, specilically,
how styles cascaue, take pieceuence, anu can Le scopeu using se-
lectoi classes, IDs, oi elements. (Foi oui iecommenueu iesouices,
please ielei to the Appenuix at the enu ol this chaptei.)
You`ie alieauy lamiliai with how to cieate anu euit a theme using
ThemeRollei. (Il not, ieview Recipe 15.1, which uesciiLes in uetail
how to cieate a theme anu apply it to youi pages.)
Each jQueiy UI wiuget is styleu to woik out ol the Lox when you uownloau the jQueiy
UI sciipts anu a theme stylesheet; no changes to the CSS aie necessaiy to incoipoiate
the wiuget oi styles into youi site. But it`s possiLle that the styling may not exactly
match the uesign conventions estaLlisheu in youi pioject. Foi example, you may want
to ieuuce the pauuing oi use a custom Lackgiounu image loi a heauei.
Let`s pick up wheie we lelt oll in the pievious iecipe anu continue woiking on oui tiavel
ieseivations application. Ve cieateu, uownloaueu, anu applieu the theme stylesheet
coiiectly; howevei, the uelault jQueiy UI styles loi the taLs anu uatepickeis uon`t guite
match the uesign loi oui pioject, as shown in Figuie 15-11.
360 | Chapter 15:jQuery UI Theming
Iigurc 15-11. Our dcsign intcrjacc with custonizcd ThcncRo||cr thcnc app|icd (A) and thc targct
dcsign providcd by thc dcsigncr (B)
Step 1. Review the widget markup and styles for jQuery UI plugins
Fiist, we`ll ieview how classes aie assigneu in the jQueiy UI wiuget maikup to Lettei
unueistanu how they`ie applieu (anu can theieloie Le oveiiiuuen).
Let`s stait with the taLs maikup. Vhen the jQueiy UI taLs wiuget is initializeu on the
page, the plugin sciipt assigns seveial classes to the wiuget maikup, as shown next.
(Please note that this is the maikup that is tiansloimeu oi inseiteu Ly the plugin sciipt;
it`s the linisheu piouuct, not the maikup seiveu to the page Leloie ]avaSciipt is iun.)
Pay paiticulai attention to the classes that Legin with the pielix ui-tabsthe Viuget-
specilic classes loi the taLshighlighteu in Lolu:
<div class="ui-tabs ui-widget ui-widget-content ui-corner-all" id="travel">
<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header
ui-corner-all">
<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active">
<a href="#travel-flight" id="tab-flight">Book a Flight</a></li>
<li class="ui-state-default ui-corner-top"><a href="#travel-car"
id="tab-car">Rent a Car</a></li>
<li class="ui-state-default ui-corner-top"><a href="#travel-package"
id="tab-package">Package Deals</a></li>
</ul>
<div id="travel-flight" class="ui-helper-clearfix ui-tabs-panel
ui-widget-content ui-corner-bottom"></div><!-- /flight -->
<div id="travel-car" class="ui-tabs-panel ui-widget-content ui-corner-bottom
ui-tabs-hide"></div><!-- /car -->
<div id="travel-package" class="ui-tabs-panel ui-widget-content ui-corner-bottom
ui-tabs-hide"></div><!-- /package -->
</div><!-- /travel -->
15.2 Overriding jQuery UI Layout and Theme Styles | 361
These classes set the styles that contiol the wiuget`s layout anu enaLle it to lunction
piopeily accoiuing to its uesign. In this case, they tiansloim an unoiueieu list ol links
anu <div> elements into taLs with associateu content panels. (Viuget-specilic classes
aie uiscusseu in uetail in Unueistanuing the Components ol jQueiy UI
CSS on page 3+2 eailiei in this chaptei.)
They also iuentily a wiuget`s inuiviuual componentslike the heauei oi content
panelsanu as such they`ie iueal loi wiiting oveiiiue iules to aujust layout leatuies oi
auu customizations like uiawn icons. The Viuget classes loi the taLs maik the lollow-
ing components:
ui-tabs
Outei containei that wiaps aiounu the taL navigation anu content.
ui-tabs-nav
Containei loi the navigation options. The taL list items anu links aie styleu using
uescenuant selectois, i.e., ui-tabs-nav li.
ui-tabs-selected
Selecteu taL on state, which is uynamically Ly the sciipt. This class is assigneu
to only one taL at a time.
ui-tabs-panel
Content aieas that map to taLs.
ui-tabs-hide
Delault state loi the content panels. They`ie hiuuen until selectively shown Ly the
usei.
To see the style iules associateu with these classes, open the theme stylesheet anu linu
(Ctil/Commanu-F) oi scioll to the Llock that Legins with ui-tabs. Notice that the iules
only apply to layout chaiacteiistics, like positioning, pauuing, oi Loiuei wiuth, anu aie
aLsent any theme styles, like Lackgiounu oi Loiuei colois:
.ui-tabs { padding: .2em; zoom: 1; }
.ui-tabs .ui-tabs-nav { list-style: none; position: relative;
padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { position: relative; float: left;
border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none;
padding: .5em 1em; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px;
border-bottom-width: 0; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav
li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing
a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav
li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems
obsolete, but required to overcome bug in Opera applying cursor: text overall
if defined elsewhere... */
.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0;
background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }
362 | Chapter 15:jQuery UI Theming
Youi theme stylesheet will contain the ui-tabs style iules only il you`ve
also uownloaueu the taLs plugin.
Step 2. Create an override stylesheet
Ve`ve lounu the Lest way to salely line-tune a wiuget`s appeaiance is to wiite new style
iules that oveiiiue the jQueiy UI theme styles anu appenu these oveiiiue iules in a
sepaiate stylesheet. Oveiiiue iules aie wiitten against jQueiy UI CSS class names anu
as such nust appcar in thc sourcc ordcr ajtcr your thcnc sty|cshcct; since styles aie ieau
in oiuei, the last style iule always takes pieceuence.
The jQueiy UI liLiaiy is constantly evolving to incluue moie leatuies with Lettei-
stieamlineu coue. By maintaining oveiiiue styles in a sepaiate lile, you can customize
the wiuget styles as much oi as little as you`u like anu still pieseive the aLility to easily
upgiaue the jQueiy UI liles as neeueu anu simply oveiwiite youi existing theme style-
sheet knowing that youi oveiiiue iules iemain intact. Oveiiiue iules can Le listeu in a
ueuicateu stylesheet loi oveiiiuing uelault theme styles, oi il you pielei to limit the
numLei ol liles linkeu to youi pages (anu theieloie limit the numLei ol ieguests to the
seivei), appenu oveiiiue iules to the mastei stylesheet loi youi entiie pioject.
As we woik thiough this iecipe, we`ll appenu oveiiiue styles to the mastei stylesheet
loi oui pioject, travel.css, just Lelow the Llock ol custom styles we uevelopeu loi oui
application:
/* ----- CUSTOM STYLES for the travel application */
body { font-size: 62.5%; }
fieldset { padding: 0 0 1.5em; margin: 0 0 1.5em; border: 0; }
p, label { padding: 0 0 .5em; margin: 0; line-height: 1.3; }
p label { display: block; }
...
/* ----- OVERRIDE RULES for jQuery UI widgets */
/* tabs background styles go here */
...
Anu we`ll ieleience travel.css altei the theme stylesheet in oui page:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>travel application | Book a Flight, Rent a Car, or Find Package
Deals</title>
<!-- jQuery UI styles -->
<link rel="stylesheet" type="text/css" href="css/custom-theme/jquery-ui-
1.7.1.custom.css" />
<!-- overrides & custom styles for the travel application -->
<link rel="stylesheet" type="text/css" href="css/travel.css" />
....
15.2 Overriding jQuery UI Layout and Theme Styles | 363
Step 3. Edit the style rules in your override stylesheet
Now that we`ve ievieweu how the Viuget classes aie nameu anu applieu, anu also how
to ieleience oveiiiue styles in oui pioject, let`s upuate oui tiavel ieseivations applica-
tion with oui customizeu taLs navigation Lai anu uatepickei heauei style. Ve`ll tackle
the taLs liist.
The uesign we cieateu loi the taLs is specilic to the tiavel ieseivations
application, anu we uon`t necessaiily want the same customizations, like the icons oi
lont size, to apply to eveiy taL wiuget in oui entiie application. To ensuie that these
styles only apply to the tiavel application, we`ll scope the oveiiiue iules to oui tiavel
application`s unigue ID.
Each new iule will stait with the Viuget-specilic class assigneu to the component we
want to change; loi example, when changing styles loi the taL`s navigation Lai, we`ll
wiite a iule against the .ui-tabs-nav class:
.ui-tabs-nav { /* our override style rule */ }
Anu scope it to oui tiavel application Ly piepenuing its ID, travel:
#travel .ui-tabs-nav { /* our override style rule */ }
Altei applying the theme stylesheet, oui taL`s navigation panel looks
like Figuie 15-12: the inuiviuual taLs aie small anu suiiounueu Ly a Loiuei that`s sep-
aiateu liom the outeimost containei Ly a lew pixels ol pauuing.
Iigurc 15-12. Our tabs with ThcncRo||cr thcnc app|icd bcjorc ovcrridcs
Howevei, oui uesign (Figuie 15-13) calls loi laige taLs with icons anu without a Lack-
giounuthey appeai to sit aLove the taL content.
Iigurc 15-13. Our targct tab dcsign
To oveiiiue the uelault taL styles, we`ll make a hanulul ol style changes:
1. Fiist we`ll iemove the outeimost Loiuei. The entiie taLs wiuget is suiiounueu Ly
a 1-pixel Loiuei anu has a lew pixels ol pauuing. Foi the taLs to appeai aLove the
content panels, we`ll iemove Loth:
#travel.ui-tabs { padding: 0; border-width: 0; }
Scope overrides.
Write override rules.
364 | Chapter 15:jQuery UI Theming
Theie`s intentionally no space Letween oui scoping ID, #travel,
anu the .ui-tabs class Lecause Loth aie applieu to the same element
in the maikup:
<div id="travel" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
2. Next, we`ll llatten the Lottom ol the taL navigation Lai (set the Lottom-coinei
iauius to zeio) anu iemove its top anu siue Loiueis. Ve`ll also iemove any extia
pauuing so that the taLs appeai llush with the lelt siue ol the wiuget, anu we`ll
thicken the Loiuei wiuth to 3 pixels to match oui uesign:
#travel .ui-tabs-nav {
border-width: 3px;
border-top-width: 0;
border-left-width: 0;
border-right-width: 0;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
padding: 0;
}
3. The taLs aie a little too close togethei, so let`s auu some iight maigin:
#travel .ui-tabs-nav li {
margin-right: .5em;
}
+. Anu upuate the selecteu taL, .ui-tabs-selected, so that it appeais connecteu to
the taL content aiea. Ve`ll inciease the Loiuei wiuth to 3 pixels so that it matches
the uesign, anu we`ll then lix the gap Letween the taL anu content. The amount ol
space Letween the taL anu its content panel is uiiectly ielateu to the taL navigation
Lai`s Loiuei thickness, so we can close the gap Ly applying a negative 3-pixel Lot-
tom maigin:
#travel .ui-tabs-nav li.ui-tabs-selected {
border-width: 3px;
margin-bottom: -3px;
}
5. Next, we`ll apply oui custom icons. Because each icon is unigue to its taL, we can
apply each icon as a Lackgiounu image using the unigue ID ol each taL. (Techni-
cally these aien`t oveiiiue styles, Lut we`ll neeu to ieleience these iules when we
style the selecteu taL`s icon next.)
#tab-flight {
background: url(../images/icon-tab-flight.png) no-repeat .3em center;
padding-left: 50px;
}
#tab-car {
background: url(../images/icon-tab-car.png) no-repeat .1em center;
padding-left: 45px;
}
15.2 Overriding jQuery UI Layout and Theme Styles | 365
#tab-package {
background: url(../images/icon-tab-package.png) no-repeat .1em center;
padding-left: 45px;
}
6. The selecteu taL uses a slightly uilleient icon that sits on a white, not giay, Lack-
giounu. Foi each taL, we`ll auu a iule that keys oll the Viuget-specilic class loi
the selecteu state, .ui-tabs-selected:
#travel .ui-tabs-nav li.ui-tabs-selected #tab-flight {
background-image: url(../images/icon-tab-flight-on.png);
}
#travel .ui-tabs-nav li.ui-tabs-selected #tab-car {
background-image: url(../images/icon-tab-car-on.png);
}
#travel .ui-tabs-nav li.ui-tabs-selected #tab-package {
background-image: url(../images/icon-tab-package-on.png);
}
7. Oui taLs shoulu also have moie pauuing anu a laigei lont size:
#travel .ui-tabs-nav a {
font-size: 1.5em;
padding-top: .7em;
padding-bottom: .7em;
}
S. To linish up the taLs, we`ll aujust the Loiuei aiounu the content panel so that it
matches the 3-pixel Loiuei wiuth we set on the selecteu taL:
#travel .ui-tabs-panel {
border-width: 3px;
border-top-width: 0;
padding-top: 1.5em;
}
Now that oui taLs match the uesign, let`s upuate the uatepickei`s heauei. As illustiateu
in Figuie 15-1+, with a lew aujustments we can make the uatepickei`s heauei compo-
nentthe Lai aLove the calenuai that contains navigation aiiows anu month/yeai
leeuLackappeai aLove, not containeu within, the uatepickei.
366 | Chapter 15:jQuery UI Theming
Iigurc 15-11. Our datcpic|cr with ThcncRo||cr thcnc app|icd (A) and our targct dcsign (B)
Like the taLs, when the uatepickei plugin is initializeu on the page, the sciipt wiites
wiuget maikup to the page that contains jQueiy UI Viuget-specilic anu Fiamewoik
classes to set its stiuctuial anu themeu appeaiance. In an aLiiugeu veision ol the
uatepickei maikup, you can see that Viuget-specilic classes conloim to the naming
convention anu Legin with ui-datepicker, anu iuentily each component:
<div id="ui-datepicker-div" class="ui-datepicker ui-widget ui-widget-content
ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible">
<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix
ui-corner-all">
<a class="ui-datepicker-prev ui-corner-all">title="Prev"><span class="ui-icon
ui-icon-circle-triangle-w">Prev</span></a>
<a class="ui-datepicker-next ui-corner-all" title="Next"><span class="ui-icon
ui-icon-circle-triangle-e">Next</span></a>
<div class="ui-datepicker-title">
<span class="ui-datepicker-month">January</span><span class="ui-datepicker-
year">2009</span>
</div>
</div>
<table class="ui-datepicker-calendar">
<thead>
<tr>
<th class="ui-datepicker-week-end"><span title="Sunday">Su</span></th>
...
</tr>
</thead>
<tbody><tr>
<td class="ui-datepicker-week-end ui-datepicker-other-month"> 1 </td>
...
</tr>
</tbody>
</table>
<div class="ui-datepicker-buttonpane ui-widget-content">
<button type="button" class="ui-datepicker-current ui-state-default
ui-priority-secondary ui-corner-all">Today</button>
15.2 Overriding jQuery UI Layout and Theme Styles | 367
<button type="button" class="ui-datepicker-close ui-state-default
ui-priority-primary ui-corner-all">Done</button>
</div>
</div>
The uatepickei Viuget classes aie assigneu the lollowing uelault style iules:
.ui-datepicker { width: 17em; padding: .2em .2em 0; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next {
position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover {
top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span {
display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%;
margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em;
text-align: center; }
.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em;
margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse;
margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold;
border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em;
text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em
0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em
.4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
...
This is just a suLset ol the uatepickei`s style iules; to view all, in the theme stylesheet
linu the style Llock that staits with ui-datepicker.
Retuining to oui tiavel application, let`s wiite a lew oveiiiue iules to make the uate-
pickei`s heauei appeai like oui uesign:
1. Fiist we`ll iemove the pauuing that sepaiates the heauei liom the uatepickei`s outei
containei:
#travel .ui-datepicker { padding: 0; }
2. Like the taL navigation Lai, we want to llatten the Lottom anu iemove its top anu
siue Loiueis:
368 | Chapter 15:jQuery UI Theming
#travel .ui-datepicker-header {
border-top-width: 0;
border-left-width: 0;
border-right-width: 0;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
}
3. Finally, we`ll iemove the Loiuei anu Lackgiounu image liom the next anu pievious
navigation aiiows on hovei:
#travel .ui-datepicker-prev-hover,
#travel .ui-datepicker-next-hover {
border-width: 0;
background-image: none;
}
Vith the oveiiiue styles applieu, oui woiking tiavel application now accuiately
matches the linal uesign (Figuie 15-15).
Iigurc 15-15. Our jina| dcsign, with both standard ThcncRo||cr and ovcrridc sty|cs app|icd
15.2 Overriding jQuery UI Layout and Theme Styles | 369
Discussion
Consiuei whethei you`u like to apply oveiiiue iules to all wiugets in youi pioject oi
whethei you only want to oveiiiue theme styles loi a suLset ol wiugets. Il theie`s even
a small chance that you may want to piesent the wiuget in uilleient ways, apply oveiiiue
styles Ly scoping them to a containei element`s class oi ID so that you uon`t altei the
uelault loimatting ol the wiuget.
Heie aie some euiting tips/ieminueis:
Il you want to iemove the Lottom Loiuei on a wiuget heauei, use border-bottom-
width: 0; insteau ol border-bottom:0;. The loimei will ietain the Loiuei style anu
coloi in the event you want it Lack.
Foi vaiiation in stackeu elements that have the same class, you might uisaLle just
the Lackgiounu image in one, letting the uilleience in Lackgiounu coloi show
thiough.
Il you neeu to change the coloi ol a paiticulai poition ol a wiuget, uesign the theme
to accommouate that change insteau ol haiu-couing a coloi into youi stylesheet.
Il you neeu to iemove a Loiuei Lut woulu like to keep it theie loi stiuctuial layout,
you can set it to tianspaient. To uo this in an IE-sale way, set the Loiuei style to
dashed.
Use em units whenevei possiLle loi stiuctuial uimensions such as pauuing anu
maigins, anu moie impoitantly loi lont sizes. Viite styles assuming 1em is the
stanuaiu wiuget size, anu tiy not to uip Lelow .Sem to keep text legiLle.
15.3 Applying a Theme to Non-jQuery UI Components
Problem
Othei page componentslike content Loxes, Luttons, anu toolLaisaie sitting next
to jQueiy UI wiugets anu have similai types ol inteiactions anu Lehaviois, Lut theii
uesigns uon`t match.
Solution
You can assign Fiamewoik classes to non-jQueiy UI elements to apply the same theme
as ThemeRollei-styleu elements. (As a Lonus, those elements will automatically upuate
when you apply an upuateu ThemeRollei theme.)
370 | Chapter 15:jQuery UI Theming
The lollowing iecipe makes the lollowing assumptions:
You have a Lasic knowleuge ol how CSS woiks anu, specilically,
how styles cascaue, take pieceuence, anu can Le scopeu using se-
lectoi classes, IDs, oi elements. (Foi oui iecommenueu iesouices,
please ielei to the Appenuix at the enu ol this chaptei.)
You`ie alieauy lamiliai with how to cieate anu euit a theme using
ThemeRollei. (Il not, ieview Recipe 15.1, which uesciiLes in uetail
how to cieate a theme anu apply it to youi pages.)
In the pievious two iecipes we useu ThemeRollei to cieate anu uownloau a theme anu
then wiote a lew CSS iules to oveiiiue uelault theme styles anu make it moie closely
match oui linisheu uesign. Now we`ll take it anothei step luithei anu apply Fiamewoik
classes to elements in oui pioject so that they cooiuinate with the jQueiy UI wiugets
anu the theme we cieateu.
Step 1: Review available Framework classes to identify those you can apply to your components
Fiamewoik classes aie pait ol the jQueiy UI theme stylesheet you uownloau when you
cieate a theme in ThemeRollei. They`ie nameu accoiuing to theii puipose anu apply
theme styles like Lackgiounu colois anu textuies, Loiuei anu lont colois, iounueu
coineis, anu icons. Fiamewoik classes aie Luilt into jQueiy UI wiugets, Lut they may
also Le applieu to any othei elementslike custom wiugets you`ve uevelopeu oi
extenueu liom a thiiu paityto achieve a consistent look anu leel acioss youi site oi
application.
The lollowing is an oveiview ol the classes that make up the liamewoik, the styles
applieu Ly each, anu geneial iules loi ieleiencing them in youi own coue.
Unless noteu otheiwise, all styles set Ly Fiamewoik classes aie inheiiteu
Ly chilu elements, incluuing any text, link, anu icon styles.
Layout helpei classes hiue content oi lix common stiuctuial issues, like completely
wiapping a containei aiounu lloateu chilu elements:
.ui-helper-hidden
Applies display: none. Content hiuuen this way may not Le accessiLle to scieen
ieaueis.
.ui-helper-hidden-accessible
Positions an element oll the page so that it`s not visiLle Lut is still accessiLle to
scieen ieaueis.
15.3 Applying a Theme to Non-jQuery UI Components | 371
.ui-helper-reset
Removes inheiiteu pauuing, maigin, Loiuei, outline, text uecoiation, anu list-
style; sets line-height to 1.3 anu font-size to 100 peicent.
.ui-helper-clearfix
Foices nonlloateu containei elements to completely wiap aiounu lloateu chilu
elements.
Viuget containei classes shoulu only Le applieu to the elements loi which they`ie
nameu Lecause theii chilu links will inheiit styles liom them:
.ui-widget
Applies the theme`s lont lamily anu size on the entiie wiuget anu explicitly sets the
same lamily anu 1em lont size to chilu loim elements to loice inheiitance.
.ui-widget-header
Applies Lolu lont.
.ui-widget-content
Applies Loiuei coloi, Lackgiounu coloi anu image, anu text coloi.
Inteiaction states style clickaLle elementslike Luttons, accoiuion heaueis, anu taLs
to pioviue the appiopiiate state leeuLack as the usei inteiacts with them; each class
applies Loiuei coloi, Lackgiounu coloi anu image, anu text coloi. The -hover,
-focus, anu -active classes aie intenueu to ieplace theii CSS pseuuoclass counteipaits
(:hover, :active, :focus) anu must Le assigneu to an element with client-siue sciipting.
State classes weie uesigneu this way to avoiu style conllicts anu auueu selectoi com-
plexity that occuis when pseuuoclasses aie Luilt into the CSS. (Il pseuuoclasses aie
necessaiy loi youi pioject, you can auu them to youi oveiiiue stylesheet as uesciiLeu
in Recipe 15.2.)
.ui-state-default
.ui-state-hover
.ui-state-focus
.ui-state-active
Inteiaction cues style content to convey leeuLack in the loim ol highlight oi eiioi mes-
saging, uisaLleu loim elements, oi visual hieiaichy. All apply Loiuei coloi, Lackgiounu
coloi anu image, anu text coloi:
.ui-state-highlight
Assign this class to tempoiaiily highlight a component.
.ui-state-error
Assign this class to any components that contain eiioi messaging.
.ui-state-error-text
Applies only the eiioi text anu icon colois without the Lackgiounu.
372 | Chapter 15:jQuery UI Theming
.ui-state-disabled
Styles a loim element to appeai uisaLleu using low opacity anu theieloie woiks
alongsiue othei classes useu to style the element. The element is still usaLle when
this class is applieu; to uisaLle lunctionality, use the disabled loim element
attiiLute.
.ui-priority-primary
Assign this class to a Lutton when its action takes piioiity ovei anothei (i.e., Save
ovei Cancel). Applies Lolu text.
.ui-priority-secondary
Assign this class to a Lutton when its action is seconuaiy to anothei (i.e., Cancel).
Applies noimal lont weight anu ieuuceu opacity.
Icon classes pioviue auuitional leeuLack in the loim ol uiiectional aiiows anu inloi-
mational symLols, like an x oi a tiash can to maik a Lutton that ueletes. An icon is
applieu to an element with two classes:
.ui-icon
Base class that sets the element`s uimensions to a 16-pixel sguaie, hiues any text,
anu sets the ThemeRollei-geneiateu icon spiite image as a Lackgiounu.
.ui-icon-[type]
Vheie type is a uesciiptoi loi the icon giaphic that will Le uisplayeu. Type can
Le a single woiu (ui-icon-document, ui-icon-print) oi a comLination ol woius,
numLeis, anu shoithanu; loi example, .ui-icon-carat-1-n will uisplay a single
caiet symLol that points noith, anu .ui-icon-arrow-2-e-w will uisplay a uouLle
aiiow icon that points east-west.
Because the ui-icon Lase class allects an element`s uimension anu hiues
all innei text, it`s goou piactice to assign icons to theii own elements,
like <span> tags, so that the styles uon`t auveisely allect any chilu content
oi elements. Foi accessiLility puiposes, incluue a Liiel uesciiption in the
icon`s <span> tag; it`s hiuuen liom the usei`s view Lut will Le availaLle
to scieen ieaueis.
Also, each element with the .ui-icon class is assigneu a spiite Lack-
giounu image uepenuing on the state ol its paient containei. Foi
example, an icon element within a .ui-state-default containei will
uisplay icons in the ui-state-default icon coloi you set in ThemeRollei.
jQueiy UI pioviues a lull suite ol Fiamewoik icons (Figuie 15-16). In ThemeRollei you
can pieview theii uelault anu hovei inteiaction states Ly hoveiing ovei an icon in the
wiuget example column, anu you can mouse ovei an icon to see its class name.
15.3 Applying a Theme to Non-jQuery UI Components | 373
Iigurc 15-1. jQucry U| inc|udcs a ju|| sct oj thcncd icons in a sing|c spritc inagc, thcir intcraction
statcs arc prcvicwab|c in ThcncRo||cr
Coinei iauius helpei classes apply iounueu coineis to a suLset oi all coineis ol a con-
tainei. The last segment ol the coinei class name inuicates wheie the coinei will appeai,
as noteu heie:
.ui-corner-tl
Top lelt
.ui-corner-tr
Top iight
.ui-corner-bl
Bottom lelt
.ui-corner-br
Bottom iight
.ui-corner-top
Both top
.ui-corner-bottom
Both Lottom
.ui-corner-right
Both iight
.ui-corner-left
Both lelt
374 | Chapter 15:jQuery UI Theming
.ui-corner-all
All loui coineis
Oveilay anu shauow classes can Le useu to auu uepth anu uimension to a site oi
application:
.ui-widget-overlay
Applies 100 peicent wiuth anu height uimensions, Lackgiounu, anu opacity to the
moual scieen, a layei that sits Letween a moual uialog anu the page content that
is commonly useu to make page content appeai tempoiaiily uisaLleu while the
moual is showing.
.ui-widget-shadow
Applies Lackgiounu, coinei iauius, opacity, top/lelt ollsets to position the shauow
Lehinu a wiuget, anu shauow thickness (similai to Loiuei wiuth).
Because these Fiamewoik classes apply theme styles to jQueiy UI wiugets anu can Le
useu to style any component on youi page, we can use them thioughout an inteilace
to cieate a uniloim appeaiance. In this iecipe, we`ll ieview how to assign thiee types
ol Fiamewoik classes:
ClickaLle state classes, incluuing .ui-state-default, .ui-state-hover,
anu .ui-state-active
A coinei class, .ui-corner-all
An inteiaction cue class loi uisaLling a loim element, .ui-state-disabled
Step 2: Apply clickable-state Framework classes
Let`s continue ielining the look ol oui tiavel ieseivations application.
Altei applying a theme we cieateu in ThemeRollei anu mouilying uelault styles with
oveiiiue iules, the inteilace ol oui tiavel application`s llight selectoi is almost uone:
the clickaLle elements in oui jQueiy UI wiugets have a consistent appeaianceLy
uelault, the taLs anu uatepickei Luttons aie all uaik giay with a glassy textuie.
But oui Seaich loi Flights suLmit Lutton uoesn`t conloim to this uesign anu insteau
looks like a stanuaiu, unstyleu Liowsei Lutton (Figuie 15-17). Ve want it to look moie
like oui polisheu theme style.
To make the seaich Lutton look like othei clickaLle elements in oui tiavel application,
we`ll assign the Fiamewoik classes that set clickaLle state styles.ui-state-
default, .ui-state-hover, anu .ui-state-activeto the Lutton maikup anu then
wiite a shoit jQueiy sciipt to apply the styles when the usei inteiacts with the Lutton.
Ve`ll also apply iounueu coineis with the same iauius value set loi the taLs anu uate-
pickei wiuget.
Fiist, let`s assign the uelault state class to the Lutton so that it matches the othei click-
aLle elements. Ve`ll simply wiite (oi copy liom the theme stylesheet) ui-default-
state into the Lutton`s class attiiLute:
15.3 Applying a Theme to Non-jQuery UI Components | 375
<button id="search-flights" class="ui-state-default">Search for Flights</button>
Othei clickaLle elements like oui taLs have iounueu coineis, so we`ll auu iounueu
coineis to all siues ol the Lutton anu appenu ui-corner-all to the class attiiLute:
<button id="search-flights" class="ui-state-default ui-corner-all">Search for
Flights</button>
Vith these guick auuitions to the maikup, we`ve applieu oui uelault theme style loi
clickaLle elements to the seaich Lutton anu also maue it themeaLlelatei il we ue-
ciue to cieate anu apply a new theme to oui tiavel application wiuget, the seaich Lutton
will pick up the uelault clickaLle anu coinei styles liom the new stylesheet.
Finally, let`s apply the hovei anu mouseuown (active) states to pioviue visual leeuLack
to useis when they`ie inteiacting with the Lutton (Figuie 15-1S).
Iigurc 15-18. Thrcc Irancwor| c|asscs arc uscd to assign c|ic|ab|c statcs
Iigurc 15-17. Our intcrjacc is ncar|y conp|ctc, cxccpt jor thc unsty|cd Scarch jor I|ights button
376 | Chapter 15:jQuery UI Theming
To upuate the Lutton`s appeaiance on hovei anu mouseuown, we`ll wiite a small
jQueiy sciipt. Since we`ve alieauy uownloaueu anu incluueu the latest veision ol the
jQueiy coie liLiaiy in oui page anu have alieauy initializeu the wiuget plugins on DOM
ieauy, we`ll appenu a lunction to the DOM ieauy Llock that toggles the state classes
assigneu to oui seaich Lutton. As noteu in the lollowing sciipt Llock, the hover event
contains two lunctionsthe liist iemoves the uelault state class anu auus the hovei
state on mouseovei, anu the seconu ieveises these class assignments on mouseout
anu the mousedown event ieplaces the uelault anu hovei state classes with the active class:
$(function(){
// initialize tabs and datepickers
$('#travel').tabs();
$('#departure-date-picker').datepicker({altField: '#departure-date', altFormat:
'MM d, yy'});
$('#arrival-date-picker').datepicker({altField: '#arrival-date', altFormat: 'MM
d, yy'});
// search button hover & active states
$('#search-flights')
.hover(
function(){ $(this).removeClass('ui-state-default').addClass('ui-state-
hover'); },
function(){ $(this).removeClass('ui-state-hover').addClass('ui-state-
default'); }
)
.mousedown(
function(){ $(this).removeClass('ui-state-default, ui-state-
hover').addClass('ui-state-active'); }
);
});
Vhy wiite a sciipt to upuate Lutton states when CSS pseuuoclasses
(:hover, :active, :focus) uo the same thing? Ve weigheu this guestion
when uesigning the jQueiy UI CSS anu ueciueu against using pseuuo-
classes loi a lew key ieasons:
They intiouuce a uegiee ol complexity to the stylesheet that maue
it neaily impossiLle to keep it lean, anu incluuing them ieguiieu
that we account loi eveiy possiLle scenaiio wheie these states may
clash.
They also auu CSS Lloat anu woulu have signilicantly incieaseu the
size ol the stylesheet.
Some Liowseis, like oluei Lut still populai veisions ol Inteinet Ex-
ploiei, only suppoit pseuuoclasses on link elements (anchoi tags),
so we hau to cieate classes loi all clickaLle states anyway.
Ultimately, oui Lutton will look like the one in Figuie 15-19.
15.3 Applying a Theme to Non-jQuery UI Components | 377
Iigurc 15-19. Our jina| dcsign with thcnc c|asscs app|icd to thc Scarch button
Now that the Lutton is styleu to match oui application, we can conuitionally auu an
inteiaction cue class, ui-state-disabled, to pioviue visual leeuLack when the Lutton
is uisaLleu (see Figuie 15-20). Foi example, let`s assume all lielus in oui llight ieseiva-
tion loim aie ieguiieu loi suLmission. In this case, the seaich Lutton shoulu appeai
uisaLleu until the usei enteis a valiu entiy loi eveiy lielu; when the loim is complete,
we`ll enaLle the Lutton loi suLmission.
Iigurc 15-20. Add thc ui-statc-disab|cd statc to na|c a jorn c|cncnt appcar disab|cd
To apply a uisaLleu appeaiance to oui seaich Lutton, we`ll appenu the Fiamewoik
class ui-state-disabled to oui uelault Lutton. (Both classes aie necessaiy to cieate the
linal appeaiance Lecause the uisaLleu state styles simply ieuuce the uelault Lutton`s
opacity.)
378 | Chapter 15:jQuery UI Theming
<button id="search-flights" class="ui-state-default ui-state-disabled ui-corner-
all">Search for Flights</button>
Applying the uisaLleu state class only changes the appeaiance ol the Lutton anu uoes
not allect its lunctionality; it`s still capaLle ol accepting usei input to suLmit the loim.
To ensuie that the Lutton is actually uisaLleu, Le suie to auu the disabled attiiLute anu
value to the Lutton maikup:
<button id="search-flights" class="ui-state-default ui-state-disabled ui-corner-all"
disabled="disabled">Search for Flights</button>
Discussion
Fiamewoik classes aie uesigneu to Le ieuseu thioughout an application, anu as such
they pioviue uevelopeis with a ieauy set ol classes loi styling ielateu components in an
application, like oui tiavel application`s Seaich loi Flights Lutton, oi even youi own
wiugets. Because Fiamewoik classes aie nameu accoiuing to theii puipose, applying
them to component paits ol a custom wiuget is laiily intuitive:
ClickaLle state classes can Le auueu to Luttons, links, oi othei elements that ieguiie
a hovei oi active state.
Coinei classes can Le applieu to any element with Llock piopeities.
Layout helpeis can Le useu thioughout the layout stiuctuie loi lixing lloat con-
taineis oi toggling content visiLility.
Inteiaction cue classes can Le assigneu to elements that must convey visual piioiity
oi eiioi messaging.
Auuing Fiamewoik classes to non-jQueiy UI elements also makes them themeaLle; il
you ueciue to euit anu uownloau an upuateu theme using ThemeRollei, the new theme
will automatically also apply youi styles to those elements.
15.4 Referencing Multiple Themes on a Single Page
Problem
Moie than one theme must Le applieu to youi application anu appeai on a single page.
Foi example, youi jQueiy UI taLs must Le styleu accoiuing to a piimaiy theme, anu
wiugets within the taL panels must conloim to a uilleient theme.
Solution
Cieate a seconu theme using ThemeRollei, anu apply it selectively to wiugets oi com-
ponents in youi application Ly associating the new theme with a class, an ID, oi othei
scoping selectoi uuiing the uownloau piocess.
15.4 Referencing Multiple Themes on a Single Page | 379
The lollowing iecipe makes the lollowing assumptions:
You have a Lasic knowleuge ol how CSS woiks anu, specilically,
how styles cascaue, take pieceuence, anu can Le scopeu using se-
lectoi classes, IDs, oi elements. (Foi oui iecommenueu iesouices,
please ielei to the Appenuix at the enu ol this chaptei.)
You`ie alieauy lamiliai with how to cieate anu euit a theme using
ThemeRollei. (Il not, ieview Recipe 15.1, which uesciiLes in uetail
how to cieate a theme anu apply it to youi pages.)
jQueiy UI themes aie intenueu to cieate a consistent look anu leel in jQueiy UI wiugets
anu othei inteilace components acioss an entiie application, Lut sometimes the uesign
is moie complex, anu a uilleient look anu leel must Le applieu to ceitain wiugets ue-
penuing on wheie they appeai in the application.
In the case ol oui tiavel application, let`s say the uesignei ieviews oui linal uesign anu
leels that using uaik giay on all clickaLle elements makes it uillicult to uistinguish the
ieseivation type taLs liom the loim lielus within the set. He ueciues the top taLs shoulu
ietain theii cuiient style, Lut all inteiactive components insiue the taLsincluuing the
uatepickeis anu seaich Luttonshoulu Le styleu uilleiently anu have a yellow uelault
state. Figuie 15-21 shows oui cuiient anu oui new uesign.
Iigurc 15-21. Our origina| thcnc (A) scts thc c|ic|ab|c dcjau|t statc to gray jor a|| intcractivc c|cncnts,
thc ncw dcsign (B) |ccps thc top tabs gray but shijts a|| intcractivc conponcnts insidc thc tabs to yc||ow
Theie aie a couple ol ways to cieate style exceptions loi the taL contents. As uesciiLeu
in Recipe 15.2, we coulu wiite anu ieleience oveiiiue iules to mouily the uelault theme
styles loi the uatepickei anu Lutton. To uo that, we`u have to use a uesign euiting tool
380 | Chapter 15:jQuery UI Theming
like AuoLe Photoshop to liguie out all ol the new coloi hexauecimal values anu then
piouuce new yellow Lackgiounu images.
Oi, we coulu just cieate a new theme in ThemeRollei that matches oui seconuaiy theme
(in this case, yellow clickaLle elements), scope it to oui taL content aiea specilically,
anu then ieleience it altei oui oiiginal theme stylesheet. The jQueiy UI uownloau
Luiluei pioviues a simple inteilace loi scoping a theme in this way: the Auvanceu
Theme Settings aiea on the Downloau page can Le set to specily a scoping selectoi
a class, an ID, oi othei hieiaichical CSS selectoithat allows you to pinpoint exactly
which components will Le styleu with the auuitional theme.
Retuining to oui tiavel ieseivations application, at this point we`ve completeu the steps
uesciiLeu in Recipes 15.1 thiough 15.3:
Cieateu anu uownloaueu a theme anu ieleienceu it in oui pioject (Recipe 15.1)
Viote anu appenueu oveiiiue iules to mouily a lew ol the theme`s uelault styles
(Recipe 15.2)
Auueu a lew Fiamewoik classes to oui seaich Lutton to apply oui theme styles
(Recipe 15.3)
Now we`ll ieview how to scope a seconu theme anu apply it to oui pioject.
Step 1. Create another theme using ThemeRoller
Open the jQueiy UI weLsite at http://jqucryui.con anu choose Themes liom the top
navigation Lai, oi go uiiectly to http://thcncro||cr.con.
Ve cieateu the oiiginal theme to style all ol the wiugets useu in oui uesign. Howevei,
in this case we only want to style the wiugets within the taL content panel; we can
uisiegaiu the top navigation taLs loi now.
As we uiu in Recipe 15.1, we`ll stait with the Sunny theme, since it closely matches the
yellow clickaLle states anu heauei styles in oui new uesign Ly uelault (Figuie 15-22).
You can use an existing custom theme as a staiting point without having
to stait liom sciatch. To uo so, open the theme stylesheet, seaich loi
the comment that staits with To view anu mouily this theme, visit
http://jgueiyui.com/themeiollei/... anu copy anu paste the theme
URL into a Liowsei`s auuiess Lai to open ThemeRollei with that
theme`s settings pieloaueu.
The Sunny theme is veiy close to oui new taiget uesign, with a couple ol exceptions:
the heauei that sits aLove the uatepickei is giay when ouis is yellow, anu the content
aiea anu active state Loiuei coloi is a uaikei Liown than is specilieu in oui uesign.
Ve`ll ietuin to the Roll Youi Own taL to tweak a lew settings:
15.4 Referencing Multiple Themes on a Single Page | 381
Changc thc hcadcr bac|ground jron gray to yc||ow: The Lackgiounu coloi anu
Loiuei ol oui auuitional theme neeus to match that ol oui ClickaLle: uelault
state.
1. Open the Heauei/ToolLai section.
2. In the Lackgiounu coloi lielu entei #FECE2F; we uon`t neeu to make any
changes to the textuie oi opacity settings.
3. The white text is now Laiely visiLle against the yellow Lackgiounu, so we`ll
uaiken it to match the giay text elsewheie in oui application; entei the value
#333333.
+. Likewise, the icons in the uatepickei heauei neeu to contiast moie with the
Lackgiounu, so we`ll make them meuium Liown; entei #A27406.
5. Finally, change the Loiuei coloi to #D19405.
Changc thc contcnt and activc statc bordcrs to |ight brown: Content Loiueis appeai
aiounu accoiuion sections anu ueline the taLs, uialog, sliuei, uatepickei, anu pio-
giess Lai outei containeis.
1. Open the Content section.
2. Upuate the Loiuei coloi to match that ol the heauei Loiuei, #D19405.
3. Hit the TaL oi Entei key, oi click elsewheie on the page, to pieview the changes
in the wiugets on the iight.
Iigurc 15-22. Thc ncw targct dcsign with yc||ow c|ic|ab|c statcs and hcadcrs jor tab contcnts c|osc|y
natchcs thc Sunny ga||cry thcnc
382 | Chapter 15:jQuery UI Theming
Step 2. Scope the new theme and download it
Vhen you`ie linisheu euiting the Sunny theme, click the Downloau theme Lutton in
the toolLai`s Roll Youi Own taL, which navigates you to the jQueiy UI uownloau
Luiluei.
Beloie we euit the uownloau Luiluei settings, we neeu to ueteimine which scoping
selectoi we`ll use to apply oui new theme to the tiavel application`s content panels.
Ve want to ensuie that we only allect the taL contents anu uon`t altei the oiiginal
theme we applieu to oui top navigation taLs.
A scoping selectoi is a class, an ID, oi an HTML tag that specilically iuentilies the paient
containei ol the elements we want to style. It`s Lest to choose a scoping selectoi with
the most limiteu iange so that you uon`t inauveitently scope styles to elements that
shoulu assume the Lase theme styles. In oui tiavel ieseivations application, the scoping
selectoi shoulu iuentily the containei that encloses the taLs` content anu uoes not also
enclose the taLs` navigation panel.
Vhen we look at the geneiateu maikup in oui application, we see that each content
panel is assigneu the class ui-tabs-panel:
<div class="ui-tabs ui-widget ui-widget-content ui-corner-all" id="travel">
<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-
corner-all">
<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active">
<a href="#travel-flight" id="tab-flight">Book a Flight</a></li>
<li class="ui-state-default ui-corner-top"><a href="#travel-car" id="tab-
car">Rent a Car</a></li>
<li class="ui-state-default ui-corner-top"><a href="#travel-package"
id="tab-package">Package Deals</a></li>
</ul>
<div id="travel-flight" class="ui-helper-clearfix ui-tabs-panel
ui-widget-content ui-corner-bottom"></div><!-- /flight -->
<div id="travel-car" class="ui-tabs-panel ui-widget-content ui-corner-bottom
ui-tabs-hide"></div><!-- /car -->
<div id="travel-package" class="ui-tabs-panel ui-widget-content
ui-corner-bottom ui-tabs-hide"></div><!-- /package -->
</div><!-- /travel -->
Because the content panel maikup appeais altei anu is sepaiate liom that ol the taLs`
navigation, we can salely scope oui new styles to the ui-tabs-panel class without
allecting the styles applieu to the top taLs.
Vith oui scoping selectoi iuentilieu, we can ietuin to the jQueiy UI uownloau Luiluei.
In the iight column unuei Theme, we`ll specily how this new theme shoulu Le scopeu
within oui application. Click Auvanceu Theme Settings to expanu this section; you`ll
see two input lielus (Figuie 15-23):
CSS Scope accepts the scoping selectoi (class, ID, oi HTML tag). Vhen compiling
the theme stylesheet, the uownloau Luiluei pielixes eveiy style iule with this value,
which applies all style iules only to elements within the specilieu containei.
15.4 Referencing Multiple Themes on a Single Page | 383
Foi oui tiavel ieseivations application, we`ll entei the class we chose to scope oui
styles, .ui-tabs-panel. Be suie to incluue the pieceuing peiiou (.) oi, il specilying
an ID, the hash (=)these maiks aie necessaiy loi the stylesheet to ienuei
piopeily.
Vhen this lielu is lelt Llank, the theme is applieu gloLally acioss all
wiugets in youi application anu is not scopeu to any paiticulai
containei.
Theme Foluei Name accepts a loluei name loi the new theme that`s incluueu in
the uownloaueu ZIP; this loluei contains the theme stylesheet anu image liles. This
value uelaults to the name ol the selecteu theme, which in oui case shoulu Le
custom-theme since we`ve aiiiveu at the uownloau Luiluei altei uesigning a cus-
tom theme in ThemeRollei.
Vhen you type a CSS scope in the liist lielu, the uownloau Luiluei suggests a loluei
name Laseu on that scope. This is meant to Le helplul, Lut you may want to oveiiiue
the suggestion with something moie meaninglul to youi pioject`s uiiectoiy
stiuctuie.
Foi the tiavel ieseivations application, we`ll wiite oui own loluei name anu use
taL-content-theme to Lettei uesciiLe the loluei contents.
Now that we`ve set up the CSS scope anu loluei name, we`ll select all jQueiy UI wiugets
that will use the new scopeu theme (Figuie 15-2+).
Iigurc 15-23. Thc jQucry U| down|oad bui|dcr`s Advanccd Thcnc Scttings cxpands to providc jic|ds
jor CSS scopc and thc ncw thcnc jo|dcr nanc
384 | Chapter 15:jQuery UI Theming
Iigurc 15-21. Down|oad a scopcd thcnc by ji||ing in Advanccd Thcnc Scttings and sc|ccting any
widgcts that wi|| usc thc scopcd thcnc on thc jQucry U| Down|oad pagc
Getting New Widgets
You`ll neeu to uownloau any wiugets that will use the scopeu theme so that the ap-
piopiiate styles aie incluueu in the scopeu CSS. ]avaSciipt loi these wiugets will auto-
matically Le incluueu in the uownloau as well. Howevei, il you neeu only the scopeu
theme, you can uiscaiu the ]avaSciipt, since it will likely Le a uuplicate ol what you
alieauy have.
Il you ieach this step anu iealize that you neeu to uownloau auuitional wiugets loi youi
pioject that you hau not incluueu in youi oiiginal uownloau (loi example, you neeu to
auu a piogiess Lai), we stiongly auvise that you not uownloau new wiugets with a
scopeu theme. Meiging ]S liles is just too complicateu.
Insteau, to auu new wiugets to the pioject, we iecommenu that you ieuo the uownloau
piocess wholesale: ieopen the oiiginal theme in ThemeRollei, anu then uownloau all
jQueiy UI components useu in the pioject. That way, you can simply oveiwiite the
oiiginal theme stylesheet anu youi jQueiy UI ]avaSciipt lile with liles that covei all
15.4 Referencing Multiple Themes on a Single Page | 385
wiugets in youi application. To uo this, simply open the oiiginal theme stylesheet,
seaich loi the comment that staits with To view anu mouily this theme, visit http://
jgueiyui.com/themeiollei/..., copy anu paste the theme URL into a Liowsei`s auuiess
Lai to open ThemeRollei with that theme`s settings pieloaueu, anu then click Down-
loau theme to select auuitional wiugets.
Select which veision ol jQueiy UI you`u like to use (the latest staLle veision is selecteu
Ly uelault), click Downloau, anu save the ZIP lile locally (the lile will Le nameu like
jqucry-ui-1.7.1.custon.zip).
Step 3. Merge files into your project directory
The uownloau loluei contains the CSS uiiectoiy (css) with youi scopeu theme loluei;
the wiuget ]avaSciipt (js), which may Le a uuplicate ol what you`ie alieauy using (to
stay sale, uouLle check Leloie oveiwiiting any liles); anu the uevelopment Lunule
(dcvc|opncnt-bund|c), which contains inuiviuual CSS liles useu to cieate the compileu
veision lounu in the css loluei, open souice license text, anu ielateu iesouices necessaiy
loi auvanceu uevelopment. The oiuei ol the lolueis anu liles may vaiy uepenuing on
youi opeiating system (Figuie 15-25 shows the loluei openeu on Mac OS X).
Iigurc 15-25. A snapshot oj thc jQucry down|oad jo|dcr structurc whcn down|oading a scopcd thcnc
Now we`ll copy anu paste the tab-contcnt-thcnc loluei into the styles uiiectoiy loi oui
tiavel ieseivations pioject.
It`s impoitant to maintain the estaLlisheu uiiectoiy stiuctuie within the
theme loluei so that the icon images aie ieleienceu piopeily Ly the
theme classes. Il you uo change the theme uiiectoiy stiuctuie, you will
likely have to ieplicate those changes il latei you ueciue to upgiaue to a
newei veision ol the jQueiy UI sciipts anu CSS.
The new theme loluei will sit alongsiue the oiiginal theme loluei in the styles uiiectoiy,
as shown in Figuie 15-26.
386 | Chapter 15:jQuery UI Theming
Iigurc 15-2. Scopcd thcnc jo|dcrs arc appcndcd to thc sty|cs dircctory
Step 4. Reference the scoped theme stylesheet in your project
Ve`ll ieleience oui scopeu stylesheet altei the oiiginal theme stylesheet anu Leloie all
jQueiy UI sciipts. The oiuei in which theme stylesheets aie ieleienceu on the page is
not impoitant:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Travel widget | Book a Flight, Rent a Car, or Find Package Deals</title>
<!-- jQuery UI styles -->
<link rel="stylesheet" type="text/css" href="css/custom-theme/jquery-ui-
1.7.1.custom.css" />
<link rel="stylesheet" type="text/css" href="css/tab-content-theme/jquery-ui-
1.7.1.custom.css" />
<!-- jQuery core & UI scripts -->
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.1.custom.min.js"></script>
<script type="text/javascript">
$(function(){
$('#travel').tabs();
$("#departure-date-picker").datepicker({altField: '#departure-date',
altFormat: 'MM d, yy'});
$("#arrival-date-picker").datepicker({altField: '#arrival-date', altFormat:
'MM d, yy'});
});
</script>
</head>
...
15.4 Referencing Multiple Themes on a Single Page | 387
Vhen the theme stylesheet links aie in place, we`ll pieview the page in a Liowsei to
conliim that the styles aie Leing applieu coiiectly. Because we scopeu the new theme
to the taL content panel, the styles aie only applieu to the content`s wiugets anu not to
the taLs aLove, as illustiateu in Figuie 15-27.
Foi anothei example ol this technigue, visit this aiticle: http://www.ji|
ancntgroup.con/|ab/using_nu|tip|c_jqucry_ui_thcncs_on_a_sing|c
_pagc/.
Iigurc 15-27. Iina| app|ication with scopcd thcnc app|icd
15.5 Appendix: Additional CSS Resources
To get the most out ol the jQueiy UI CSS Fiamewoik anu ThemeRollei, it helps to
have a Lasic knowleuge ol how CSS woiks anu, specilically, how styles cascaue, take
pieceuence, anu can Le scopeu using selectoi classes, IDs, oi elements.
388 | Chapter 15:jQuery UI Theming
Ve iecommenu the lollowing Looks anu online iesouices loi a piimei on these
concepts:
CSS Basics Tutoria|
http://www.cssbasics.con/
CSS Chcat Shcct
http://|cs|icjran|c.con/ji|cs/rcjcrcncc/csschcatshcct.htn|
Dcsigning with Wcb Standards
http://www.zc|dnan.con/dwws/
Wcb Standards So|utions
http://www.jricndsojcd.con/boo|.htn|?isbn=1590593812
Eric Mcycr on CSS
http://www.cricncycroncss.con/
15.5 Appendix: Additional CSS Resources | 389
CHAPTER 16
jQuery, Ajax, Data Formats:
HTML, XML, JSON, JSONP
]onathan Sharp
16.0 Introduction
VeL uevelopeis woik with a numLei ol uata loimats anu piotocols in tiansleiiing
inloimation Letween Liowseis anu seiveis. This chaptei pioviues a numLei ol iecipes
loi hanuling anu woiking with some ol the most common uata loimats, Ajax
technigues, anu jQueiy.
16.1 jQuery and Ajax
Problem
You want to make a ieguest to the seivei loi some auuitional uata without leaving the
page the visitoi is cuiiently on.
Solution
Heie`s a simple Ajax ieguest:
(function($) {
$(document).ready(function() {
$('#update').click(function() {
$.ajax({
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
success: function(html, textStatus) {
$('body').append(html);
},
error: function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + ( errorThrown ? errorThrown :
391
xhr.status );
}
});
});
});
})(jQuery);
Discussion
At the coie ol jQueiy`s Ajax aichitectuie is the jQuery.ajax() methou. This pioviues
the Lasis ol all Liowseis to seivei ieguests anu iesponses. So, let`s look at this in a little
moie uetail. To initiate a ieguest to the seivei, a settings oLject that contains paiameteis
loi the ieguest is passeu to the $.ajax methou. A vast numLei ol options aie availaLle,
with the most common options ol a ieguest Leing type, url, complete, dataType,
error, anu success:
var options = {
type: 'GET'
};
The liist option that neeus to Le auuiesseu when staiting an Ajax ieguest is the type ol
HTTP ieguest you`ie going to make to the seivei, which in the majoiity ol cases will
Le eithei a GET oi POST type:
var options = {
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html'
};
Next we`ll look at the URL anu dataType options. URL is laiily sell-explanatoiy with the
lollowing inteiactions woith noting. Vhen setting the cache option to false, jQueiy
will appenu a get vaiiaLle ol _=<random number> (loi example /server-ajax-gateway?
_=6273551235126), which is useu to pievent the Liowsei, pioxies, anu seiveis liom
senuing a cacheu iesponse. Finally, the dataType option specilies the uata loimat that
is the expecteu iesponse liom the seivei. Foi example, il you`ie expecting the seivei to
ietuin XML, then a value ol xml woulu Le appiopiiate:
var options = {
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
error: function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + errorThrown);
},
success: function(data, textStatus) {
$('body').append( data );
}
};
The next two options that we ueline aie two callLack methous, one calleu error anu
the othei calleu success. They lunction as they aie appiopiiately titleu, with error Leing
calleu when theie is an eiioi with the ieguest anu success Leing calleu with a successlul
392 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
iesponse (ueteimineu il a seivei iesponse type ol 200 is ietuineu). The othei common
option mentioneu is the complete option, which uelines a callLack to execute upon altei
eithei success oi eiioi ol the iesponse:
var options = {
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
complete: function(xhr, textStatus) {
// Code to process response
}
};
Once the settings have Leen uelineu, we can go aheau anu execute oui ieguest:
var options = {
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
complete: function(xhr, textStatus) {
// Code to process response
}
};
$.ajax( options );
Ve can also set oui options inline:
$.ajax({
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
complete: function(xhr, textStatus) {
// Code to process response
}
});
Oui linal solution ieguests the lile hello-ajax.html anu appenus the contents (html)
to the <body> element upon the ietuin ol a successlul ieguest. Il the ieguest lails, the
error methou is tiiggeieu insteau, aleiting the usei with a message:
(function($) {
$(document).ready(function() {
$('#update').click(function() {
$.ajax({
type: 'GET',
url: 'hello-ajax.html',
dataType: 'html',
success: function(html, textStatus) {
$('body').append(html);
},
error: function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + errorThrown);
}
});
});
16.1 jQuery and Ajax | 393
});
})(jQuery);
16.2 Using Ajax on Your Whole Site
Problem
You have a laige weL application with Ajax calls occuiiing thioughout the coue Lase
anu neeu to ueline uelault settings loi all ieguests thioughout the application.
Solution
(function($) {
$(document).ready(function() {
$('#loadingIndicator')
.bind('ajaxStart', function() {
$(this).show();
})
.bind('ajaxComplete', function() {
$(this).hide();
});
$.ajaxSetup({
cache: true,
dataType: 'json',
error: function(xhr, status, error) {
alert('An error occurred: ' + error);
},
timeout: 60000, // Timeout of 60 seconds
type: 'POST',
url: 'ajax-gateway.php'
}); // Close $.ajaxSetup()
}); // Close .read()
})(jQuery);
Discussion
Vhen woiking with laigei applications, olten theie is a common Ajax gateway thiough
which all ieguests aie passeu. Using the $.ajaxSetup() methou, we can set Ajax ieguest
uelault settings. This woulu iesult in an ease ol Ajax ieguests thioughout the applica-
tion such as lollows:
$.ajax({
data: {
// My request data for the server
},
success: function(data) {
// Now update the user interface
}
});
A Liiel siue point is that the timeout option takes its value in milliseconus (seconus
1,000), so a timeout ol 6,000 woulu Le six seconus. One thing to consiuei when setting
394 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
this value is the extent to which the Inteinet has giown gloLally. Some ol youi visitois
oi useis may Le in locations that have a highei latency than you woulu expect loi useis
within youi iegion. So, uon`t set this value too low (loi example live seconus). Speci-
lying a highei timeout value such as 30 oi 60 seconus will allow useis with highei-
latency connections (such as those using satellite) to still enjoy the Lenelits ol youi
application.
In the pievious example, the ieguest will Le a POST to ajax-gateway.php. Il an eiioi
occuis, it will Le hanuleu Ly the eiioi lunction as uelineu in $.ajaxSetup(). It is possiLle
to still oveiiiue settings loi a specilic ieguest as lollows:
$.ajax({
url: 'another-url.php',
data: {
// My request data for the server
},
success: function(data) {
// Now update the user interface
}
});
The pievious ieguest woulu Le sent to another-url.php insteau ol ajax-gateway.php.
One Lenelicial leatuie ol jQueiy`s Ajax aichitectuie is the gloLal events availaLle such
as ajaxComplete, ajaxError, ajaxSend, ajaxStart, ajaxStop, anu ajaxSuccess. These
events may Le set up using the .bind('event', callback) methou oi the shoit-
cut .event(callback). The lollowing example shows the two methous loi Linuing the
callLack loi the ajaxError event:
(function($) {
$(document).ready(function() {
$('#loadingIndicator')
.ajaxError(function() {
// Your code
});
// Or using bind()
$('#loadingIndicator')
.bind('ajaxError', function() {
// Your code
});
});
})(jQuery);
Heie is a iunuown anu uesciiption ol the events that aie availaLle as well as the oiuei
in which they`ie tiiggeieu:
ajaxStart
Tiiggeieu at the stait ol an Ajax ieguest il no othei ieguests aie in piogiess
ajaxSend
Tiiggeieu Leloie each inuiviuual ieguest is sent
ajaxSuccess or ajaxError
Tiiggeieu upon a successlul oi an unsuccesslul ieguest
16.2 Using Ajax on Your Whole Site | 395
ajaxComplete
Tiiggeieu eveiy time a ieguest is complete (iegaiuless ol whethei it was a success
oi hau an eiioi)
ajaxStop
Tiiggeieu il theie aie no auuitional Ajax ieguests in piogiess
In the next iecipe we will Luilu upon these events in moie uetail.
16.3 Using Simple Ajax with User Feedback
Problem
You neeu to show a status inuicatoi to the usei when Ajax ieguests aie in piogiess anu
hiue it upon completion.
Solution
(function($) {
$(document).ready(function() {
$('#ajaxStatus')
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
});
// Start our ajax request when doAjaxButton is clicked
$('#doAjaxButton').click(function() {
$.ajax({
url: 'ajax-gateway.php',
data: { val: "Hello world" },
dataType: 'json',
success: function(json) {
// Data processing code
$('body').append( 'Response Value: ' + json.val );
}
});
});
});
})(jQuery);
Discussion
One ol the huge Lenelits ol jQueiy`s Ajax implementation is the exposuie ol gloLal
Ajax events that aie tiiggeieu on all elements with each Ajax ieguest. In the lollowing
solution, we Linu two ol the events, ajaxStart anu ajaxStop using the shoitcut methous
to the XHTML element with the ID ajaxStatus. Vhen the Ajax ieguest is tiiggeieu
upon clicking #doAjaxButton, the ajaxStart event is also uispatcheu anu calls show()
396 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
on the #ajaxStatus element. Notice that these events aie tiiggeieu automatically anu
aie a Ly-piouuct ol using the $.ajax() (oi othei shoitcut methous such as $.get()).
This pioviues an elegant uecoupleu solution loi having an application-wiue ieguest
status as Ajax ieguests aie suLmitteu:
(function($) {
$(document).ready(function() {
$('#ajaxStatus')
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
});
// Start our ajax request when doAjaxButton is clicked
$('#doAjaxButton').click(function() {
$.ajax({
url: 'ajax-gateway.php',
data: { val : 'Hello world' },
dataType: 'json',
success: function(json) {
// Data processing code
$('body').append( 'Response value: ' + json.val );
}
});
});
});
})(jQuery);
Let`s look at some ol the auuitional events anu the uilleience Letween local anu gloLal
Ajax events. Local Ajax events (set up using $.ajaxSetup() oi uelineu at the time ol
$.ajax()) consist ol beforeSend, success, error, anu complete. These events aie uelineu
inline anu tightly coupleu to each Ajax ieguest. GloLal Ajax events aie inteileaveu with
the local events Lut aie tiiggeieu loi any element that Linus to them anu also make use
ol jQueiy`s native event-hanuling aichitectuie. Heie`s a guick ieview on how to hanule
local Ajax events (such as the complete event):
$.ajax({
type: 'GET',
url: 'ajax-gateway.php',
dataType: 'html',
complete: function(xhr, textStatus) {
// Code to process response
}
});
Now let`s examine the Lieakuown, oiuei, anu scope in which events aie tiiggeieu on
a successlul Ajax ieguest:
ajaxStart (gloLal)
beforeSend (local)
16.3 Using Simple Ajax with User Feedback | 397
ajaxSend (gloLal)
success (local)
ajaxSuccess (gloLal)
complete (local)
ajaxComplete (gloLal)
ajaxStop (gloLal)
Foi an unsuccesslul Ajax ieguest, the oiuei ol tiiggeieu events woulu Le as lollows with
success anu ajaxSuccess Leing ieplaceu Ly error anu ajaxError, iespectively:
ajaxStart (gloLal)
beforeSend (local)
ajaxSend (gloLal)
error (local)
ajaxError (local)
complete (local)
ajaxComplete (gloLal)
ajaxStop (gloLal)
ajaxStart anu ajaxStop aie two special events in the gloLal scope. They aie uilleient
in that theii Lehavioi opeiates acioss multiple simultaneous ieguests. ajaxStart is tiig-
geieu when a ieguest is maue il no othei ieguests aie in piogiess. ajaxStop is tiiggeieu
upon completion ol a ieguest il theie aie no auuitional ieguests in piogiess. These two
events aie only tiiggeieu once when multiple simultaneous ieguests aie uispatcheu:
(function($) {
$(document).ready(function() {
$('#ajaxStatus')
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
});
// Start our Ajax request when doAjaxButton is clicked
$('#doAjaxButton').click(function() {
$.ajax({
url: 'ajax-gateway.php',
complete: function() {
// Data processing code
}
});
$.ajax({
url: 'ajax-data.php',
complete: function() {
// Data-processing code
398 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
}
});
});
});
})(jQuery);
One setting that can Le passeu into the $.ajax() methou is global, which can Le set to
eithei true oi false. By setting global to false, it`s possiLle to suppiess the gloLal events
liom Leing tiiggeieu.
Il you expeiience peiloimance issues in youi application, it may Le Le-
cause ol the cost ol event piopagation il theie is a signilicantly laige
numLei ol elements. In this case, setting global to false may give you
a peiloimance impiovement.
The beforeSend callLack is a local event that allows loi mouilying the XMLHttpRequest
oLject (which is passeu in as an aigument) piioi to the ieguest Leing sent. In the lol-
lowing example, we specily a custom HTTP heauei loi the ieguest. It is possiLle to
cancel the ieguest Ly ietuining false liom the callLack:
(function($) {
$(document).ready(function() {
// Start our ajax request when doAjaxButton is clicked
$('#doAjaxButton').click(function() {
$.ajax({
url: 'ajax-gateway.php',
beforeSend: function(xmlHttpRequest) {
xmlHttpRequest.setRequestHeader('X-SampleHeader',
'Hello world);
},
complete: function() {
// Data processing code
}
});
});
});
})(jQuery);
Now taking all ol the events il we ievise oui solution, we come up with the lollowing:
(function($) {
$(document).ready(function() {
$('#ajaxError')
.ajaxError(function(evt, xhr, ajaxOptions, error) {
$(this)
.html( 'Error: ' + ( xhr ? xhr.status : '' )
+ ' ' + ( error ? error :'Unknown' ) )
.show();
})
.ajaxSuccess(function() {
$(this).hide();
});
16.3 Using Simple Ajax with User Feedback | 399
$('#ajaxStatus')
.ajaxStart(function() {
$(this).show();
})
.ajaxSend(function() {
$(this).html('Sending request...');
})
.ajaxStop(function() {
$(this).html('Request completed...');
var t = this;
setTimeout(function() {
$(t).hide();
}, 1500);
});
// Start our ajax request when doAjaxButton is clicked
$('#doAjaxButton').click(function() {
$.ajax({
url: 'ajax-gateway.php',
complete: function() {
// Data processing code
}
});
});
});
})(jQuery);
16.4 Using Ajax Shortcuts and Data Types
Problem
You neeu to make a GET Ajax ieguest to the seivei anu place the contents ol the
iesulting HTML in a <div> with an ID ol contents.
Solution
(function($) {
$(document).ready(function() {
$('#contents').load('hello-world.html');
});
})(jQuery);
Discussion
This iecipe uilleis slightly liom otheis in that we`ll suivey a vaiiety ol the lunctions anu
shoitcuts pioviueu Ly jQueiy in an elloit to cleaily piesent theii uilleiences.
jQueiy pioviues a numLei ol shoitcuts loi making Ajax ieguests. Baseu upon
the pievious iecipes coveiing Ajax, the lollowing shoitcuts exist: .load(), $.get(),
$.getJSON(), $.getScript(), anu $.post(). But liist, let`s ieview oui solution:
$('#contents').load('hello-world.html');
400 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
The .load(url) methou is making a GET Ajax ieguest to hello-world.html anu placing
the contents ol that iesult into the element #contents. Two optional paiameteis to
the .load() methou aie data anu callback. The data paiametei can Le eithei a map (oi
]avaSciipt oLject) oi as ol jQueiy 1.3 a stiing. The lollowing example is passing in the
vaiiaLle hello with the value world. (This is the same as the lollowing URL: hello-
world.html?hello=world.)
$('#contents').load('hello-world.html', { hello: 'world' });
The thiiu optional paiametei is a callLack lunction that is calleu when the ieguest
completes (eithei on success oi error). In the lollowing example, an aleit message is
Leing tiiggeieu upon the completion ol the ieguest:
$('#contents').load('hello-world.html', { hello: 'world' }, function() {
alert('Request completed!');
});
The next two methous we will look at aie $.get() anu $.post(). Both methous accept
the same aiguments, with the $.get() methou senuing a GET HTTP ieguest anu the
$.post() methou senuing a POST HTTP ieguest. Ve`ll look at a sample using the
$.get() ieguest. The $.get() methou accepts url, data, callback, anu type paiameteis.
The liist thiee paiameteis lunction the same as with the pievious load() methou, so
we`ll only covei the linal type paiametei:
$.get(
'hello-world.html',
{ hello: 'world' },
function(data) {
alert('Request completed!');
},
'html'
);
The type paiametei can accept one ol the lollowing: xml, html, script, json, jsonp, oi
text. These type values ueteimine how the iesponse text liom the Ajax ieguest is pio-
cesseu piioi to Leing passeu to the callLack lunction. In the pievious example, since
we specilieu a type ol html, the uata aigument ol oui callLack will Le in DOM oLject
loim. Specilying xml as the type will iesult in an xml DOM oLject Leing passeu in. Il
you specily script as the type, the iesulting uata ietuineu Ly the seivei will Le executeu
piioi to the callback methou Leing tiiggeieu. Both json anu jsonp loimats iesult in a
]avaSciipt oLject Leing passeu to youi callback methou, with the uilleience ol jsonp
Leing that jQueiy will pass in a methou name in the ieguest anu map that callLack
methou to the anonymous lunction uelineu with the ieguest. This allows loi cioss-
uomain ieguests. Finally, the text loimat is just as the name suggests: plain text that
is passeu in as a stiing to youi callback methou.
16.4 Using Ajax Shortcuts and Data Types | 401
Ve`ll now look at the linal two shoitcuts: $.getJSON() anu $.getScript(). The
$.getJSON() methou accepts url, data, anu callback as aiguments. $.getJSON() is es-
sentially a comLination ol the $.get() methou with appiopiiate paiameteis Leing set
loi JSON oi JSONP. The lollowing example woulu make a JSONP ieguest to Flicki anu
ieguest photos liom the puLlic timeline:
$.getJSON(
'http://www.flickr.com/services/feeds/photos_public.gne?
format=json&jsoncallback=?,
function(json) {
}
);
Since this ieguest is cioss-uomain, jQueiy will automatically tieat the ieguest as a
JSONP anu lill in the appiopiiate callback lunction name. This also means that jQueiy
will initiate the ieguest Ly inseiting a <script> tag into the uocument insteau ol using
the XMLHttpRequest oLject. Flicki`s API allows loi the callback lunction name to Le
specilieu Ly setting the jsoncallback get vaiiaLle. You`ll notice the jsoncallback=?
poition ol the URL. jQueiy will intelligently ieplace the ? with the appiopiiate lunction
name automatically. By uelault jQueiy will appenu a callback= vaiiaLle Lut allows loi
easily mouilying this, as uemonstiateu. The callback ieplacement woiks on Loth GET
anu POST ieguest URLs Lut will not woik with paiameteis passeu in the uata oLject.
See Recipes 16.7 anu 16.S loi woiking with ]SON anu Recipe 16.9 loi a lull ]SONP
implementation ol oui Flicki example.
$.getScript() executes a ieguest eithei via an Ajax ieguest oi via uynamically inseiting
a <script> tag loi cioss-uomain suppoit anu then evaluating the ietuineu uata anu
linally tiiggeiing the callLack pioviueu. In the lollowing example, we`ie auuing a sciipt
to the uocument anu then calling one ol the lunctions it pioviues in the callLack:
// hello-world.js
function helloWorld(msg) {
alert('Hello world! I have a message for you: ' + msg);
}
// hello-world.html
(function($) {
$(function() {
$.getScript('hello-world.js', function() {
helloWorld('It is a beautiful day!');
});
});
})(jQuery);
402 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
16.5 Using HTML Fragments and jQuery
Problem
You want to take a stiing ol HTML anu conveit it into a seiies ol DOM noues anu then
inseit it into the uocument.
Solution
(function($) {
$(document).ready(function() {
$('<div>Hello World</div>')
.append('<a href="http://jquery.com">A Link</a>')
.appendTo('body');
});
})(jQuery);
Discussion
Manipulating stiings ol HTML is one ol the moie common tasks when using jQueiy.
At the heait ol jQueiy is an elegant inteilace loi tianslating a stiing ol maikup into its
DOM iepiesentation. Insteau ol passing in a selectoi, we can simply pass in a stiing ol
HTML. (The lollowing uoes not woik loi XML; see Recipe 16.6 loi conveiting a stiing
ol XML to a DOM.)
$('<div>Hello World</div>');
At this point oui HTML has Leen conveiteu into a DOM iepiesentation anu is ieauy
loi manipulation with jQueiy. Ve can opeiate on this liagment using any ol the jQueiy
methous:
$('<div>Hello World</div>')
.append('<a href="http://jquery.com">A Link</a>')
.appendTo('body');
One caveat woith noting is that piioi to the HTML liagment Leing ap-
penueu to the uocument, some visual attiiLutes such as width anu
height may not Le availaLle. So in the lollowing example, call-
ing .width() will ietuin a value ol 0.
$('<div>Hello World</div>').width();
// Returns '0'
16.5 Using HTML Fragments and jQuery | 403
16.6 Converting XML to DOM
Problem
You neeu to conveit a stiing ol XML to a DOM oLject loi use with jQueiy.
Solution
<h1 id="title"></h1>
(function($) {
$(document).ready(function() {
var xml = '<myxml><title>Hello world!</title></myxml>';
var title = $.xmlDOM( xml ).find('myxml > title').text();
$('#title').html( title );
});
})(jQuery);
Discussion
A lieguent guestion appeaiing on the jQueiy mailing list is how to conveit a stiing ol
XML to its DOM iepiesentation that jQueiy is aLle to opeiate on. Vhen making an
Ajax ieguest with a iesponse type ol xml, the Liowsei will automatically paise the ie-
tuineu XML text into a DOM oLject.
So, what woulu you uo il you hau a stiing ol XML that you neeueu to piocess with
jQueiy? The xmlDOM plugin pioviues native cioss-Liowsei paising ol a stiing ol XML
anu ietuins a jQuery-wiappeu DOM oLject. This allows you to conveit anu access the
XML in one step:
(function($) {
$(document).ready(function() {
var xml = '<myxml><title>Hello world!</title></myxml>';
var title = $.xmlDOM( xml ).find('myxml > title').text();
$('#title').html( title );
});
})(jQuery);
Anothei common piactice is passing in the DOM oLject as the seconu aigument to
jQueiy (the context) as lollows:
(function($) {
$(document).ready(function() {
var $xml = $.xmlDOM( '<myxml><title>Hello world!</title></myxml>' );
var title = $('myxml > title', $xml).text();
$('#title').html( title );
});
})(jQuery);
This allows you to iun youi jQueiy selection against the context oLject passeu in;
otheiwise, jQueiy iuns the gueiy against the uocument oLject.
404 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
The xmlDOM plugin Ly the authoi may Le uownloaueu liom http://jqucry-coo|boo|
.con/go/p|ugin-xn|don.
16.7 Creating JSON
Problem
You have a ]avaSciipt oLject that contains uata that neeus to Le seiializeu loi easiei
stoiage anu ietiieval.
Solution
(function($) {
$(document).ready(function() {
var messageObject = { title: 'Hello World!', body: 'It\'s great to be
alive!' };
var serializedJSON = JSON.stringify( messageObject );
});
})(jQuery);
Discussion
]avaSciipt OLject Notation (]SON) is a common uata loimat useu to exchange uata
Letween the Liowsei anu the seivei. It is lightweight in natuie anu is easy to use anu
paise in ]avaSciipt. Let`s liist look at a simple oLject:
var messageObject = { title: 'Hello World!', body: 'It\'s great to be alive!' };
In this example, we have a simple oLject with two attiiLutes, title anu body. Being aLle
to stoie a seiializeu veision ol the oLject is guite simple. The seiializeu veision is as
lollows:
var serializedJSON = '{"title":"Hello World!","body":"It\'s great to be alive!"}';
The two common tasks when woiking with ]SON aie seiialization (encouing an oLject
into a stiing iepiesentation) anu ueseiialization (uecouing a stiing iepiesentation into
an oLject liteial). Cuiiently, only a hanulul ol Liowseis have native Luilt-in ]SON han-
uling (such as Fiielox 3.1- anu Inteinet Exploiei S). Othei Liowseis have plans to auu
suppoit Lecause ]SON is now pait ol the ECMA 3.1 specilication. In the meantime,
theie aie two main appioaches to take when woiking with ]SON uata. Douglas
Ciockloiu has wiitten a ]avaSciipt implementation loi encouing anu uecouing ]SON,
which you can get liom http://jqucry-coo|boo|.con/go/json. Let`s seiialize the pievious
oLject utilizing the JSON liLiaiy:
var serializedJSON = JSON.stringify( messageObject );
Ve now have a stiing iepiesentation that we can senu to oui seivei such as in an Ajax
ieguest oi suLmit in a loim.
16.7 Creating JSON | 405
16.8 Parsing JSON
Problem
You`ie passeu a stiing ol ]SON uata anu neeu to conveit it to oLject loimat.
Solution
(function($) {
$(document).ready(function() {
var serializedJSON = '{"title":"Hello World!","body":"It\'s great to be
alive!"}';
var message = JSON.parse( serializedJSON );
});
})(jQuery);
Discussion
As uiscusseu in the pievious iecipe, we`ll now look at paising oi uecouing a ]SON
stiing.
It is impoitant to note that some ol the appioaches outlineu heie aie
unsale anu may cause potential secuiity issues. Make suie that you tiust
the souice ol youi uata.
The easiest appioach in consuming ]SON uata is to eval() the message. Theie aie some
inheient secuiity issues though with this appioach Lecause eval() encompasses the
entiie ]avaSciipt specilication insteau ol simply the ]SON suLset. Vhat this means is
that a malicious peison coulu execute coue emLeuueu in the ]SON stiing. So, we uon`t
iecommenu this appioach. Insteau, let`s use Douglas Ciockloiu`s JSON liLiaiy men-
tioneu in the pievious iecipe. (Note that his liLiaiy uoes utilize eval() except that it
pie-piocesses the uata to make suie the uata is sale.)
var serializedJSON = '{"title":"Hello World!","body":"It\'s great to be alive!"}';
var message = JSON.parse( serializedJSON );
So, now we can woik with oui message oLject as we woulu any othei ]avaSciipt oLject:
alert( "New Message!\nTitle: " + message.title + "\nBody: " + message.body);
The JSON liLiaiy as well as auuitional ]SON iesouices may Le uownloaueu liom http:
//jqucry-coo|boo|.con/go/json.
406 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
16.9 Using jQuery and JSONP
Problem
You want to consume a list ol photos liom Flicki`s puLlic photo stieam anu uisplay
the liist thiee images.
Solution
(function($) {
$(document).ready(function() {
var url = 'http://www.flickr.com/services/feeds/photos_public.gne?
jsoncallback=?';
var params = { format: 'json' };
$.getJSON(url, params, function(json) {
if ( json.items ) {
$.each( json.items, function(i, n) {
var item = json.items[i];
$('<a href="' + item.link + '"></a>')
.append('<img src="' + item.media.m + '" />')
.appendTo('#photos');
// Display the first 3 photos (returning false will
// Exit the loop
return i < 2;
});
}
});
});
})(jQuery);
Discussion
Secuiity is a ciitical issue when Luiluing a weLsite oi application anu especially so with
the auvent ol Ajax. VeL Liowseis have enloiceu a same oiigin policy on ieguests, which
means that you`ie iestiicteu to making ieguests to the same uomain as the page`s URL
oi a suLuomain ol the cuiient uomain. So, loi example, a page seiveu liom http://
www.cxanp|c.con is alloweu to make Ajax ieguests to http://www.cxanp|c.con anu
http://x.www.cxanp|c.con Lut not http://cxanp|c.con oi http://y.cxanp|c.con. As the
semantic VeL emeigeu anu weLsites such as Flicki staiteu exposing an API loi othei
useis anu seivices to consume, the secuiity policy enloiceu Ly weL Liowseis Lecame a
hinuiance. One aiea that has nevei hau same oiigin policies was the use ol the sciipt
element with a src attiiLute. It`s possiLle loi http://www.cxanp|c.con to incluue a sciipt
liom http://static.cxanp|c2.con, Lut the issue ol uynamically incluuing that sciipt anu
managing piogiam llow Lecame an issue. Thus, ]SONP emeigeu as a stanuaiu to ovei-
come the same oiigin limitation.
16.9 Using jQuery and JSONP | 407
It is impoitant to note that some ol the appioaches outlineu heie aie
unsale anu may cause potential secuiity issues. Make suie that you tiust
the souice ol youi uata. Also, when incluuing a sciipt element in a page,
that entiie sciipt will have access to the entiie HTML DOM anu any
piivate oi sensitive uata that it may contain. It coulu Le possiLle loi a
malicious sciipt to senu this uata to an untiusteu paity. Take extia pie-
caution such as placing the sciipt in a sanuLox. Extenueu secuiity is
outsiue the scope ol this iecipe, Lut we wanteu to make suie you weie
awaie ol it.
]SONP makes use ol ieguesting uata thiough a <script> tag with a src attiiLute as well
as manages the piogiam llow loi the uevelopei Ly wiapping the uata in a callLack
lunction that the uevelopei can implement. Let`s liist look at a sample ]SON message.
{"title":"Hello World!","body":"It's great to be alive!"}
Heie is the same message wiappeu in a callLack:
myCallback({"title":"Hello World!","body":"It's great to be alive!"})
Vhat this allows loi is when the iesouice is ieguesteu upon Leing loaueu in the Liowsei
the myCallback lunction will Le calleu anu have the ]SON oLject passeu in as the liist
aigument. The uevelopei can then implement the myCallback lunction as lollows to
piocess the uata:
function myCallback(json) {
alert( json.title );
}
Now let`s ieview oui Flicki solution. Fiist we ueline the URL ol the Flicki weL seivice
lolloweu Ly ueclaiing a params oLject loi the get vaiiaLles. The jsoncallback paiam is
a special paiam uelineu Ly the Flicki seivice that allows loi us to pass in a lunction
name. Since we`ve set this paiametei to a ?, jQueiy will automatically geneiate a lunc-
tion name anu Linu it with oui callLack methou.
jQueiy uetects that this is a ]SONP (cioss-uomain ieguest) Ly the =? in
the URL. It is not possiLle to pass this in the params aiiay.
var url = 'http://www.flickr.com/services/feeds/photos_public.gne?
jsoncallback=?';
var params = { format: 'json' };
408 | Chapter 16:jQuery, Ajax, Data Formats: HTML, XML, JSON, JSONP
Next, we call jQueiy`s $.getJSON() methou, passing in oui url, params, anu oui callLack
lunction, which will accept a ]SON oLject. In oui callLack methou, we check anu make
suie that an item`s aiiay exists anu then use jQueiy`s $.each() to iteiate ovei the liist
thiee items, cieate a link, appenu an image to it, anu then appenu the link to an element
with an ID ol photos. Finally, oui callLack lunction will ietuin false on the thiiu itei-
ation (when i = 2), Lieaking the loop.
$.getJSON(url, params, function(json) {
if ( json.items ) {
$.each( json.items, function(i, n) {
var item = json.items[i];
$('<a href="' + item.link + '"></a>')
.append('<img src="' + item.media.m + '" />')
.appendTo('#photos');
return i < 2;
});
}
});
Vith the comLination ol the ]SON uata loimat anu the cioss-uomain capaLilities ol
]SONP, weL uevelopeis aie aLle to cieate new applications aggiegating anu tians-
loiming uata in new anu innovative ways anu giowing the semantic VeL.
16.9 Using jQuery and JSONP | 409
CHAPTER 17
Using jQuery in Large Projects
Rob Burns
17.0 Introduction
jQueiy is olten useu to auu small usei inteilace enhancements to a weLsite. Howevei,
loi laigei, moie complex weL applications, jQueiy is also guite uselul. The sample
iecipes thioughout this chaptei show how jQueiy can Le useu to auuiess the neeus ol
moie suLstantial anu inteiactive weL content. The liist thiee iecipes exploie uilleient
methous ol peisisting uata in a weL Liowsei. These aie lolloweu Ly a look at easing
the use ol Ajax anu ]avaSciipt as the guantity ol coue anu uata in youi application
giows.
17.1 Using Client-Side Storage
Problem
You aie wiiting a iich Inteinet application that piocesses nontiivial amounts ol usei
uata in the weL Liowsei. Motivateu Ly the uesiie to cache this uata loi peiloimance
ieasons oi to enaLle ollline use ol youi application, you neeu to stoie uata on the client.
Solution
A simple to-uo list will Le useu to illustiate stoiing uata on the client. As with many ol
the iecipes in this chaptei, a jQueiy plugin will Le useu to hanule Liowsei
inconsistencies:
<!DOCTYPE html>
<html><head>
<title>17.1 - Using Client-Side Storage</title>
<script type="text/javascript" src="../../jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="jquery.jstore-all.js"></script>
</head>
411
<body>
<h1>17.1 - Using Client-Side Storage</h1>
<p>Storage engine: <span id="storage-engine"></span></p>
<input id="task-input"></input>
<input id="task-add" type="submit" value="Add task"></input>
<input id="list-clear" type="submit" value="Remove all tasks"></input>
<ul id="task-list"></ul>
</body></html>
The HTML consists ol loim elements loi manipulating the to-uo list: a text lielu to
input a task, anu Luttons loi auuing a task anu ueleting all tasks. The cuiient tasks will
Le listeu using an unoiueieu list:
(function($) {
$.jStore.ready(function(ev,engine) {
engine.ready(function(ev,engine) {
$('#storage-engine').html($.jStore.CurrentEngine.type);
$('#task-list').append($.store('task-list'));
});
});
The jStoie plugin pioviues two callLacks: jStore.ready() anu engine.ready(). Much
like jQueiy`s ready() lunction, these allow us to uo some initial setup once jStoie anu
the cuiient stoiage engine have completeu theii inteinal initialization. This oppoitunity
is useu to uisplay the cuiiently useu stoiage engine anu any saveu to-uo items on
the page:
$('document').ready(function() {
$('#task-add').click(function() {
var task = $('#task-input').val();
var taskHtml = '<li><a href="#">done</a> ' + task + '</li>';
$.store('task-list',$('#task-list').append(taskHtml).html());
return false;
});
Once the uocument is ieauy, click events aie Lounu to the appiopiiate contiols. Vhen
the Auu task Lutton is clickeu, a list-item element is constiucteu with the contents
ol the task text lielu anu a link to maik this task as uone. The list item is then appenueu
to the contents ol the task list, anu the task list is saveu in local stoiage using the task-
list key. At a latei time, the list can Le ietiieveu using this key, as is Leing uone in the
engine.ready() callLack:
$('#list-clear').click(function() {
$('#task-list').empty();
$.remove('task-list');
return false;
});
Vhen the Remove all tasks Lutton is clickeu, the element containing the to-uo list
is emptieu ol its contents. The task-list key anu its associateu value aie then iemoveu
liom local stoiage:
412 | Chapter 17:Using jQuery in Large Projects
$('#task-list a').live('click',function() {
$(this).parent().remove();
var taskList = $('#task-list').html();
if( taskList ) { $.store('task-list',taskList); }
else { $.remove('task-list'); }
return false;
});
});
})(jQuery);
Lastly, a live event is Lounu to the done links loi each item in the to-uo list. By using
the live() lunction, insteau ol the bind() lunction oi a shoitcut such as click(), all
elements that match #task-list a will have the given lunction Lounu to the click event,
even elements that uo not yet exist at the time live() is calleu. This allows us to inseit
uone links loi each new item, without ieLinuing the click event each time the insei-
tion occuis.
Vhen an item is maikeu as uone, it is iemoveu liom the list, anu the upuateu list saveu
in local stoiage using the task-list key. Some caie neeus to Le taken when saving the
upuateu list:
if( taskList ) { $.store('task-list',taskList); }
else { $.remove('task-list'); }
In the case that the last item in the list is Leing iemoveu, the taskList vaiiaLle will Le
empty. This causes the store() lunction to Le evaluateu as il it weie calleu with a single
paiametei, not two. Vhen store() is passeu a single paiametei, the value helu at that
key is ietiieveu, anu the saveu list is unmouilieu. The goal is to save an empty list. The
remove() lunction in the else clause iemoves the task-list key anu its associateu value.
This meets the goal ol setting the saveu state to an empty list.
Discussion
Tiauitionally, the only option availaLle to stoie uata on the client was cookies. The
amount ol uata that can Le stoieu in a cookie is veiy limiteu. Bettei alteinatives now
exist. The lollowing taLle contains cuiiently availaLle stoiage mechanisms anu theii
Liowsei compatiLility.
Firefox Safari Internet Explorer
DOM Storage 2.0+ no 8.0+
Gears yes yes yes
Flash yes yes yes
SQL Storage API no 3.1+ no
userData behavior no no 5.0+
DOM Stoiage anu the SQL Stoiage API aie pait ol emeiging HTML stanuaius. As such,
they uon`t yet enjoy thoiough cioss-Liowsei suppoit. Google Geais anu Flash aie
17.1 Using Client-Side Storage | 413
Liowsei plugins that can Le useu loi client-siue stoiage. Inteinet Exploiei has, loi some
time, incluueu the useiData Lehavioi loi client-siue stoiage. Il a single mechanism to
suppoit all majoi Liowseis is neeueu, a Flash oi Google GeaisLaseu appioach olleis
suppoit loi the wiuest vaiiety. Howevei, it ieguiies useis to have a Liowsei plugin
installeu.
The 1.0.3 ielease ol the jStoie plugin contains a Lug. A typo neeus to Le
coiiecteu. Line +03 ol jquery.jstore-all.js shoulu ieau as lollows:
return !!(jQuery.hasFlash('8.0.0'));
Foitunately, jStoie (availaLle at http://p|ugins.jqucry.con/projcct/jStorc) alloius a layei
ol aLstiaction, which enaLles cioss-Liowsei anu client-siue stoiage anu, in most cases,
uoesn`t iely on Liowsei plugins. jStoie pioviues a unilieu inteilace to the stoiage mech-
anisms listeu pieviously. Vhile manual selection is suppoiteu, this example illustiates
jStoie`s aLility to automatically select the appiopiiate stoiage mechanism loi the
Liowsei cuiiently in use. Vhen vieweu in uilleient Liowseis, this iecipe uisplays the
cuiiently selecteu stoiage mechanism.
17.2 Saving Application State for a Single Session
Problem
You want to peisist uata on the client only until the cuiient session is enueu, i.e., the
winuow oi taL is closeu.
Solution
In this example theie aie two HTML pages. Each page contains a set ol selectaLle
elements. Vhen elements aie selecteu anu ueselecteu, the state ol the page is peisisteu.
By navigating to anu liom the two pages, you can see how the state ol any given page
can Le maintaineu as a usei navigates thiough a weLsite. The sessionStorage oLject is
useu loi uata that uoesn`t ieguiie peisisting Letween a usei`s suLseguent visits:
<!DOCTYPE html>
<html><head>
<title>17.2 Saving Application State for a Single Session</title>
<style>
.square {
width: 100px; height: 100px; margin: 15px;
background-color: gray; border: 3px solid white; }
.selected {
border: 3px solid orange; }
</style>
<script src="../../jquery-1.3.2.min.js"></script>
</head>
414 | Chapter 17:Using jQuery in Large Projects
<body>
<h1>17.2 Saving Application State for a Single Session</h1>
<a href="one.html">page one</a>
<a href="two.html">page two</a>
<div id="one" class="square"></div>
<div id="two" class="square"></div>
<div id="three" class="square"></div>
</body></html>
Each ol the two HTML pages (one.html anu two.html) have the same content. The
lollowing ]avaSciipt coue takes caie ol managing the state ol each page, such that each
page iellects past usei manipulation:
jQuery(document).ready(function() {
$('.square').each(function(){
if( sessionStorage[window.location + this.id] == 'true' ) {
$(this).addClass('selected');
}
});
$('.square').click(function() {
$(this).toggleClass('selected');
sessionStorage[window.location + this.id] = $(this).hasClass('selected');
return false;
});
});
Vhen the uocument is loaueu, the sessionStorage oLject is gueiieu loi keys compiising
the cuiient URL anu the id ol each ol the selectaLle sguaies. Each sguaie has a CSS
class applieu il appiopiiate. Vhen a sguaie is clickeu, its uisplay is allecteu Ly toggling
a CSS class, anu its state is peisisteu accoiuingly. Each sguaie`s state is peisisteu using
a key geneiateu liom the cuiient URL anu cuiient element id paii.
Discussion
Similai session-uelimiteu client-siue stoiage is availaLle when using the jStoie plugin
liom the pievious iecipe. By using jStoie, you gain the Lenelits ol cioss-Liowsei com-
patiLility. This iecipe will only woik in Inteinet Exploiei S.0 anu Fiielox 2.0 oi highei.
Salaii 3.1 uoesn`t have this leatuie, though lutuie veisions aie slateu to incluue it.
The DOM stoiage API is attiactive in cases wheie Lioau Liowsei compatiLility isn`t a
concein. Applications uevelopeu loi inteinal company intianets may lall into this cat-
egoiy. It is also pait ol the upcoming HTML5 specilication. In the lutuie its availaLility
is likely to spieau. Using a Luilt-in stoiage API has the Lenelit ol incuiiing no oveiheau
liom auuitional ]avaSciipt coue. The minilieu jStoie plugin anu jStore.swf llash com-
ponent aie 20 KB in size.
17.2 Saving Application State for a Single Session | 415
17.3 Saving Application State Between Sessions
Problem
You want to peisist uata on the client Letween sessions. Recipe 17.1 saves the state ol
the to-uo list in Letween sessions. This iecipe illustiates how to enaLle similai lunc-
tionality without using the jStoie plugin.
Solution
Foi the HTML pait ol this solution, please ielei to Recipe 17.1 (as it is iuentical). The
]avaSciipt is listeu heie:
(function($) {
$('document').ready(function() {
if( window.localStorage ) { appStorage = window.localStorage; }
else { appStorage = globalStorage[location.hostname]; }
var listHtml = appStorage['task-list'];
$('#task-list').append(listHtml.value ? listHtml.value : listHtml);
The initial setup is somewhat moie veiLose than the jStoie-Laseu solution. Fiielox has
a nonstanuaiu implementation ol the long-teim stoiage poition ol the DOM stoiage
API. It uses the globalStorage aiiay, as opposeu to the localStorage oLject to peisist
uata Letween sessions. Each stoiage oLject in the globalStorage aiiay is keyeu on the
uomain that the cuiient uocument is Leing seiveu liom. This coue will use
localStorage il it is availaLle. Otheiwise, it will lall Lack to globalStorage.
In the next section ol coue, the unoiueieu list is populateu with any existing tasks. In
the jStoie-Laseu example this was a single line ol coue. The auuitional complexity heie
is Lecause ol Fiielox`s paiticulai Lehavioi. A stiing is ietuineu liom localStorage. But,
an oLject with two attiiLutes, value anu secure, is ietuineu when accessing
globalStorage. The value attiiLute is useu il piesent. Otheiwise, a stiing ietuineu liom
localStorage is assumeu:
$('#task-add').click(function() {
var task = $('#task-input').val();
var taskHtml = '<li><a href="#">done</a> ' + task + '</li>';
appStorage['task-list'] = $('#task-list').append(taskHtml).html();
return false;
});
$('#list-clear').click(function() {
$('#task-list').empty();
appStorage['task-list'] = '';
return false;
});
$('#task-list a').live('click',function() {
$(this).parent().remove();
appStorage['task-list'] = $('#task-list').html();
416 | Chapter 17:Using jQuery in Large Projects
return false;
});
});
})(jQuery);
The iemainuei ol the coue auus new tasks, iemoves tasks when maikeu uone, anu
cleais the task list Ly attaching events to DOM elements like the pievious jStoie-Laseu
iecipe. Howevei, insteau ol using the jStoie lunction-Laseu inteilace loi manipulating
peisisteu uata, values in the appStorage oLject cieateu eailiei can Le assigneu uiiectly.
This allows the coue to iemove a task to Le simplilieu.
Discussion
The DOM Stoiage API consists ol two inteilaces: sessionStorage anu localStorage.
Fiielox has incluueu this leatuie since veision 2.0, when the stanuaiu was still in ue-
velopment. Since then, the stanuaiu has unueigone ievision. Inteinet Exploiei S.0 has
an implementation ol the cuiient API. Foithcoming veisions ol Salaii anu Fiielox will
conloim to the cuiient specilication as well. That saiu, Fiielox 2.03.0 Liowseis will
peisist loi some time. Couing an application to suppoit globalStorage will auuitionally
seive these legacy Liowseis.
17.4 Using a JavaScript Template Engine
Problem
You want to use a ]avaSciipt template engine to uisplay ]SON uata.
Solution
This iecipe is a Look listing. It giaLs inloimation aLout a Look liom a seivei-siue sciipt
anu auus it to a list ol Looks uisplayeu in the Liowsei. The Look uetails aie ietuineu
liom the seivei as a ]SON stiing. The Puie templating engine (availaLle at http://p|ugins
.jqucry.con/projcct/purc) is useu to loimat the uata anu inseit it into the weL page:
<!DOCTYPE html>
<html><head>
<title>jQuery Cookbook - 17.4 Using a Javascript Template Engine</title>
<style>.hidden { display: none }</style>
<script type="text/javascript" src="../../jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="pure.js"></script>
</head>
<body>
<h1>17.4 - Using a Javascript Template Engine</h1>
<input type="button" id="add-book" value="Add book"></input>
<input type="button" id="clear-list" value="Clear booklist"></input>
<div id="book-list"></div>
17.4 Using a JavaScript Template Engine | 417
Theie aie two Luttons. One will letch Look uetails liom the seivei when clickeu. The
othei will cleai the locally uisplayeu Look list. The Look list will Le uisplayeu insiue a
<div> element with an id ol book-list. These elements aie visiLle when the page is
loaueu:
<div id="book-template" class="hidden book">
<ul class="author-list"><li class="author"><span class="name"></span>
</li></ul>
<p class="title"></p>
<p class="year"></p>
<div class='book-footer'>
<div class="rating-div">Rating: <span class="rating"></span></div>
<div>Location: <span class="location"></span></div>
</div>
</div>
</body></html>
The <div> with an id ol book-template has a class hidden assigneu to it. This <div> is
not uisplayeu. It will Le useu as a template loi the uata ieceiveu liom the seivei. The
Puie templating engine associates attiiLutes in a uata stiuctuie with HTML elements
that have the same class. Theieloie, the contents ol the paiagiaph element with class
year will iellect the value ol the year attiiLute in oui uata stiuctuie:
{
"title": "Democracy and the Post-Totalitarian Experience",
"author": [
{
"name": "Leszek Koczanowicz"
},
{
"name": "Beth J. Singer"
}
],
"year": "2005",
"rating": "3",
"location": "Mandalay"
}
The pieceuing coue is an example ol the ]SON uata that is ietuineu liom the seivei.
The title, year, rating, anu location attiiLutes have a single value anu map uiiectly
to a single element in the HTML template. In oiuei to iepeat any ol these values moie
than once, one only has to assign the appiopiiate class to auuitional elements in the
template.
The author attiiLute contains an aiiay ol oLjects. Each oLject has a single attiiLute:
name. Multiple authois aie iepiesenteu this way in oiuei to illustiate the iteiation ca-
paLilities ol the templating engine. The template contains a single list item element
with class author. The list item contains a <span> element with class <name>. Foi attiiL-
utes within the uata stiuctuie that have an aiiay value, an instance ol the associateu
HTML element will Le cieateu loi each element ol the aiiay. In this way, an aiLitiaiy
numLei ol list items can Le cieateu:
418 | Chapter 17:Using jQuery in Large Projects
(function($) {
$('document').ready(function() {
$('#add-book').data('id',1);
Once the uocument is ieauy, the ]avaSciipt coue staits Ly using the jQueiy data()
lunction to stoie the cuiient id ol the Look we will Le ieguesting. This id will Le
inciementeu each time a Look is ieguesteu. The data() lunction allows aiLitiaiy uata
to Le stoieu in DOM elements:
$('#add-book').click(function() {
var curId = $(this).data('id');
$.getJSON('server.php', {id: +curId}, function(data) {
if( data.none ) { return false; }
var divId = 'book-' + curId;
$('#book-list').append($('#book-template').clone().attr('id',divId));
$('#'+divId).autoRender(data).removeClass('hidden');
$('#add-book').data('id', curId + 1);
});
return false;
});
Vhen the Auu Look Lutton is clickeu, a ieguest is maue to the seivei using the jQueiy
getJSON() lunction. The templating piocess staits Ly making a clone ol the hiuuen
<div> in oui HTML. The id ol this clone must Le changeu Leloie it is appenueu to the
Look list. Il the id isn`t changeu, then a DOM element with a non-unigue id will have
Leen intiouuceu. The autoRender() lunction liom the Puie plugin is then calleu with
the ]SON uata as an aigument. This ienueis the template using the pioviueu uata.
Lastly, the hidden class is iemoveu, making the Look uetails visiLle:
$('#clear-list').click(function() {
$('#add-book').data('id',1);
$('#book-list').empty();
return false;
});
});
})(jQuery);
The lunction to cleai the Look list is laiily stiaightloiwaiu. The appiopiiate <div>
element is emptieu, anu the Look id countei is ieset to 1.
Discussion
Theie aie two Lenelits to using ]avaSciipt-Laseu templating engines. One is that they
allow the tiansloimation ol a ]SON uata stiuctuie into styleu anu stiuctuieu HTML
without manually manipulating each element ol the uata stiuctuie. This Lenelit can Le
iealizeu Ly applying a templating engine to the vaiiety ol small chunks ol uata that aie
commonly ietiieveu Ly Ajax calls, as this example illustiateu.
The seconu Lenelit ol using a ]avaSciipt templating engine is that it piouuces puie
HTML templates. These templates contain no tiaces ol the sciipting languages, which
aie usually useu to uenote the uata to Le templateu, anu implement lunctionality such
as iteiation. It`s uillicult to take auvantage ol this when using the templating engine in
17.4 Using a JavaScript Template Engine | 419
the Liowsei, as uone in this iecipe. The negative impact this has on a site`s appeal to
seaich engines uissuaues most people liom going this ioute. Howevei, jQueiy anu the
Puie templating engine can Le iun in seivei-siue ]avaSciipt enviionments, as well.
]axei, Rhino, anu SpiueiMonkey have all Leen known to woik.
17.5 Queuing Ajax Requests
Problem
You want to have gieatei contiol ovei the oiuei ol many sepaiate Ajax ieguests.
Solution
This iecipe illustiates two uilleient ways to gueue Ajax ieguests. The liist lills a gueue
with ieguests, senuing suLseguent ieguests once the pievious ieguest has ietuineu a
iesponse. The seconu senus gioups ol ieguests in paiallel. But, it uoesn`t execute the
callLack lunctions loi each ieguest until all iesponses have ietuineu. An example ol
noimal ungueueu ieguests is incluueu loi compaiison:
<!DOCTYPE html>
<html><head>
<title>jQuery Cookbook - 17.5 - Queuing Ajax Requests</title>
<script type="text/javascript" src="../../jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="jquery-ajax-queue_1.0.js"></script>
</head>
<body>
<h1>17.5 - Queuing Ajax Requests</h1>
<input type="button" id="unqueued-requests" value="Unqueued requests"></input>
<input type="button" id="queued-requests" value="Queued requests"></input>
<input type="button" id="synced-requests" value="Synced requests"></input>
<p id="response"></p>
</body></html>
The ajaxgueue jQueiy plugin (availaLle at http://p|ugins.jqucry.con/projcct/ajax
qucuc/) is useu loi gueuing Lehaviois. Thiee Luttons tiiggei each set ol Ajax ieguests.
A log ol the iesponses is uisplayeu in a paiagiaph element:
(function($) {
$('document').ready(function() {
$('#unqueued-requests').click(function() {
$('#response').empty();
$.each([1,2,3,4,5,6,7,8,9,10], function() {
$.get('server.php',{ data: this }, function(data) {
$('#response').append(data);
});
});
return false;
});
420 | Chapter 17:Using jQuery in Large Projects
The liist Lutton tiiggeis noimal Ajax ieguests. Ten ieguests aie sent, each with a num-
Lei loi theii position in the seguence. The server.php sciipt simulates a seivei unuei
loau Ly sleeping ianuom amounts ol time Leloie ietuining a iesponse. Vhen it aiiives,
the iesponse is appenueu to the contents ol the #response paiagiaph:
$('#queued-requests').click(function() {
$('#response').empty();
$.each([1,2,3,4,5,6,7,8,9,10], function() {
$.ajaxQueue({url: 'server.php',
data: { data: this },
success: function(data) { $('#response').append(data); }
});
});
$.dequeue( $.ajaxQueue, "ajax" );
return false;
});
The Queueu ieguests Lutton auus each ieguest to a gueue Ly calling the
ajaxQueue() lunction. Inteinally, the ajax() lunction is calleu with the pioviueu op-
tions, each time a ieguest is uegueueu. Altei each ol the ieguests has auueu to the
gueue, a call to dequeue() with the ajaxQueue lunction as a paiametei tiiggeis the liist
ieguest. Each suLseguent ieguest will Le sent in tuin:
$('#synced-requests').click(function() {
$('#response').empty();
$.each([1,2,3,4,5,6,7,8,9,10], function() {
$.ajaxSync({url: 'server.php',
data: { data: this },
success: function(data) { $('#response').append(data); }
});
});
return false;
});
});
})(jQuery);
The linal set ol ieguests use the ajaxSync() lunction to senu the ieguests in paiallel Lut
synchionize the execution ol the pioviueu callLacks when the iesponses ietuin.
Discussion
Responses liom the ungueueu ieguests come Lack out ol oiuei. This Lehavioi is not
necessaiily unuesiiaLle anu in many cases may Le pieleiieu. Howevei, theie aie sce-
naiios wheie one woulu like moie contiol ovei Ajax ieguests anu theii iesponses. The
lunctionality pioviueu in ajaxQueue() suits the case wheie each suLseguent ieguest is
uepenuent upon the iesponse to the pievious ieguest, wheieas ajaxSync() suppoits the
use case ol manipulating uata, which is gatheieu liom a vaiiety ol seiveis. In this sce-
naiio, piocessing is unaLle to commence until all seiveis have ietuineu a iesponse anu
the complete set ol uata is piesent.
17.5 Queuing Ajax Requests | 421
17.6 Dealing with Ajax and the Back Button
Problem
Populating weL pages using Ajax cieates a convenient, inteiactive usei expeiience,
which can`t Le ieplicateu with tiauitional HTTP ieguests. Unloitunately, each time
you upuate the contents ol the Liowsei winuow with Ajax, that content Lecomes
inaccessiLle to the Lack anu loiwaiu Luttons ol youi Liowsei. The Lookmaiking lunc-
tionality lounu in most Liowseis is also ienueieu nonlunctional.
Solution
The solution to this pioLlem is to ielate each Ajax ieguest to a unigue URL. This URL
can then Le Lookmaikeu anu accesseu Ly the Lack anu loiwaiu Liowsei Luttons. One
methou loi uoing this is to use hash values. Hash values aie geneially useu to link into
a specilic position within a uocument. http://cn.wi|ipcdia.org/wi|i/App|c=History links
to the histoiy section ol the Vikipeuia page loi Apple. Foi the puiposes ol this iecipe,
the hash value will ielei to content loaueu Ly an Ajax ieguest.
In this example, the sample pioject is a small glossaiy. It has thiee entiies. Vhen you
click each entiy, the uelinition loi the woiu is ietiieveu anu uisplayeu via Ajax. Gianteu,
the content coulu easily Le uisplayeu all at once on a single page. Howevei, this same
appioach is appiopiiate loi laigei, moie vaiieu uata, such as the contents ol each taL
in a taLLeu inteilace:
<!DOCTYPE html>
<html><head>
<title>17.6 Dealing with Ajax and the Back Button</title>
<script src="../../jquery-1.3.2.min.js"></script>
<script src="jquery.history.js"></script>
</head>
<body>
<h1>17.6 Ajax and the Back Button</h1>
<a href="#apples" class='word'>apples</a>
<a href="#oranges" class='word'>oranges</a>
<a href="#bananas" class='word'>bananas</a>
<p id='definition'></p>
</body></html>
Necessaiy ]avaSciipt liles aie incluueu in the heau ol the uocument. The
jquery.history.js lile contains the jQueiy histoiy plugin (availaLle at http://p|ugins
.jqucry.con/projcct/history). Theie is an anchoi element loi each ol the thiee entiies in
the glossaiy. The uelinition loi each entiy will Le uisplayeu in the paiagiaph with an
id ol definition:
(function($) {
function historyLoad(hash) {
if(hash) { $('#definition').load('server.php',{word: hash}); }
else { $('#definition').empty(); }
422 | Chapter 17:Using jQuery in Large Projects
}
$(document).ready(function() {
$.history.init(historyLoad);
$('a.word').click(function() {
$.history.load($(this).html());
return false;
});
});
})(jQuery);
The histoiy plugin has two lunctions that aie ol concein: init() anu load(). The
init() lunction is calleu insiue the ready lunction. A callLack to hanule Ajax ieguests
is passeu in as an aigument. load() is Lounu to the woiu links. The content ol each
anchoi tag is passeu in as an aigument. The callLack historyLoad() takes caie ol ie-
guesting the content loi the passeu-in hash value. It also neeus to Le aLle to hanule
instances wheie theie is no hash value.
Discussion
Theie aie two instances when the historyLoad() callLack is calleu. Fiist, it is calleu
insiue the $.history.init() lunction, when the page is loaueu. The hash value is stiip-
peu liom the enu ol the URL anu passeu as the aigument. Il theie is not a hash value
piesent, the aigument is empty. The load() lunction also calls historyLoad(). The ai-
gument we pass to $.history.load(), the woiu we clickeu, in this case, is passeu on as
the hash aigument to oui callLack.
In this solution, a jQueiy plugin was useu. It is ielatively easy to implement similai
lunctionality without a plugin, Ly using ]avaSciipt`s window.location.hash oLject. The
jQueiy histoiy plugin compiises only 156 lines ol coue. The ieason it was chosen ovei
wiiting a solution liom sciatch is that a laige pait ol the plugin coue hanules cioss-
Liowsei inconsistencies. Vhen hanuling Liowsei uilleiences, it`s olten moie ellective
to uiaw liom the communal pool ol expeiience that accumulates in a plugin than tiy
anu to account loi eveiy implementation uisciepancy onesell.
17.7 Putting JavaScript at the End of a Page
Problem
As a pioject giows in size, olten the amount ol ]avaSciipt it contains giows as well.
This iesults in slowei page loau times. ComLining seveial uispaiate ]avaSciipt liles into
one monolithic lile, using minilication, anu using compiession can help ieuuce the
]avaSciipt size anu ieuuce the numLei ol HTTP ieguests maue. But, one will always
Le lelt with some amount ol coue to loau. It woulu Le nice il the impact ol this coue
on peiceiveu loau times coulu Le ieuuceu.
17.7 Putting JavaScript at the End of a Page | 423
Solution
A usei peiceives loau times Laseu on what they see on the scieen. A Liowsei has a
limiteu numLei ol HTTP connections at its uisposal to loau exteinal content, such as
]avaSciipt, CSS stylesheets, anu images. Vhen ]avaSciipt is placeu at the top ol the
uocument, it can uelay the loauing ol othei visiLle iesouices. The solution is to place
youi ]avaSciipt liles at the enu ol youi page:
<!DOCTYPE html>
<html><head>
<title>17.7 Putting JavaScript at the End of a Page</title>
</head>
<body>
<h1>17.7 Putting JavaScript at the End of a Page</h1>
<p>Lorem ipsum dolor...</p>
<script src="../../jquery-1.3.2.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('p').after('<p>Ut ac dui ipsum...</p>').show();
});
</script>
</body></html>
Discussion
By placing the ]avaSciipt just Leloie the closing <body> tags, any images oi CSS style-
sheets that aie ieleienceu pieviously in the uocument aie loaueu liist. This won`t cause
the page to loau any lastei. Howevei, it will ueciease the peiceiveu loau time. VisiLle
elements will Le given piioiity ovei the ]avaSciipt coue. Loauing the ]avaSciipt liles
late in the page uoesn`t incui any uiawLacks Lecause it geneially shoulun`t Le executeu
until the entiie page is loaueu.
No Lenelit is gaineu liom putting the inline ]avaSciipt at the enu ol the uocument. It
is placeu theie in this example Lecause the jQueiy lunction can`t Le calleu until
jquery-1.3.2.min.js is loaueu. Il we placeu the inline ]avaSciipt in the <head> element,
an eiioi woulu Le geneiateu Lecause ol jQueiy not Leing uelineu.
424 | Chapter 17:Using jQuery in Large Projects
CHAPTER 18
Unit Testing
Scott Gonzlcz and ]orn Zacjjcrcr
18.0 Introduction
Automateu testing ol soltwaie is an essential tool in uevelopment. Unit tests aie the
Lasic Luiluing Llocks loi automateu tests: each component, the unit, ol soltwaie is
accompanieu Ly a test that can Le iun Ly a test iunnei ovei anu ovei again without any
human inteiaction. In othei woius, you can wiite a test once anu iun it as olten as
necessaiy without any auuitional cost.
In auuition to the Lenelits ol goou test coveiage, testing can also uiive the uesign ol
soltwaie, known as tcst-drivcn dcsign, wheie a test is wiitten Leloie an implementation.
You stait wiiting a veiy simple test, veiily that it lails (Lecause the coue to Le testeu
uoesn`t exist yet), anu then wiite the necessaiy implementation until the test passes.
Once that happens, you extenu the test to covei moie ol the uesiieu lunctionality anu
implement again. By iepeating those steps, the iesulting coue looks usually much uil-
leient liom what you`u get Ly staiting with the implementation.
Unit testing in ]avaSciipt isn`t much uilleient liom in othei piogiamming languages.
You neeu a small liamewoik that pioviues a test iunnei, as well as some utilities to
wiite the actual tests.
18.1 Automating Unit Testing
Problem
You want to automate testing youi applications anu liamewoiks, mayLe even Lenelit
liom test-uiiven uesign. Viiting youi own testing liamewoik may Le tempting, Lut it
involves a lot ol woik to covei all the uetails anu special ieguiiements ol testing ]ava-
Sciipt coue in vaiious Liowseis.
425
Solution
Vhile theie aie othei unit testing liamewoiks loi ]avaSciipt, we will take a look at
QUnit. QUnit is jQueiy`s unit test liamewoik anu is useu Ly a wiue vaiiety ol piojects.
To use QUnit, you neeu to incluue jQueiy anu two QUnit liles on youi HTML page.
QUnit consists ol testrunner.js, the test iunnei anu testing liamewoik, anu
testsuite.css, which styles the test suite page to uisplay test iesults:
<!DOCTYPE html>
<html>
<head>
<title>QUnit basic example</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<link rel="stylesheet"
href="http://jqueryjs.googlecode.com/svn/trunk/qunit/testsuite.css" type="text/css"
media="screen" />
<script type="text/javascript"
src="http://jqueryjs.googlecode.com/svn/trunk/qunit/testrunner.js"></script>
<script type="text/javascript">
test("a basic test example", function() {
ok( true, "this test is fine" );
var value = "hello";
equals( value, "hello", "We expect value to be hello" );
});
</script>
</head>
<body>
<div id="main"></div>
</body>
</html>
Opening this lile in a Liowsei gives the iesult shown in Figuie 1S-1.
Iigurc 18-1. Tcst rcsu|t in a browscr
426 | Chapter 18:Unit Testing
The only maikup necessaiy in the <body> element is a <div> with id="main". This is
ieguiieu loi all QUnit tests, even when the element itsell is empty. This pioviues the
lixtuie loi tests, which will Le explaineu in Recipe 1S.6.
The inteiesting pait is the <script> element lollowing the testrunner.js incluue. It
consists ol a call to the test lunction, with two aiguments: the name ol the test as a
stiing, which is latei useu to uisplay the test iesults, anu a lunction. The lunction con-
tains the actual testing coue, which involves one oi moie asseitions. The example uses
two asseitions, ok() anu equals(), which aie explaineu in uetail in Recipe 1S.2.
Note that theie is no document-ready Llock. The test iunnei hanules that: calling
test() just auus the test to a gueue, anu its execution is ueleiieu anu contiolleu Ly the
test iunnei.
Discussion
The heauei ol the test suite uisplays the page title, a gieen Lai when all tests passeu (a
ieu Lai when at least one test laileu), a giay Lai with the navigator.userAgent stiing
(hanuy loi scieenshots ol test iesults in uilleient Liowseis), anu a Lai with a lew check-
Loxes to liltei test iesults.
Hiue passeu tests is uselul when a lot ol tests ian anu only a lew laileu. Checking the
checkLox will hiue eveiything that passeu, making it easiei to locus on the tests that
laileu.
Hiue missing tests is uselul when you have a lot ol tests that aie just placeholueis,
inuicateu Ly the test name missing testuntesteu coue is Lioken coue. This can Le
uselul when you have a laige untesteu coue Lase anu auueu placeholueis loi eveiy test
that still neeus to Le wiitten. In oiuei to locus on tests that aie alieauy implementeu,
you can use the checkLox to tempoiaiily hiue the placeholuei tests.
The actual contents ol the page aie the test iesults. Each entiy in the numLeieu list
staits with the name ol the test lolloweu Ly, in paientheses, the numLei ol laileu,
passeu, anu total asseitions. Clicking the entiy will show the iesults ol each asseition,
usually with uetails aLout expecteu anu actual iesults. DouLle-clicking will iun just
that test (see Recipe 1S.S loi uetails).
Below the test iesults is a summaiy, showing the total time it took to iun all tests as
well as the oveiall numLei ol total anu laileu asseitions.
18.2 Asserting Results
Problem
Essential elements ol any unit test aie asseitions. The authoi ol the test neeus to expiess
the iesults expecteu anu have the unit testing liamewoik compaie them to the actual
values that an implementation piouuces.
18.2 Asserting Results | 427
Solution
QUnit pioviues thiee asseitions.
ok( boolean[, message ])
The most Lasic one is ok(), which ieguiies just one Boolean aigument. Vhen the ai-
gument is tiue, the asseition passes; otheiwise, it lails. In auuition, it accepts a stiing
to uisplay as a message in the test iesults:
test("ok test", function() {
ok(true, "ok succeeds");
ok(false, "ok fails");
});
equals( actual, expected[, message ])
The equals asseition uses the simple compaiison opeiatoi (==) to compaie the actual
anu expecteu aiguments. Vhen they aie egual, the asseition passes; otheiwise, it lails.
Vhen it lails, Loth actual anu expecteu values aie uisplayeu in the test iesult, in auuition
to a given message:
test("equals test", function() {
equals("", 0, "equals succeeds");
equals("three", 3, "equals fails");
});
Compaieu to ok(), equals() makes it much easiei to ueLug tests that laileu, Lecause
it`s oLvious which value causeu the test to lail.
same( actual, expected[, message ])
The same() asseition can Le useu just like equals() anu is a Lettei choice in most cases.
Insteau ol the simple compaiison opeiatoi (==), it uses the moie accuiate compaiison
opeiatoi (===). That way, undefined uoesn`t egual null, 0, oi the empty stiing (""). It
also compaies the content ol oLjects so that {key: value} is egual to {key: value}, even
when compaiing two oLjects with uistinct iuentities.
same() also hanules NaN, uates, iegulai expiessions, aiiays, anu lunctions, while
equals() woulu just check the oLject iuentity:
test("same test", function() {
same(undefined, undefined, "same succeeds");
same("", 0, "same fails");
});
In case you want to explicitly not compaie the content ol two values, equals() can still
Le useu. In geneial, same() is the Lettei choice.
428 | Chapter 18:Unit Testing
18.3 Testing Synchronous Callbacks
Problem
Vhen testing coue with a lot ol callLacks, it happens eveiy once in a while that a test
that actually shoulu lail just passes, with the asseitions in guestion nevei showing up
in the test iesults. Vhen the asseitions aie in a callLack that is nevei calleu, the assei-
tions aien`t calleu eithei, causing the test to silently pass.
Solution
QUnit pioviues a special asseition to ueline the numLei ol asseitions a test contains.
Vhen the test completes without the coiiect numLei ol asseitions, it will lail, no mattei
what iesult the othei asseitions, il any, piouuceu.
Usage is plain anu simple; just call expect() at the stait ol a test, with the numLei ol
expecteu asseitions as the only aigument:
test("a test", function() {
expect(1);
$("input").myPlugin({
initialized: function() {
ok(true, "plugin initialized");
}
});
});
Discussion
expect() pioviues the most value when actually testing callLacks. Vhen all coue is
iunning in the scope ol the test lunction, expect() pioviues no auuitional valueany
eiioi pieventing asseitions to iun woulu cause the test to lail anyway, Lecause the test
iunnei catches the eiioi anu consiueis the test as laileu.
18.4 Testing Asynchronous Callbacks
Problem
Vhile expect() is uselul to test synchionous callLacks (see Recipe 1S.3), it lalls shoit
when testing asynchionous callLacks. Asynchionous callLacks conllict with the way
the test iunnei gueues anu executes tests. Vhen coue unuei test staits a timeout oi
inteival oi an Ajax ieguest, the test iunnei will just continue iunning the iest ol the
test, as well as othei tests lollowing it, insteau ol waiting loi the iesult ol the asynchio-
nous opeiation.
18.4 Testing Asynchronous Callbacks | 429
Solution
Theie aie two lunctions to manually synchionize the test iunnei with the asynchionous
opeiation. Call stop() Leloie any asynchionous opeiation, anu call start() altei all
asseitions aie uone, anu the test iunnei can continue with othei tests:
test("a test", function() {
stop();
$.getJSON("/someurl", function(result) {
equals(result.value, "someExpectedValue");
start();
});
});
Discussion
A shoitcoming ol this appioach to manual synchionization is the iisk that start() is
nevei calleu when the coue unuei test lails elsewheie. In that case, the test iunnei nevei
continues anu theieloie nevei linishes to uisplay the enu iesult. It can`t even uisplay
the iesult loi the cuiient test, so all that is uisplayeu is the iesult ol the pievious test.
Vhen that happens, you liist neeu to iuentily the test that uoesn`t linish Ly looking loi
the pievious test that linisheu anu then linuing that test in coue anu skipping to the
next test. Once that is uone, you can ease ueLugging Ly auuing a timeout aigument to
the call to stop():
test("a test", function() {
stop(500);
$.getJSON("/someurl", function(result) {
equals(result.value, "someExpectedValue");
start();
});
});
In this example, the test iunnei woulu wait 500 ms loi the test to linish (using
setTimeout); otheiwise, it woulu ueclaie the test as laileu anu continue iunning. By
seeing the iesult ol othei tests, it can Le much easiei to iuentily the actual pioLlem anu
lix it.
Nonetheless, the timeout aigument shoulun`t Le useu loi iegulai tests. Il you auueu it
loi ueLugging, iemove it once the test woiks again.
Vhy is that? The uiawLack ol the timeout is that it makes tests unueteiministic. Vhen
iunning the test on a slow machine oi unuei heavy loau, the timeout may Le too shoit,
causing an otheiwise peilectly line test to lail. Hunting a Lug that uoesn`t exist at all is
a veiy time-consuming anu liustiating expeiienceavoiu it.
430 | Chapter 18:Unit Testing
18.5 Testing User Actions
Problem
Coue that ielies on actions initiateu Ly the usei can`t Le testeu Ly just calling a lunction.
Usually an anonymous lunction is Lounu to an element`s event, e.g., a click, which has
to Le simulateu.
Solution
You can tiiggei the event using jQueiy`s trigger() methou anu test that the expecteu
Lehavioi occuiieu. Il you uon`t want the native Liowsei events to Le tiiggeieu, you can
use triggerHandler() to just execute the Lounu event hanuleis. This is uselul when
testing a click event on a link, wheie trigger() woulu cause the Liowsei to change the
location, which is haiuly uesiieu Lehavioi in a test.
Let`s assume we have a simple key loggei that we want to test:
var keylogger = {
log: null,
init: function() {
keylogger.log = [];
$(document).unbind("keydown").keydown(function(event) {
keylogger.log.push(event.keyCode);
});
}
};
Ve can manually tiiggei a keypiess event to see whethei the loggei is woiking:
test("basic keylogger behavior", function() {
// initialize
keylogger.init();
// trigger event
var event = $.Event("keydown");
event.keyCode = 9;
$(document).trigger(event);
// verify expected behavior
same(keylogger.log.length, 1, "a key was logged");
same(keylogger.log[0], 9, "correct key was logged");
});
Discussion
Il youi event hanulei uoesn`t iely on any specilic piopeities ol the event, you can just
call .trigger(eventType). Howevei, il youi event hanulei uoes iely on specilic piop-
eities ol the event, you will neeu to cieate an event oLject using $.Event anu set the
necessaiy piopeities, as shown pieviously.
18.5 Testing User Actions | 431
It`s also impoitant to tiiggei all ielevant events loi complex Lehaviois such as uiagging,
which is compiiseu ol mouseuown, at least one mousemove, anu a mouseup. Keep in
minu that even some events that seem simple aie actually compounu; e.g., a click is
ieally a mouseuown, mouseup, anu then click. Vhethei you actually neeu to tiiggei
all thiee ol these uepenus on the coue unuei test. Tiiggeiing a click woiks loi most cases.
18.6 Keeping Tests Atomic
Problem
Vhen tests aie lumpeu togethei, it`s possiLle to have tests that shoulu pass Lut lail oi
tests that shoulu lail Lut pass. This is a iesult ol a test having invaliu iesults Lecause ol
siue ellects ol a pievious test:
test("2 asserts", function() {
$("#main").append("<div>Click here for <span class='bold'>messages</span>.</div>");
same($("#main div").length, 1, "added message link successfully");
$("#main").append("<span>You have a message!</span>");
same($("#main span").length, 1, "added notification successfully");
});
Notice the liist append() auus a <span> that the seconu asseit uoesn`t take into account.
Solution
Use the test() methou to keep tests atomic, Leing caielul to keep each asseition clean
ol any possiLle siue ellects. You shoulu only iely on the lixtuie maikup, insiue the
#main element. Mouilying anu ielying on anything else can have siue ellects:
test("test 1", function() {
$("#main").append("<div>Click here for <span class='bold'>messages
</span>.</div>");
same($("#main div").length, 1, "added message link successfully");
});
test("test 2", function() {
$("#main").append("<span>You have a message!</span>");
same($("#main span").length, 1, "added notification successfully");
});
QUnit will ieset the elements insiue the #main element altei each test, iemoving any
events that may have existeu. As long as you use elements only within this lixtuie, you
uon`t have to manually clean up altei youi tests to keep them atomic.
Discussion
In auuition to the #main lixtuie element, QUnit will also clean up piopeities ol jQueiy
itsell: $.event.global anu $.ajaxSettings. Any gloLal events like $().ajaxStart() aie
manageu Ly jQueiy in $.event.globalil youi test hau Lounu lots ol them, it coulu
432 | Chapter 18:Unit Testing
slow uown the test iunnei signilicantly when iunning a lot ol tests. By cleaning the
piopeity, QUnit ensuies that youi tests aien`t allecteu Ly gloLal events.
The same applies to $.ajaxSettings, which is usually useu via $.ajaxSetup() to con-
liguie common piopeities loi $.ajax() calls.
In auuition to the lilteis explaineu in Recipe 1S.S, QUnit also olleis a ?noglobals llag.
Consiuei the lollowing test:
test("global pollution", function(){
window.pollute = true;
same(pollute, true);
});
In a noimal test iun, this passes as a valiu iesult. Running the same test with the
noglobals llag will cause the test to lail, Lecause QUnit uetecteu that it polluteu the
winuow oLject.
Theie is no neeu to use this llag all the time, Lut it can Le hanuy to uetect gloLal
namespace pollution that may Le pioLlematic in comLination with thiiu-paity liLiaiies.
Anu it helps to uetect Lugs in tests causeu Ly siue ellects.
18.7 Grouping Tests
Problem
You`ve split up all ol youi tests to keep them atomic anu liee ol siue ellects, Lut you
want to keep them logically oiganizeu anu Le aLle to iun a specilic gioup ol tests on
theii own.
Solution
You can use the module() lunction to gioup tests togethei:
module("group a");
test("a basic test example", function() {
ok( true, "this test is fine" );
});
test("a basic test example 2", function() {
ok( true, "this test is fine" );
});
module("group b");
test("a basic test example 3", function() {
ok( true, "this test is fine" );
});
test("a basic test example 4", function() {
ok( true, "this test is fine" );
});
18.7 Grouping Tests | 433
All tests that occui altei a call to module() will Le gioupeu into that mouule. The test
names will all Le pieceueu Ly the mouule name in the test iesults. You can then use
that mouule name to select tests to iun (see Recipe 1S.S).
Discussion
In auuition to giouping tests, module() can Le useu to extiact common coue liom tests
within that mouule. The module() lunction takes an optional seconu paiametei to ue-
line lunctions to iun Leloie anu altei each test within the mouule:
module("module", {
setup: function() {
ok(true, "one extra assert per test");
}, teardown: function() {
ok(true, "and one extra assert after each test");
}
});
test("test with setup and teardown", function() {
expect(2);
});
You can specily Loth setup anu teaiuown piopeities togethei, oi just one ol them.
Calling module() again without the auuitional aigument will simply ieset any setup/
teaiuown lunctions uelineu Ly anothei mouule pieviously.
18.8 Selecting Tests to Run
Problem
Vhen ueLugging a lailing test, it can Le a huge waste ol time to ieiun the entiie test
suite altei eveiy little change to youi coue just to see whethei a single test now passes.
Solution
QUnit olleis URL lilteiing to select the tests to iun. This woiks Lest when
comLineu with mouules. You can iun just the tests liom a given mouule Ly appenuing
a gueiy stiing with the mouule name to the test suite URL. Foi example,
test.html?validation will iun all tests in the mouule nameu validation:
// test.html?validation - just the validation module
// test.html?validation&tooltip - validation and tooltip module
// test.html?!validation - exclude the validation module
// test.html?test 3 - just "test 3", the url will be displayed as test.html?test%203
module("validation");
test("test 1", function () {
ok(true, "bool succeeds");
});
test("test 2", function () {
equals(5, 5.0, "equals succeeds");
});
434 | Chapter 18:Unit Testing
module("tooltip");
test("test 3", function () {
same(true, 3 == 3, "same succeeds");
});
test("test 4", function () {
ok(false, "bool fails");
});
module("other");
test("test 5", function () {
equals(3, 5, "equals fails");
});
Discussion
You can comLine tests liom vaiious mouules Ly specilying multiple mouules at once,
uelimiteu with the ampeisanu; e.g., test.html?validation&tooltip woulu iun tests that
contain validation oi tooltip.
You can excluue tests using the exclamation maik; e.g., test.html?!validation woulu
iun all tests except those liom the validation mouule.
Insteau ol manually mouilying the URL, you can also uouLle-click any ol the test iesults
to ieiun just that test. QUnit will use the same lilteiing mechanism Ly appenuing the
name ol the test to the cuiient location.
18.8 Selecting Tests to Run | 435
Index
Symbols
$ (uollai sign)
as a vaiiaLle, 271
pielix, 107
shoitcut, 71
vaiiaLle, 69
$ alias
using without gloLal conllicts, 32
$ lunction, 270
$ shoitcut
using with jQueiy plugins, 270
$(), S9 (see jQueiy() lunction)
- (plus sign)
aujacent siLling comLinatoi, 37
. (peiiou)
opeiatois, 93
.loau(uil) methou, +01
> (gieatei than)
uiiect uescenuant comLinatoi, 36
~ (tilue)
geneial siLling comLinatoi, 3S
A
aLsolute positioning
elements, 1+7
accessiLility
weL pages, 130133
AccessiLle Rich Inteinet Applications (ARIA)
auuing semantics to wiugets, 130
accessing elements, 1791S2
accoiuions
expanuing, 2SS293
hoiizontal accoiuions, 157161
actions
peiloiming on suLsets ol selecteu sets, 67
6S
testing usei actions, +31
auuClass, 170
auuing select options, 221
aujacent siLling comLinatoi (-), 37
Ajax
Llack Lutton, +22
events, 395
anu jQueiy, 391393
gueuing Ajax ieguests, +20
shoitcuts anu uata types, +00+02
suLmitting loims, 22S
usei leeuLack, 396399
using on a whole site, 39+
Ajax events
uelineu, 171
ajax() methou, 392
ajaxFoim methou, 256
ajaxQueue() lunction, +21
ajaxSetup() methou, 39+
ajaxSync() lunction, +21
aleit() winuow, 11
anuSell() methou, 20
animate methou, 152, 162, 165, 16S
:animateu liltei, +1
:animateu selectoi, 165
animation
ueteimining whethei elements aie cuiiently
Leing animateu, 16+
multiple hovei() animations in paiallel,
1S5
selecting elements that aie cuiiently
animating, +1
speeus, 152
Ve`u like to heai youi suggestions loi impioving oui inuexes. Senu email to indcxorci||y.con.
437
stopping anu iesetting, 165
APIs
DOM stoiage API, +15, +17
oiganization, 7
appenuTo() methou, 23, 2+, 27, 221
application states
saving, +1++17
aiguments keywoiu, 163
ARIA (AccessiLle Rich Inteinet Applications)
auuing semantics to wiugets, 130
aiiays
comLining with meige(), S1
lilteiing out uuplicate entiies with unigue(),
S2
lilteiing with giep(), S0
iteiating anu mouilying entiies with map(),
S1
iteiating ovei with, 79
making unigue aiiays ol values liom existing
aiiays, 6+
asynchionous callLacks
unit testing, +29
attaching
oLjects anu uata to DOM with uata(), S+
atti() methou, 29, 213, 222
attiDelta paiametei, 167
attiiLutes
DOM elements, 29
list ol, 7S
selecting elements Laseu on, ++
toggling, 99
attiStait paiametei, 167
autocomplete wiuget, 2+9
autocompleting text lielus, 2+9
autotaLLing Laseu on chaiactei count, 222
B
Laie-metal loops
couing, 112
LeloieSenu callLack, 399
Linu(), 91, 173, 20S, 223, 23+, 325
Linuing
sliueis, 251
Llack Lutton
Ajax, +22
Llui event, 22S
Llui() methou, 216
Loiueis
Lottom Loiueis on wiuget heaueis, 370
Lottlenecks
linuing, 101105
LoxMouel attiiLute, 7S
Lioaucast() lunction, 20S
Liowsei events
uelineu, 171
Liowseis
stoiage, +13
switching stylesheets Laseu on Liowsei
wiuth, 1+S150
:Lutton liltei, +6
Luttons
Ajax anu the Llack Lutton, +22
selecting iauio Luttons, 216
C
caching jQueiy oLjects, 105
callLacks
testing asynchionous callLacks, +29
testing synchionous callLacks, +29
testing with isFunction(), S2
calling
jQueiy methous, 20520S
jQueiy UI plugin methous, 323
captcha
loim uesign, 23S
centeiing
elements within viewpoits, 1+6
chaining
aLout, 5
uelineu, xviii
DOM elements, 27
tiaveising methous, 22
chains
ueLugging, 11S
change event, 91
change() event, 220
chaiactei count
autotaLLing Laseu on, 222
uisplaying iemaining, 22+
chaiacteis
constiaining text input to specilic
chaiacteis, 226
:checkLox liltei, +6
checkLoxes
selecting oi ueselecting using a single toggle,
219
selecting oi ueselecting using ueuicateu
links, 21S
438 | Index
chilu elements
selecting, 36
chiluien() methou, 37, 92
choosing uates, 260
class name selectois
peiloimance, 107
classes
categoiies ol, 3+2
clean() methou, 11S
cleaiFoim methou, 256
click hanulei, 77
click listeneis, 302
clickaLle elements
states, 359
client-siue stoiage, +11+1+
client-siue valiuation, 23S
clone() methou, 27
cloning
DOM elements, 27
coue
liom othei liLiaiies, 9+
couing
Laie-metal loops, 112
coloi
changing using themes, 370
comLinei/minilieis
list ol, 125
comLining aiiays with meige(), S1
complete option, 393
conliguiation
conllicts with othei liLiaiies, 69
conllicts
gloLal, 32
with othei liLiaiies, 69
:contains liltei, +2
content
giowing input with its content, 259
HTML content, 30
selecting elements Laseu on, +2
text content, 31
context
selecting DOM elements, 15
tiaveising DOM, 21
context paiametei
selecting elements, +S
.context piopeity, 7+
conveiting jQueiy oLjects to DOM oLjects, 59
61
cieateElement() methou, 2+
cieating
DOM elements, 23
events, 195
liltei selectois, 50
jQueiy UI music playeis, 327339
]SON, +05
tool tips, 2S02S+
cioss-lauing iotating images, 305310
CSS
jQueiy UI CSS, 356
piopeities, 1+7
pseuuoclasses, 39
iesouices, 3SS
visiLility piopeity, ++
cssFloat attiiLute, 7S
custom iteiatois
wiiting, 9699
cycle plugin, 72
D
uata
attaching to DOM with uata(), S+
uynamic uata, 177
event hanuleis, 19S200
ieusing hanulei lunctions, 173
:uata liltei, 51
uata types
Ajax, +00+02
uata() methou, S+
attaching oLjects anu uata to DOM, S+
uataType, 392
uatepickei plugin, 260
uates
choosing, 260
ueLugging
chains, 11S
jQueiy coue, 120
sciipt anu CSS ieleiences to plugin liles as
ueLugging aius, 319
tiacing into jQueiy, 121
using ueLuggeis, 123
ueuicateu links
selecting oi ueselecting checkLoxes, 21S
uelaults
jQueiy UI plugins, 319, 321
plugins, 270
uelining methous, 267
uepenuencies, 2+3
uescenuant elements
Index | 439
linuing with wiappei set, 1S
veisus chilu elements, 36
uescenuant selectois
nesteu unoiueieu lists, 2S5
ueselecting checkLoxes
using a single toggle, 219
using ueuicateu links, 21S
ueseiialization
]SON, +05
uestioying
jQueiy UI plugins, 326
uestiuctive changes
ietuining to piioi selection, 19
uimensions, 135150
aLsolute positioning elements, 1+7
centeiing elements in viewpoits, 1+6
ueteimining whethei elements aie with
viewpoits, 1+3
elements, 137
ollsets ol elements, 1391+1
ielative positioning ol elements, 1+7
sciolling elements into views, 1+1
switching stylesheets Laseu on Liowsei
wiuth, 1+S150
ol winuows anu uocuments, 135
uiiect uescenuant comLinatoi (>), 36
uiiectoiy stiuctuie
theme lolueis, 3S6
uisaLling
ellects, 16S
loim elements, 213215
uisplay:Llock ueclaiation, 230
uisplay:none ueclaiation, 229
uisplaying
laLels aLove input lielus, 257
moual winuows, 296302
iemaining chaiactei count, 22+
uiv.eiioiMessage selectoi, 229
uiv.showEiioiMessage selectoi, 230
uocument.ieauy() lunction, 2S0
uocument.ieauy() methou, 212
uocument.wiite(), 2S0
uocumentation
jQueiy, S7
jQueiy API, 7
uocuments
uimensions, 135
taLLing thiough, 293296
uollai sign ($)
as a vaiiaLle, 271
pielix, 107
shoitcut, 71
vaiiaLle, 69
DOM
conveiting liom XML, +0+
locating sets ol elements in, +
tiaveising, 21
upuating, 117
DOM elements
attiiLutes, 29
cloning, 27
cieating, opeiating on anu inseiting, 23
lilteiing a wiappei set ol, 16
memoiy leaks, 193
iemoving, 2+
ieplacing, 26
selecting, 1316
DOM oLjects
conveiting liom jQueiy oLjects, 5961
DOM stoiage API, +15, +17
DOM tiaveisal methous, 35
uiag plugin, 19S
uiop plugin, 19S
uiop-uown menus
Luiluing, 303305
uuplicate aiiay entiies
lilteiing out with unigue(), S2
uuiation paiametei, 167
uynamic uata
passing to event hanuleis, 177
E
each() callLack, 116
each() methou, 5+, 79, 96, 112, 292
iteiating ovei aiiays anu oLjects with, 79
easing lunctions
custom, 166
ellect() methou, 170
ellects, 151170
animation, 152, 16+166
custom easing methous, 166
uisaLling, 16S
lauing elements, 153155
hoiizontal accoiuions, 157161
jQueiy UI, 16S, 316
seguential ellects, 162
sliuing elements, 153157, 161
template, 152
440 | Index
elapseu paiametei, 167
elastic plugin, 259
ElementReauy plugin, 1S1
elements, 3551
(see also uimensions; DOM elements)
aLout, +
aLsolute positioning, 1+7
accessing, 1791S2
animation, 16+166
context paiametei, +S
custom liltei selectois, 50
uescenuant elements, 1S
event hanuleis, 1S7
lauing, 153155, 161
linuing uimensions ol, 137
getting elements using event.taiget, 1S+
ollsets, 1391+1
ielative positioning, 1+7
sciolling into views, 1+1
selecting Laseu on attiiLutes, ++
selecting Laseu on contents, +2
selecting Laseu on visiLility, +3
selecting Ly inuex oiuei, 39
selecting Ly what they uon`t match, +3
selecting chilu elements, 36
selecting elements that aie cuiiently
animating, +1
selecting loim elements Ly type, +6
selecting siLlings, 37
selecting with specilic chaiacteiistics, +7
sliuing, 153157, 161
viewpoits, 1+3, 1+6
enaLling
loim elements, 213215
enu() methou, 19, 92
engine.ieauy() callLack, +12
enteiing
iange-constiaineu values, 253
:eg liltei, +0
eg() methou, 56, 220
eguals(), +2S
eiioi callLack methou, 392
eiioi messages, 2+3
eiioi methou, 393
eiioiElement, 2++
eiioiLaLelContainei, 2+5
eiioiPlacement, 2+5
esc() lunction, 117
eval() lunction, 103, +06
:even liltei, +0
event LuLLling, 1S5
event uelegation, 1S0, 1SS
event hanuleis
newly auueu elements, 1S7
event oLject
custom, 325
event-uiiven piogiamming, 171
event.special, 195, 20S
event.specialAll, 196
event.taiget
getting elements, 1S+
events, 171190, 191210
accessing elements, 1791S2
Ajax, 395
attaching hanuleis, 172
cieating event-uiiven plugins, 20120+
cieating events, 195
event hanuleis anu newly auueu elements,
1S7
getting elements using event.taiget, 1S+
gloLal event tiiggeiing, 192195
gloLal events anu Ajax aichitectuie, 395
hanuling jQueiy UI plugin events, 32+
letting event hanuleis pioviue uata, 19S
200, 19S200
loauing jQueiy uynamically, 191
multiple hovei() animations in paiallel,
1S5
mutation events, 205
notilication when jQueiy methous calleu,
20520S
oLjects` methous as event listeneis, 20S
passing uynamic uata to event hanuleis,
177
iemoving sets ol event hanuleis, 175
ieusing hanulei lunctions, 173
stopping hanulei execution loops, 1S2
tiiggeiing specilic event hanuleis, 176
executing
]avaSciipt coue, 10
expanuing
accoiuions, 2SS293
expect(), +29
expiessions, 2+3
extenu() methou, S6
extenuing oLjects, S5
extenuing
oLjects with extenu(), S5
Index | 441
F
laueIn() methou, 166, 306
laueOut() methou, 166
laueTo() methou, 155, 166
lauing elements, 153155, 161
lielus
autocompleting text lielus, 2+9
cieating maskeu input lielus, 2+7
uisplaying laLels aLove input lielus, 257
:lile liltei, +6
lile-tiee expanuei, 2S52SS
liles
uploauing in Lackgiounu, 255
liltei selectois
cieating, 50
liltei() methou, 16, 19, ++, +5, +7
lilteiing
aiiays with giep(), S0
wiappei sets ol DOM elements, 16
lilteis
:animateu liltei, +1
:Lutton liltei, +6
:checkLox liltei, +6
:contains liltei, +2
:uata liltei, 51
:eg liltei, +0
:even liltei, +0
:lile liltei, +6
:has liltei, +2
:hiuuen liltei, ++, +6
:image liltei, +6
list ol loim lilteis, +6
:lt liltei, +0
:not liltei, +3
:ouu liltei, +0
:passwoiu liltei, +6
:iauio liltei, +6
:ieset liltei, +6
:suLmit liltei, +6
:text liltei, +6
:visiLle liltei, ++
linu() methou, 16, 1S, 23, 76
linuing
Lottlenecks, 101105
uescenuant elements in wiappei sets, 1S
jQueiy plugins, 263
FiieLug
timing pioLlem, 103
ln oLject, 96
uelining plugins, 267
locus() methou, 216, 223
locusin plugin, 19S
locusout plugin, 19S
lont size, 157
loi..in loop, 11+
loim elements
enaLling anu uisaLling, 213215
selecting Ly type, +6
selecting input elements, 15
loim plugin, 255
loimatting
jQueiy chains, 92
loims (see HTML loims)
liaction paiametei, 167
Fiamewoik classes
aLout, 3+3
list ol, 371
Function(), 103
lunctions, S2
(see also callLacks)
attaching to main jQueiy oLject, 26S
piivate lunctions in jQueiy plugins, 272
ieusing hanulei lunctions, 173
static lunctions in jQueiy plugins, 275
G
geneial siLling comLinatoi (~), 3S
get() methou, 59, +01
get]SON() methou, +09
getTime() methou, 102
getting
DOM element attiiLutes, 29
HTML content, 30
jQueiy UI plugin options, 323
text content, 31
GitHuL, 26+
gloLal conllicts
using $ alias, 32
gloLal events
Ajax aichitectuie, 395
tiiggeiing, 192195
Google
minilieu veision ol jQueiy, 10
themes in the jQueiy UI ThemeRollei
galleiy, 317
Google Coue, 26+
Google maps, 25+
gieatei than (>)
442 | Index
uiiect uescenuant comLinatoi, 36
giep() methou, S0
lilteiing aiiays, S0
giouping tests
unit testing, +33
H
hanuleis
attaching to events, 172
event hanuleis anu newly auueu elements,
1S7
letting event hanuleis pioviue uata, 19S
200
passing uynamic uata to event hanuleis,
177
iemoving sets ol event hanuleis, 175
ieusing hanulei lunctions, 173
stopping hanulei execution loops, 1S2
tiiggeiing specilic event hanuleis, 176
hanuling jQueiy UI plugin events, 32+
:has liltei, +2
height methou, 135
:hiuuen liltei, ++, +6
hiue() methou, 151, 155
histoiy plugin, +22
histoiyLoau() callLack, +23
hoisting
selectois, 106
hoiizontal accoiuions
cieating, 157161
hovei() animations
multiple in paiallel, 1S5
hiel attiiLute, 7S
hielNoimalizeu attiiLute, 7S
HTML
ielationship with ]avaSciipt, 211
HTML content
getting anu setting, 30
HTML loims, 211236, 237262
auuing anu iemoving select options, 221
autocompleting text lielus, 2+9
autotaLLing Laseu on chaiactei count, 222
choosing uates, 260
constiaining text input to specilic
chaiacteis, 226
cieating maskeu input lielus, 2+7
uisaLling anu enaLling loim elements, 213
215
uisplaying laLels aLove input lielus, 257
uisplaying iemaining chaiactei count, 22+
enteiing iange-constiaineu values, 253
giowing input with its content, 259
limiting length ol text inputs, 256
selecting loim elements Ly type, +6
selecting oi ueselecting checkLoxes using a
single toggle, 219
selecting oi ueselecting checkLoxes using
ueuicateu links, 21S
selecting iauio Luttons, 216
selecting ianges ol values, 250252
suLmitting using Ajax, 22S
text input on page loau, 212
uploauing liles in Lackgiounu, 255
valiuating, 229236, 23S2+7
HTML liagments, +03
HTML pages
incluuing jQueiy liLiaiy in, 9
html() methou, 31, 117, 122
HTML5 Meuia Element API, 32S
htmlSeiialize attiiLute, 7S
I
IE (Inteinet Exploiei)
hiel attiiLute, 7S
ienueiing veitical CSS Loiueis Lug, 305
il/else statement, SS
:image liltei, +6
images
cioss-lauing iotating images, 305310
incluuing jQueiy coue in HTML pages, 9
inuex oiuei
selecting elements Ly, 39
inuex() methou, 6+
inuexes
getting liom items in selections, 62
inheiitance
Ly chilu elements in Fiamewoik classes,
371
inneiHeight methou, 137
inneiHTML piopeity, 31, 117
inneiViuth methou, 137
input
choosing uates, 260
constiaining text input to specilic
chaiacteis, 226
cieating maskeu input lielus, 2+7
uisplaying laLels aLove input lielus, 257
giowing input with its content, 259
Index | 443
limiting length ol text inputs, 256
text input on page loau, 212
input:text selectoi, 215
inseiting
DOM elements, 23
inteiactions
jQueiy UI, 315
Inteilace package, 315
Inteinet Exploie (see IE)
invaliuHanulei callLack, 2+6
is() methou, +2
isFunction() methou, S3
testing callLack lunctions, S2
iteiating
aiiay entiies with map(), S1
J
]avaSciipt
anu jQueiy, S7
liLiaiies, 2
packing, 125
piolileis, 101
putting ]avaSciipt at the enu ol a page, +23
ielationship with HTML, 211
wiiting unoLtiusive ]avaSciipt, 126
]avaSciipt coue
executing, 10
]avaSciipt OLject Notation (see ]SON)
]avaSciipt template engine
uisplaying ]SON uata, +17+20
jQueiy
aLout, 2
API oiganization, 7
uelineu, 1
anu ]avaSciipt, S7
loauing uynamically, 191
philosophy, 3
jQueiy chains
loimatting, 92
jQueiy lunction, 23
selecting DOM elements, 13
jQueiy oLjects
caching, 105
conveiting to DOM oLjects, 5961
jQueiy Plugin Repositoiy, 26+
jQueiy plugins, 26327S, 315339
$ shoitcut, 270
calling jQueiy UI plugin methous, 323
cieating a jQueiy UI music playei, 327
339
cieating jQueiy UI uelaults, 321
uestioying jQueiy UI plugins, 326
linuing, 263
getting anu setting jQueiy UI plugin
options, 323
hanuling jQueiy UI plugin events, 32+
incluuing jQueiy UI plugins, 31S
initializing jQueiy UI plugins, 319321
metauata plugin, 273
passing options to, 26S
piivate lunctions, 272
static lunctions, 275
testing plugins with QUnit, 277
wiiting, 26526S
jQueiy UI, 279313, 315339, 3+13S9
applying themes to non-jQueiy UI
components, 370379
Luiluing uiop-uown menus, 303305
calling jQueiy UI plugin methous, 323
cieating a jQueiy UI music playei, 327
339
cieating custom tool tips, 2S02S+
cieating uelaults, 321
cioss-lauing iotating images, 305310
uestioying jQueiy UI plugins, 326
uisplaying moual winuows, 296302
ellects, 16S
expanuing accoiuions, 2SS293
getting anu setting options, 323
hanuling jQueiy UI plugin events, 32+
incluuing entiie jQueiy UI suite, 317
incluuing inuiviuual jQueiy UI plugins,
31S
initializing jQueiy UI plugins, 319321
navigating with lile-tiee expanuei, 2S5
2SS
oveiiiuing jQueiy UI layout anu theme
styles, 360370
ieleiencing multiple themes on a single
page, 3793SS
sliuing panels, 310313
styling jQueiy wiugets with ThemeRollei,
3+5360
taLLing thiough uocuments, 293296
jQueiy UI CSS
veisions, 356
jQueiy() lunction, 13
444 | Index
jQueiy.Event, 19S, 207
.js liles
minily, 12+
]SON (]avaSciipt OLject Notation)
cieating, +05
]avaSciipt template engine, +17+20
paising, +06
using, +07+09
]SONP, +07
jStoie plugin, +12
jStoie.ieauy() callLack, +12
K
keyuown event, 223, 227
keyup event, 91, 223, 227
L
laLels
uisplaying aLove input lielus, 257
layout
oveiiiuing jQueiy UI layout anu theme
styles, 360370
leauingVhitespace attiiLute, 7S
length
limiting length ol text inputs, 256
liLiaiies
Loiiowing coue liom, 9+
conllicts with, 69
]avaSciipt, 2
namespace conllict, 71
licensing plugins, 266
lineai lunction, 166
links
selecting oi ueselecting checkLoxes using
ueuicateu links, 21S
live(), 1SS, +13
LiveQueiy plugin, 1S1
loauing
jQueiy uynamically, 191
pages, 212
plugins, 12+
taLles, 109112
weL pages, 12
localization, 2++, 261
lookups
name lookups, 115
looping thiough sets ol iesults, 5356
loops
Laie-metal loops, 112
:lt liltei, +0
M
macios, 17+
map() methou, 65, S1, 207
iteiating anu mouilying aiiay entiies, S1
maigins
animation methous, 151
maskeu input lielus
cieating, 2+7
maskeu input plugin, 2+7
maxlength plugin, 256
memoiy leaks
DOM elements, 193
menus
Luiluing uiop-uown menus, 303305
meige() methou
comLining two aiiays, S1
metauata plugin, 2+2, 25S, 273
methous
Lase methous in jQueiy UI plugins, 32+
uelining, 267
jQueiy UI plugin methous, 323
notilication when jQueiy methous calleu,
20520S
oLjects` methous as event listeneis, 20S
plugins, 2+0
minilication
.js liles, 12+
minilieu coue, 10
minilieu veision ol jQueiy, 122
ieuucing ]avaSciipt size anu numLei ol
HTTP ieguests, +23
moual winuows
uisplaying, 296302
mouilying aiiay entiies with map(), S1
mouule() lunction, +33
mouseoveis, 165
mousewheel plugin, 197
music playeis
cieating a jQueiy UI music playei, 327
339
mutation events, 205
N
name lookups
ieuucing, 115
Index | 445
namespace
jQueiy anu othei liLiaiies, 71
plugins, 175
tiiggeiing event hanuleis, 176
nesteu uata
piesenting, 2S5
next() methou, 39
nextAll() methou, 3S
noCloneEvent attiiLute, 7S
noConllict() methou, 70
:not liltei, +3
not() methou, +3
notilications
jQueiy methous, 20520S
O
oLjects
attaching to DOM using uata(), S+
DOM oLjects, 5961
extenuing with extenu(), S5
iteiating ovei with, 79
jQueiy oLjects, 5961, 105
oLjects` methous as event listeneis, 20S
:ouu liltei, +0
ollset methou, 139, 1+1
ollsetPaient methou, 139
ollsets
elements, 1391+1
ok(), +2S
one(), 173
opacity attiiLute, 7S
opeiating on DOM elements, 23
optimization
selectois, 35
option methou, 32+
options
metauata plugin, 27+
passing to plugins, 26S
outeiHeight methou, 137
outeiViuth methou, 137
oveiloaus
jQueiy events, 20S
P
packing
]avaSciipt, 125
pauuing
animation methous, 151
pages
accessiLility, 130133
loauing, 12
putting ]avaSciipt at the enu ol a page, +23
ieleiencing multiple themes on a single
page, 3793SS
text input on page loau, 212
panels
sliuing panels in jQueiy UI, 310313
paising ]SON, +06
paiticipation
in plugin uevelopment, 267
passing options to jQueiy plugins, 26S
:passwoiu liltei, +6
peiloimance, S7133
animation speeus, 152
attiiLutes, 99
Laie-metal loops, 112
Lottlenecks, 101105
coue liom othei liLiaiies, 9+
custom iteiatois, 9699
ueLugging chains, 11S
ueLugging jQueiy coue, 120
event piopagation, 399
gloLal event tiiggeiing, 192195
jQueiy chains, 92
jQueiy oLjects, 105
making youi pages accessiLle, 130133
name lookups, 115
piogiessive enhancement, 12S
ieuunuant iepetition, 91
selectois, 107
seivei ieguests, 123
taLles, 109112
tiacing into jQueiy, 121
upuating DOM, 117
wiiting unoLtiusive ]avaSciipt, 126
peiiou (.)
opeiatois, 93
peisisting uata
weL Liowseis, +11
philosophy ol jQueiy, 3
playeis
cieating a jQueiy UI music playei, 327
339
plugins, 237262, 26327S, 315339
(see also jQueiy plugins)
$ shoitcut, 270
auuing lunctionality with, 727+
446 | Index
autocompleting text lielus, 2+9
calling jQueiy UI plugin methous, 323
choosing uates, 260
cieating a jQueiy UI music playei, 327
339
cieating event-uiiven plugins, 20120+
cieating maskeu input lielus, 2+7
uestioying jQueiy UI plugins, 326
uisplaying laLels aLove input lielus, 257
enteiing iange-constiaineu values, 253
event.special, 197
linuing jQueiy plugins, 263
getting anu setting jQueiy UI plugin
options, 323
giowing input with its content, 259
hanuling jQueiy UI plugin events, 32+
incluuing inuiviuual jQueiy UI plugins,
31S
initializing jQueiy UI plugins, 319321
jQueiy UI uelaults, 321
limiting length ol text inputs, 256
loauing, 12+
metauata plugin, 273
namespaces, 175
passing options to, 26S
polling with, 1S1
piivate lunctions, 272
selecting ianges ol values, 250252
static lunctions, 275
stopImmeuiatePiopagation(), 1S3
testing plugins with QUnit, 277
uploauing liles in Lackgiounu, 255
valiuating loims, 23S2+7
wiiting jQueiy plugins, 26526S
plus sign (-)
aujacent siLling comLinatoi, 37
polling, 1S1
position methou, 139
positioning
aLsolute positioning, 1+7
ielative positioning, 1+7
post() methou, +01
pieventDelault() methou, 200
piivate lunctions
jQueiy lunctions, 272
piolileis
linuing Lottlenecks, 101
piogiessive enhancement
using jQueiy loi, 12S
pseuuoclasses, 39
(see also lilteis)
Puie templating engine, +17
Q
gueiies
ueteimining exact gueiies useu, 7+
gueuing Ajax ieguests, +20
QuiiksMoue, 151
QUnit
aLout, +26
testing jQueiy plugins, 277
R
iauio Luttons
aLout, 2+9
selecting, 216
:iauio liltei, +6
iauioClass() methou, 9+
ieauy() lunction, 191
ieauy() methou, 11
ieLinuing, 1SS
ielative positioning
elements, 1+7
iemove() methou, 25, 222
iemoveAtti() methou, 30, 213
iemoveClass, 170
iemoving
DOM element attiiLutes, 29
DOM elements, 2+
ieuunuant iepetition, 91
select options, 221
whitespace liom stiings oi loim values using
tiim(), S3
ieplaceAll() methou, 27
ieplaceVith() methou, 26
ieplacing DOM elements, 26
ieguests
gueuing Ajax ieguests, +20
:ieset liltei, +6
iesetting animations, 165
iesizaLle plugin, 259
ieveiseEach() methou, 9S
iotating images
cioss-lauing, 305310
S
same(), +2S
Index | 447
saving application states, +1++17
<sciipt> tags, 125
sciiptEval attiiLute, 7S
sciipts
compaieu to liLiaiy wiugets, 3+2
sciolling
elements into views, 1+1
sciollLelt methou, 1+3
sciollTo plugin, 1+6
sciollTop methou, 1+1
secuiity
Ajax, +07
<select> element, 233
selecting
checkLoxes using a single toggle, 219
checkLoxes using ueuicateu links, 21S
iauio Luttons, 216
ianges ol values, 250252
selecting elements, 3551
Laseu on attiiLutes, ++
Laseu on contents, +2
Laseu on visiLility, +3
Ly what they uon`t match, +3
chilu elements, 36
context paiametei, +S
custom liltei selectois, 50
DOM elements, 1316
loim elements Ly type, +6
Ly inuex oiuei, 39
siLlings, 37
that aie cuiiently animating, +1
with specilic chaiacteiistics, +7
selections
incluuing pievious in cuiient, 20
ietuining to Leloie a uestiuctive change,
19
.selectoi piopeity, 7+
selectoi.locus() methou, 212
selectois
aLout, 1+
constiucting, 35
uescenuant selectois, 2S5
hoisting, 106
ieuucing sets to a specilieu item, 5659
wiiting, 107
selects, 2+9
seiialization
]SON, +05
seivei ieguests
ieuucing, 123
sessions
saving application states, +1++17
setData event, S5
setInteival, 226
sets
looping thiough, 5356
peiloiming actions on suLsets ol selecteu
sets, 676S
ieuucing to a specilieu item, 5659
setTimeout() lunction, SS, 97, 9S, 120
setting
DOM element attiiLutes, 29
HTML content, 30
jQueiy UI plugin options, 323
text content, 31
setVisiLility() lunction, 92
shoitcuts
Ajax, +00+02
Liowsei anu Ajax events, 171
loi making Ajax ieguests, +00
show() methou, 122, 155
siLlings
selecting, 37
siLlings() methou, 3S, 93, 217
sleep() lunction, 9S
slice() methou, 67
sliue callLack, 251
sliueDown() methou, 292
sliuei wiuget, 250
sliuei() lunction, 332
sliueis
Linuing, 251
sliueToggle, 157
sliueUp() methou, 151, 156, 292
sliuing
elements, 153157, 161
panels in jQueiy UI, 310313
slowEach() methou, 97
SouiceFoige, 265
spinnei plugin, 253
split() methou, SS
stait event, 325
stait(), +30
states
clickaLle elements, 359
saving application states, +1++17
static lunctions
jQueiy plugins, 275
448 | Index
stop(), 165, 1S6, +30
stopImmeuiatePiopagation() methou, 1S2
stopping
animations, 165
hanulei execution loops, 1S2
stoiage
Liowseis, +13
client-siue, +11+1+
stiings
iemoving whitespace liom using tiim(), S3
style attiiLute, 7S
stylesheets
switching, 1+S150
styling
oveiiiuing jQueiy UI layout anu theme
styles, 360370
styling jQueiy wiugets with ThemeRollei,
3+5360
:suLmit liltei, +6
suLmitHanulei, 2+6
suLmitting
loims using Ajax, 22S
suLsets
peiloiming actions on, 676S
success callLack methou, 392
suppoit
loi plugins, 266
suppoit oLject, 7S
swing lunction, 166
switch() statement, 233
switching
stylesheets, 1+S150
synchionous callLacks
unit testing, +29
T
taLLing
thiough uocuments, 293296
<taLle> element, 111
taLles
loauing, 109112
tLouy attiiLute, 7S
template
ellects, 152
testing, +25
(see also unit testing)
callLack lunctions with isFunction(), S2
jQueiy plugins with QUnit, 277
selectoi speeu test pages, 10S
using ueLuggeis, 123
text
constiaining text input to specilic
chaiacteis, 226
limiting length ol text inputs, 256
text input on page loau, 212
text content
getting anu setting, 31
text lielus
autocompleting, 2+9
:text liltei, +6
text() methou, 31, 222
textaiea
size ol, 256, 259
<textaiea> element, 22+
ThemeRollei
aLout, 3+3
ieleiencing multiple themes on a single
page, 379
styling jQueiy wiugets, 3+5360
theming, 3+13S9
applying themes to non-jQueiy UI
components, 370379
oveiiiuing jQueiy UI layout anu theme
styles, 360370
ieleiencing multiple themes on a single
page, 3793SS
styling jQueiy wiugets with ThemeRollei,
3+5360
ThickBox, 297
this(), SS
tilue (~)
geneial siLling comLinatoi, 3S
time() lunction, 102, 11+
toggleAtti() methou, 99
toggleCheck() methou, 99
.toggleCheck() plugin, 99
toggleClass, 170
toggling
attiiLutes, 99
tool tips
cieating, 2S02S+
<ti> element, 111
tiacing
into jQueiy, 121
tiaveising DOM, 21
tiiggei() methou, 92, 177, 192, 207, +31
tiiggeiHanulei(), 199, +31
tiiggeiHanulei() methou, 207
Index | 449
tiiggeiing
gloLal events, 192195
tiim() methou, S+
iemoving whitespace liom stiings oi loim
values, S3
Twittei
chaiactei limit, 256
type
selecting loim elements Ly, +6
type paiametei, +01
typeol opeiatoi, S3
U
UI (see jQueiy UI)
ui aigument, 325
unLinu(), 173, 23+
unigue() lunction, S2
lilteiing out uuplicate aiiay entiies, S2
unit testing, +25+35
asseiting iesults, +27
asynchionous callLacks, +29
atomic, +32
automatic unit testing, +25+27
giouping tests, +33
selecting test to iun, +3+
synchionous callLacks, +29
usei actions, +31
upuating
DOM, 117
uploauing
liles in Lackgiounu, 255
URL, 392
usei actions
unit testing, +31
usei events
uelineu, 171
usei leeuLack
Ajax, 396399
usei inteilace (see jQueiy UI)
utilities, 77S6
uata(), S+
each(), 79
extenu(), S5
giep(), S0
isFunction(), S2
map(), S1
meige(), S1
suppoit(), 77
tiim(), S3
unigue(), S2
V
valiuating loims, 229236, 23S2+7
valueOl() methou, 102
values
enteiing iange-constiaineu values, 253
iemoving whitespace liom using tiim(), S3
selecting ianges ol, 250252
viewpoits
elements, 1+3, 1+6
height anu wiuth in Liowsei, 297
views
sciolling elements into, 1+1
visiLility
selecting elements Laseu on, +3
visiLility piopeity, ++
:visiLle liltei, ++
W
wateimaik plugin, 25S
weL pages (see pages)
whitespace
iemoving liom stiings oi loim values, S3
Viuget-specilic classes, 3+2
wiugets
ARIA, 130
Lottom Loiueis on wiuget heaueis, 370
jQueiy UI, 316
liLiaiy wiugets compaieu to setting up
sciipts, 3+2
styling jQueiy wiugets with ThemeRollei,
3+5360
wiuth methou, 135
winuow.onloau event, 10
winuows
uimensions, 135
uisplaying moual winuows, 296302
wiappei sets
aLout, 6
DOM elements, 16
linuing uescenuant elements, 1S
wiiting
custom iteiatois, 9699
jQueiy plugins, 26526S
selectois, 107
450 | Index
X
XML
conveiting to DOM, +0+
Index | 451
Colophon
The animal on the covei ol the jQucry Coo|boo| is an eimine (Mustc|a crninca), also
known as a stoat. Eimine sometimes ieleis to the animal`s white wintei lui, anu
stoat to the Liown lui it has uuiing the iest ol the yeai. It Lelongs to the weasel lamily,
which incluues maitens, leiiets, minks, otteis, anu polecats, though it is uistinguisheu
liom these othei memLeis Ly its Llack-tippeu tail.
The eimine lives in noithein wooulanu iegions ol Euiope, Asia, anu Noith Ameiica.
It is mainly noctuinal anu makes uens in tiee ioots, unuei stones, anu in tunnels. A
solitaiy animal, the eimine can tiavel up to 10 miles in one night seaiching loi loou.
Its pieuatois incluue loxes, Laugeis, cats, anu Liius ol piey.
The eimine`s slenuei Louy helps it iun swiltly, even acioss snow, as well as climL anu
swim. Although this shape has auvantages, it also causes the eimine to guickly lose
heat liom its Louy. Thick lui anu a last metaLolism help compensate, anu the eimine
must eat uaily to meet its eneigy uemanus. Its uiet incluues small mammals, Liius, lish,
anu insects. Vhen the eimine spots its piey, it sneaks up on it in a seiies ol leaps, giasps
the victim`s neck, anu kills it with iepeateu Lites.
Vhite eimine lui is highly piizeu anu is useu in tiimming coats, although uemanu has
uioppeu in iecent yeais. Typically, seveial luis aie sewn togethei to loim a pattein ol
Llack uots on a white lielu. This pattein was imitateu in heialuiythe uesign ol coats
ol aimsas eaily as the 12th centuiy, most lamously in the aims ol Biittany. Eimine
lui is also a symLol ol ioyalty oi puiity, which is peihaps why ElizaLeth I ol Englanu,
the Viigin Queen, was painteu with an eimine Ly hei siue.
The covei image is liom Riveisiue Natuial Histoiy. The covei lont is AuoLe ITC Ga-
iamonu. The text lont is Linotype Biika; the heauing lont is AuoLe Myiiau Conuenseu;
anu the coue lont is LucasFont`s TheSansMonoConuenseu.

Vous aimerez peut-être aussi