Beginning-JavaScript-5th-Edition.pdf -

829
www.allitebooks.com

Transcript of Beginning-JavaScript-5th-Edition.pdf -

www.allitebooks.com

CONTENTSINTRODUCTION

WHOTHISBOOKISFORWHATTHISBOOKCOVERSWHATYOUNEEDTOUSETHISBOOKCONVENTIONSSOURCECODEERRATAP2P.WROX.COM

CHAPTER1:INTRODUCTIONTOJAVASCRIPTANDTHEWEBINTRODUCTIONTOJAVASCRIPTWHEREDOMYSCRIPTSGO?YOURFIRSTSIMPLEJAVASCRIPTPROGRAMWRITINGMOREJAVASCRIPTABRIEFLOOKATBROWSERSANDCOMPATIBILITYPROBLEMSSUMMARY

CHAPTER2:DATATYPESANDVARIABLESTYPESOFDATAINJAVASCRIPTVARIABLES—STORINGDATAINMEMORYUSINGDATA—CALCULATIONSANDBASICSTRINGMANIPULATIONDATATYPECONVERSIONARRAYSSUMMARYEXERCISES

CHAPTER3:DECISIONSANDLOOPSDECISIONMAKING—THEIFANDSWITCHSTATEMENTSLOOPING—THEFORANDWHILESTATEMENTSSUMMARYEXERCISES

CHAPTER4:FUNCTIONSANDSCOPECREATINGYOUROWNFUNCTIONSSCOPEANDLIFETIMEFUNCTIONSASVALUESSUMMARY

www.allitebooks.com

EXERCISESCHAPTER5:JAVASCRIPT—ANOBJECT-BASEDLANGUAGE

OBJECT-BASEDPROGRAMMINGJAVASCRIPT’SNATIVEOBJECTTYPESCREATINGYOUROWNCUSTOMOBJECTSCREATINGNEWTYPESOFOBJECTS(REFERENCETYPES)SUMMARYEXERCISES

CHAPTER6:STRINGMANIPULATIONADDITIONALSTRINGMETHODSREGULAREXPRESSIONSTHESTRINGOBJECTUSINGTHEREGEXPOBJECT’SCONSTRUCTORSUMMARYEXERCISES

CHAPTER7:DATE,TIME,ANDTIMERSWORLDTIMETIMERSINAWEBPAGESUMMARYEXERCISES

CHAPTER8:PROGRAMMINGTHEBROWSERINTRODUCTIONTOTHEBROWSER’SOBJECTSDETERMININGTHEUSER’SBROWSERSUMMARYEXERCISES

CHAPTER9:DOMSCRIPTINGTHEWEBSTANDARDSTHEDOCUMENTOBJECTMODELMANIPULATINGTHEDOMSUMMARYEXERCISES

CHAPTER10:EVENTSTYPESOFEVENTSCONNECTINGCODETOEVENTSTHESTANDARDEVENTMODELEVENTHANDLINGINOLDVERSIONSOFINTERNETEXPLORER

www.allitebooks.com

WRITINGCROSS-BROWSERCODENATIVEDRAGANDDROPSUMMARYEXERCISES

CHAPTER11:HTMLFORMS:INTERACTINGWITHTHEUSERHTMLFORMSTRADITIONALFORMOBJECTPROPERTIESANDMETHODSHTML5FORMOBJECTPROPERTIESANDMETHODSSUMMARYEXERCISES

CHAPTER12:JSONXMLJSONSUMMARYEXERCISES

CHAPTER13:DATASTORAGEBAKINGYOURFIRSTCOOKIECREATINGACOOKIEGETTINGACOOKIE’SVALUECOOKIELIMITATIONSCOOKIESECURITYANDIEWEBSTORAGESUMMARYEXERCISES

CHAPTER14:AJAXWHATISAJAX?USINGTHEXMLHTTPREQUESTOBJECTCREATINGASIMPLEAJAXMODULEVALIDATINGFORMFIELDSWITHAJAXTHINGSTOWATCHOUTFORSUMMARYEXERCISES

CHAPTER15:HTML5MEDIAAPRIMERSCRIPTINGMEDIASUMMARY

www.allitebooks.com

EXERCISESCHAPTER16:JQUERY

GETTINGJQUERYjQUERY’SAPISUMMARYEXERCISES

CHAPTER17:OTHERJAVASCRIPTLIBRARIESDIGGINGINTOMODERNIZRDIVINGINTOPROTOTYPEDELVINGINTOMOOTOOLSSUMMARYEXERCISES

CHAPTER18:COMMONMISTAKES,DEBUGGING,ANDERRORHANDLINGD’OH!ICAN’TBELIEVEIJUSTDIDTHAT:SOMECOMMONMISTAKESERRORHANDLINGDEBUGGINGSUMMARYEXERCISES

APPENDIXA:ANSWERSTOEXERCISESCHAPTER2CHAPTER3CHAPTER4CHAPTER5CHAPTER6CHAPTER7CHAPTER8CHAPTER9CHAPTER10CHAPTER11CHAPTER12CHAPTER13CHAPTER14CHAPTER15CHAPTER16CHAPTER17CHAPTER18

www.allitebooks.com

APPENDIXB:JAVASCRIPTCOREREFERENCEBROWSERREFERENCERESERVEDWORDSJAVASCRIPTOPERATORSJAVASCRIPTSTATEMENTSTOP-LEVELPROPERTIESANDFUNCTIONSJAVASCRIPTCOREOBJECTS

APPENDIXC:W3CDOMREFERENCEDOMCOREOBJECTSHTMLDOMOBJECTSDOMEVENTMODELANDOBJECTSMISCELLANEOUSEVENTS

APPENDIXD:LATIN-1CHARACTERSETTITLEPAGECOPYRIGHTDEDICATIONCREDITSABOUTTHEAUTHORSACKNOWLEDGMENTSADVERTEULA

www.allitebooks.com

ListofIllustrationsChapter1

Figure1.1

Figure1.2

Figure1.3

Figure1.4

Chapter2

Figure2.1

Figure2.2

Figure2.3

Figure2.4

Figure2.5

Figure2.6

Figure2.7

Figure2.8

Figure2.9

Figure2.10

Figure2.11

Chapter3

Figure3.1

Figure3.2

Figure3.3

Figure3.4

Figure3.5

Figure3.6

Figure3.7

Figure3.8

Figure3.9

Figure3.10

Figure3.11

Figure3.12

www.allitebooks.com

Chapter4

Figure4.1

Figure4.2

Chapter5

Figure5.1

Figure5.2

Figure5.3

Figure5.4

Figure5.5

Figure5.6

Chapter6

Figure6.1

Figure6.2

Figure6.3

Figure6.4

Figure6.5

Figure6.6

Figure6.7

Figure6.8

Figure6.9

Figure6.10

Chapter7

Figure7.1

Figure7.2

Figure7.3

Chapter8

Figure8.1

Figure8.2

Figure8.3

Figure8.4

Chapter9

Figure9.1

www.allitebooks.com

Figure9.2

Figure9.3

Figure9.4

Figure9.5

Figure9.6

Figure9.7

Figure9.8

Figure9.9

Figure9.10

Figure9.11

Chapter10

Figure10.1

Figure10.2

Figure10.3

Figure10.4

Figure10.5

Figure10.6

Figure10.7

Figure10.8

Figure10.9

Chapter11

Figure11.1

Figure11.2

Figure11.3

Figure11.4

Figure11.5

Figure11.6

Figure11.7

Figure11.8

Figure11.9

Figure11.10

Chapter13

www.allitebooks.com

Figure13.1

Figure13.2

Figure13.3

Figure13.4

Figure13.5

Figure13.6

Figure13.7

Figure13.8

Figure13.9

Figure13.10

Figure13.11

Figure13.12

Figure13.13

Figure13.14

Figure13.15

Figure13.16

Figure13.17

Figure13.18

Figure13.19

Figure13.20

Chapter14

Figure14.1

Figure14.2

Figure14.3

Figure14.4

Figure14.5

Figure14.6

Figure14.7

Chapter15

Figure15.1

Figure15.2

Figure15.3

www.allitebooks.com

Figure15.4

Figure15.5

Figure15.6

Figure15.7

Chapter17

Figure17.1

Figure17.2

Chapter18

Figure18.1

Figure18.2

Figure18.3

Figure18.4

Figure18.5

Figure18.6

Figure18.7

Figure18.8

Figure18.9

Figure18.10

Figure18.11

Figure18.12

Figure18.13

Figure18.14

Figure18.15

Figure18.16

Figure18.17

Figure18.18

Figure18.19

Figure18.20

Figure18.21

Figure18.22

Figure18.23

Figure18.24

Figure18.25

Figure18.26

Figure18.27

Figure18.28

Figure18.29

Figure18.30

Figure18.31

INTRODUCTIONJAVASCRIPTISASCRIPTINGLANGUAGEthatenablesyoutoenhancestaticwebapplicationsbyprovidingdynamic,personalized,andinteractivecontent.Thisimprovestheexperienceofvisitorstoyoursiteandmakesitmorelikelythattheywillvisitagain.Youmusthaveseentheflashydrop-downmenus,movingtext,andchangingcontentthatarenowwidespreadonwebsites—theyareenabledthroughJavaScript.Supportedbyallthemajorbrowsers,JavaScriptisthelanguageofchoiceontheweb.Itcanevenbeusedoutsidewebapplications—toautomateadministrativetasks,forexample.

ThisbookaimstoteachyouallyouneedtoknowtostartexperimentingwithJavaScript:whatitis,howitworks,andwhatyoucandowithit.Startingfromthebasicsyntax,you’llmoveontolearnhowtocreatepowerfulwebapplications.Don’tworryifyou’veneverprogrammedbefore—thisbookwillteachyouallyouneedtoknow,stepbystep.You’llfindthatJavaScriptcanbeagreatintroductiontotheworldofprogramming:withtheknowledgeandunderstandingthatyou’llgainfromthisbook,you’llbeabletomoveontolearnnewerandmoreadvancedtechnologiesintheworldofcomputing.

WHOTHISBOOKISFORTogetthemostoutofthisbook,you’llneedtohaveanunderstandingofHTML,CSS,andhowtocreateastaticwebpage.Youdon’tneedtohaveanyprogrammingexperience.

Thisbookwillalsosuityouifyouhavesomeprogrammingexperiencealreadyandwouldliketoturnyourhandtowebprogramming.Youwillknowafairamountaboutcomputingconcepts,butmaybenotasmuchaboutwebtechnologies.

Alternatively,youmayhaveadesignbackgroundandknowrelativelylittleaboutthewebandcomputingconcepts.Foryou,JavaScriptwillbeacheapandrelativelyeasyintroductiontotheworldofprogrammingandwebapplicationdevelopment.

Whoeveryouare,Ihopethatthisbooklivesuptoyourexpectations.

WHATTHISBOOKCOVERSYou’llbeginbylookingatexactlywhatJavaScriptis,andtakingyourfirststepswiththeunderlyinglanguageandsyntax.You’lllearnallthefundamentalprogrammingconcepts,includingdataanddatatypes,andstructuringyourcodetomakedecisionsinyourprogramsortoloopoverthesamepieceofcodemanytimes.

Onceyou’recomfortablewiththebasics,you’llmoveontooneofthekeyideasinJavaScript—theobject.You’lllearnhowtotakeadvantageoftheobjectsthatarenativetotheJavaScriptlanguage,suchasfunctions,dates,andstrings,andfindouthowtheseobjectsenableyoutomanagecomplexdataandsimplifyyourprograms.Next,you’llseehowyoucanuseJavaScripttomanipulateanddetectobjectsmadeavailabletoyouinthebrowseranddetectthebrowsers.

Fromhere,you’llmoveontomoreadvancedtopics,suchaswritingcodetodynamicallymanipulateelementswithinawebpageandexecutingcodewhencertainthingshappenwithinyourpage.You’llalsolearnhowtoscriptformsandothercontrols.Usingthisknowledge,youcanstarttocreatetrulyprofessional-lookingapplicationsthatenableyoutointeractwiththeuser.

You’llthenlearnhowtostoredatawithinthebrowserandcommunicatedirectlywithaserver.You’llalsolearnhowtowritecodeforthenewHTML5mediaelements,andwriteyourowncustomuserinterfaceforthem.

You’llexploresomeofthetimesavingJavaScriptframeworkssuchasjQuery,Modernizr,Prototype,andMooToolsandseehowtheyworkandhowtheycanhelpyoucreatesophisticatedJavaScriptpoweredapplications.

Finally,you’lllookatcommonsyntaxandlogicalerrors,howyoucanspotthem,andhowtousetheJavaScriptdebuggersforChrome,InternetExplorer,Firefox,Safari,andOperatoaidyouwiththistask.Also,youneedtoexaminehowtohandletheerrorsthatslipthroughthenet,andensurethatthesedonotdetractfromtheexperienceoftheenduserofyourapplication.

Allthenewconceptsintroducedinthisbookwillbeillustratedwithpracticalexamples,whichenableyoutoexperimentwithJavaScriptandbuildonthetheorythatyouhavejustlearned.

You’llfindfourappendixesattheendofthebook.AppendixAprovidessolutionstotheexercisesincludedattheendofmostchaptersthroughoutthebook.Theremainingappendixescontainthereferencematerialthatyourauthorshopeyoufindusefulandinformational.AppendixBcontainstheJavaScriptlanguage’scorereference.AppendixCcontainsacompleteW3CDOMCorereference—aswellasinformationontheHTMLDOMandDOMlevel2Eventmodel.AppendixDcontainsthedecimalandhexadecimalcharactercodesfortheLatin-1characterset.

WHATYOUNEEDTOUSETHISBOOKBecauseJavaScriptisatext-basedtechnology,allyoureallyneedtocreatedocumentscontainingJavaScriptisatexteditor.Anywilldo.

Also,inordertotryoutthecodeinthisbook,youwillneedawebbrowserthatsupportsamodernversionofJavaScript.Ideally,thismeansthelatestversionsofChrome,InternetExplorer,Firefox,Safari,andOpera.Thebookhasbeenextensivelytestedwiththesebrowsers.However,thecodeshouldworkinanymodernwebbrowser.Wherethereareexceptions,theywillbeclearlynoted.

CONVENTIONSTohelpyougetthemostfromthetextandkeeptrackofwhat’shappening,we’veusedanumberofconventionsthroughoutthebook.

TRYITOUT

TheTryItOutisanexerciseyoushouldworkthrough,followingthetextinthebook.

1. Itusuallyconsistsofasetofsteps.

2. Eachstephasanumber.

3. Followthestepswithyourcopyofthedatabase.

AsyouworkthrougheachTryItOut,thecodeyou’vetypedwillbeexplainedindetail.

WARNINGBoxeslikethisoneholdimportant,not-to-beforgotteninformationthatisdirectlyrelevanttothesurroundingtext.

NOTETips,hints,tricks,andasidestothecurrentdiscussionareoffsetandplacedinitalicslikethis.

Asforstylesinthetext:

Wehighlightinitalictypenewtermsandimportantwordswhenweintroducethem.

Weshowkeyboardstrokeslikethis:Ctrl+A.

Weshowfilenames,URLs,andcodewithinthetextlikeso:

persistence.properties.

Wepresentcodeintwodifferentways:

Importantcodeincodeexamplesishighlightedwithagraybackground.Thegrayhighlightingisnotusedforcodethat’slessimportantinthe

presentcontext,orthathasbeenshownbefore.

SOURCECODEAsyouworkthroughtheexamplesinthisbook,youmaychooseeithertotypeinallthecodemanuallyortousethesource-codefilesthataccompanythebook.Allofthesourcecodeusedinthisbookisavailablefordownloadatwww.wrox.com.Onceatthesite,simplylocatethebook’stitle(eitherbyusingtheSearchboxorbyusingoneofthetitlelists)andclicktheDownloadCodelinkonthebook’sdetailpagetoobtainallthesourcecodeforthebook.

NOTEBecausemanybookshavesimilartitles,youmayfinditeasiesttosearchbyISBN;thisbook’sISBNis978-1-118-90333-9.

Onceyoudownloadthecode,justdecompressitwithyourfavoritecompressiontool.Alternately,youcangotothemainWroxcodedownloadpageatwww.wrox.com/dynamic/books/download.aspxtoseethecodeavailableforthisbookandallotherWroxbooks.

Youcanalsoviewtheexamplespresentedinthisbookathttp://beginningjs.com.

www.allitebooks.com

ERRATAWemakeeveryefforttoensurethattherearenoerrorsinthetextorinthecode.However,nooneisperfect,andmistakesdooccur.Ifyoufindanerrorinoneofourbooks,likeaspellingmistakeorfaultypieceofcode,wewouldbeverygratefulforyourfeedback.Bysendinginerrata,youmaysaveanotherreaderhoursoffrustration,andatthesametimeyouwillbehelpingusprovideevenhigher-qualityinformation.

Tofindtheerratapageforthisbook,gotowww.wrox.comandlocatethetitleusingtheSearchboxoroneofthetitlelists.Then,onthebookdetailspage,clicktheBookErratalink.OnthispageyoucanviewallerratathathavebeensubmittedforthisbookandpostedbyWroxeditors.Acompletebooklist,includinglinkstoeachbook’serrata,isalsoavailableatwww.wrox.com/misc-pages/booklist.shtml.

Ifyoudon’tspot“your”errorontheBookErratapagegotowww.wrox.com/contact/techsupport.shtmlandcompletetheformtheretosendustheerroryouhavefound.We’llchecktheinformationand,ifappropriate,postamessagetothebook’serratapageandfixtheprobleminsubsequenteditionsofthebook.

P2P.WROX.COMForauthorandpeerdiscussion,jointheP2Pforumsatp2p.wrox.com.Theforumsareaweb-basedsystemonwhichyoucanpostmessagesrelatingtoWroxbooksandrelatedtechnologiesandinteractwithotherreadersandtechnologyusers.Theforumsofferasubscriptionfeaturetoe-mailyoutopicsofinterestofyourchoosingwhennewpostsaremadetotheforums.Wroxauthors,editors,otherindustryexperts,andyourfellowreadersarepresentontheseforums.

Athttp://p2p.wrox.comyouwillfindanumberofdifferentforumsthatwillhelpyounotonlyasyoureadthisbook,butalsoasyoudevelopyourownapplications.Tojointheforums,justfollowthesesteps:

1. Gotop2p.wrox.comandclicktheRegisterlink.

2. ReadthetermsofuseandclickAgree.

3. Completetherequiredinformationtojoinaswellasanyoptionalinformationyouwishtoprovide,andclickSubmit.

4. Youwillreceiveane-mailwithinformationdescribinghowtoverifyyouraccountandcompletethejoiningprocess.

NOTEYoucanreadmessagesintheforumswithoutjoiningP2P,butinordertopostyourownmessages,youmustjoin.

Onceyoujoin,youcanpostnewmessagesandrespondtomessagesotheruserspost.Youcanreadmessagesatanytimeontheweb.Ifyouwouldliketohavenewmessagesfromaparticularforume-mailedtoyou,clicktheSubscribetothisForumiconbytheforumnameintheforumlisting.

FormoreinformationabouthowtousetheWroxP2P,besuretoreadtheP2PFAQsforanswerstoquestionsabouthowtheforumsoftwareworks,aswellasmanycommonquestionsspecifictoP2PandWroxbooks.ToreadtheFAQs,clicktheFAQlinkonanyP2Ppage.

1IntroductiontoJavaScriptandtheWebWHATYOUWILLLEARNINTHISCHAPTER:

AddingJavaScripttoyourwebpages

ReferencingexternalJavaScriptfiles

Changingthebackgroundcolorofawebpage

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Inthisintroductorychapter,youlookatwhatJavaScriptis,whatitcandoforyou,andwhatyouneedinordertouseit.Withthesefoundationsinplace,youwillseethroughouttherestofthebookhowJavaScriptcanhelpyoutocreatepowerfulwebapplicationsforyourwebsite.

Theeasiestwaytolearnsomethingisbyactuallydoingit,sothroughoutthebookyoucreateanumberofusefulexampleprogramsusingJavaScript.Thisprocessstartsinthischapter,bytheendofwhichyouwillhavecreatedyourfirstpieceofJavaScriptcode.

INTRODUCTIONTOJAVASCRIPTInthissectionyoutakeabrieflookatwhatJavaScriptis,whereitcamefrom,howitworks,andwhatsortsofusefulthingsyoucandowithit.

WhatIsJavaScript?Havingboughtthisbook,youareprobablyalreadywellawarethatJavaScriptissomesortofcomputerlanguage,butwhatisacomputerlanguage?Putsimply,acomputerlanguageisaseriesofinstructionsthattellthecomputertodosomething.Thatsomethingcanbeoneofawidevarietyofthings,includingdisplayingtext,movinganimage,oraskingtheuserforinformation.Normally,theinstructions,orwhatistermedcode,areprocessedfromthetoplinedownward.Thissimplymeansthatthecomputerlooksatthecodeyou’vewritten,worksoutwhatactionyouwantittotake,andthentakesthataction.Theactofprocessingthecodeiscalledrunningorexecutingit.

InnaturalEnglish,hereareinstructions,orcode,youmightwritetomakeacupofinstantcoffee:

1. Putcoffeecrystalsincup.

2. Fillkettlewithwater.

3. Putkettleontoboil.

4. Hasthekettleboiled?Ifso,thenpourwaterintocup;otherwise,continuetowait.

5. Drinkcoffee.

You’dstartrunningthiscodefromthefirstline(instruction1),andthencontinuetothenext(instruction2),thenthenext,andsoonuntilyoucametotheend.Thisisprettymuchhowmostcomputerlanguageswork,JavaScriptincluded.However,onsomeoccasionsyoumightchangetheflowofexecutionorevenskipoversomecode,butyouseemoreofthisinChapter3.

JavaScriptisaninterpretedlanguageratherthanacompiledlanguage.Whatismeantbythetermsinterpretedandcompiled?

Well,toletyouinonasecret,yourcomputerdoesn’treallyunderstandJavaScriptatall.ItneedssomethingtointerprettheJavaScriptcodeandconvertitintosomethingthatitunderstands;henceitisaninterpretedlanguage.Computersunderstandonlymachinecode,whichisessentiallyastringofbinarynumbers(thatis,astringofzerosandones).AsthebrowsergoesthroughtheJavaScript,itpassesittoaspecialprogramcalledaninterpreter,whichconvertstheJavaScripttothemachinecodeyourcomputerunderstands.It’sabitlikehavingatranslatortranslateEnglishtoSpanish,forexample.TheimportantpointtonoteisthattheconversionoftheJavaScripthappensatthetimethecodeisrun;ithastoberepeatedeverytimethishappens.JavaScriptisnottheonlyinterpretedlanguage;othersexist,includingPHPandRuby.

Thealternativecompiledlanguageisoneinwhichtheprogramcodeisconvertedtomachinecodebeforeit’sactuallyrun,andthisconversionhastobedoneonlyonce.The

programmerusesacompilertoconvertthecodethathewrotetomachinecode,andthismachinecodeisrunbytheprogram’suser.CompiledlanguagesincludeC#,Java,andmanyothers.Usingareal-worldanalogy,it’sabitlikehavingaSpanishtranslatorverballytellyouinEnglishwhataSpanishdocumentsays.Unlessyouchangethedocument,youcanuseitwithoutretranslationasmuchasyoulike.

Perhapsthisisagoodplacetodispelawidespreadmyth:JavaScriptisnotthescriptversionoftheJavalanguage.Infact,althoughtheysharethesamename,that’svirtuallyalltheydoshare.ParticularlygoodnewsisthatJavaScriptismuch,mucheasiertolearnandusethanJava.Infact,languageslikeJavaScriptaretheeasiestofalllanguagestolearn,buttheyarestillsurprisinglypowerful.

JavaScriptandtheWebFormostofthisbookyoulookatJavaScriptcodethatrunsinsideawebpageloadedintoabrowser.Allyouneedtocreatethesewebpagesisatexteditor—forexample,WindowsNotepad—andawebbrowser,suchasChrome,Firefox,orInternetExplorer(IE),withwhichyoucanviewyourpages.ThesebrowserscomeequippedwithJavaScriptinterpreters(morecommonlyknownasJavaScriptengines).

NOTEThroughoutthisbook,weusetheterms“IE”and“InternetExplorer”interchangeablywhenreferringtoMicrosoft’sInternetExplorerbrowser.

Infact,theJavaScriptlanguagefirstbecameavailableinNetscape’sNavigator2.Initially,itwascalledLiveScript,butbecauseJavawasthehottechnologyofthetime,NetscapedecidedthatJavaScriptsoundedmoreexciting.WhenJavaScriptreallytookoff,MicrosoftdecidedtoadditsowndialectofJavaScript,calledJScript,toInternetExplorer3.

In1997,JavaScriptwasstandardizedbyEcmaInternational,amembership-basednon-profitorganization,andrenamedtoECMAScript.Today’sbrowsermakerslooktotheECMAScriptstandardtoimplementtheJavaScriptenginesincludedintheirrespectivebrowsers,butthatdoesn’tnecessarilymeanthatallbrowserssupportthesamefeatures.JavaScriptsupportamongtoday’sbrowsersiscertainlymoreunifiedthanithaseverbeen,butasyouseeinfuturechapters,developersstillhavetocopewitholder,andinmanycasesnon-standard,JavaScriptimplementations.

TheECMAScriptstandardcontrolsvariousaspectsofthelanguageandhelpsensurethatdifferentversionsofJavaScriptarecompatible.However,althoughEcmasetsstandardsfortheactuallanguage,itdoesn’tspecifyhowit’susedinparticularhosts.Byhost,wemeanhostingenvironment;inthisbook,thatisthewebbrowser.OtherhostingenvironmentsincludePDFfiles,webservers,andmany,manyotherplaces.Inthisbook,wediscussonlyitsusewithinthewebbrowser.TheorganizationthatsetsthestandardsforwebpagesistheWorldWideWebConsortium(W3C).ItnotonlysetsstandardsforHTMLandCSS,butalsoforhowJavaScriptinteractswithwebpagesinsideawebbrowser.Youlearnmuchmoreaboutthisinlaterchaptersofthebook.Initially,you’lllookattheessentialsofJavaScriptbeforethemoreadvancedstuff.Intheappendicesofthisbook,you’llfindusefulguidestotheJavaScriptlanguageandhowitinteractswith

thewebbrowser.

ThemajorityofthewebpagescontainingJavaScriptthatyoucreateinthisbookcanbestoredonyourharddriveandloadeddirectlyintoyourbrowserfromtheharddriveitself,justasyou’dloadanynormalfile(suchasatextfile).However,thisisnothowwebpagesareloadedwhenyoubrowsewebsitesontheInternet.TheInternetisreallyjustonegreatbignetworkconnectingcomputers.AccesstowebsitesisaspecialserviceprovidedbyparticularcomputersontheInternet;thecomputersprovidingthisserviceareknownaswebservers.

Basically,thejobofawebserveristoholdlotsofwebpagesonitsharddrive.Whenabrowser,usuallyonadifferentcomputer,requestsawebpagecontainedonthatwebserver,thewebserverloadsitfromitsownharddriveandthenpassesthepagebacktotherequestingcomputerviaaspecialcommunicationsprotocolcalledHypertextTransferProtocol(HTTP).Thecomputerrunningthewebbrowserthatmakestherequestisknownastheclient.Thinkoftheclient/serverrelationshipasabitlikeacustomer/shopkeeperrelationship.Thecustomergoesintoashopandsays,“Givemeoneofthose.”Theshopkeeperservesthecustomerbyreachingfortheitemrequestedandpassingitbacktothecustomer.Inawebsituation,theclientmachinerunningthewebbrowserislikethecustomer,andthewebserverprovidingthepagerequestedisliketheshopkeeper.

Whenyoutypeanaddressintothewebbrowser,howdoesitknowwhichwebservertogetthepagefrom?Well,justasshopshaveaddresses,say,45CentralAvenue,Sometownsville,sodowebservers.Webserversdon’thavestreetnames;instead,theyhaveInternetprotocol(IP)addresses,whichuniquelyidentifythemontheInternet.Theseconsistoffoursetsofnumbers,separatedbydots(forexample,127.0.0.1).

Ifyou’veeversurfedtheNet,you’reprobablywonderingwhatonearthwe’retalkingabout.Surelywebservershavenicewww.somewebsite.comnames,notIPaddresses?Infact,thewww.somewebsite.comnameisthe“friendly”namefortheactualIPaddress;it’sawholeloteasierforushumanstoremember.OntheInternet,thefriendlynameisconvertedtotheactualIPaddressbycomputerscalleddomainnameservers,whichyourInternetserviceproviderwillhavesetupforyou.

WhatCanJavaScriptDoforMe?JavaScriptisprimarilyusedtointeractwithusers.That’saratherbroadstatement,solet’sbreak“interactwithusers”intotwocategories:userinputvalidationandenhancement.

JavaScriptwasoriginallycreatedforvalidatingforminput.Forexample,ifyouhadaformthattakesauser’screditcarddetailsinpreparationforononlinepurchaseofgoods,you’dwanttomakesurehehadactuallyfilledinthosedetailsbeforeyousentthegoods.Youmightalsowanttocheckthatthedatabeingenteredisofthecorrecttype,suchasanumberforhisageratherthantext.

Thankstotheadvancesmadeintoday’sJavaScriptengines,JavaScriptisusedformuch,muchmorethaninput-relatedtasks.Infact,advancedJavaScript-drivenapplicationscanbecreatedthatrivalthespeedandfunctionalityofconventionaldesktopapplications.ExamplesofsuchapplicationsincludeGoogleMaps,GoogleCalendar,andevenfull-fledgedproductivitysoftwaresuchasMicrosoft’sOfficeWebApps.Theseapplications

providearealservice.Inmostoftheseapplications,JavaScriptonlypowerstheuserinterface,withtheactualdataprocessingbeingdoneontheserver.Buteventhen,JavaScriptcouldbeusedontheserverifusedwithaJavaScript-basedprocessingengine(onesuchenvironmentiscalledNode).

ToolsNeededtoCreateJavaScriptWebApplicationsThegreatnewsisthatlearningJavaScriptrequiresnoexpensivesoftwarepurchases;youcanlearnJavaScriptforfreeonanyPCorMac.Thissectiondiscusseswhattoolsareavailableandhowtoobtainthem.

DevelopmentToolsAllthatyouneedtogetstartedwritingJavaScriptcodeforwebapplicationsisasimpletexteditor,suchasNotepadforWindowsorTextEditforMacOSX.Youcanalsouseoneofthemanyadvancedtexteditorsthatprovidelinenumbering,colorcoding,searchandreplace,andsoon.Herearejustafew:

Notepad2(Windows):www.flos-freeware.ch/notepad2.html

WebMatrix(Windows):www.microsoft.com/web/webmatrix/

Brackets(Cross-Platform):brackets.io

SublimeText(Cross-Platform):www.sublimetext.com

SublimeTextisnotfreesoftware,butitdoeshaveatime-limitedevaluation.Ifyoutryitandlikeit,pleasesupportthedevelopersofthatapplication.

YoumightalsopreferaproperHTMLeditor;you’llneedonethatenablesyoutoedittheHTMLsourcecode,becausethat’swhereyouneedtoaddyourJavaScript.Anumberofverygoodtoolsspecificallyaimedatdevelopingweb-basedapplications,suchasAdobe’sDreamweaver,arealsoavailable.However,thisbookconcentratesonJavaScriptratherthananyspecificdevelopmenttool.Whenitcomestolearningthebasics,it’softenbesttowritethecodebyhandratherthanrelyonatooltodoitforyou.Thishelpsyouunderstandthefundamentalsofthelanguagebeforeyouattemptthemoreadvancedlogicthatisbeyondatool’scapability.Whenyouhaveagoodunderstandingofthebasics,youcanusetoolsastimesaverssothatyoucanspendtimeonthemoreadvancedandmoreinterestingcoding.

Onceyoubecomemoreproficient,youmayfindthatawebpageeditormakeslifeeasierbyinclusionoffeaturessuchascheckingthevalidityofyourcode,color-codingimportantJavaScriptwords,andmakingiteasiertoviewyourpagesbeforeloadingthemintoawebbrowser.Manyother,equallygood,freewebpageeditorsareavailable.AGooglesearchonwebeditingsoftwarewillbringbackalonglistofsoftwareyoucanuse.

Asyouwritewebapplicationsofincreasingcomplexity,you’llfindusefultoolsthathelpyouspotandsolveerrors.Errorsincodearewhatprogrammerscallbugs,thoughwhenourprogramsgowrong,weprefertocallthem“unexpectedadditionalfeatures.”Veryusefulinsolvingbugsaredevelopmenttoolscalleddebuggers.Debuggersletyoumonitorwhatishappeninginyourcodeasit’srunning.InChapter18,youtakeanin-depthlookat

bugsanddebuggerdevelopmenttools.

WebBrowsersInadditiontosoftwarethatletsyoueditwebpages,you’llalsoneedabrowsertoviewyourwebpages.It’sbesttodevelopyourJavaScriptcodeonthesortsofbrowsersyouexpectvisitorstousetoaccessyourwebsite.Youseelaterinthechapterthatalthoughbrowsersaremuchmorestandardsbased,differencesexistinhowtheyviewwebpagesandtreatJavaScriptcode.AlltheexamplesprovidedinthisbookhavebeentestedonChrome,IE9-11,Firefox,Safari,andOpera.Whereverapieceofcodedoesnotworkonanyofthesebrowsers,anotetothiseffectismadeinthetext.

Ifyou’rerunningWindows,you’llalmostcertainlyhaveIEinstalled.Ifnot,atriptowindows.microsoft.com/en-us/internet-explorer/download-iewillgetyouthelatestversionforyourversionofWindows.

YoucanfindChromeatwww.google.com/chrome,andyoucandownloadFirefoxatwww.getfirefox.com.

Bydefault,mostbrowsershaveJavaScriptsupportenabled,butitispossibletodisablethisfunctionalityinallbrowsersexceptFirefox.SobeforeyoustartonyourfirstJavaScriptexamplesinthenextsection,youshouldchecktomakesureJavaScriptisenabledinyourbrowser.

TodothisinChrome,youwanttomodifytheJavaScriptsettingsinContentSettings,asshowninFigure1.1.Youcanaccessthesesettingsbynavigatingtochrome://settings/contentorbyfollowingtheseinstructions:

1. GototheSettingsoptioninthemenu.

2. Clickthe“Showadvancedsettings…”link.

3. UnderPrivacy,clickthe“Contentsettings…”button.

Figure1.1

ItishardertoturnoffscriptinginInternetExplorer.ChooseInternetOptionsfromthemenu(thegeariconintheupper-rightcorner),clicktheSecuritytab,andcheckwhethertheInternetorLocalintranetoptionshavecustomsecuritysettings.Ifeitherofthemdoes,clicktheCustomLevelbuttonandscrolldowntotheScriptingsection.CheckthatActiveScriptingissettoEnable.

Afinalpointtonoteishowtoopenthecodeexamplesinyourbrowser.Forthisbook,yousimplyneedtoopenthefileonyourharddriveinwhichanexampleisstored.Youcandothisinanumberofways,buttheeasiestistojustdouble-clickthefile.

WHEREDOMYSCRIPTSGO?InsertingJavaScriptintoawebpageismuchlikeinsertinganyotherHTMLcontent;youusetagstomarkthestartandendofyourscriptcode.Theelementyouusetodothisis<script/>.Thistellsthebrowserthatthefollowingchunkoftext,boundedbytheclosing</script>tag,isnotHTMLtobedisplayed,butratherscriptcodetobeprocessed.Thechunkofcodesurroundedbythe<script>and</script>tagsiscalledascriptblock.Here’sanexample:

<script>

//JavaScriptgoeshere

</script>

Basically,whenthebrowserspots<script>tags,insteadoftryingtodisplaythecontainedtexttotheuser,itusesthebrowser’sJavaScriptenginetorunthecode’sinstructions.Ofcourse,thecodemightgiveinstructionsaboutchangestothewaythepageisdisplayedorwhatisshowninthepage,butthetextofthecodeitselfisnevershowntotheuser.

Youcanputthe<script/>elementinsidetheheader(betweenthe<head>and</head>tags)orinsidethebody(betweenthe<body>and</body>tags)oftheHTMLpage.However,althoughyoucanputthemoutsidetheseareas—forexample,beforethe<html>tagorafterthe</html>tag—thisisnotpermittedinthewebstandardsandsoisconsideredbadpractice.Today’sJavaScriptdeveloperstypicallyaddtheir<script/>elementsdirectlybeforethe</body>tag.

The<script/>elementhasatypeattributethattellsthebrowserwhattypeoftextiscontainedwithintheelement.ForJavaScript,thebestpracticeistoomitthetypeattribute(browsersautomaticallyassumethatany<script/>elementwithoutatypeattributeisJavaScript).Weusedtoalwayssetthetypeattributetotext/javascript,butwiththeintroductionoftheHTML5specification,itisnolongerconsideredgoodpracticetodoso.Onlyincludethetypeattributeifthe<script/>elementcontainssomethingotherthanJavaScript.

NOTEThe<script/>elementcanbeusedformorethanjustJavaScript.SomeJavaScript-basedtemplatingenginesuse<script/>elementstocontainsnippetsofHTML.

LinkingtoanExternalJavaScriptFileThe<script/>elementhasanotherarrowinitsquiver:thecapabilitytospecifythattheJavaScriptcodeisnotinsidethewebpage,butinsideaseparatefile.Youshouldgiveanyexternalfilesthefileextension.js.Thoughit’snotcompulsory,itdoesmakeiteasierforyoutoworkoutwhatiscontainedineachofyourfiles.

TolinktoanexternalJavaScriptfile,youneedtocreatea<script/>elementasdescribedearlieranduseitssrcattributetospecifythelocationoftheexternalfile.Forexample,imagineyou’vecreatedafilecalledMyCommonFunctions.jstowhichyouwanttolink,

www.allitebooks.com

andthefileisinthesamedirectoryasyourwebpage.The<script/>elementwouldlooklikethis:

<scriptsrc="MyCommonFunctions.js"></script>

Thewebbrowserwillreadthiscodeandincludethefilecontentsaspartofyourwebpage.Whenlinkingtoexternalfiles,youmustnotputanycodewithintheopeningandclosing<script>tags;forexample,thefollowingwouldbeinvalid:

<scriptsrc="MyCommonFunctions.js">

varmyVariable;

if(myVariable==1){

//dosomething

}

</script>

It’simportanttonotethatanopening<script>tagmustbeaccompaniedbyaclosing</script>tag.Youcannotusetheself-closingsyntaxfoundinXML.Therefore,thefollowingisinvalid:

<scriptsrc="MyCommonFunctions.js"/>

Generally,youusethe<script/>elementtoloadlocalfiles(thoseonthesamecomputerasthewebpageitself).However,youcanloadexternalfilesfromawebserverbyspecifyingthewebaddressofthefile.Forexample,ifyourfilewascalledMyCommonFunctions.jsandwasloadedonawebserverwiththedomainnamewww.mysite.com,the<script/>elementwouldlooklikethis:

<scriptsrc="http://www.mysite.com/MyCommonFunctions.js"></script>

Linkingtoanexternalfileiscommonwhenincorporatingwell-knownJavaScriptlibrariesintoawebpage.TheservershostingtheselibrariesarereferredtoasContentDeliveryNetworks,orCDNs.CDNsarerelativelysafe,butbewareoflinkingtoexternalfilesiftheyarecontrolledbyotherpeople.Itwouldgivethosepeopletheabilitytocontrolandchangeyourwebpage,soyouneedtobeverysureyoutrustthem!

AdvantagesofUsinganExternalFileThebiggestadvantageofexternalfilesiscodereuse.SayyouwriteacomplexbitofJavaScriptthatperformsageneralfunctionyoumightneedinlotsofpages.Ifyouincludethecodeinline(withinthewebpageratherthanviaanexternalfile),youneedtocutandpastethecodeintoeachwebpagethatusesit.Thisisfineaslongasyouneverneedtochangethecode,buttherealityisyouprobablywillneedtochangeorimprovethecodeatsomepoint.Ifyou’vecutandpastedthecodeto30differentwebpages,you’llneedtoupdateitin30differentplaces.Quiteaheadache!Byusingoneexternalfileandincludingitinallthepagesthatneedit,youneedtoupdatethecodeonlyonceandallthe30pagesareupdatedinstantly.Somucheasier!

Anotheradvantageofusingexternalfilesisthatthebrowserwillcachethem,muchasitdoeswithimagessharedbetweenpages.Ifyourfilesarelarge,thiscouldsavedownloadtimeandalsoreducebandwidthusage.

YOURFIRSTSIMPLEJAVASCRIPTPROGRAMEnoughtalkaboutthesubjectofJavaScript;let’swritesome!We’llstartwithasimpleexamplethatchangesthebackgroundcolorofthewebpage.

TRYITOUTPaintingthePageRed

ThisisasimpleexampleofusingJavaScripttochangethebackgroundcolorofthebrowser.Inyourtexteditor,typethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8"/>

<title>Chapter1,Example1</title>

</head>

<bodybgcolor="white">

<p>Paragraph1</p>

<script>

document.bgColor="red";

</script>

</body>

</html>

Savethepageasch1_example1.htmltoaconvenientplaceonyourharddrive,andloaditintoyourwebbrowser.YoushouldseearedwebpagewiththetextParagraph1inthetop-leftcorner.Butwait—don’tyousetthe<body>tag’sBGCOLORattributetowhite?Okay,let’slookatwhat’sgoingonhere.

Thepageiscontainedwithin<html>and</html>tags.Thisblockcontainsa<body>element.Whenyoudefinetheopening<body>tag,youuseHTMLtosetthepage’sbackgroundcolortowhite:

<bodybgcolor="white">

ThenyouletthebrowserknowthatyournextlinesofcodeareJavaScriptcodebyusingthe<script>starttag:

<script>

Everythingfromhereuntiltheclosetag,</script>,isJavaScriptandistreatedassuchbythebrowser.Withinthisscriptblock,youuseJavaScripttosetthedocument’sbackgroundcolortored:

document.bgColor="red";

Whatyoumightcallthepageisknownasthedocumentforthepurposeofscriptinginawebpage.Thedocumenthaslotsofproperties,includingitsbackgroundcolor,bgColor.Youcanreferencepropertiesofthedocumentbywritingdocument,

followedbyadot,followedbythepropertyname.Don’tworryabouttheuseofdocumentatthemoment;youlookatitingreaterdepthlaterinthebook.

NotethattheprecedinglineofcodeisanexampleofaJavaScriptstatement.Everylineofcodebetweenthe<script>and</script>tagsiscalledastatement,althoughsomestatementsmayrunontomorethanoneline.

You’llalsoseethatthere’sasemicolon(;)attheendoftheline.YouuseasemicoloninJavaScripttoindicatetheendofastatement.Inpractice,JavaScriptisveryrelaxedabouttheneedforsemicolons,andwhenyoustartanewline,JavaScriptwillusuallybeabletoworkoutwhetheryoumeantostartanewlineofcode.However,forgoodcodingpractice,youshoulduseasemicolonattheendofstatementsofcode,andasingleJavaScriptstatementshouldfitontoonelineratherthancontinueontotwoormorelines.Moreover,you’llfindsomesituationsinwhichyoumustincludeasemicolon,whichyou’llcometolaterinthebook.

Finally,totellthebrowsertostopinterpretingyourtextasJavaScriptandstartinterpretingitasHTML,youusethescriptclosetag:

</script>

You’venowlookedathowthecodeworks,butyouhaven’tlookedattheorderinwhichitworks.Whenthebrowserloadsinthewebpage,thebrowsergoesthroughit,renderingittagbytagfromtoptobottomofthepage.Thisprocessiscalledparsing.Thewebbrowserstartsatthetopofthepageandworksitswaydowntothebottomofthepage.Thebrowsercomestothe<body>tagfirstandsetsthedocument’sbackgroundtowhite.Thenitcontinuesparsingthepage.WhenitcomestotheJavaScriptcode,itisinstructedtochangethedocument’sbackgroundtored.

WRITINGMOREJAVASCRIPTThefirstexampleletyoudipyourtoesintotheJavaScriptwaters.We’llwriteafewmoreJavaScriptprogramstodemonstratethewebpageflowandoneofthemanywaystodisplayaresultinthebrowser.

TRYITOUTWayThingsFlow

Let’sextendthepreviousexampletodemonstratetheparsingofawebpageinaction.Typethefollowingintoyourtexteditor:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8"/>

<title>Chapter1,Example2</title>

</head>

<bodybgcolor="white">

<p>Paragraph1</p>

<script>

//scriptblock1

alert("FirstScriptBlock");

</script>

<p>Paragraph2</p>

<script>

//scriptblock2

alert("SecondScriptBlock");

</script>

<p>Paragraph3</p>

</body>

</html>

Savethefiletoyourharddriveasch1_example2.htmlandthenloaditintoyourbrowser.Whenyouloadthepage,youshouldseethefirstparagraph,Paragraph1,followedbyamessageboxdisplayedbythefirstscriptblock.ThebrowserhaltsitsparsinguntilyouclicktheOKbutton.AsyouseeinFigure1.2,thepagebackgroundiswhite,assetinthe<body>tag,andonlythefirstparagraphisdisplayed.

Figure1.2

ClicktheOKbutton,andtheparsingcontinues.Thebrowserdisplaysthesecondparagraph,andthesecondscriptblockisreached,whichchangesthebackgroundcolortored.Anothermessageboxisdisplayedbythesecondscriptblock,asshowninFigure1.3.

Figure1.3

ClickOK,andagaintheparsingcontinues,withthethirdparagraph,Paragraph3,beingdisplayed.Thewebpageiscomplete,asshowninFigure1.4.

Figure1.4

Thefirstpartofthepageisthesameasinourearlierexample.Thebackgroundcolorforthepageissettowhiteinthedefinitionofthe<body>tag,andthenaparagraphiswrittentothepage:

<bodybgcolor="white">

<p>Paragraph1</p>

Thefirstnewsectioniscontainedinthefirstscriptblock:

<script>

//scriptblock1

alert("FirstScriptBlock");

</script>

Thisscriptblockcontainstwolines,bothofwhicharenewtoyou.Thefirstline

//Scriptblock1

isjustacomment,solelyforyourbenefit.Thebrowserrecognizesanythingonalineafteradoubleforwardslash(//)tobeacommentanddoesnotdoanythingwithit.Itisusefulforyouasaprogrammerbecauseyoucanaddexplanationstoyourcodethatmakeiteasiertorememberwhatyouweredoingwhenyoucomebacktoyourcodelater.

Thealert()functioninthesecondlineofcodeisalsonewtoyou.Beforelearningwhatitdoes,youneedtoknowwhatafunctionis.

FunctionsaredefinedmorefullyinChapter4,butfornowyouneedonlythinkofthemaspiecesofJavaScriptcodethatyoucanusetodocertaintasks.Ifyouhaveabackgroundinmath,youmayalreadyhavesomeideaofwhatafunctionis:ittakessomeinformation,processesit,andgivesyouaresult.Afunctionmakeslifeeasier

foryouasaprogrammerbecauseyoudon’thavetothinkabouthowthefunctiondoesthetask—youcanjustconcentrateonwhenyouwantthetaskdone.

Inparticular,thealert()functionenablesyoutoalertorinformtheuseraboutsomethingbydisplayingamessagebox.Themessagetobegiveninthemessageboxisspecifiedinsidetheparenthesesofthealert()functionandisknownasthefunction’sparameter.

Themessageboxdisplayedbythealert()functionismodal.Thisisanimportantconcept,whichyou’llcomeacrossagain.Itsimplymeansthatthemessageboxwon’tgoawayuntiltheuserclosesitbyclickingtheOKbutton.Infact,parsingofthepagestopsatthelinewherethealert()functionisusedanddoesn’trestartuntiltheuserclosesthemessagebox.Thisisquiteusefulforthisexample,becauseitenablesyoutodemonstratetheresultsofwhathasbeenparsedsofar:Thepagecolorhasbeensettowhite,andthefirstparagraphhasbeendisplayed.

WhenyouclickOK,thebrowsercarriesonparsingdownthepagethroughthefollowinglines:

<p>Paragraph2</p>

<script>

//scriptblock2

document.bgColor="red";

alert("SecondScriptBlock");

</script>

Thesecondparagraphisdisplayed,andthesecondblockofJavaScriptisrun.Thefirstlineofthescriptblockcodeisanothercomment,sothebrowserignoresthis.Yousawthesecondlineofthescriptcodeinthepreviousexample—itchangesthebackgroundcolorofthepagetored.Thethirdlineofcodeisthealert()function,whichdisplaysthesecondmessagebox.ParsingisbroughttoahaltuntilyouclosethemessageboxbyclickingOK.

Whenyouclosethemessagebox,thebrowsermovesontothenextlinesofcodeinthepage,displayingthethirdparagraphand,finally,endingthewebpage:

<p>Paragraph3</p>

</body>

</html>

Anotherimportantpointraisedbythisexampleisthedifferencebetweensettingpropertiesofthepage,suchasbackgroundcolor,viaHTMLanddoingthesamethingusingJavaScript.ThemethodofsettingpropertiesusingHTMLisstatic:AvaluecanbesetonlyonceandneverchangedagainbymeansofHTML.SettingpropertiesusingJavaScriptenablesyoutodynamicallychangetheirvalues.Thetermdynamicreferstosomethingthatcanbechangedandwhosevalueorappearanceisnotsetinstone.

Thisexampleisjustthat,anexample.Inpractice,ifyouwantthepage’sbackgroundtobered,simplysetthebackgroundcolorwithCSS(don’tusethebgcolorattributeinpractice).WhereyouwanttouseJavaScriptiswhereyouwanttoaddsomesortofintelligenceorlogictothepage.Forexample,iftheuser’sscreenresolutionis

particularlylow,youmightwanttochangewhat’sdisplayedonthepage,andyoucandothatwithJavaScript.

TRYITOUTDisplayingResultsinaWebPageInthisfinalexample,youdiscoverhowtowriteinformationdirectlytoawebpageusingJavaScript.Thisprovesmoreusefulwhenyou’rewritingtheresultsofacalculationortextyou’vecreatedusingJavaScript,asyouseeinthenextchapter.Fornow,you’lljustwrite“HelloWorld!”toablankpageusingJavaScript:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8"/>

<title>Chapter1,Example3</title>

</head>

<body>

<pid="results"></p>

<script>

document.getElementById("results").innerHTML="Hello

World!";

</script>

</body>

</html>

Savethepageasch1_example3.htmltoaconvenientplaceonyourharddrive.Nowloaditintoyourwebbrowserandyou’llseeHelloWorld!inthepage.AlthoughitwouldbeeasiertouseHTMLtodothesamething,thistechniquewillproveusefulinlaterchapters.

Thefirstpartofthepageisthesameasinourearlierexamples,butthingsstarttochangewhenyoureachthisline:

<pid="results"></p>

You’llnoticethe<p/>elementhasbeengivenanIDusingtheidattribute.ThisIDmustbeuniqueinthewebpage,becauseitisusedbyJavaScripttoidentifythespecificHTMLelementinthefollowingline:

document.getElementById("results").innerHTML="HelloWorld!";

Don’tworryifthisseemscomplexatthemoment;youlearnmoreabouthowthisworksinlaterchapters.Basically,thecodeissaying,“GetmetheelementwiththeIDofresultsandsettheHTMLinsidethatelementtoHelloWorld!”

It’simportantinthatthecodeaccessingtheparagraphisaftertheactual<p/>element.Otherwise,thecodewouldbeattemptingtoaccessaparagraphbeforeitexistedinthepageandwouldthrowanerror.

www.allitebooks.com

ABRIEFLOOKATBROWSERSANDCOMPATIBILITYPROBLEMSIntheprecedingexampleyousawthatbyusingJavaScriptyoucanchangeawebpage’sdocumentbackgroundcolorusingthebgColorpropertyofthedocument.TheexampleworkedregardlessofwhatbrowseryouusedbecausetheyallsupportadocumentwithabgColorproperty.Youcansaythattheexampleiscross-browsercompatible.However,it’snotalwaysthecasethatthepropertyorlanguagefeatureavailableinonebrowserwillbeavailableinanotherbrowser.Thisisevensometimesthecasebetweenversionsofthesamebrowser.

Oneofthemainheadachesinvolvedincreatingweb-basedJavaScriptisthedifferencesbetweendifferentwebbrowsers,thelevelofHTMLandCSStheysupport,andthefunctionalitytheirJavaScriptenginescanhandle.EachnewreleaseofanybrowserseesnewandexcitingfeaturesaddedtoitsHTML,CSS,andJavaScriptsupport.Thegoodnewsisthattoamuchgreaterextentthaneverbefore,browsercreatorsarecomplyingwithstandardssetbyorganizationssuchasEcmaandtheW3C.

Whichbrowsersyouwanttosupportreallycomesdowntothebrowsersyouthinkthemajorityofyourwebsite’svisitors—thatis,youruserbase—willbeusing.Thisbookisaimedatstandards-compliantbrowsers,suchasChrome,IE9+,Firefox,Safari,andOpera.

Ifyouwantyourwebsitetobeprofessional,youneedtosomehowdealwitholderbrowsers.Youcouldmakesureyourcodeisbackwardcompatible—thatis,itonlyusesfeaturesavailableinolderbrowsers.However,youmaydecidethatit’ssimplynotworthlimitingyourselftothefeaturesofolderbrowsers.Inthiscaseyouneedtomakesureyourpagesdegradegracefully.Inotherwords,makesurethatalthoughyourpageswon’tworkinolderbrowsers,theywillfailinawaythatmeanstheuseriseitherneverawareofthefailureorisalertedtothefactthatcertainfeaturesonthewebsitearenotcompatiblewithhisorherbrowser.Thealternativetodegradinggracefullyisforyourcodetoraiselotsoferrormessages,causestrangeresultstobedisplayedonthepage,andgenerallymakeyoulooklikeanidiotwhodoesn’tknowwhathe’sdoing!

Sohowdoyoumakeyourwebpagesdegradegracefully?YoucandothisbyusingJavaScripttodeterminewhichbrowserthewebpageisrunninginafterithasbeenpartiallyorcompletelyloaded.Youcanusethisinformationtodeterminewhatscriptstorunoreventoredirecttheusertoanotherpagewrittentomakebestuseofherparticularbrowser.Inlaterchapters,youseehowtofindoutwhatfeaturesthebrowsersupportsandtakeappropriateactionsothatyourpagesworkacceptablyonasmanybrowsersaspossible.

SUMMARYAtthispoint,youshouldhaveafeelforwhatJavaScriptisandwhatitcando.Inparticular,thisbriefintroductioncoveredthefollowing:

Youlookedintotheprocessthebrowserfollowswheninterpretingyourwebpage.Itgoesthroughthepageelementbyelement(parsing)andactsuponyourHTMLtagsandJavaScriptcodeasitcomestothem.

Unlikemanyprogramminglanguages,JavaScriptrequiresjustatexteditortostartcreatingcode.SomethinglikeWindowsNotepadisfineforgettingstarted,thoughmoreextensivetoolswillprovevaluableonceyougetmoreexperience.

JavaScriptcodeisembeddedintothewebpageitself,alongwiththeHTML.Itsexistenceismarkedoutbytheuseof<script/>elements.AswithHTML,thescriptexecutesfromthetopofthepageandworksdowntothebottom,interpretingandexecutingthecodestatementbystatement.

2DataTypesandVariablesWHATYOUWILLLEARNINTHISCHAPTER:

Representingdataincode

Storingdatainmemory

Makingcalculations

Convertingdata

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Oneofthemainusesofcomputersistoprocessanddisplayinformation.Byprocessing,wemeantheinformationismodified,interpreted,orfilteredinsomewaybythecomputer.Forexample,onanonlinebankingwebsite,acustomermayrequestdetailsofallmoneypaidoutfromhisaccountinthepastmonth.Herethecomputerwouldretrievetheinformation,filteroutanyinformationnotrelatedtopaymentsmadeinthepastmonth,andthendisplaywhat’sleftinawebpage.Insomesituations,informationisprocessedwithoutbeingdisplayed,andatothertimes,informationisobtaineddirectlywithoutbeingprocessed.Forexample,inabankingenvironment,regularpaymentsmaybeprocessedandtransferredelectronicallywithoutanyhumaninteractionordisplay.

Incomputing,informationisreferredtoasdata.Datacomesinallsortsofforms,suchasnumbers,text,dates,andtimes,tomentionjustafew.Inthischapter,youlookspecificallyathowJavaScripthandlesdatasuchasnumbersandtext.Anunderstandingofhowdataishandledisfundamentaltoanyprogramminglanguage.

InthischapteryoustartbylookingatthevarioustypesofdataJavaScriptcanprocess.Thenyoulookathowyoucanstorethisdatainthecomputer’smemorysoyoucanuseitagainandagaininthecode.Finally,youseehowtouseJavaScripttomanipulateandprocessthedata.

TYPESOFDATAINJAVASCRIPTDatacancomeinmanydifferentforms,ortypes.You’llrecognizesomeofthedatatypesthatJavaScripthandlesfromtheworldoutsideofprogramming—forexample,numbersandtext.Otherdatatypesarealittlemoreabstractandareusedtomakeprogrammingeasier;oneexampleistheobjectdatatype,whichyouwon’tseeindetailuntilChapter5.

Someprogramminglanguagesarestronglytyped.Intheselanguages,wheneveryouuseapieceofdata,youneedtoexplicitlystatewhatsortofdatayouaredealingwith,anduseofthatdatamustfollowstrictrulesapplicabletoitstype.Forexample,inastronglytypedlanguageyoucan’taddanumberandaword.

JavaScript,ontheotherhand,isaweaklytypedlanguageandalotmoreforgivingabouthowyouusedifferenttypesofdata.Whenyoudealwithdata,youoftendon’tneedtospecifytype;JavaScriptwillworkthatoutforitself.Furthermore,whenyouareusingdifferenttypesofdataatthesametime,JavaScriptwillworkoutbehindthesceneswhatitisyou’retryingtodo.

GivenhoweasygoingJavaScriptisaboutdata,whytalkaboutdatatypesatall?Whynotjustcuttothechaseandstartusingdatawithoutworryingaboutitstype?

Firstofall,althoughJavaScriptisverygoodatworkingoutwhatdatait’sdealingwith,onoccasionit’llgetthingswrongoratleastnotdowhatyouwantittodo.Inthesesituations,youneedtomakeitexplicittoJavaScriptwhatsortofdatatypeyouintendedandhowitshouldbeused.Todothat,youfirstneedtoknowalittlebitaboutdatatypes.

Asecondreasonisthatdatatypesenableyoutousedataeffectivelyinyourcode.Thethingsthatyoucandowithdataandtheresultsyou’llgetdependonthetypeofdatabeingused,evenifyoudon’texplicitlyspecifywhattypeitis.Forexample,althoughtryingtomultiplytwonumbersmakessense,doingthesamethingwithtextdoesn’t.Also,theresultofaddingnumbersisverydifferentfromtheresultofaddingtext.Withnumbersyougetthesum,butwithtextyougetonebigpieceoftextconsistingoftheotherpiecesjoinedtogether.

Let’stakeabrieflookatsomeofthemorecommonlyuseddatatypes:numerical,text,andboolean.Youseehowtousethemlaterinthechapter.

NumericalDataNumericaldatacomesintwoforms:

Wholenumbers,suchas145,whicharealsoknownasintegers.ThesenumberscanbepositiveornegativeandcanspanaverywiderangeinJavaScript:–253to253.

Fractionalnumbers,suchas1.234,whicharealsoknownasfloating-pointnumbers.Likeintegers,theycanbepositiveornegative,andtheyalsohaveamassiverange.

Insimpleterms,unlessyou’rewritingspecializedscientificapplications,you’renotgoingtofaceproblemswiththesizeofnumbersavailableinJavaScript.Also,althoughyoucantreatintegersandfloating-pointnumbersdifferentlywhenitcomestostoringthem,

JavaScriptactuallytreatsthembothasfloating-pointnumbers.Itkindlyhidesthedetailfromyousoyougenerallydon’tneedtoworryaboutit.Oneexceptioniswhenyouwantanintegerbutyouhaveafloating-pointnumber,inwhichcaseyou’llroundthenumbertomakeitaninteger.Youtakealookatroundingnumberslaterinthischapter.

TextDataAnothertermforoneormorecharactersoftextisastring.YoutellJavaScriptthattextistobetreatedastextandnotascodesimplybyenclosingitinsidequotationmarks(").Forexample,"HelloWorld"and"A"areexamplesofstringsthatJavaScriptwillrecognize.Youcanalsousethesinglequotationmarks('),so'HelloWorld'and'A'arealsoexamplesofstringsthatJavaScriptwillrecognize.However,youmustendthestringwiththesamequotationmarkthatyoustarteditwith.Therefore,"A'isnotavalidJavaScriptstring,andneitheris'HelloWorld".

Whatifyouwantastringwithasinglequotationmarkinthemiddle,sayastringlikePeterO'Toole?Ifyouencloseitindoublequotes,you’llbefine,so"PeterO'Toole"isrecognizedbyJavaScript.However,'PeterO'Toole'willproduceanerror.ThisisbecauseJavaScriptthinksthatyourtextstringisPeterO(thatis,ittreatsthemiddlesinglequoteasmarkingtheendofthestring)andfallsoverwonderingwhattheToole'is.

AnotherwayaroundthisistotellJavaScriptthatthemiddle'ispartofthetextandisnotindicatingtheendofthestring.Youdothisbyusingthebackslashcharacter(\),whichhasspecialmeaninginJavaScriptandisreferredtoasanescapecharacter.Thebackslashtellsthebrowserthatthenextcharacterisnottheendofthestring,butpartofthetext.So'PeterO\'Toole'willworkasplanned.

Whatifyouwanttouseadoublequoteinsideastringenclosedindoublequotes?Well,everythingjustsaidaboutthesinglequotestillapplies.So'Hello"Paul"'works,but"Hello"Paul""won’t.However,"Hello\"Paul\""willwork.

JavaScripthasalotofotherspecialcharacters,whichcan’tbetypedinbutcanberepresentedusingtheescapecharacterinconjunctionwithothercharacterstocreateescapesequences.TheseworkmuchthesameasinHTML.Forexample,morethanonespaceinarowisignoredinHTML,soaspaceisrepresentedbytheterm&nbsp;.Similarly,inJavaScriptyou’llfindinstanceswhereyoucan’tuseacharacterdirectlybutmustuseanescapesequence.Thefollowingtabledetailssomeofthemoreusefulescapesequences.

ESCAPESEQUENCES

CHARACTERREPRESENTED

\b Backspace\f Formfeed\n Newline\r Carriagereturn\t Tab\' Singlequote\" Doublequote\\ Backslash\xNN NNisahexadecimalnumberthatidentifiesacharacterintheLatin-

1characterset.

Theleastobviousoftheseisthelast,whichrepresentsindividualcharactersbytheircharacternumberintheLatin-1charactersetratherthanbytheirnormalappearance.Let’spickanexample:Sayyouwantedtoincludethecopyrightsymbol(©)inyourstring.Whatwouldyourstringneedtolooklike?Theansweris"\xA9PaulWilton".

Similarly,youcanrefertocharactersusingtheirUnicodeescapesequence.Thesearewritten\uNNNN,whereNNNNreferstotheUnicodenumberforthatparticularcharacter.Forexample,torefertothecopyrightsymbolusingthismethod,youusethestring\u00A9.

BooleanDataTheuseofyesorno,positiveornegative,andtrueorfalseiscommonplaceinthephysicalworld.Theideaoftrueandfalseisalsofundamentaltodigitalcomputers;theydon’tunderstandmaybes,onlytrueandfalse.Infact,theconceptof“yesorno”issousefulithasitsowndatatypeinJavaScript:thebooleandatatype.Thebooleantypehastwopossiblevalues:trueforyesandfalseforno.

ThepurposeofbooleandatainJavaScriptisjustthesameasintheworldoutsideprogramming:itenablesyoutoanswerquestionsandmakedecisionsbasedontheanswer.Forexample,ifyouareasked,“IsthisbookaboutJavaScript?”youwouldhopefullyanswer,“Yesitis,”oryoumightalsosay,“That’strue.”Similarly,youmightsay,“Ifit’sfalsethatthesubjectofthebookisJavaScript,thenputitdown.”Hereyouhaveabooleanlogicstatement(namedafteritsinventorGeorgeBoole),whichasksaquestionandthendoessomethingbasedonwhethertheansweristrueorfalse.InJavaScript,youcanusethesamesortofbooleanlogictogiveyourprogramsdecision-makingabilities.Youtakeamoredetailedlookatbooleanlogicinthenextchapter.

VARIABLES—STORINGDATAINMEMORYDatacanbestoredeitherpermanentlyortemporarily.

Youwillwanttokeepimportantdata,suchasthedetailsofaperson’sbankaccount,inapermanentstore.Forexample,whenMs.Bloggstakestendollarsorpoundsoreurosoutofheraccount,youwanttodeductthemoneyfromheraccountandkeepapermanentrecordofthenewbalance.Informationlikethismightbestoredinsomethingcalledadatabase.

However,inothercasesyoudon’twanttopermanentlystoredata,butsimplywanttokeepatemporarynoteofit.Let’slookatanexample.SayMs.BloggshasaloanfromBigBankInc.,andshewantstofindouthowmuchisstilloutstandingonthisloan.Shegoestotheonlinebankingpageforloansandclicksalinktofindouthowmuchsheowes.Thisisdatathatwillbestoredpermanentlysomewhere.However,supposeyoualsoprovideafacilityforincreasingloanrepaymentstopayofftheloanearly.IfMs.Bloggsentersanincreasedrepaymentamountintothetextboxonthewebpage,youmightwanttoshowhowmuchsoonertheloanwillbepaid.Thiswillinvolveafewpossiblycomplexcalculations,sotomakeiteasier,youwanttowritecodethatcalculatestheresultinseveralstages,storingtheresultateachstageasyougoalong,beforeprovidingafinalresult.Afteryou’vedonethecalculationanddisplayedtheresults,there’snoneedtopermanentlystoretheresultsforeachstage,soratherthanuseadatabase,youneedtousesomethingcalledavariable.Whyisitcalledavariable?Well,perhapsbecauseavariablecanbeusedtostoretemporarydatathatcanbealtered,orvaried.

Anotherbonusofvariablesisthatunlikepermanentstorage,whichmightbesavedtodiskormagnetictape,variablesareheldinthecomputer’smemory.Thismeansthatitismuch,muchfastertostoreandretrievethedata.

Sowhatmakesvariablesgoodplacesfortemporarilystoringyourdata?Well,variableshavealimitedlifetime.Whenyourvisitorsclosethepageormovetoanewone,yourvariablesarelost,unlessyoutakesomestepstosavethemsomewhere.

Yougiveeachvariableanamesothatyoucanrefertoitelsewhereinyourcode.Thesenamesmustfollowcertainrules.

AswithmuchofJavaScriptcode,variablenamesarecasesensitive.Forexample,myVariableisnotthesameasmyvariable.You’llfindthatthisisaveryeasywayforerrorstoslipintoyourcode,evenwhenyoubecomeanexpertatJavaScript.

Also,youcan’tusecertainnamesandcharactersforyourvariablenames.Namesyoucan’tusearecalledreservedwords.ReservedwordsarewordsthatJavaScriptkeepsforitsownuse(forexample,thewordvarorthewordwith).Certaincharactersarealsoforbiddeninvariablenames:forexample,theampersand(&)andthepercentsign(%).Youareallowedtousenumbersinyourvariablenames,butthenamesmustnotbeginwithnumbers.So101myVariableisnotokay,butmyVariable101is.Let’slookatsomemoreexamples.

Invalidnamesinclude:

with

99variables

my%Variable

theGood&theBad

Validnamesinclude:

myVariable99

myPercent_Variable

the_Good_and_the_Bad

Youmaywanttouseanamingconventionforyourvariables(forexample,onethatdescribeswhatsortofdatayouplantoholdinthevariable).Youcannotateyourvariablesinlotsofdifferentways—nonearerightorwrong,butit’sbesttostickwithoneofthem.

Today,theconventionmostJavaScriptdevelopersuseistosimplygivetheirvariablesdescriptivenames.Forexample,avariableforaperson’sfirstnamewouldbecalledfirstName;hisaccountnumberwouldbeaccountNumber.However,aslongasthenamesyouusemakesenseandareusedconsistently,itreallydoesn’tmatterwhatconventionyouchoose.

CreatingVariablesandGivingThemValuesBeforeyoucanuseavariable,youshoulddeclareitsexistencetotheJavaScriptengineusingthevarkeyword.Thiswarnstheenginethatitneedstoreservesomememoryinwhichtostoreyourdatalater.TodeclareanewvariablecalledmyFirstVariable,writethefollowing:

varmyFirstVariable;

Notethatthesemicolonattheendofthelineisnotpartofthevariablename,butinsteadisusedtoindicatetoJavaScripttheendofastatement.ThislineisanexampleofaJavaScriptstatement.

Oncedeclared,youcanuseavariabletostoreanytypeofdata.Asmentionedearlier,manyotherprogramminglanguages(calledstronglytypedlanguages)requireyoutodeclarenotonlythevariable,butalsothetypeofdatathatwillbestored,suchasnumbersortext.However,JavaScriptisaweaklytypedlanguage;youdon’tneedtolimityourselftowhattypeofdataavariablecanhold.

Youputdataintoyourvariables,aprocesscalledassigningvaluestoyourvariables,byusingtheequalssign(=).Forexample,ifyouwantyourvariablenamedmyFirstVariabletoholdthenumber101,youwouldwritethis:

myFirstVariable=101;

Theequalssignhasaspecialnamewhenusedtoassignvaluestoavariable;it’scalledtheassignmentoperator.

TRYITOUTDeclaringVariablesLet’slookatanexampleinwhichavariableisdeclared,storesomedatainit,andfinally,accessitscontents.You’llalsoseethatvariablescanholdanytypeofdata,andthatthetypeofdatabeingheldcanbechanged.Forexample,youcanstartbystoringtextandthenchangetostoringnumberswithoutJavaScripthavinganyproblems.Typethefollowingcodeintoyourtexteditorandsaveitasch2 _ example1.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example1</title>

</head>

<body>

<script>

varmyFirstVariable;

myFirstVariable="Hello";

alert(myFirstVariable);

myFirstVariable=54321;

alert(myFirstVariable);

</script>

</body>

</html>

Assoonasyouloadthisintoyourwebbrowser,itshouldshowanalertboxwith“Hello”init,asshowninFigure2.1.ThisisthecontentofthevariablemyFirstVariableatthatpointinthecode.

Figure2.1

ClickOKandanotheralertboxappearswith54321init,asshowninFigure2.2.ThisisthenewvalueyouassignedtothevariablemyFirstVariable.

Figure2.2

Withinthescriptblock,youfirstdeclareyourvariable:

varmyFirstVariable;

Currently,itsvalueistheundefinedvaluebecauseyou’vedeclaredonlyitsexistencetotheJavaScriptengine,notanyactualdata.Itmaysoundodd,butundefinedisanactualprimitivevalueinJavaScript,anditenablesyoutodocomparisons.(For

www.allitebooks.com

example,youcanchecktoseewhetheravariablecontainsanactualvalueorwhetherithasnotyetbeengivenavalue,thatis,whetheritisundefined.)However,inthenextlineyouassignmyFirstVariableastringvalue,namelythevalueHello:

myFirstVariable="Hello";

Hereyouhaveassignedthevariablealiteralvalue(thatis,apieceofactualdataratherthandataobtainedbyacalculationorfromanothervariable).Almostanywherethatyoucanusealiteralstringornumber,youcanreplaceitwithavariablecontainingnumberorstringdata.Youseeanexampleofthisinthenextlineofcode,whereyouuseyourvariablemyFirstVariableinthealert()functionthatyousawinthepreviouschapter:

alert(myFirstVariable);

Thiscausesthefirstalertboxtoappear.Nextyoustoreanewvalueinyourvariable,thistimeanumber:

myFirstVariable=54321;

ThepreviousvalueofmyFirstVariableislostforever.ThememoryspaceusedtostorethevalueisfreedupautomaticallybyJavaScriptinaprocesscalledgarbagecollection.WheneverJavaScriptdetectsthatthecontentsofavariablearenolongerusable,suchaswhenyouallocateanewvalue,itperformsthegarbagecollectionprocessandmakesthememoryavailable.Withoutthisautomaticgarbagecollectionprocess,moreandmoreofthecomputer’smemorywouldbeconsumed,untileventuallythecomputerwouldrunoutandthesystemwouldgrindtoahalt.However,garbagecollectionisnotalwaysasefficientasitshouldbeandmaynotoccuruntilanotherpageisloaded.

Justtoprovethatthenewvaluehasbeenstored,usethealert()functionagaintodisplaythevariable’snewcontents:

alert(myFirstVariable);

AssigningVariableswiththeValueofOtherVariablesYou’veseenthatyoucanassignavariablewithanumberorstring,butcanyouassignavariablewiththedatastoredinsideanothervariable?Theanswerisyes,veryeasily,andinexactlythesamewayasgivingavariablealiteralvalue.Forexample,ifyouhavedeclaredthetwovariablesmyVariableandmyOtherVariableandhavegiventhevariablemyOtherVariablethevalue22,likethis:

varmyVariable;

varmyOtherVariable;

myOtherVariable=22;

youcanusethefollowinglinetoassignmyVariablethesamevalueasmyOtherVariable(thatis,22):

myVariable=myOtherVariable;

TRYITOUTAssigningVariablestheValuesofOtherVariablesLet’slookatanotherexample,thistimeassigningvariablesthevaluesofothervariables.

1. Typethefollowingcodeintoyourtexteditorandsaveitasch2_example2.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example2</title>

</head>

<body>

<script>

varstring1="Hello";

varstring2="Goodbye";

alert(string1);

alert(string2);

string2=string1;

alert(string1);

alert(string2);

string1="Nowforsomethingdifferent";

alert(string1);

alert(string2);

</script>

</body>

<html>

2. Loadthepageintoyourbrowser,andyou’llseeaseriesofsixalertboxesappear.

3. ClickOKoneachalertboxtoseethenextalert.Thefirsttwoshowthevaluesofstring1andstring2—HelloandGoodbye,respectively.Thenyouassignstring2thevaluethat’sinstring1.Thenexttwoalertboxesshowthecontentsofstring1andstring2;thistimebothareHello.

4. Finally,youchangethevalueofstring1.Notethatthevalueofstring2remainsunaffected.Thefinaltwoalertboxesshowthenewvalueofstring1(Nowforsomethingdifferent)andtheunchangedvalueofstring2(Hello).

Thefirstthingyoudointhescriptblockisdeclareyourtwovariables:string1andstring2.However,noticethatyouhaveassignedthemvaluesatthesametimethatyouhavedeclaredthem.Thisisashortcut,calledinitializing,thatsavesyoutyping

toomuchcode:

varstring1="Hello";

varstring2="Goodbye";

Notethatyoucanusethisshortcutwithalldatatypes,notjuststrings.Inthenexttwolinesyouusethealert()functiontoshowthecurrentvalueofeachvariabletotheuser:

alert(string1);

alert(string2);

Thenyouassignstring2thevaluethat’scontainedinstring1.Toprovethattheassignmenthasreallyworked,youagainusethealert()functiontoshowtheuserthecontentsofeachvariable:

string2=string1;

alert(string1);

alert(string2);

Next,yousetstring1toanewvalue:

string1="Nowforsomethingdifferent";

Thisleavesstring2withitscurrentvalue,demonstratingthatstring2hasitsowncopyofthedataassignedtoitfromstring1inthepreviousstep.Youseeinlaterchaptersthatthisisnotalwaysthecase.However,asageneralrule,basicdatatypes,suchastextandnumbers,arealwayscopiedwhenassigned,whereasmorecomplexdatatypes,liketheobjectsyoucomeacrossinChapter5,areactuallysharedandnotcopied.Forexample,ifyouhaveavariablewiththestringHelloandassignfiveothervariablesthevalueofthisvariable,younowhavetheoriginaldataandfiveindependentcopiesofthedata.However,ifitwasanobjectratherthanastringandyoudidthesamething,you’dfindyoustillhaveonlyonecopyofthedata,butthatsixvariablesshareit.Changingthedatausinganyofthesixvariablenameswouldchangeitforallthevariables.

Finally,youusethealert()functiontoshowthecurrentvaluesofeachvariable:

alert(string1);

alert(string2);

USINGDATA—CALCULATIONSANDBASICSTRINGMANIPULATIONYou’veseenhowtodeclarevariablesandhowtheycanstoreinformation,butsofaryouhaven’tdoneanythingreallyusefulwiththisknowledge—sojustwhywouldyouwanttousevariablesatall?

Whatvariablesenableyoutodoistemporarilyholdinformationthatyoucanuseforprocessinginmathematicalcalculations,inbuildinguptextmessages,orinprocessingwordsthattheuserhasentered.VariablesarealittlebitliketheMemoryStorebuttonontheaveragepocketcalculator.Sayyouwereaddingupyourfinances.Youmightfirstaddupallthemoneyyouneededtospend,andthenstoreitintemporarymemory.Afteryouhadaddedupallyourmoneycomingin,youcoulddeducttheamountstoredinthememorytofigureouthowmuchwouldbeleftover.Youcanusevariablesinasimilarway:Youcanfirstgainthenecessaryuserinputandstoreitinvariables,andthenyoucandoyourcalculationsusingthevaluesobtained.

Inthissectionyouseehowyoucanputthevaluesstoredinvariablestogooduseinbothnumber-crunchingandtext-basedoperations.

NumericalCalculationsJavaScripthasarangeofbasicmathematicalcapabilities,suchasaddition,subtraction,multiplication,anddivision.Eachofthebasicmathfunctionsisrepresentedbyasymbol:plus(+),minus(−),star(*),andforwardslash(/),respectively.Thesesymbolsarecalledoperatorsbecausetheyoperateonthevaluesyougivethem.Inotherwords,theyperformsomecalculationoroperationandreturnaresult.Youcanusetheresultsofthesecalculationsalmostanywhereyou’duseanumberoravariable.

Imagineyouwerecalculatingthetotalvalueofitemsonashoppinglist.Youcouldwritethiscalculationasfollows:

Totalcostofshopping=10+5+5

Or,ifyouactuallycalculatethesum,it’s:

Totalcostofshopping=20

Nowlet’sseehowtodothisinJavaScript.Inactualfact,itisverysimilarexceptthatyouneedtouseavariabletostorethefinaltotal:

vartotalCostOfShopping;

totalCostOfShopping=10+5+5;

alert(totalCostOfShopping);

First,youdeclareavariable,totalCostOfShopping,toholdthetotalcost.

Inthesecondline,youhavethecode10+5+5.Thispieceofcodeisknownasanexpression.WhenyouassignthevariabletotalCostOfShoppingthevalueofthisexpression,JavaScriptautomaticallycalculatesthevalueoftheexpression(20)andstores

itinthevariable.NoticethattheequalssigntellsJavaScripttostoretheresultsofthecalculationinthetotalCostOfShoppingvariable.Thisiscalledassigningthevalueofthecalculationtothevariable,whichiswhythesingleequalssign(=)iscalledtheassignmentoperator.

Finally,youdisplaythevalueofthevariableinanalertbox.

Theoperatorsforsubtractionandmultiplicationworkinexactlythesameway.Divisionisalittledifferent.

TRYITOUTCalculationsLet’stakealookatanexampleusingthedivisionoperatortoseehowitworks.

1. Enterthefollowingcodeandsaveitasch2_example3.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example3</title>

</head>

<body>

<script>

varfirstNumber=15;

varsecondNumber=10;

varanswer;

answer=15/10;

alert(answer);

alert(15/10);

answer=firstNumber/secondNumber;

alert(answer);

</script>

</body>

</html>

2. Loadthisintoyourwebbrowser.Youshouldseeasuccessionofthreealertboxes,eachcontainingthevalue1.5.Thesevaluesaretheresultsofthreecalculations.

3. Thefirstthingyoudointhescriptblockisdeclareyourthreevariablesandassignthefirsttwoofthemvaluesthatyou’llbeusinglater:

varfirstNumber=15;

varsecondNumber=10;

varanswer;

4. Next,yousettheanswervariabletotheresultsofthecalculationoftheexpression15/10.Youshowthevalueofthisvariableinanalertbox:

answer=15/10;

alert(answer);

Thisexampledemonstratesonewayofdoingthecalculation,butinrealityyou’dalmostneverdoitthisway.

Todemonstratethatyoucanuseexpressionsinplacesyou’dusenumbersorvariables,youshowtheresultsofthecalculationof15/10directlybyincludingitinthealert()function:

alert(15/10);

Finally,youdothesamecalculation,butthistimeusingthetwovariables:firstNumber,whichwassetto15,andsecondNumber,whichwassetto10.YouhavetheexpressionfirstNumber/secondNumber,theresultofwhichyoustoreinyouranswervariable.Then,toproveithasallworked,youshowthevaluecontainedinanswerbyusingyourfriendthealert()function:

answer=firstNumber/secondNumber;

alert(answer);

You’lldomostcalculationsthethirdway(thatis,usingvariables,ornumbersandvariables,andstoringtheresultinanothervariable).Thereasonforthisisthatifthecalculationusedliteralvalues(actualvalues,suchas15/10),thenyoumightaswellprogramintheresultofthecalculation,ratherthanforceJavaScripttocalculateitforyou.Forexample,ratherthanwriting15/10,youmightaswelljustwrite1.5.Afterall,themorecalculationsyouforceJavaScripttodo,thesloweritwillbe,thoughadmittedlyjustonecalculationwon’ttaxittoomuch.

Anotherreasonforusingtheresultratherthanthecalculationisthatitmakescodemorereadable.Whichwouldyouprefertoreadincode:1.5*45–56/67+2.567or69.231?Stillbetter,avariablenamed,forexample,pricePerKG,makescodeeveneasiertounderstandforsomeonenotfamiliarwithit.

IncrementandDecrementOperatorsAnumberofoperationsusingthemathoperatorsaresocommonlyusedthattheyhavebeengiventheirownoperators.Thetwoyou’llbelookingatherearetheincrementanddecrementoperators,whicharerepresentedbytwoplussigns(++)andtwominussigns(−−),respectively.Basically,alltheydoisincreaseordecreaseavariable’svaluebyone.Youcouldusethenormal+and−operatorstodothis,forexample:

myVariable=myVariable+1;

myVariable=myVariable−1;

NOTEYoucanassignavariableanewvaluethatistheresultofanexpressioninvolvingitspreviousvalue.

However,usingtheincrementanddecrementoperatorsshortensthisto:

myVariable++;

myVariable−−;

Theresultisthesame—thevalueofmyVariableisincreasedordecreasedbyone—butthecodeisshorter.Whenyouarefamiliarwiththesyntax,thisbecomesveryclearandeasytoread.

Rightnow,youmaywellbethinkingthattheseoperatorssoundasusefulasapokeintheeye.However,inChapter3,whenyoulookathowyoucanrunthesamecodeanumberoftimes,you’llseethattheseoperatorsareveryusefulandwidelyused.Infact,the++operatorissowidelyusedithasacomputerlanguagenamedafterit:C++.ThejokehereisthatC++isoneupfromC.(Well,that’sprogrammerhumorforyou!)

Aswellasplacingthe++or−−afterthevariable,youcanalsoplaceitbefore,likeso:

++myVariable;

−−myVariable;

Whenthe++and−−areusedontheirown,astheyusuallyare,itmakesnodifferencewheretheyareplaced,butitispossibletousethe++and−−operatorsinanexpressionalongwithotheroperators.Forexample:

myVar=myNumber++−20;

Thiscodetakes20awayfrommyNumberandthenincrementsthevariablemyNumberbyonebeforeassigningtheresulttothevariablemyVar.Ifinsteadyouplacethe++beforeandprefixitlikethis:

myVar=++myNumber−20;

myNumberisfirstincrementedbyone,andthenmyNumberhas20subtractedfromit.It’sasubtledifference,butinsomesituationsaveryimportantone.Takethefollowingcode:

myNumber=1;

myVar=(myNumber++*10+1);

WhatvaluewillmyVarcontain?Well,becausethe++ispostfixed(it’safterthemyNumbervariable),itwillbeincrementedafterward.Sotheequationreads:MultiplymyNumberby10plus1andthenincrementmyNumberbyone.

myVar=1*10+1=11

Thenadd1tomyNumbertoget12,butdothisafterthevalue11hasbeenassignedtomyVar.Nowtakealookatthefollowingcode:

myNumber=1;

myVar=++myNumber*10+1;

ThistimemyNumberisincrementedbyonefirst,thentimes10andplus1:

myVar=2*10+1=21

Asyoucanimagine,suchsubtletycaneasilybeoverlookedandleadtobugsincode;therefore,it’susuallybesttoavoidthissyntax.

Beforegoingon,thisseemstobeagoodplacetointroduceanotheroperator:+=.Youcanusethisoperatorasashortcutforincreasingthevalueheldbyavariablebyasetamount.Forexample,

myVar+=6;

doesexactlythesamethingas:

myVar=myVar+6;

Youcanalsodothesamethingforsubtractionandmultiplication,asshownhere:

myVar−=6;

myVar*=6;

whichisequivalentto:

myVar=myVar−6;

myVar=myVar*6;

OperatorPrecedenceYou’veseenthatsymbolsthatperformsomefunction—like+,whichaddstwonumbers,and−,whichsubtractsonenumberfromanother—arecalledoperators.Unlikepeople,notalloperatorsarecreatedequal;somehaveahigherprecedence—thatis,theygetdealtwithsooner.Aquicklookatasimpleexamplewillhelpdemonstratethispoint:

varmyVariable;

myVariable=1+1*2;

alert(myVariable);

Ifyouweretotypethis,whatresultwouldyouexpectthealertboxtoshowasthevalueofmyVariable?Youmightexpectthatbecause1+1=2and2*2=4,theansweris4.Actually,you’llfindthatthealertboxshows3asthevaluestoredinmyVariableasaresultofthecalculation.Sowhatgives?Doesn’tJavaScriptaddupright?

Well,youprobablyalreadyknowthereasonfromyourunderstandingofmathematics.ThewayJavaScriptdoesthecalculationistofirstcalculate1*2=2,andthenusethisresultintheaddition,sothatJavaScriptfinishesoffwith1+2=3.

Why?Because*hasahigherprecedencethan+.The=symbol,alsoanoperator(calledtheassignmentoperator),hasthelowestprecedence—italwaysgetsleftuntillast.

The+and−operatorshaveanequalprecedence,sowhichonegetsdonefirst?Well,JavaScriptworksfromlefttoright,soifoperatorswithequalprecedenceexistinacalculation,theygetcalculatedintheorderinwhichtheyappearwhengoingfromlefttoright.Thesameappliesto*and/,whicharealsoofequalprecedence.

TRYITOUTFahrenheittoCentigrade

Takealookataslightlymorecomplexexample—aFahrenheittocentigradeconverter.(CentigradeisanothernamefortheCelsiustemperaturescale.)Typethiscodeandsaveitasch2_example4.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example4</title>

</head>

<body>

<script>

//Equationis°C=5/9(°F-32).

vardegFahren=prompt("EnterthedegreesinFahrenheit",50);

vardegCent;

degCent=5/9*(degFahren-32);

alert(degCent);

</script>

</body>

</html>

Ifyouloadthepageintoyourbrowser,youshouldseeapromptbox,likethatshowninFigure2.3,thatasksyoutoenterthedegreesinFahrenheittobeconverted.Thevalue50isalreadyfilledinbydefault.

Figure2.3

Ifyouleaveitat50andclickOK,analertboxwiththenumber10initappears.Thisrepresents50degreesFahrenheitconvertedtocentigrade.

Reloadthepageandtrychangingthevalueinthepromptboxtoseewhatresultsyouget.Forexample,changethevalueto32andreloadthepage.Thistimeyoushould

see0appearinthebox.

Becauseit’sstillafairlysimpleexample,there’snocheckingofdatainput,soit’llletyouenterabcasthedegreesFahrenheit.Later,inthe“DataTypeConversion”sectionofthischapter,youseehowtospotinvalidcharactersposingasnumericdata.

TRYITOUTSecurityIssueswithInternetExplorerWhenloadingthepagetoInternetExplorer(IE),youmayseethesecuritywarningissueshowninFigure2.4,andthepromptwindowdoesn’tappear.

Figure2.4

Ifitdoesyou’llneedtochangeIE’ssecuritysettingstoallowactivecontentfromyourcomputer.Todothis:

1. OpenIEandselectthe“Internetoptions”menufromtheToolsmenu,asshowninFigure2.5.

2. ClicktheAdvancedtabandthenscrolldowntotheSecuritysection.Checkthe“AllowactivecontenttoruninfilesonMyComputer”option,asshowninFigure2.6.

3. ClicktheOKbuttonontheInternetOptionsdialogboxandcloseInternetExplorer.OpenExample4fromthe“FahrenheittoCentigrade”TryItOutagain,andtheexamplewillnowwork.

www.allitebooks.com

Figure2.5

Figure2.6

Thefirstlineofthescriptblockisacomment,becauseitstartswithtwoforwardslashes(//).ItcontainstheequationforconvertingFahrenheittemperaturestocentigradeandisintheexamplecodesolelyforreference:

//Equationis°C=5/9(°F-32).

YourtaskistorepresentthisequationinJavaScriptcode.Youstartbydeclaringyourvariables,degFahrenanddegCent:

vardegFahren=prompt(“EnterthedegreesinFahrenheit”,50);

vardegCent;

InsteadofinitializingthedegFahrenvariabletoaliteralvalue,yougetavaluefromtheuserusingtheprompt()function.Theprompt()functionworksinasimilarwaytoanalert()function,exceptthataswellasdisplayingamessage,italsocontainsatextboxinwhichtheusercanenteravalue.ItisthisvaluethatwillbestoredinsidethedegFahrenvariable.Thevaluereturnedisatextstring,butthiswillbeimplicitlyconvertedbyJavaScripttoanumberwhenyouuseitasanumber,asdiscussedinthesection“DataTypeConversion”laterinthischapter.

Youpasstwopiecesofinformationtotheprompt()function:

Thetexttobedisplayed—usuallyaquestionthatpromptstheuserforinput

Thedefaultvaluethatiscontainedintheinputboxwhenthepromptdialogboxfirstappears

Thesetwopiecesofinformationmustbespecifiedinthegivenorderandseparatedbyacomma.Ifyoudon’twantadefaultvaluetobecontainedintheinputboxwhenthepromptboxopens,useanemptystring("")forthesecondpieceofinformation.

Asyoucanseeintheprecedingcode,thetextis“EnterthedegreesinFahrenheit,”andthedefaultvalueintheinputboxis50.

NextinthescriptblockcomestheequationrepresentedinJavaScript.YoustoretheresultoftheequationinthedegCentvariable.YoucanseethattheJavaScriptlooksverymuchliketheequationyouhaveinthecomment,exceptyouusedegFahreninsteadof°F,anddegCentratherthan°C:

degCent=5/9*(degFahren-32);

Thecalculationoftheexpressionontheright-handsideoftheequalssignraisesanumberofimportantpoints.First,justasinmath,theJavaScriptequationisreadfromlefttoright,atleastforthebasicmathfunctionslike+,-,andsoon.Secondly,asyousawearlier,justasthereisprecedenceinmath,thereisprecedenceinJavaScript.

Startingfromtheleft,firstJavaScriptworksout5/9=.5556(approximately).Thenitcomestothemultiplication,butwait…thelastbitofyourequation,degFahren–32,isinparentheses.ThisraisestheorderofprecedenceandcausesJavaScripttocalculatetheresultofdegFahren–32beforedoingthemultiplication.Forexample,whendegFahrenissetto50,(degFahren-32)=(50–32)=18.NowJavaScriptdoesthemultiplication,.5556*18,whichisapproximately10.

Whatifyoudidn’tusetheparentheses?Thenyourcodewouldbe:

degCent=5/9*degFahren-32;

Thecalculationof5/9remainsthesame,butthenJavaScriptwouldhavecalculatedthemultiplication,5/9*degFahren.Thisisbecausethemultiplicationtakesprecedenceoverthesubtraction.WhendegFahrenis50,thisequatesto5/9*50=27.7778.Finally,JavaScriptwouldhavesubtractedthe32,leavingtheresultas–4.2221;nottheansweryouwant!

Finally,inyourscriptblock,youdisplaytheanswerusingthealert()function:

alert(degCent);

ThatconcludesabrieflookatbasiccalculationswithJavaScript.However,inChapter5youlookattheMathobject,whichenablesyoutodomorecomplexcalculations.

BasicStringOperations

Inanearliersection,youlookedatthetextorstringdatatype,aswellasnumericaldata.Justasnumericaldatahasassociatedoperators,stringshaveoperatorstoo.Thissectionintroducessomebasicstringmanipulationtechniquesusingsuchoperators.StringsarecoveredinmoredepthinChapter5,andadvancedstringhandlingiscoveredinChapter6.

Onethingyou’llfindyourselfdoingagainandagaininJavaScriptisjoiningtwostringstomakeonestring—aprocesstermedconcatenation.Forexample,youmaywanttoconcatenatethetwostrings"Hello"and"Paul"tomakethestring"HelloPaul".Sohowdoyouconcatenate?Easy!Usethe+operator.Recallthatwhenappliedtonumbers,the+operatoraddsthemup,butwhenusedinthecontextoftwostrings,itjoinsthem:

varconcatString="Hello"+"Paul";

ThestringnowstoredinthevariableconcatStringis"HelloPaul".Noticethatthelastcharacterofthestring"Hello"isaspace—ifyouleftthisout,yourconcatenatedstringwouldbe"HelloPaul".

TRYITOUTConcatenatingStringsLet’slookatanexampleusingthe+operatorforstringconcatenation.

1. Typethefollowingcodeandsaveitasch2_example5.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example5</title>

</head>

<body>

<script>

vargreetingString="Hello";

varmyName=prompt("Pleaseenteryourname","");

varconcatString;

document.write(greetingString+""+myName+"<br/>");

concatString=greetingString+""+myName;

document.write(concatString);

</script>

</body>

</html>

2. Ifyouloaditintoyourwebbrowser,youshouldseeapromptboxaskingforyourname.

3. EnteryournameandclickOK.Youshouldseeagreetingandyournamedisplayedtwiceonthewebpage.

Youstartthescriptblockbydeclaringthreevariables.Yousetthefirstvariable,greetingString,toastringvalue.Thesecondvariable,myName,isassignedto

whateverisenteredbytheuserinthepromptbox.Youdonotinitializethethirdvariable,concatString,here.Itwillbeusedtostoretheresultoftheconcatenationthatyou’lldolaterinthecode.

vargreetingString="Hello";

varmyName=prompt("Pleaseenteryourname","");

varconcatString;

Inthepreviouschapter,yousawhowthewebpagewasrepresentedbytheconceptofadocumentandthatithadanumberofdifferentproperties,suchasbgColor.YoucanalsousedocumenttowritetextandHTMLdirectlyintothepageitself.Youdothisbyusingtheworddocument,followedbyadot,andthenwrite().Youthenusedocument.write()muchasyoudothealert()function,inthatyouputthetextthatyouwantdisplayedinthewebpageinsidetheparenthesesfollowingthewordwrite.Don’tworrytoomuchaboutthishere,though,becauseitisallexplainedindetailinlaterchapters.However,younowmakeuseofdocument.write()inyourcodetowritetheresultofanexpressiontothepage:

document.write(greetingString+""+myName+"<br/>");

TheexpressionwrittentothepageistheconcatenationofthevalueofthegreetingStringvariable,aspace(""),thevalueofthemyNamevariable,andtheHTML<br/>element,whichcausesalinebreak.Forexample,ifyouenterJeremyintothepromptbox,thevalueofthisexpressionwillbeasfollows:

HelloJeremy<br/>

Inthenextlineofcodeisasimilarexpression.ThistimeitisjusttheconcatenationofthevalueinthevariablegreetingString,aspace,andthevalueinthevariablemyName.YoustoretheresultofthisexpressioninthevariableconcatString.Finally,youwritethecontentsofthevariableconcatStringtothepageusingdocument.write():

concatString=greetingString+""+myName;

document.write(concatString);

MixingNumbersandStringsWhatifyouwanttomixtextandnumbersinanexpression?Aprimeexampleofthiswouldbeinthetemperatureconverteryousawearlier.Intheexample,youjustdisplaythenumberwithouttellingtheuserwhatitactuallymeans.Whatyoureallywanttodoisdisplaythenumberwithdescriptivetextwrappedaroundit,suchas“Thevalueconvertedtodegreescentigradeis10.”

Mixingnumbersandtextisactuallyveryeasy.Youcansimplyjointhemusingthe+operator.JavaScriptisintelligentenoughtoknowthatwhenbothastringandanumberareinvolved,you’renottryingtodonumericalcalculations,butratherthatyouwanttotreatthenumberasastringandjoinittothetext.Forexample,tojointhetextMyageisandthenumber101,youcouldsimplydothefollowing:

alert("Myageis"+101);

Thiswouldproduceanalertboxwith“Myageis101”insideit.

TRYITOUTMakingtheTemperatureConverterUser-FriendlyYoucantryoutthistechniqueofconcatenatingstringsandnumbersinthetemperature-converterexample.Yououtputsomeexplanatorytext,alongwiththeresultoftheconversioncalculation.Thechangesthatyouneedtomakeareverysmall,soloadch2_example4.htmlintoyourtexteditorandchangethefollowingline.Thensaveitasch2_example6.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example6</title>

</head>

<body>

<script>

//Equationis°C=5/9(°F-32).

vardegFahren=prompt("EnterthedegreesinFahrenheit",50);

vardegCent;

degCent=5/9*(degFahren-32);

alert(degFahren+"\xB0Fahrenheitis"+degCent+"\xB0

centigrade");

</script>

</body>

</html>

Loadthepageintoyourwebbrowser.ClickOKinthepromptboxtosubmitthevalue50,andthistimeyoushouldseetheboxshowninFigure2.7.

Figure2.7

Thisexampleisidenticaltoch2 _ example4.html,exceptforoneline:

alert(degFahren+"\xB0Fahrenheitis"+degCent+"\xB0centigrade");

Sowewilljustlookatthislinehere.Youcanseethatthealert()functioncontainsanexpression.Let’slookatthatexpressionmoreclosely.

FirstisthevariabledegFahren,whichcontainsnumericaldata.Youconcatenatethattothestring"\xBOFahrenheitis“.JavaScriptrealizesthatbecauseyouareaddinganumberandastring,youwanttojointhemintoonestringratherthantryingtotaketheirsum,andsoitautomaticallyconvertsthenumbercontainedindegFahrentoastring.YounextconcatenatethisstringtothevariabledegCent,containingnumericaldata.AgainJavaScriptconvertsthevalueofthisvariabletoastring.Finally,youconcatenatetothestring"\xBOcentigrade".

Notealsotheescapesequenceusedtoinsertthedegreecharacterintothestrings.You’llrememberfromearlierinthechapterthatyoucanuse\xNNtoinsertspecialcharactersnotavailabletotypeindirectly.(NNisahexadecimalnumberrepresentingacharacterfromtheLatin-1charactertable.)SowhenJavaScriptspots\xB0inastring,insteadofshowingthosecharactersitdoesalookuptoseewhatcharacterisrepresentedbyB0andshowsthatinstead.

Somethingtobeawareofwhenusingspecialcharactersisthattheyarenotnecessarilycross-platform–compatible.Althoughyoucanuse\xNNforacertaincharacteronaWindowscomputer,youmayfindyouneedtouseadifferentcharacteronaMacoraUnixmachine.

YoulookatmorestringmanipulationtechniquesinChapter5—youseehowtosearchstringsandinsertcharactersinthemiddleofthem,andinChapter6youseesomeverysophisticatedstringtechniques.

DATATYPECONVERSIONAsyou’veseen,ifyouaddastringandanumber,JavaScriptmakesthesensiblechoiceandconvertsthenumbertoastring,thenconcatenatesthetwo.Usually,JavaScripthasenoughsensetomakedatatypeconversionslikethiswheneveritneedsto,butinsomesituationsyouneedtoconvertthetypeofapieceofdatayourself.Forexample,youmaybegivenapieceofstringdatathatyouwanttothinkofasanumber.Thisisespeciallylikelyifyouareusingformstocollectdatafromtheuser.Anyvaluesinputbytheuseraretreatedasstrings,eventhoughtheymaycontainnumericaldata,suchastheuser’sage.

Whyischangingthetypeofthedatasoimportant?Considerasituationinwhichyoucollecttwonumbersfromtheuserusingaformandwanttocalculatetheirsum.Thetwonumbersareavailabletoyouasstrings,forexample"22"and"15".Whenyoutrytocalculatethesumofthesevaluesusing"22"+"15"yougettheresult"2215",becauseJavaScriptthinksyouaretryingtoconcatenatetwostringsratherthantryingtofindthesumoftwonumbers.Toaddtothepossibleconfusion,theorderalsomakesadifference.So:

1+2+"abc"

resultsinastringcontaining"3abc",whereas:

"abc"+1+2

wouldresultinthestringcontaining"abc12".

Inthissectionyoulookattwoconversionfunctionsthatconvertstringstonumbers:parseInt()andparseFloat().

Let’stakeparseInt()first.Thisfunctiontakesastringandconvertsittoaninteger.Thenameisalittleconfusingatfirst—whyparseInt()ratherthanconvertToInt()?Themainreasonforthenamecomesfromthewaythatthefunctionworks.Itactuallygoesthrough(thatis,parses)eachcharacterofthestringyouaskittoconvertandseesifit’savalidnumber.Ifitisvalid,parseInt()usesittobuildupthenumber;ifitisnotvalid,thecommandsimplystopsconvertingandreturnsthenumberithasconvertedsofar.

Forexample,ifyourcodeisparseInt("123"),JavaScriptwillconvertthestring"123"tothenumber123.ForthecodeparseInt("123abc"),JavaScriptwillalsoreturnthenumber123.WhentheJavaScriptenginegetstothelettera,itassumesthenumberhasendedandgives123astheintegerversionofthestring"123abc".

TheparseFloat()functionworksinthesamewayasparseInt(),exceptthatitreturnsfloating-pointnumbers—fractionalnumbers—andthatadecimalpointinthestring,whichitisconverting,isconsideredtobepartoftheallowablenumber.

TRYITOUTConvertingStringstoNumbers

Let’slookatanexampleusingparseInt()andparseFloat().Enterthefollowing

codeandsaveitasch2_example7.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example7</title>

</head>

<body>

<script>

varmyString="56.02degreescentigrade";

varmyInt;

varmyFloat;

document.write("\""+myString+"\"is"+parseInt(myString,

10)+

"asaninteger"+"<br/>");

myInt=parseInt(myString,10);

document.write("\""+myString+

"\"whenconvertedtoanintegerequals"+myInt+"

<br/>");

myFloat=parseFloat(myString);

document.write("\""+myString+

"\"whenconvertedtoafloatingpointnumberequals"+

myFloat);

</script>

</body>

</html>

Loaditintoyourbrowser,andyou’llseethreelineswritteninthewebpage,asshowninFigure2.8.

Figure2.8

Yourfirsttaskinthescriptblockistodeclaresomevariables.ThevariablemyStringisdeclaredandinitializedtothestringyouwanttoconvert.Youcouldjustaseasilyhaveusedthestringdirectlyinthisexampleratherthanstoringitinavariable,butinpracticeyou’llfindthatyouusevariablesmoreoftenthanliteralvalues.YoualsodeclarethevariablesmyIntandmyFloat,whichwillholdtheconvertednumbers:

varmyString="56.02degreescentigrade";

varmyInt;

varmyFloat;

Next,youwritetothepagetheconvertedintegervalueofmyStringdisplayedinsideauser-friendlysentenceyoubuildupusingstringconcatenation.Noticethatyouusetheescapesequence\"todisplayquotes(")aroundthestringyouareconverting:

document.write("\""+myString+"\"is"+parseInt(myString,10)+

"asaninteger"+"<br/>");

Asyoucansee,youcanuseparseInt()andparseFloat()inthesameplacesyouwoulduseanumberitselforavariablecontaininganumber.Infact,inthislinetheJavaScriptengineisdoingtwoconversions.First,itconvertsmyStringtoaninteger,becausethat’swhatyouaskedforbyusingparseInt().Thenitautomaticallyconvertsthatintegernumberbacktoastring,soitcanbeconcatenatedwiththeotherstringstomakeupyoursentence.Alsonotethatonlythe56partofthemyStringvariable’svalueisconsideredavalidnumberwhenyou’redealingwithintegers.Anythingafterthe6isconsideredinvalidandisignored.

Noticethesecondvalue,thenumber10,thatispassedtoparseInt().Thisiscalledtheradix,anditdetermineshowthestringisparsedintoanumber.Bypassingthenumber10,youtelltheparseInt()functiontoconvertthenumberusingtheBase10numbersystem.Base10isourcommonnumbersystem,butyoucanuseparseInt()toconvertnumberstobinary(Base2),hex(Base16),andothernumbersystems.Forexample,parseInt(10,2)convertsthenumber10usingthebinarynumbersystem,resultinginthenumber2.Alwaysspecifytheradix!Withoutit,JavaScriptguesseswhatnumbersystemtouse,andyoucouldencounterunexpectedresults.

Next,youdothesameconversionofmyStringusingparseInt(),butthistimeyoustoretheresultinthemyIntvariable.Onthefollowinglineyouusetheresultinsometextyoudisplaytotheuser:

myInt=parseInt(myString,10);

document.write("\""+myString+

"\"whenconvertedtoanintegerequals"+myInt+"<br/>");

Again,thoughmyIntholdsanumber,theJavaScriptinterpreterknowsthat+,whenastringandanumberareinvolved,meansyouwantthemyIntvalueconvertedtoastringandconcatenatedtotherestofthestringsoitcanbedisplayed.

Finally,youuseparseFloat()toconvertthestringinmyStringtoafloating-pointnumber,whichyoustoreinthevariablemyFloat.Thistimethedecimalpointisconsideredtobeavalidpartofthenumber,soit’sanythingafterthe2thatisignored.Againyouusedocument.write()towritetheresulttothewebpageinsideauser-

www.allitebooks.com

friendlystring:

myFloat=parseFloat(myString);

document.write("\""+myString+

"\"whenconvertedtoafloatingpointnumberequals"+myFloat);

DealingwithStringsThatWon’tConvertSomestringssimplyarenotconvertibletonumbers,suchasstringsthatdon’tcontainanynumericaldata.Whathappensifyoutrytoconvertthesestrings?Asalittleexperiment,trychangingtheprecedingexamplesothatmyStringholdssomethingthatisnotconvertible.Forexample,changetheline

varmyString="56.02degreescentigrade";

to

varmyString="I'manamenotanumber";

Nowreloadthepageinyourbrowserandyoushouldseewhat’sshowninFigure2.9.

Figure2.9

Youcanseethatintheplaceofthenumbersyougotbefore,yougetNaN.Whatsortofnumberisthat?Well,it’sNotaNumberatall!

IfyouuseparseInt()orparseFloat()withanystringthatisemptyordoesnotstartwithatleastonevaliddigit,yougetNaN,meaningNotaNumber.

NaNisactuallyaspecialvalueinJavaScript.Ithasitsownfunction,isNaN(),whichcheckswhethersomethingisNaNornot.Forexample,

myVar1=isNaN("Hello");

willstorethevaluetrueinthevariablemyVar1,because"Hello"isnotanumber,whereas

myVar2=isNaN("34");

willstorethevaluefalseinthevariablemyVar2,because34canbeconvertedsuccessfullyfromastringtoanumberbytheisNaN()function.

InlaterchaptersyouseehowyoucanusetheisNaN()functiontocheckthevalidityofstringsasnumbers,somethingthatprovesinvaluablewhendealingwithuserinput.

ARRAYSNowwe’regoingtolookatanewconcept—somethingcalledanarray.Anarrayissimilartoanormalvariable,inthatyoucanuseittoholdanytypeofdata.However,ithasoneimportantdifference,whichyouseeinthissection.

Asyouhavealreadyseen,anormalvariablecanonlyholdonepieceofdataatatime.Forexample,youcansetmyVariabletobeequalto25likeso:

myVariable=25;

andthengoandsetittosomethingelse,say35:

myVariable=35;

However,whenyousetthevariableto35,thefirstvalueof25islost.ThevariablemyVariablenowholdsjustthenumber35.

Thefollowingtableillustratesthevariable:

VARIABLENAME VALUEmyVariable 35

Thedifferencebetweensuchanormalvariableandanarrayisthatanarraycanholdmorethanoneitemofdataatthesametime.Forexample,youcoulduseanarraywiththenamemyArraytostoreboththenumbers25and35.Eachplacewhereapieceofdatacanbestoredinanarrayiscalledanelement.

Howdoyoudistinguishbetweenthesetwopiecesofdatainanarray?Yougiveeachpieceofdataanindexvalue.Torefertothatpieceofdata,youencloseitsindexvalueinsquarebracketsafterthenameofthearray.Forexample,anarraycalledmyArraycontainingthedata25and35couldbeillustratedusingthefollowingtable:

ELEMENTNAME VALUEmyArray[0] 25

myArray[1] 35

Noticethattheindexvaluesstartat0andnot1.Whyisthis?Surely1makesmoresense—afterall,wehumanstendtosaythefirstitemofdata,followedbytheseconditem,andsoon.Computersstartfrom0,andthinkofthefirstitemasthezeroitem,thesecondasthefirstitem,andsoon.Confusing,butyou’llsoongetusedtothis.

Arrayscanbeveryusefulbecauseyoucanstoreasmany(withinthelimitsofthelanguage,whichspecifiesamaximumoftwotothepowerof32elements)orasfewitemsofdatainanarrayasyouwant.Also,youdon’thavetosayupfronthowmanypiecesofdatayouwanttostoreinanarray.

Sohowdoyoucreateanarray?Thisisslightlydifferentfromdeclaringanormalvariable.Tocreateanewarray,youneedtodeclareavariablenameandtellJavaScriptthatyouwantittobeanewarrayusingthenewkeywordandtheArray()function.Forexample,

youcoulddefinethearraymyArraylikethis:

varmyArray=newArray();

Notethat,aswitheverythinginJavaScript,thecodeiscase-sensitive,soifyoutypearray()ratherthanArray(),thecodewon’twork.UsingthenewoperatorisexplainedinChapter5.

Today’sJavaScriptdeveloperscreatearrayslikethis:

varmyArray=[];

Thisusesanarrayliteraltocreatethearray.ItisfunctionallythesameasusingnewArray(),butitrequireslesstyping.Thereisnorightorwrongwaytocreateanarray,butfortheremainderofthisbook,weusethearrayliteraltocreatearrays.

Aswithnormalvariables,youcanalsodeclareyourvariablefirst,andthentellJavaScriptyouwantittobeanarray.Forexample:

varmyArray;

myArray=[];

Youhaveseenhowtodeclareanewarray,buthowdoyoustoreyourpiecesofdatainsideit?Youcandothiswhenyoudefineyourarraybyincludingyourdatainsidethesquarebrackets,witheachpieceofdataseparatedbyacomma.Forexample:

varmyArray=["Paul",345,"John",112,"Bob",99];

Herethefirstitemofdata,"Paul",willbeputinthearraywithanindexof0.Thenextpieceofdata,345,willbeputinthearraywithanindexof1,andsoon.ThismeansthattheelementwiththenamemyArray[0]containsthevalue"Paul",theelementwiththenamemyArray[1]containsthevalue345,andsoon.

Youdon’thavetoprovideanarray’sdatawhenyoufirstcreatethearray.Forexample,youcouldalsowritetheprecedinglinelikethis:

varmyArray=[];

myArray[0]="Paul";

myArray[1]=345;

myArray[2]="John";

myArray[3]=112;

myArray[4]="Bob";

myArray[5]=99;

Youuseeachelementnameasyouwouldavariable,assigningthemwithvalues.Youlearnthismethodofdeclaringthevaluesofarrayelementsinthefollowing“TryItOut”section.

Obviously,inthisexamplethefirstwayofdefiningthedataitemsismucheasier.However,therewillbesituationsinwhichyouwanttochangethedatastoredinaparticularelementinanarrayafterthedataitemshavebeendeclared.Inthatcaseyouwillhavetousethelattermethodofdefiningthevaluesofthearrayelements.

You’llalsospotfromtheprecedingexamplethatyoucanstoredifferentdatatypesinthe

samearray.JavaScriptisveryflexibleastowhatyoucanputinanarrayandwhereyoucanputit.

TRYITOUTAnArrayInthisexample,youcreateanarraytoholdsomenames,andyouusethesecondmethoddescribedintheprecedingsectiontostorethesepiecesofdatainthearray.Youthendisplaythedatatotheuser.Typethiscodeandsaveitasch2_example8.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example8</title>

</head>

<body>

<script>

varmyArray=[];

myArray[0]="Jeremy";

myArray[1]="Paul";

myArray[2]="John";

document.write("myArray[0]="+myArray[0]+"<br/>");

document.write("myArray[2]="+myArray[2]+"<br/>");

document.write("myArray[1]="+myArray[1]+"<br/>");

myArray[1]="Mike";

document.write("myArray[1]changedto"+myArray[1]);

</script>

</body>

</html>

Ifyouloadthisintoyourwebbrowser,youshouldseeawebpagethatlookssomethingliketheoneshowninFigure2.10.

Figure2.10

Thefirsttaskinthescriptblockistodeclareavariableandinitializeitasanarray:

varmyArray=[];

Nowthatyouhaveyourarraydefined,youcanstoresomedatainit.Eachtimeyoustoreanitemofdatawithanewindex,JavaScriptautomaticallycreatesanewstoragespaceforit.RememberthatthefirstelementwillbeatmyArray[0].

Takeeachadditiontothearrayinturnandseewhat’shappening.Beforeyouaddanything,yourarrayisempty.Thenyouaddanarrayelementwiththefollowingline:

myArray[0]="Jeremy";

Yourarraynowlookslikethis:

INDEX DATASTORED0 Jeremy

Thenyouaddanotherelementtothearray,thistimewithanindexof1:

myArray[1]="Paul";

Yourarraynowlookslikethis:

INDEX DATASTORED0 Jeremy1 Paul

Finally,youaddanotherelementtothearraywithanindexof2:

myArray[2]="John";

Yourarraynowlookslikethis:

INDEX DATASTORED0 Jeremy1 Paul2 John

Next,youuseaseriesofdocument.write()functionstoinsertthevaluesthateachelementofthearraycontainsintothewebpage.Herethearrayisoutoforderjusttodemonstratethatyoucanaccessitthatway:

document.write("myArray[0]="+myArray[0]+"<br/>");

document.write("myArray[2]="+myArray[2]+"<br/>");

document.write("myArray[1]="+myArray[1]+"<br/>");

Youcantreateachparticularpositioninanarrayasifit’sastandardvariable,soyoucanuseittodocalculations,transferitsvaluetoanothervariableorarray,andsoon.However,ifyoutrytoaccessthedatainsideanarraypositionbeforeyouhavedefinedit,you’llgetundefinedasavalue.

Finally,youchangedthevalueofthesecondarraypositionto"Mike".Youcouldhavechangedittoanumberbecause,justaswithnormalvariables,youcanstoreanydatatypeatanytimeineachindividualdatapositioninanarray:

myArray[1]="Mike";

Nowyourarray’scontentslooklikethis:

INDEX DATASTORED0 Jeremy1 Mike2 John

Justtoshowthatthechangeyoumadehasworked,youusedocument.write()todisplaythesecondelement’svalue:

document.write("myArray[1]changedto"+myArray[1]);

AMulti-DimensionalArraySupposeyouwanttostoreacompany’spersonnelinformationinanarray.Youmighthavedatasuchasnames,ages,addresses,andsoon.Onewaytocreatesuchanarraywouldbetostoretheinformationsequentially—thefirstnameinthefirstelementofthearray,thenthecorrespondingageinthenextelement,theaddressinthethird,thenextnameinthefourthelement,andsoon.Yourarraycouldlooksomethinglikethis:

INDEX DATASTORED0 Name11 Age12 Address13 Name24 Age25 Address26 Name37 Age38 Address3

Thiswouldwork,butthereisaneatersolution:usingamulti-dimensionalarray.Uptonowyouhavebeenusingsingle-dimensionarrays.Inthesearrayseachelementisspecifiedbyjustoneindex—thatis,onedimension.So,takingtheprecedingexample,youcanseeName1isatindex0,Age1isatindex1,andsoon.

Amulti-dimensionalarrayisonewithtwoormoreindexesforeachelement.Forexample,thisishowyourpersonnelarraycouldlookasatwo-dimensionalarray:

INDEX 0 1 20 Name1 Name2 Name31 Age1 Age2 Age32 Address1 Address2 Address3

Youseehowtocreatesuchmulti-dimensionalarraysinthefollowing“TryItOut”section.

TRYITOUTATwo-DimensionalArrayThisexampleillustrateshowyoucancreatesuchamulti-dimensionalarrayinJavaScriptcodeandhowyoucanaccesstheelementsofthisarray.Typethiscodeandsaveitasch2_example9.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Example9</title>

</head>

<body>

<script>

varpersonnel=[];

personnel[0]=[];

personnel[0][0]="Name0";

personnel[0][1]="Age0";

personnel[0][2]="Address0";

personnel[1]=[];

personnel[1][0]="Name1";

personnel[1][1]="Age1";

personnel[1][2]="Address1";

personnel[2]=[];

personnel[2][0]="Name2";

personnel[2][1]="Age2";

personnel[2][2]="Address2";

document.write("Name:"+personnel[1][0]+"<br/>");

document.write("Age:"+personnel[1][1]+"<br/>");

document.write("Address:"+personnel[1][2]);

</script>

</body>

</html>

Ifyouloaditintoyourwebbrowser,you’llseethreelineswrittenintothepage,whichrepresentthename,age,andaddressofthepersonwhosedetailsarestoredinthepersonnel[1]elementofthearray,asshowninFigure2.11.

Figure2.11

Thefirstthingtodointhisscriptblockisdeclareavariable,personnel,andtellJavaScriptthatyouwantittobeanewarray:

varpersonnel=[];

Thenyoudosomethingnew;youtellJavaScriptyouwantindex0ofthepersonnelarray,thatis,theelementpersonnel[0],tobeanothernewarray:

personnel[0]=[];

Sowhat’sgoingon?Well,thetruthisthatJavaScriptdoesn’tactuallysupportmulti-

dimensionalarrays,onlysingleones.However,JavaScriptenablesyoutofakemulti-dimensionalarraysbycreatinganarrayinsideanotherarray.Sowhattheprecedinglineisdoingiscreatinganewarrayinsidetheelementwithindex0ofyourpersonnelarray.

Inthenextthreelines,youputvaluesintothenewlycreatedpersonnel[0]array.JavaScriptmakesiteasytodothis:Youjuststatethenameofthearray,personnel[0],followedbyanotherindexinsquarebrackets.Thefirstindex(0)belongstothepersonnelarray;thesecondindexbelongstothepersonnel[0]array:

personnel[0][0]="Name0";

personnel[0][1]="Age0";

personnel[0][2]="Address0";

Aftertheselinesofcode,yourarraylookslikethis:

INDEX 00 Name01 Age02 Address0

Thenumbersatthetop,atthemomentjust0,refertothepersonnelarray.Thenumbersgoingdowntheside,0,1,and2,areactuallyindicesforthenewpersonnel[0]arrayinsidethepersonnelarray.

Forthesecondperson’sdetails,yourepeattheprocess,butthistimeyouareusingthepersonnelarrayelementwithindex1:

personnel[1]=[];

personnel[1][0]="Name1";

personnel[1][1]="Age1";

personnel[1][2]="Address1";

Nowyourarraylookslikethis:

INDEX 0 10 Name0 Name11 Age0 Age12 Address0 Address1

Youcreateathirdperson’sdetailsinthenextfewlines.Youarenowusingtheelementwithindex2insidethepersonnelarraytocreateanewarray:

personnel[2]=[];

personnel[2][0]="Name2";

personnel[2][1]="Age2";

personnel[2][2]="Address2";

Thearraynowlookslikethis:

INDEX 0 1 20 Name0 Name1 Name21 Age0 Age1 Age22 Address0 Address1 Address2

Youhavenowfinishedcreatingyourmulti-dimensionalarray.Youendthescriptblockbyaccessingthedataforthesecondperson(Name1,Age1,Address1)anddisplayingitinthepagebyusingdocument.write().Asyoucansee,accessingthedataisverymuchthesameasstoringit.Youcanusethemulti-dimensionalarrayanywhereyouwoulduseanormalvariableorsingle-dimensionarray.

document.write("Name:"+personnel[1][0]+"<br/>");

document.write("Age:"+personnel[1][1]+"<br/>");

document.write("Address:"+personnel[1][2]);

Trychangingthedocument.write()commandssothattheydisplaythefirstperson’sdetails.Thecodewouldlooklikethis:

document.write("Name:"+personnel[0][0]+"<br/>");

document.write("Age:"+personnel[0][1]+"<br/>");

document.write("Address:"+personnel[0][2]);

It’spossibletocreatemulti-dimensionalarraysofthree,four,orevenahundreddimensions,butthingscanstarttogetveryconfusing,andyou’llfindthatyourarely,ifever,needmorethantwodimensions.Togiveyouanidea,here’showtodeclareandaccessafive-dimensionalarray:

varmyArray=[];

myArray[0]=[];

myArray[0][0]=[];

myArray[0][0][0]=[];

myArray[0][0][0][0]=[];

myArray[0][0][0][0][0]="Thisisgettingoutofhand";

document.write(myArray[0][0][0][0][0]);

That’sitforarraysfornow,butyoureturntotheminChapter5,whereyou’llfindoutsomethingshockingaboutthem.Youalsolearnaboutsomeoftheirmoreadvancedfeatures.

SUMMARYInthischapteryouhavebuiltupknowledgeofthefundamentalsofJavaScript’sdatatypesandvariablesandhowtousetheminoperations.Inparticular,yousawthat:

JavaScriptsupportsanumberoftypesofdata,suchasnumbers,text,andbooleans.

Textisrepresentedbystringsofcharactersandissurroundedbyquotes.Youmustmatchthequotessurroundingstrings.Escapecharactersenableyoutoincludecharactersinyourstringthatcannotbetyped.

VariablesareJavaScript’smeansofstoringdata,suchasnumbersandtext,inmemorysothattheycanbeusedagainandagaininyourcode.

Variablenamesmustnotincludecertainillegalcharacters,likethepercentsign(%)andtheampersand(&),orbeareservedword,likewith.

Beforeyoucangiveavaluetoavariable,youmustdeclareitsexistencetotheJavaScriptinterpreter.

JavaScripthasthefourbasicmathoperators,representedbythesymbolsplus(+),minus(−),star(*),andforwardslash(/).Toassignvaluesofacalculationtoavariable,youusetheequalssign(=),termedtheassignmentoperator.

Operatorshavedifferentlevelsofprecedence,somultiplicationanddivisionwillbecalculatedbeforeadditionandsubtraction.

Stringscanbejoined,orconcatenated,toproduceonebigstringbymeansofthe+operator.Whennumbersandstringsareconcatenatedwiththe+operator,JavaScriptautomaticallyconvertsthenumberintoastring.

AlthoughJavaScript’sautomaticdataconversionsuitsusmostofthetime,onsomeoccasionsyouneedtoforcetheconversionofdata.YousawhowparseInt()andparseFloat()canbeusedtoconvertstringstonumbers.Attemptingtoconvertstringsthatwon’tconvertwillresultinNaN(NotaNumber)beingreturned.

Arraysareaspecialtypeofvariablethatcanholdmorethanonepieceofdata.Thedataisinsertedandaccessedbymeansofauniqueindexnumber.

EXERCISES1. WriteaJavaScriptprogramtoconvertdegreescentigradeintodegreesFahrenheit,

andtowritetheresulttothepageinadescriptivesentence.TheJavaScriptequationforFahrenheittocentigradeisasfollows:

degFahren=9/5*degCent+32

2. Thefollowingcodeusestheprompt()functiontogettwonumbersfromtheuser.Itthenaddsthosetwonumbersandwritestheresulttothepage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Question2</title>

</head>

<body>

<script>

varfirstNumber=prompt("Enterthefirstnumber","");

varsecondNumber=prompt("Enterthesecondnumber","");

vartheTotal=firstNumber+secondNumber;

document.write(firstNumber+"addedto"+secondNumber+

"equals"+theTotal);

</script>

</body>

</html>

However,ifyoutryoutthecode,you’lldiscoverthatitdoesn’twork.Whynot?Changethecodesothatitdoeswork.

3DecisionsandLoopsWHATYOUWILLLEARNINTHISCHAPTER:

Comparingnumberandstringvalues

Makingdecisionswiththeif,else,andswitchstatements

Repeatingcodeforaslongasaconditionistrue

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Sofar,you’veseenhowtouseJavaScripttogetuserinput,performcalculationsandtaskswiththatinput,andwritetheresultstoawebpage.However,apocketcalculatorcandoallthis,sowhatisitthatmakescomputersdifferent?Thatistosay,whatgivescomputerstheappearanceofhavingintelligence?Theansweristhecapabilitytomakedecisionsbasedoninformationgathered.

Howwilldecision-makinghelpyouincreatingwebsites?IntheprecedingchapteryouwrotesomecodethatconvertedtemperatureindegreesFahrenheittocentigrade.YouobtainedthedegreesFahrenheitfromtheuserusingtheprompt()function.Thisworkedfineiftheuserenteredavalidnumber,suchas50.If,however,theuserenteredsomethinginvalidfortheFahrenheittemperature,suchasthestringaaa,youwouldfindthatyourcodenolongerworksasexpected.Now,ifyouhadsomedecision-makingcapabilitiesinyourprogram,youcouldchecktoseeifwhattheuserhasenteredisvalid.Ifitis,youcandothecalculation,andifitisn’t,youcantelltheuserwhyandaskhimtoenteravalidnumber.

ValidationofuserinputisprobablyoneofthemostcommonusesofdecisionmakinginJavaScript,butit’sfarfrombeingtheonlyuse.

InthischapteryoulookathowdecisionmakingisimplementedinJavaScriptandhowyoucanuseittomakeyourcodesmarter.

DECISIONMAKING—THEIFANDSWITCHSTATEMENTSAllprogramminglanguagesenableyoutomakedecisions—thatis,theyenabletheprogramtofollowacertaincourseofactiondependingonwhetheraparticularconditionismet.Thisiswhatgivesprogramminglanguagestheirintelligence.

Conditionsarecomparisonsbetweenvariablesanddata,suchasthefollowing:

IsAbiggerthanB?

IsXequaltoY?

IsMnotequaltoN?

Forexample,ifthevariabletodayheldthedayoftheweekonwhichyouarereadingthischapter,theconditionwouldbethis:

IstodayequaltoFriday?

You’llnoticethatallofthesequestionshaveayesornoanswer—thatis,theyareboolean-basedandcanonlyevaluatetotrueorfalse.Howdoyouusethistocreatedecision-makingcapabilitiesinyourcode?Yougetthebrowsertotestforwhethertheconditionistrue.If(andonlyif)itistrue,youexecuteaparticularsectionofcode.

Lookatanotherexample.RecallfromChapter1thenaturalEnglishinstructionsusedtodemonstratehowcodeflows.Oneoftheseinstructionsformakingacupofcoffeeis:

Hasthekettleboiled?Ifso,thenpourwaterintocup;otherwise,continuetowait.

Thisisanexampleofmakingadecision.Theconditioninthisinstructionis“Hasthekettleboiled?”Ithasatrueorfalseanswer.Iftheansweristrue,youpourthewaterintothecup.Ifitisn’ttrue,youcontinuetowait.

InJavaScript,youcanchangetheflowofthecode’sexecutiondependingonwhetheraconditionistrueorfalse,usinganifstatementoraswitchstatement.Youlookattheseshortly,butfirstweneedtointroducesomenewoperatorsthatareessentialforthedefinitionofconditions—comparisonoperators.

ComparisonOperatorsInChapter2yousawhowmathematicalfunctions,suchasadditionanddivision,wererepresentedbysymbols,suchasplus(+)andforwardslash(/),calledoperators.Youalsosawthatifyouwanttogiveavariableavalue,youcanassigntoitavalueortheresultofacalculationusingtheequalssign(=),termedtheassignmentoperator.

Decisionmakingalsohasitsownoperators,whichenableyoutotestconditions.Comparisonoperators,justlikethemathematicaloperatorsyousawintheprecedingchapter,havealeft-handside(LHS)andaright-handside(RHS),andthecomparisonis

madebetweenthetwo.Thetechnicaltermsforthesearetheleftoperandandtherightoperand.Forexample,theless-thanoperator,withthesymbol<,isacomparisonoperator.Youcouldwrite23<45,whichtranslatesas“Is23lessthan45?”Here,theanswerwouldbetrue(seeFigure3.1).

Figure3.1

Othercomparisonoperatorsexist,themoreusefulofwhicharesummarizedinthefollowingtable:

OPERATORSYMBOL PURPOSE== TestsifLHSisequaltoRHS< TestsifLHSislessthanRHS> TestsifLHSisgreaterthanRHS<= TestsifLHSislessthanorequaltoRHS>= TestsifLHSisgreaterthanorequaltoRHS!= TestsifLHSisnotequaltoRHS

Youseethesecomparisonoperatorsinuseinthenextsectionwhenyoulookattheifstatement.

PrecedenceRecallfromChapter2thatoperatorshaveanorderofprecedence.Thisappliesalsotothecomparisonoperators.The==and!=comparisonoperatorshavethelowestorderofprecedence,andtherestofthecomparisonoperators,<,>,<=,and>=,haveanequalprecedence.

Allofthesecomparisonoperatorshaveaprecedencethatisbelowarithmeticoperators,suchas+,−,*,and/.Thismeansthatifyoumakeacomparisonsuchas3*5>2*5,themultiplicationcalculationsareworkedoutfirst,beforetheirresultsarecompared.However,inthesecircumstances,it’sbothsaferandclearerifyouwrapthecalculationsoneithersideinsideparentheses;forexample,(3*5)>(2*5).Asageneralrule,it’sagoodideatouseparenthesestoensurethattheprecedenceisclear,oryoumayfindyourselfsurprisedbytheoutcome.

AssignmentversusComparisonOneveryimportantpointtomentionistheeasewithwhichtheassignmentoperator(=)

andthecomparisonoperator(==)canbemixedup.Rememberthatthe=operatorassignsavaluetoavariableandthatthe==operatorcomparesthevalueoftwovariables.Evenwhenyouhavethisideaclear,it’samazinglyeasytoputoneequalssignwhereyoumeanttoputtwo.

AssigningtheResultsofComparisonsYoucanstoretheresultsofacomparisoninavariable,asshowninthefollowingexample:

varage=prompt("Enterage:","");

varisOverSixty=parseInt(age,10)>60;

document.write("Olderthan60:"+isOverSixty);

Hereyouobtaintheuser’sageusingtheprompt()function.Thisreturns,asastring,whatevervaluetheuserenters.YouthenconvertthattoanumberusingtheparseInt()functionyousawinthepreviouschapterandusethegreater-thanoperatortoseeifit’sgreaterthan60.Theresult(eithertrueorfalse)ofthecomparisonwillbestoredinthevariableisOverSixty.

Iftheuserenters35,thedocument.write()onthefinallinewillwritethistothepage:

Olderthan60:false

Iftheuserenters61,thiswillbedisplayed:

Olderthan60:true

TheifStatementTheifstatementisoneyou’llfindyourselfusinginalmosteveryprogramthatismorethanacoupleoflineslong.ItworksverymuchasitdoesintheEnglishlanguage.Forexample,youmightsayinEnglish,“Iftheroomtemperatureismorethan80degreesFahrenheit,thenI’llturntheairconditioningon.”InJavaScript,thiswouldtranslateintosomethinglikethis:

if(roomTemperature>80){

roomTemperature=roomTemperature–10;

}

Howdoesthiswork?SeeFigure3.2.

Figure3.2

Noticethatthetestconditionisplacedinparenthesesandfollowstheifkeyword.Also,

notethatthereisnosemicolonattheendofthisline.Thecodetobeexecutediftheconditionistrueisplacedincurlybracesonthelineafterthecondition,andeachoftheselinesofcodedoesendwithasemicolon.

Thecurlybraces,{},haveaspecialpurposeinJavaScript:Theymarkoutablockofcode.MarkingoutlinesofcodeasbelongingtoasingleblockmeansthatJavaScriptwilltreatthemallasonepieceofcode.Iftheconditionofanifstatementistrue,JavaScriptexecutesthenextlineorblockofcodefollowingtheifstatement.Intheprecedingexample,theblockofcodehasonlyonestatement,sowecouldequallyaswellhavewrittenthis:

if(roomTemperature>80)

roomTemperature=roomTemperature–10;

However,ifyouhaveanumberoflinesofcodethatyouwanttoexecute,youneedthebracestomarkthemoutasasingleblockofcode.Forexample,amodifiedversionoftheexamplewiththreestatementsofcodewouldhavetoincludethebraces:

if(roomTemperature>80){

roomTemperature=roomTemperature–10;

alert("It'sgettinghotinhere");

alert("Airconditioningswitchedon");

}

Aparticularlyeasymistaketomakeistoforgetthebraceswhenmarkingoutablockofcodetobeexecuted.Insteadofthecodeintheblockbeingexecutedwhentheconditionistrue,you’llfindthatonlythefirstlineaftertheifstatementisexecuted.However,theotherlineswillalwaysbeexecutedregardlessoftheoutcomeofthetestcondition.Toavoidmistakeslikethese,it’sagoodideatoalwaysusebraces,evenwherethereisonlyonestatement.Ifyougetintothishabit,you’llbelesslikelytoleavethemoutwhentheyareactuallyneeded.

TRYITOUTTheifStatementLet’sreturntothetemperatureconverterexamplefromChapter2andaddsomedecision-makingfunctionality.

1. Enterthefollowingcodeandsaveitasch3_example1.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter3,Example1</title>

</head>

<body>

<script>

vardegFahren=parseInt(prompt("Enterthedegrees

Fahrenheit",32),10);

vardegCent=5/9*(degFahren-32);

document.write(degFahren+"\xB0Fahrenheitis"+degCent

+

"\xB0centigrade<br/>");

if(degCent<0){

document.write("That'sbelowthefreezingpointof

water");

}

if(degCent==100)

document.write("That'stheboilingpointofwater");

</script>

</body>

</html>

2. Loadthepageintoyourbrowserandenter32intothepromptboxfortheFahrenheitvaluetobeconverted.Withavalueof32,neitheroftheifstatement’sconditionswillbetrue,sotheonlylinewritteninthepagewillbethatshowninFigure3.3.

Figure3.3

3. Nowreloadthepageandenter31fortheFahrenheitvalue.Thistimeyou’llseetwolinesinthepage,asshowninFigure3.4.

Figure3.4

4. Finally,reloadthepageagain,butthistime,enter212inthepromptbox.ThetwolinesshowninFigure3.5willappearinthepage.

Figure3.5

Thefirstpartofthescriptblockinthispageissimilartotheexamplech2_example4.htmlinChapter2.Youdeclaretwovariables,degFahrenanddegCent.ThevariabledegFahrenisgivenaninitialvalueobtainedfromtheuserwiththeprompt()function.Notetheprompt()functionreturnsastringvalue,whichyouthenconverttoanumericvalueusingtheparseInt()function.ThevariabledegCentisinitializedtotheresultofthecalculation5/9*(degFahren-32),whichisthe

Fahrenheit-to-centigradeconversioncalculation:

vardegFahren=parseInt(prompt("EnterthedegreesFahrenheit",32),

10);

vardegCent=5/9*(degFahren-32);

Thenyouwritetheresultofyourcalculationtothepage:

document.write(degFahren+"\xB0Fahrenheitis"+degCent+

"\xB0centigrade<br/>");

Nowcomesthenewcode;thefirstoftwoifstatements:

if(degCent<0){

document.write("That'sbelowthefreezingpointofwater");

}

Thisifstatementhastheconditionthatasks,“IsthevalueofthevariabledegCentlessthanzero?”Iftheanswerisyes(true),thecodeinsidethecurlybracesexecutes.Inthiscase,youwriteasentencetothepageusingdocument.write().Iftheanswerisno(false),theprocessingmovesontothenextlineaftertheclosingbrace.Alsoworthnotingisthefactthatthecodeinsidetheifstatement’sopeningbraceisindented.Thisisnotnecessary,butitisagoodpracticetogetintobecauseitmakesyourcodemucheasiertoread.

Whentryingouttheexample,youstartedbyentering32,sothatdegFahrenwillbeinitializedto32.InthiscasethecalculationdegCent=5/9*(degFahren−32)willsetdegCentto0.Sotheanswertothequestion“IsdegCentlessthanzero?”isfalse,becausedegCentisequaltozero,notlessthanzero.Thecodeinsidethecurlybraceswillbeskippedandneverexecuted.Inthiscase,thenextlinetobeexecutedwillbethesecondifstatement’scondition,whichwe’lldiscussshortly.

Whenyouentered31inthepromptbox,degFahrenwassetto31,sothevariabledegCentwillbe−0.55555555556.Sohowdoesyourifstatementlooknow?Itevaluatesto“Is–0.55555555556lessthanzero?”Theanswerthistimeistrue,andthecodeinsidethebraces,herejustadocument.write()statement,executes.

Finally,whenyouentered212,howdidthisaltertheifstatement?ThevariabledegCentissetto100bythecalculation,sotheifstatementnowasksthequestion,“Is100lessthanzero?”Theanswerisfalse,andthecodeinsidethebraceswillbeskippedover.

Inthesecondifstatement,youevaluatethecondition“IsthevalueofvariabledegCentequalto100?”:

if(degCent==100)

document.write("That'stheboilingpointofwater");

Therearenobraceshere,soiftheconditionistrue,theonlycodetoexecuteisthefirstlinebelowtheifstatement.Whenyouwanttoexecutemultiplelinesinthecaseoftheconditionbeingtrue,bracesarerequired.

YousawthatwhendegFahrenis32,degCentwillbe0.Soyourifstatementwillbe

“Is0equalto100?”Theanswerisclearlyfalse,andthecodewon’texecute.Again,whenyousetdegFahrento31,degCentwillbecalculatedtobe-0.55555555556;“Is–0.55555555556equalto100?”isalsofalse,andthecodewon’texecute.

Finally,whendegFahrenissetto212,degCentwillbe100.Thistimetheifstatementis“Is100equalto100?”andtheansweristrue,sothedocument.write()statementexecutes.

Asyouhaveseenalready,oneofthemostcommonerrorsinJavaScript,evenforexperts,isusingoneequalssignforevaluating,ratherthanthenecessarytwo.Takealookatthefollowingcodeextract:

if(degCent=100)

document.write("That'stheboilingpointofwater");

Thisconditionwillalwaysevaluatetotrue,andthecodebelowtheifstatementwillalwaysexecute.Worsestill,yourvariabledegCentwillbesetto100.Why?Becauseasingleequalssignassignsvaluestoavariable;onlyadoubleequalssigncomparesvalues.Thereasonanassignmentalwaysevaluatestotrueisthattheresultoftheassignmentexpressionisthevalueoftheright-handsideexpressionandthisisthenumber100,whichisthenimplicitlyconvertedtoabooleanandanynumberbesides0andNaNconvertstotrue.

LogicalOperatorsYoushouldhaveageneralideaofhowtouseconditionsinifstatementsnow,buthowdoyouuseaconditionsuchas“IsdegFahrengreaterthanzerobutlessthan100?”Youhavetwoconditionstotesthere.YouneedtotestwhetherdegFahrenisgreaterthanzeroandwhetherdegFahrenislessthan100.

JavaScriptenablesyoutousesuchmultipleconditions.Todothis,youneedtolearnaboutthreemoreoperators:thelogicaloperatorsAND,OR,andNOT.Thesymbolsforthesearelistedinthefollowingtable:

OPERATOR SYMBOLAND &&

OR ||

NOT !

NoticethattheANDandORoperatorsaretwosymbolsrepeated:&&and||.Ifyoutypejustonesymbol,&or|,strangethingswillhappenbecausethesearespecialoperatorscalledbitwiseoperatorsusedinbinaryoperations—forlogicaloperationsyoumustalwaysusetwo.

Afteryou’velearnedaboutthethreelogicaloperators,youtakealookathowtousetheminifstatements,withplentyofpracticalexamples.Soifitseemsabitconfusingonfirstread,don’tpanic.Allwillbecomeclear.Let’slookathoweachoftheseworks,startingwiththeANDoperator.

ANDRecallthatwetalkedabouttheleft-handside(LHS)andtheright-handside(RHS)oftheoperator.ThesameistruewiththeANDoperator.However,nowtheLHSandRHSoftheconditionarebooleanvalues(usuallytheresultofacondition).

TheANDoperatorworksverymuchasitdoesinEnglish.Forexample,youmightsay,“IfIfeelcoldandIhaveacoat,thenI’llputmycoaton.”Here,theleft-handsideofthe“and”wordis“DoIfeelcold?”andthiscanbeevaluatedastrueorfalse.Theright-handsideis“DoIhaveacoat?”whichagainisevaluatedtoeithertrueorfalse.Iftheleft-handsideistrue(Iamcold)andtheright-handsideistrue(Idohaveacoat),thenyouputyourcoaton.

ThisisverysimilartohowtheANDoperatorworksinJavaScript.TheANDoperatoractuallyproducesaresult,justasaddingtwonumbersproducesaresult.However,theANDoperatortakestwobooleanvalues(onitsLHSandRHS)andresultsinanotherbooleanvalue.IftheLHSandRHSconditionsevaluatetotrue,theresultwillbetrue.Inanyothercircumstance,theresultwillbefalse.

Followingisatruthtableofpossibleevaluationsofleft-handsidesandright-handsidesandtheresultwhenANDisused:

LEFT-HANDSIDE RIGHT-HANDSIDE RESULTtrue true true

false true false

true false false

false false false

Althoughthetableis,strictlyspeaking,true,it’sworthnotingthatJavaScriptdoesn’tlikedoingunnecessarywork.Well,whodoes!Iftheleft-handsideisfalse,eveniftheright-handsidedoesevaluatetotrue,itwon’tmakeanydifferencetothefinalresult—it’llstillbefalse.Sotoavoidwastingtime,iftheleft-handsideisfalse,JavaScriptdoesn’tevenbothercheckingtheright-handsideandjustreturnsaresultoffalse.

ORJustlikeAND,ORalsoworksmuchasitdoesinEnglish.Forexample,youmightsaythatifitisrainingorifitissnowing,thenyou’lltakeanumbrella.Ifeitheroftheconditions“itisraining”or“itissnowing”istrue,youwilltakeanumbrella.

Again,justlikeAND,theORoperatoractsontwobooleanvalues(onefromitsleft-handsideandonefromitsright-handside)andreturnsanotherbooleanvalue.Iftheleft-handsideevaluatestotrueortheright-handsideevaluatestotrue,theresultreturnedistrue.Otherwise,theresultisfalse.Thefollowingtableshowsthepossibleresults:

LEFT-HANDSIDE RIGHT-HANDSIDE RESULTtrue true true

false true true

true false true

false false false

AswiththeANDoperator,JavaScriptlikestoavoiddoingthingsthatmakenodifferencetothefinalresult.Iftheleft-handsideistrue,thenwhethertheright-handsideistrueorfalsemakesnodifferencetothefinalresult—it’llstillbetrue.So,toavoidwork,iftheleft-handsideistrue,theright-handsideisnotevaluated,andJavaScriptsimplyreturnstrue.Theendresultisthesame—theonlydifferenceisinhowJavaScriptarrivesattheconclusion.However,itdoesmeanyoushouldnotrelyontheright-handsideoftheORoperatortobeexecuted.

NOTInEnglish,wemightsay,“IfI’mnothot,thenI’lleatsoup.”Theconditionbeingevaluatediswhetherwe’rehot.Theresultistrueorfalse,butinthisexampleweact(eatsoup)iftheresultisfalse.

However,JavaScriptisusedtoexecutingcodeonlyifaconditionistrue.Soifyouwantafalseconditiontocausecodetoexecute,youneedtoswitchthatfalsevaluetotrue(andanytruevaluetofalse).ThatwayyoucantrickJavaScriptintoexecutingcodeafterafalsecondition.

YoudothisusingtheNOToperator.Thisoperatorreversesthelogicofaresult;ittakesonebooleanvalueandchangesittotheotherbooleanvalue.Soitchangestruetofalseandfalsetotrue.Thisissometimescallednegation.

TousetheNOToperator,youputtheconditionyouwantreversedinparenthesesandputthe!symbolinfrontoftheparentheses.Forexample:

if(!(degCent<100)){

//Somecode

}

AnycodewithinthebraceswillbeexecutedonlyiftheconditiondegCent<100isfalse.

ThefollowingtabledetailsthepossibleresultswhenusingNOT:

RIGHT-HANDSIDE RESULTtrue false

false true

MultipleConditionsInsideanifStatementTheprevioussectionstartedbyaskinghowyoucouldusethecondition“IsdegFahrengreaterthanzerobutlessthan100?”Onewayofdoingthiswouldbetousetwoifstatements,onenestedinsideanother.Nestedsimplymeansthatthereisanouterif

statement,andinsidethisisaninnerifstatement.Iftheconditionfortheouterifstatementistrue,then(andonlythen)willthenestedinnerifstatement’sconditionbetested.

Usingnestedifstatements,yourcodewouldbe:

if(degCent<100){

if(degCent>0){

document.write("degCentisbetween0and100");

}

}

Thiswouldwork,butit’salittleverboseandcanbequiteconfusing.JavaScriptoffersabetteralternative—usingmultipleconditionsinsidetheconditionpartoftheifstatement.Themultipleconditionsarestrungtogetherwiththelogicaloperatorsyoujustlookedat.Sotheprecedingcodecouldberewrittenlikethis:

if(degCent>0&&degCent<100){

document.write("degCentisbetween0and100");

}

Theifstatement’sconditionfirstevaluateswhetherdegCentisgreaterthanzero.Ifthatistrue,thecodegoesontoevaluatewhetherdegCentislessthan100.Onlyifbothoftheseconditionsaretruewillthedocument.write()codelineexecute.

TRYITOUTMultipleConditionsThisexampledemonstratesmulti-conditionifstatementsusingtheAND,OR,andNOToperators.Typethefollowingcode,andsaveitasch3 _ example2.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter3,Example2</title>

</head>

<body>

<script>

varmyAge=parseInt(prompt("Enteryourage",30),10);

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10<br/>");

}

if(!(myAge>=0&&myAge<=10)){

document.write("myAgeisNOTbetween0and10<br/>");

}

if(myAge>=80||myAge<=10){

document.write("myAgeis80oraboveOR10orbelow<br

/>");

}

if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=

89)){

document.write("myAgeisbetween30and39ormyAgeis"+

"between80and89");

}

</script>

</body>

</html>

Whenyouloaditintoyourbrowser,apromptboxshouldappear.Enterthevalue30,thenpressReturn,andthelinesshowninFigure3.6arewrittentothewebpage.

Figure3.6

ThescriptblockstartsbydefiningthevariablemyAgeandinitializingittothevalueenteredbytheuserinthepromptboxandconvertedtoanumber:

varmyAge=parseInt(prompt("Enteryourage",30),10);

Afterthisarefourifstatements,eachusingmultipleconditions.Youlookateachindetailinturn.

Theeasiestwaytoworkoutwhatmultipleconditionsaredoingistosplitthemupintosmallerpiecesandthenevaluatethecombinedresult.Inthisexampleyouhaveenteredthevalue30,whichhasbeenstoredinthevariablemyAge.You’llsubstitutethisvalueintotheconditionstoseehowtheywork.

Here’sthefirstifstatement:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10<br/>");

}

Thefirstifstatementisaskingthequestion,“IsmyAgebetween0and10?”You’ll

taketheLHSoftheconditionfirst,substitutingyourparticularvalueformyAge.TheLHSasks,“Is30greaterthanorequalto0?”Theansweristrue.ThequestionposedbytheRHSconditionis“Is30lessthanorequalto10?”Theanswerisfalse.Thesetwohalvesoftheconditionarejoinedusing&&,whichindicatestheANDoperator.UsingtheANDresultstableshownearlier,youcanseethatifLHSistrueandRHSisfalse,youhaveanoverallresultoffalse.Sotheendresultoftheconditionfortheifstatementisfalse,andthecodeinsidethebraceswon’texecute.

Let’smoveontothesecondifstatement:

if(!(myAge>=0&&myAge<=10)){

document.write("myAgeisNOTbetween0and10<br/>");

}

Thesecondifstatementisposingthequestion,“IsmyAgenotbetween0and10?”Itsconditionissimilartothatofthefirstifstatement,butwithonesmalldifference:YouhaveenclosedtheconditioninsideparenthesesandputtheNOToperator(!)infront.

Thepartoftheconditioninsidetheparenthesesisevaluatedand,asbefore,producesthesameresult—false.However,theNOToperatorreversestheresultandmakesittrue.Becausetheifstatement’sconditionistrue,thecodeinsidethebraceswillexecutethistime,causingadocument.write()towritearesponsetothepage.

Whataboutthethirdifstatement?

if(myAge>=80||myAge<=10){

document.write("myAgeis80oraboveOR10orbelow<br/>");

}

Thethirdifstatementasks,“IsmyAgegreaterthanorequalto80,orlessthanorequalto10?”TakingtheLHSconditionfirst—“Is30greaterthanorequalto80?”—theanswerisfalse.TheanswertotheRHScondition—“Is30lessthanorequalto10?”—isagainfalse.Thesetwohalvesoftheconditionarecombinedusing| |,whichindicatestheORoperator.LookingattheORresulttableearlierinthissection,youseethatfalseORfalseproducesaresultoffalse.Soagaintheifstatement’sconditionevaluatestofalse,andthecodewithinthecurlybracesdoesnotexecute.

Thefinalifstatementisalittlemorecomplex:

if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)){

document.write("myAgeisbetween30and39ormyAgeisbetween80

and89");

}

Itasksthequestion,“IsmyAgebetween30and39orbetween80and89?”Let’sbreakdowntheconditionintoitscomponentparts.Thereisaleft-hand-sideandaright-hand-sidecondition,combinedbymeansofanORoperator.However,theLHSandRHSthemselveshaveanLHSandRHSeach,whicharecombinedusingANDoperators.NoticehowparenthesesareusedtotellJavaScriptwhichpartsoftheconditiontoevaluatefirst,justasyouwoulddowithnumbersinamathematicalcalculation.

Let’slookattheLHSoftheconditionfirst,namely(myAge>=30&&myAge<=39).Byputtingtheconditionintoparentheses,youensurethatit’streatedasasinglecondition;nomatterhowmanyconditionsareinsidetheparentheses,itonlyproducesasingleresult,eithertrueorfalse.Breakingdowntheconditionsintheparentheses,youhave“Is30greaterthanorequalto30?”witharesultoftrue,and“Is30lessthanorequalto39?”againwitharesultoftrue.FromtheANDtable,youknowtrueANDtrueproducesaresultoftrue.

Nowlet’slookattheRHSofthecondition,namely(myAge>=80&&myAge<=89).Againbreakingdownthecondition,youseethattheLHSasks,“Is30greaterthanorequalto80?”whichgivesafalseresult,andtheRHSasks,“Is30lessthanorequalto89?”whichgivesatrueresult.YouknowthatfalseANDtruegivesafalseresult.

Nowyoucanthinkofyourifstatement’sconditionaslookinglike(true| |false).LookingattheORresultstable,youcanseethattrueORfalsegivesaresultoftrue,sothecodewithinthebracesfollowingtheifstatementwillexecute,andalinewillbewrittentothepage.

However,rememberthatJavaScriptdoesnotevaluateconditionswheretheywon’taffectthefinalresult,andtheprecedingconditionisoneofthosesituations.TheLHSoftheconditionevaluatedtotrue.Afterthat,itdoesnotmatteriftheRHSoftheconditionistrueorfalsebecauseonlyoneoftheconditionsinanORoperationneedstobetrueforaresultoftrue.ThusJavaScriptdoesnotactuallyevaluatetheRHSofthecondition.Wedidsosimplyfordemonstrationpurposes.

Asyouhaveseen,theeasiestwaytoapproachunderstandingorcreatingmultipleconditionsistobreakthemdownintothesmallestlogicalchunks.You’llfindthatwithexperience,youwilldothisalmostwithoutthinking,unlessyouhaveaparticularlytrickyconditiontoevaluate.

Althoughusingmultipleconditionsisoftenbetterthanusingmultipleifstatements,sometimesitmakesyourcodehardertoreadandthereforehardertounderstandanddebug.It’spossibletohave10,20,ormorethan100conditionsinsideyourifstatement,butcanyouimaginetryingtoreadanifstatementwitheven10conditions?Ifyoufeelthatyourmultipleconditionsaregettingtoocomplex,breakthemdownintosmallerlogicalchunks.

Forexample,imagineyouwanttoexecutesomecodeifmyAgeisintheranges30–39,80–89,or100–115,usingdifferentcodeineachcase.Youcouldwritethestatementlikeso:

if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)||

(myAge>=100&&myAge<=115)){

document.write("myAgeisbetween30and39"+

"ormyAgeisbetween80"+

"and89ormyAgeisbetween100and115");

}

There’snothingwrongwiththis,butitisstartingtogetalittlelonganddifficulttoread.Instead,youcouldcreateanotherifstatementforthecodeexecutedforthe

100–115range.

elseandelseifImagineasituationwhereyouwantsomecodetoexecuteifacertainconditionistrueandsomeothercodetoexecuteifitisfalse.Youcanachievethisbyhavingtwoifstatements,asshowninthefollowingexample:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10");

}

if(!(myAge>=0&&myAge<=10)){

document.write("myAgeisNOTbetween0and10");

}

ThefirstifstatementtestswhethermyAgeisbetween0and10,andthesecondforthesituationwheremyAgeisnotbetween0and10.However,JavaScriptprovidesaneasierwayofachievingthis:withanelsestatement.Again,theuseofthewordelseissimilartoitsuseintheEnglishlanguage.Youmightsay,“Ifitisraining,Iwilltakeanumbrella;otherwiseIwilltakeasunhat.”InJavaScriptyoucansayiftheconditionistrue,thenexecuteoneblockofcode;elseexecuteanalternativeblock.Rewritingtheprecedingcodeusingthistechnique,youwouldhavethefollowing:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10");

}else{

document.write("myAgeisNOTbetween0and10");

}

Writingthecodelikethismakesitsimplerandthereforeeasiertoread.PlusitalsosavesJavaScriptfromtestingaconditiontowhichyoualreadyknowtheanswer.

Youcouldalsoincludeanotherifstatementwiththeelsestatement.Forexample:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10");

}elseif((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)){

document.write("myAgeisbetween30and39"+

"ormyAgeisbetween80and89");

}else{

document.write("myAgeisNOTbetween0and10,"+

"norisitbetween30and39,nor"+

"isitbetween80and89");

}

ThefirstifstatementcheckswhethermyAgeisbetween0and10andexecutessomecodeifthat’strue.Ifit’sfalse,anelseifstatementchecksifmyAgeisbetween30and39or80and89,andexecutessomeothercodeifeitherofthoseconditionsistrue.Failingthat,youhaveafinalelsestatement,whichcatchesthesituationinwhichthevalueofmyAgedidnottriggertrueinanyoftheearlierifconditions.

Whenusingifandelseif,youneedtobeextracarefulwithyourcurlybracestoensurethattheifandelseifstatementsstartandstopwhereyouexpect,andyoudon’tendupwithanelsethatdoesn’tbelongtotherightif.Thisisquitetrickytodescribewithwords—it’seasiertoseewhatwemeanwithanexample:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10");

if(myAge==5){

document.write("You're5yearsold");

}

}else{

document.write("myAgeisNOTbetween0and10");

}

Noticethatwehaven’tindentedthecode.AlthoughthisdoesnotmattertoJavaScript,itdoesmakethecodemoredifficultforhumanstoreadandhidesthemissingcurlybracethatshouldbebeforethefinalelsestatement.

Correctlyformattedandwiththemissingbracketinserted,thecodelookslikethis:

if(myAge>=0&&myAge<=10){

document.write("myAgeisbetween0and10<br/>");

if(myAge==5){

document.write("You're5yearsold");

}

}else{

document.write("myAgeisNOTbetween0and10");

}

Asyoucansee,thecodeisworkingnow;itisalsoaloteasiertoseewhichcodeispartofwhichifblock.

ComparingStringsUptothispoint,youhavebeenlookingexclusivelyatusingcomparisonoperatorswithnumbers.However,theyworkjustaswellwithstrings.Allthat’sbeensaidanddonewithnumbersappliestostrings,butwithoneimportantdifference.Youarenowcomparingdataalphabeticallyratherthannumerically,soyouhaveafewtrapstowatchoutfor.

Inthefollowingcode,youcomparethevariablemyName,whichcontainsthestring"Paul",withthestringliteral"Paul":

varmyName="Paul";

if(myName=="Paul"){

alert("myNameisPaul");

}

HowdoesJavaScriptdealwiththis?Well,itgoesthrougheachletterinturnontheLHSandchecksitwiththeletterinthesamepositionontheRHStoseeifit’sactuallythesame.Ifatanypointitfindsadifference,itstops,andtheresultisfalse.If,afterhavingcheckedeachletterinturnallthewaytotheend,itconfirmsthattheyareallthesame,itreturnstrue.Theconditionintheprecedingifstatementwillreturntrue,soyou’llseeanalertbox.

However,stringcomparisoninJavaScriptiscasesensitive.So"P"isnotthesameas"p".Takingtheprecedingexample,butchangingthevariablemyNameto"paul",youfindthattheconditionisfalseandthecodeinsidetheifstatementdoesnotexecute:

varmyName="paul";

if(myName=="Paul"){

alert("myNameisPaul");

}

The>=,>,<=,and<operatorsworkwithstringsaswellaswithnumbers,butagainitisanalphabeticalcomparison.So"A"<"B"istrue,becauseAcomesbeforeBinthealphabet.However,JavaScript’scasesensitivitycomesintoplayagain."A"<"B"istrue,but"a"<"B"isfalse.Why?Becauseuppercaselettersaretreatedasalwayscomingbeforelowercaseletters.Whyisthis?EachletterhasacodenumberintheASCIIandUnicodecharactersets,andthecodenumbersforuppercaselettersarelowerthanthecodenumbersforlowercaseletters.Thisissomethingtowatchoutforwhenwritingyourowncode.

Thesimplestwaytoavoidconfusionwithdifferentcasesistoconvertbothstringstoeitheruppercaseorlowercasebeforeyoucomparethem.YoucandothiseasilyusingthetoUpperCase()ortoLowerCase()function,whichyoulearnaboutinChapter5.

TheswitchStatementYousawearlierhowtheifandelseifstatementscouldbeusedforcheckingvariousconditions;ifthefirstconditionisnotvalid,thenanotherischecked,andanother,andsoon.However,whenyouwanttocheckthevalueofaparticularvariableforalargenumberofpossiblevalues,thereisamoreefficientalternative,namelytheswitchstatement.ThestructureoftheswitchstatementisgiveninFigure3.7.

Figure3.7

Thebestwaytothinkoftheswitchstatementis“Switchtothecodewherethecasematches.”Theswitchstatementhasfourimportantelements:

Thetestexpression

Thecasestatements

Thebreakstatements

Thedefaultstatement

Thetestexpressionisgivenintheparenthesesfollowingtheswitchkeyword.Inthepreviousexample,youaretestingusingthevariablemyName.Insidetheparentheses,however,youcouldhaveanyvalidexpression.

Nextcomethecasestatements.Thecasestatementsdotheconditionchecking.Toindicatewhichcasestatementsbelongtoyourswitchstatement,youmustputtheminsidethecurlybracesfollowingthetestexpression.Eachcasestatementspecifiesavalue,forexample"Paul".Thecasestatementthenactslikeif(myName=="Paul").IfthevariablemyNamedidcontainthevalue"Paul",executionwouldcommencefromthecodestartingbelowthecase"Paul"statementandwouldcontinuetotheendoftheswitchstatement.Thisexamplehasonlytwocasestatements,butyoucanhaveasmanyasyoulike.

Inmostcases,youwantonlytheblockofcodedirectlyunderneaththerelevantcasestatementtoexecute,notallthecodebelowtherelevantcasestatement,includinganyothercasestatements.Toachievethis,youputabreakstatementattheendofthecodethatyouwantexecuted.ThistellsJavaScripttostopexecutingatthatpointandleavetheswitchstatement.

Finally,youhavethedefaultcase,which(asthenamesuggests)isthecodethatwillexecutewhennoneoftheothercasestatementsmatch.Thedefaultstatementisoptional;ifyouhavenodefaultcodethatyouwanttoexecute,youcanleaveitout,butrememberthatinthiscasenocodewillexecuteifnocasestatementsmatch.Itisagoodideatoincludeadefaultcase,unlessyouareabsolutelysurethatyouhaveallyouroptionscovered.

TRYITOUTUsingtheswitchStatementLet’stakealookattheswitchstatementinaction.Thefollowingexampleillustratesasimpleguessinggame.Typethecodeandsaveitasch3_example3.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter3,Example3</title>

</head>

<body>

<script>

varsecretNumber=prompt("Pickanumberbetween1and5:",

"");

secretNumber=parseInt(secretNumber,10);

switch(secretNumber){

case1:

document.write("Toolow!");

break;

case2:

document.write("Toolow!");

break;

case3:

document.write("Youguessedthesecretnumber!");

break;

case4:

document.write("Toohigh!");

break;

case5:

document.write("Toohigh!");

break;

default:

document.write("Youdidnotenteranumberbetween1

and5.");

break;

}

document.write("<br/>Executioncontinueshere");

</script>

</body>

</html>

Loadthisintoyourbrowserandenter,forexample,thevalue1inthepromptbox.YoushouldthenseesomethinglikewhatisshowninFigure3.8.

Figure3.8

If,ontheotherhand,youenterthevalue3,youshouldseeafriendlymessagelettingyouknowthatyouguessedthesecretnumbercorrectly,asshowninFigure3.9.

Figure3.9

FirstyoudeclarethevariablesecretNumberandsetittothevalueenteredbytheuserviathepromptbox.NotethatyouusetheparseInt()functiontoconvertthestringthatisreturnedfromprompt()toanintegervalue:

varsecretNumber=prompt("Pickanumberbetween1and5:","");

secretNumber=parseInt(secretNumber,10);

Nextyoucreatethestartoftheswitchstatement:

switch(secretNumber){

TheexpressioninparenthesesissimplythevariablesecretNumber,andit’sthisnumberthatthecasestatementswillbecomparedagainst.

Youspecifytheblockofcodeencompassingthecasestatementsusingcurlybraces.Eachcasestatementchecksoneofthenumbersbetween1and5,becausethisiswhatyouhavespecifiedtotheuserthatsheshouldenter.Thefirstsimplyoutputsamessagethatthenumbershehasenteredistoolow:

case1:

document.write("Toolow!");

break;

Thesecondcasestatement,forthevalue2,hasthesamemessage,sothecodeisnotrepeatedhere.Thethirdcasestatementletstheuserknowthatshehasguessedcorrectly:

case3:

document.write("Youguessedthesecretnumber!");

break;

Finally,thefourthandfifthcasestatementsoutputamessagethatthenumbertheuser

hasenteredistoohigh:

case4:

document.write("Toohigh!");

break;

Youdoneedtoaddadefaultcaseinthisexample,becausetheusermightverywell(despitetheinstructions)enteranumberthatisnotbetween1and5,orevenperhapsaletter.Inthiscase,youaddamessagetolettheuserknowthatthereisaproblem:

default:

document.write("Youdidnotenteranumberbetween1and5.");

break;

Adefaultstatementisalsoveryusefulforpickingupbugs—ifyouhavecodedsomeofthecasestatementsincorrectly,youwillpickthatupveryquicklyifyouseethedefaultcodebeingrunwhenitshouldn’tbe.

Finally,youhaveaddedtheclosingbraceindicatingtheendoftheswitchstatement.Afterthisyououtputalinetoindicatewheretheexecutioncontinues:

}

document.write("<br/>Executioncontinueshere");

Notethateachcasestatementendswithabreakstatement.Thisisimportanttoensurethatexecutionofthecodemovestothelineaftertheendoftheswitchstatement.Ifyouforgettoincludethis,youcouldendupexecutingthecodeforeachcasefollowingthecasethatmatches.

ExecutingtheSameCodeforDifferentCasesYoumayhavespottedaproblemwiththeswitchstatementinthisexample—youwanttoexecutethesamecodeiftheuserentersa1ora2,andthesamecodefora4ora5.However,toachievethis,youhavehadtorepeatthecodeineachcase.WhatyouwantisaneasierwayofgettingJavaScripttoexecutethesamecodefordifferentcases.Well,that’seasy!Simplychangethecodesothatitlookslikethis:

switch(secretNumber){

case1:

case2:

document.write("Toolow!");

break;

case3:

document.write("Youguessedthesecretnumber!");

break;

case4:

case5:

document.write("Toohigh!");

break;

default:

document.write("Youdidnotenteranumberbetween1and5.");

break;

}

Ifyouloadthisintoyourbrowserandexperimentwithenteringsomedifferentnumbers,youshouldseethatitbehavesexactlylikethepreviouscode.

Here,youaremakinguseofthefactthatifthereisnobreakstatementunderneaththecodeforacertaincasestatement,executionwillcontinuethrougheachfollowingcasestatementuntilabreakstatementortheendoftheswitchisreached.Thinkofitasasortoffreefallthroughtheswitchstatementuntilyouhitthebreakstatement.

Ifthecasestatementforthevalue1ismatched,executionsimplycontinuesuntilthebreakstatementundercase2,soeffectivelyyoucanexecutethesamecodeforbothcases.Thesametechniqueisusedforthecasestatementswithvalues4and5.

LOOPING—THEFORANDWHILESTATEMENTSLoopingmeansrepeatingablockofcodewhenaconditionistrue.ThisisachievedinJavaScriptwiththeuseoftwostatements:thewhilestatementandtheforstatement.You’llbelookingattheseshortly,butwhywouldyouwanttorepeatblocksofcodeanyway?

Well,takethesituationwhereyouhaveaseriesofresults,saytheaveragetemperatureforeachmonthinayear,andyouwanttoplottheseonagraph.Thecodeneededforplottingeachpointwillmostlikelybethesame.So,ratherthanwritethecode12times(onceforeachpoint),it’smucheasiertoexecutethesamecode12timesbyusingthenextitemofdataintheseries.Thisiswheretheforstatementwouldcomeinhandy,becauseyouknowhowmanytimesyouwantthecodetoexecute.

Inanothersituation,youmightwanttorepeatthesamepieceofcodewhenacertainconditionistrue,forexample,whiletheuserkeepsclickingaStartAgainbutton.Inthissituation,thewhilestatementwouldbeveryuseful.

TheforLoopTheforstatementenablesyoutorepeatablockofcodeacertainnumberoftimes.ThesyntaxisillustratedinFigure3.10.

Figure3.10

Let’slookatthemakeupofaforstatement.YoucanseefromFigure3.10that,justliketheifandswitchstatements,theforstatementalsohasitslogicinsideparentheses.However,thistimethatlogicissplitintothreeparts,eachpartseparatedbyasemicolon.Forexample,inFigure3.10youhavethefollowing:

(varloopCounter=1;loopCounter<=3;loopCounter++)

Thefirstpartoftheforstatement’slogicistheinitializationpartoftheforstatement.Tokeeptrackofhowmanytimesyouhaveloopedthroughthecode,youneedavariabletokeepcount.It’sintheinitializationpartthatyouinitializevariables.Intheexample,you

havedeclaredloopCounterandsetittothevalueof1.Thispartisonlyexecutedonceduringtheexecutionoftheloops,unliketheotherparts.Youdon’tneedtodeclarethevariableifitwasdeclaredearlierinthecode:

varloopCounter;

for(loopCounter=1;loopCounter<=3;loopCounter++)

Followingthesemicolon,youhavethetestconditionpartoftheforstatement.Thecodeinsidetheforstatementwillkeepexecutingforaslongasthistestconditionevaluatestotrue.Afterthecodeisloopedthrougheachtime,thisconditionistested.InFigure3.10,youexecuteforaslongasloopCounterislessthanorequalto3.Thenumberoftimesaloopisperformedisoftencalledthenumberofiterations.

Finally,youhavetheincrementpartoftheforloop,wherevariablesinyourloop’stestconditionhavetheirvaluesincremented.HereyoucanseethatloopCounterisincrementedbyonebymeansofthe++operatoryousawinChapter2.Again,thispartoftheforstatementisrepeatedwitheveryloopofthecode.Althoughwecallittheincrementpart,itcanactuallybeusedtodecrease,ordecrement,thevalue—forexample,ifyouwantedtocountdownfromthetopelementinanarraytothefirst.

Aftertheforstatementcomestheblockofcodethatwillbeexecutedrepeatedly,aslongasthetestconditionistrue.Thisblockofcodeiscontainedwithincurlybraces.Iftheconditionisnevertrue,evenatthefirsttestoftheloopcondition,thecodeinsidetheforloopwillbeskippedoverandneverexecuted.

Puttingallthistogether,howdoestheforloopwork?

1. Executeinitializationpartoftheforstatement.

2. Checkthetestcondition.Iftrue,continue;ifnot,exittheforstatement.

3. Executecodeintheblockaftertheforstatement.

4. Executetheincrementpartoftheforstatement.

5. Repeatsteps2through4untilthetestconditionisfalse.

TRYITOUTConvertingaSeriesofFahrenheitValuesLet’schangethetemperatureconvertersothatitconvertsaseriesofvalues,storedinanarray,fromFahrenheittocentigrade.Youwillbeusingtheforstatementtogothrougheachelementofthearray.Typethefollowingcodeandsaveitasch3_example4.html:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter3,Example4</title>

</head>

<body>

<script>

vardegFahren=[212,32,-459.15];

vardegCent=[];

varloopCounter;

for(loopCounter=0;loopCounter<=2;loopCounter++){

degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);

}

for(loopCounter=2;loopCounter>=0;loopCounter−−){

document.write("Value"+loopCounter+

"was"+degFahren[loopCounter]+

"degreesFahrenheit");

document.write("whichis"+degCent[loopCounter]+

"degreescentigrade<br/>");

}

</script>

</body>

</html>

Onloadingthisintoyourbrowser,you’llseeaseriesofthreelinesinthepage,containingtheresultsofconvertingyourarrayofFahrenheitvaluesintocentigrade(asshowninFigure3.11).

Figure3.11

Thefirsttaskistodeclarethevariablesyouaregoingtouse.First,youdeclareandinitializedegFahrentocontainanarrayofthreevalues:212,32,and–459.15.Next,youdeclaredegCentasanemptyarray.Finally,youdeclareloopCounterandwilluseittokeeptrackofwhicharrayindexyouareaccessingduringyourlooping:

vardegFahren=[212,32,-459.15];

vardegCent=[];

varloopCounter;

Followingthiscomesyourfirstforloop:

for(loopCounter=0;loopCounter<=2;loopCounter++){

degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);

}

Inthefirstline,youstartbyinitializingtheloopCounterto0.Thentheforloop’stestcondition,loopCounter<=2,ischecked.Ifthisconditionistrue,theloopexecutesforthefirsttime.Afterthecodeinsidethecurlybraceshasexecuted,theincrementingpartoftheforloop,loopCounter++,willbeexecuted,andthenthetestconditionwillbere-evaluated.Ifit’sstilltrue,anotherexecutionoftheloopcodeisperformed.Thiscontinuesuntiltheforloop’stestconditionevaluatestofalse,atwhichpointloopingwillend,andthefirststatementaftertheclosingcurlybracewillbeexecuted.

Thecodeinsidethecurlybracesistheequationyousawinearlierexamples,onlythistimeyouareplacingitsresultintothedegCentarray,withtheindexbeingthevalueofloopCounter.

Inthesecondforloop,youwritetheresultscontainedinthedegCentarraytothescreen:

for(loopCounter=2;loopCounter>=0;loopCounter−−){

document.write("Value"+loopCounter+

"was"+degFahren[loopCounter]+

"degreesFahrenheit");

document.write("whichis"+degCent[loopCounter]+

"degreescentigrade<br/>");

}

Thistimeyou’recountingdownfrom2to0.ThevariableloopCounterisinitializedto2,andtheloopconditionremainstrueuntilloopCounterislessthan0.ThistimeloopCounterisactuallydecrementedeachtimeratherthanincremented,bymeansofloopCounter−−.Again,loopCounterisservingadualpurpose:Itkeepscountofhowmanyloopsyouhavedoneandalsoprovidestheindexpositioninthearray.

NOTEIntheseexamples,you’veusedwholenumbersinyourloops.However,thereisnoreasonwhyyoucan’tusefractionalnumbers,althoughit’smuchlesscommontodoso.

Thefor…inLoopThisloopenablesyoutoloopthrougheachelementinthearraywithouthavingtoknowhowmanyelementsthearrayactuallycontains.InplainEnglish,whatthisloopsaysis“Foreachelementinthearray,executesomecode.”Ratherthanhavingtoworkouttheindexnumberofeachelement,thefor… inloopdoesitforyouandautomaticallymoves

tothenextindexwitheachiteration(loopthrough).

Itssyntaxforusewitharraysis:

for(indexinarrayName){

//somecode

}

Inthiscodeextract,indexisavariableyoudeclarepriortotheloop,whichwillautomaticallybepopulatedwiththenextindexvalueinthearray.arrayNameisthenameofthevariableholdingthearrayyouwanttoloopthrough.

Let’slookatanexampletomakethingsclearer.Youdefineanarrayandinitializeitwiththreevalues:

varmyArray=["Paul","Paula","Pauline"];

Toaccesseachelementusingaconventionalforloop,you’dwritethis:

for(varloopCounter=0;loopCounter<3;loopCounter++){

document.write(myArray[loopCounter]);

}

Todoexactlythesamethingwiththefor… inloop,youwritethis:

for(varelementIndexinmyArray){

document.write(myArray[elementIndex]);

}

Asyoucansee,thecodeinthesecondexampleisalittleclearer,aswellasshorter.Bothmethodsworkequallywellandwilliteratethreetimes.However,ifyouincreasethesizeofthearray,forexample,byaddingtheelementmyArray[3]="Philip",thefirstmethodwillstilllooponlythroughthefirstthreeelementsinthearray,whereasthesecondmethodwillloopthroughallfourelements.

ThewhileLoopWhereastheforloopisusedforloopingacertainnumberoftimes,thewhileloopenablesyoutotestaconditionandkeeponloopingwhileit’strue.Theforloopisusefulwhenyouknowhowmanytimesyouneedtoloop;forexample,whenyouareloopingthroughanarraythatyouknowhasacertainnumberofelements.Thewhileloopismoreusefulwhenyoudon’tknowhowmanytimesyou’llneedtoloop.Forexample,ifyouareloopingthroughanarrayoftemperaturevaluesandwanttocontinueloopingwhenthetemperaturevaluecontainedinthearrayelementislessthan100,youwillneedtousethewhilestatement.

Let’stakealookatthestructureofthewhilestatement,asillustratedinFigure3.12.

Figure3.12

Youcanseethatthewhileloophasfewerpartstoitthantheforloop.Thewhileloopconsistsofaconditionwhich,ifitevaluatestotrue,causestheblockofcodeinsidethecurlybracestoexecuteonce;thentheconditionisre-evaluated.Ifit’sstilltrue,thecodeisexecutedagain,theconditionisre-evaluated,andsoonuntiltheconditionevaluatestofalse.

Onethingtowatchoutforisthatiftheconditionisfalsetostartwith,thewhileloopneverexecutes.Forexample:

vardegCent=100;

while(degCent!=100){

//somecode

}

Here,theloopwillrunifdegCentdoesnotequal100.However,becausedegCentis100,theconditionisfalse,andthecodeneverexecutes.

Inpracticeyouwouldnormallyexpectthelooptoexecuteonce;whetheritexecutesagainwilldependonwhatthecodeinsidetheloophasdonetovariablesinvolvedintheloop

condition.Forexample:

vardegCent=[];

degFahren=[34,123,212];

varloopCounter=0;

while(loopCounter<3){

degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);

loopCounter++;

}

TheloopwillexecutesolongasloopCounterislessthan3.It’sthecodeinsidetheloop(loopCounter++;)thatincrementsloopCounterandwilleventuallycauseloopCounter<3tobefalsesothattheloopstops.Executionwillthencontinueonthefirstlineaftertheclosingbraceofthewhilestatement.

Somethingtowatchoutforistheinfiniteloop—aloopthatwillneverend.SupposeyouforgottoincludetheloopCounter++;lineinthecode.LeavingthislineoutwouldmeanthatloopCounterwillremainat0,sothecondition(loopCounter<3)willalwaysbetrue,andtheloopwillcontinueuntiltheusergetsboredandcross,andshutsdownherbrowser.However,itisaneasymistaketomake,andonethatJavaScriptwon’twarnyouabout.

It’snotjustmissinglinesthatcancauseinfiniteloops,butalsomistakesinsidetheloop’scode.Forexample:

vartestVariable=0;

while(testVariable<=10){

alert("TestVariableis"+testVariable);

testVariable++;

if(testVariable=10){

alert("Thelastloop");

}

}

Seeifyoucanspotthedeliberatemistakethatleadstoaninfiniteloop—yes,it’stheifstatementthatwillcausethiscodetogoonforever.Insteadofusing==asthecomparisonoperatorintheconditionoftheifstatement,youput=,sotestVariableissetto10againineachloop,despitethelinetestVariable++.Thismeansthatatthestartofeachloop,thetestconditionalwaysevaluatestotrue,because10islessthanorequalto10.Puttheextra=intomakeif(testVariable==10),andeverythingisfine.

Thedo…whileloopWiththewhileloop,yousawthatthecodeinsidethelooponlyexecutesiftheconditionistrue;ifit’sfalse,thecodeneverexecutes,andexecutioninsteadmovestothefirstlineafterthewhileloop.However,theremaybetimeswhenyouwantthecodeinthewhilelooptoexecuteatleastonce,regardlessofwhethertheconditioninthewhilestatementevaluatestotrue.Itmightevenbethatsomecodeinsidethewhileloopneedstobeexecutedbeforeyoucantestthewhilestatement’scondition.It’ssituationslikethisfor

whichthedo… whileloopisideal.

Lookatanexampleinwhichyouwanttogettheuser’sageviaapromptbox.Youwanttoshowthepromptboxbutalsomakesurethatwhattheuserhasenteredisanumber:

varuserAge;

do{

userAge=prompt("Pleaseenteryourage","")

}while(isNaN(userAge)==true);

Thecodelinewithintheloop:

userAge=prompt("Pleaseenteryourage","")

willbeexecutedregardlessofthewhilestatement’scondition.Thisisbecausetheconditionisnotcheckeduntiloneloophasbeenexecuted.Iftheconditionistrue,thecodeisloopedthroughagain.Ifit’sfalse,loopingstops.

Notethatwithinthewhilestatement’scondition,youareusingtheisNaN()functionthatyousawinChapter2.ThischeckswhethertheuserAgevariable’svalueisNaN(NotaNumber).Ifitisnotanumber,theconditionreturnsavalueoftrue;otherwise,itreturnsfalse.Asyoucanseefromtheexample,itenablesyoutotesttheuserinputtoensuretherightdatahasbeenentered.Theusermightlieabouthisage,butatleastyouknowheenteredanumber!

Thedo… whileloopisfairlyrare;there’snotmuchyoucan’tdowithoutit,soit’sbestavoidedunlessreallynecessary.

ThebreakandcontinueStatementsYoumetthebreakstatementearlierwhenyoulookedattheswitchstatement.Itsfunctioninsideaswitchstatementistostopcodeexecutionandmoveexecutiontothenextlineofcodeaftertheclosingcurlybraceoftheswitchstatement.However,youcanalsousethebreakstatementaspartoftheforandwhileloopswhenyouwanttoexittheloopprematurely.Forexample,supposeyou’reloopingthroughanarray,asyoudidinthetemperatureconversionexample,andyouhitaninvalidvalue.Inthissituation,youmightwanttostopthecodeinitstracks,notifytheuserthatthedataisinvalid,andleavetheloop.Thisisonesituationwherethebreakstatementcomesinhandy.

Let’sseehowyoucouldchangetheexamplewhereyouconvertedaseriesofFahrenheitvalues(ch3_example4.html)sothatifyouhitavaluethat’snotanumberyoustoptheloopandlettheuserknowabouttheinvaliddata:

<script>

vardegFahren=[212,"stringdata",-459.67];

vardegCent=[];

varloopCounter;

for(loopCounter=0;loopCounter<=2;loopCounter++){

if(isNaN(degFahren[loopCounter])){

alert("Data'"+degFahren[loopCounter]+"'atarrayindex"+

loopCounter+"isinvalid");

break;

}

degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);

}

YouhavechangedtheinitializationofthedegFahrenarraysothatitnowcontainssomeinvaliddata.Then,insidetheforloop,youaddanifstatementtocheckwhetherthedatainthedegFahrenarrayisnotanumber.YoudothisbymeansoftheisNaN()function;itreturnstrueifthevaluepassedtoitintheparentheses,heredegFahren[loopCounter],isnotanumber.Ifthevalueisnotanumber,youtelltheuserwhereinthearrayyouhavetheinvaliddata.Thenyoubreakoutoftheforloopaltogether,usingthebreakstatement,andcodeexecutioncontinuesonthefirstlineaftertheendoftheforstatement.

That’sthebreakstatement,butwhataboutcontinue?Thecontinuestatementissimilartobreakinthatitstopstheexecutionofaloopatthepointwhereitisfound,butinsteadofleavingtheloop,itstartsexecutionatthenextiteration,startingwiththefororwhilestatement’sconditionbeingre-evaluated,justasifthelastlineoftheloop’scodehadbeenreached.

Inthebreakexample,itwasallornothing—ifevenonepieceofdatawasinvalid,youbrokeoutoftheloop.ItmightbebetterifyoutriedtoconvertallthevaluesindegFahren,butifyouhitaninvaliditemofdatainthearray,younotifytheuserandcontinuewiththenextitem,ratherthangivingupasthebreakstatementexampledoes:

if(isNaN(degFahren[loopCounter])){

alert("Data'"+degFahren[loopCounter]+"'atarrayindex"+

loopCounter+"isinvalid");

continue;

}

Justchangethebreakstatementtoacontinue.Youwillstillgetamessageabouttheinvaliddata,butthethirdvaluewillalsobeconverted.

SUMMARYInthischapteryoucontinuedyourlookatthecoreoftheJavaScriptlanguageanditssyntax.

Thechapterlookedatthefollowing:

Decisionmakingwiththeifandswitchstatements:Theabilitytomakedecisionsisessentiallywhatgivesthecodeits“intelligence.”Basedonwhetheraconditionistrueorfalse,youcandecideonacourseofactiontofollow.

Comparisonoperators:Thecomparisonoperatorscomparethevalueontheleftoftheoperator(left-handside,LHS)withthevalueontherightoftheoperator(right-handside,RHS)andreturnabooleanvalue.Hereisalistofthemaincomparisonoperators:

==means“istheLHSequaltotheRHS?”

!=means“istheLHSnotequaltotheRHS?”

<=means“istheLHSlessthanorequaltotheRHS?”

>=means“istheLHSgreaterthanorequaltotheRHS?”

<means“istheLHSlessthantheRHS?”

>means“istheLHSgreaterthantheRHS?”

Theifstatement:Usingtheifstatement,youcanchoosetoexecuteablockofcode(definedbybeingincurlybraces)whenaconditionistrue.Theifstatementhasatestcondition,specifiedinparentheses.Ifthisconditionevaluatestotrue,thecodeaftertheifstatementwillexecute.

Theelsestatement:Ifyouwantcodetoexecutewhentheifstatementisfalse,youcanusetheelsestatementthatappearsaftertheifstatement.

Logicaloperators:Tocombineconditions,youcanusethethreelogicaloperators:AND,OR,andNOT,representedby&&,||,and!,respectively:

TheANDoperatorreturnstrueonlyifbothsidesoftheexpressionaretrue.

TheORoperatorreturnstruewheneitheroneorbothsidesofanexpressionaretrue.

TheNOToperatorreversesthelogicofanexpression.

Theswitchstatement:Thiscomparestheresultofanexpressionwithaseriesofpossiblecasesandissimilarineffecttoamultipleifstatement.

Loopingwithfor,for… in,while,anddo… while:It’softennecessarytorepeatablockofcodeanumberoftimes,somethingJavaScriptenablesbylooping.

Theforloop:Usefulforloopingthroughcodeacertainnumberoftimes,theforloopconsistsofthreeparts:theinitialization,testcondition,andincrementparts.Loopingcontinueswhilethetestconditionistrue.Eachloopexecutesthe

blockofcodeandthenexecutestheincrementpartoftheforloopbeforere-evaluatingthetestconditiontoseeiftheresultsofincrementinghavechangedit.

Thefor… inloop:Thisisusefulwhenyouwanttoloopthroughanarraywithoutknowingthenumberofelementsinthearray.JavaScriptworksthisoutforyousothatnoelementsaremissed.

Thewhileloop:Thisisusefulforloopingthroughsomecodeforaslongasatestconditionremainstrue.Itconsistsofatestconditionandtheblockofcodethat’sexecutedonlyiftheconditionistrue.Iftheconditionisnevertrue,thecodeneverexecutes.

Thedo… whileloop:Thisissimilartoawhileloop,exceptthatitexecutesthecodeonceandthenkeepsexecutingthecodeaslongasthetestconditionremainstrue.

breakandcontinuestatements:Sometimesyouhaveagoodreasontobreakoutofaloopprematurely,inwhichcaseyouneedtousethebreakstatement.Onhittingabreakstatement,codeexecutionstopsfortheblockofcodemarkedoutbythecurlybracesandstartsimmediatelyaftertheclosingbrace.Thecontinuestatementissimilartobreak,exceptthatwhencodeexecutionstopsatthatpointintheloop,theloopisnotbrokenoutofbutinsteadcontinuesasiftheendofthatreiterationhadbeenreached.

EXERCISES1. Ajuniorprogrammercomestoyouwithsomecodethatappearsnottowork.Can

youspotwherehewentwrong?Givehimahandandcorrectthemistakes.

varuserAge=prompt("Pleaseenteryourage");

if(userAge=0){;

alert("Soyou'reababy!");

}elseif(userAge<0|userAge>200)

alert("Ithinkyoumaybelyingaboutyourage");

else{

alert("That'sagoodage");

}

2. Usingdocument.write(),writecodethatdisplaystheresultsofthe12timestable.Itsoutputshouldbetheresultsofthecalculations.

12*1=12

12*2=24

12*3=36…

12*11=132

12*12=144

4FunctionsandScopeWHATYOUWILLLEARNINTHISCHAPTER:

Creatingyourownfunctions

Identifying,creating,andusingglobalandlocalvariables

Usingfunctionsasavalue

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Afunctionissomethingthatperformsaparticulartask.Takeapocketcalculatorasanexample.Itperformslotsofbasiccalculations,suchasadditionandsubtraction.However,manyalsohavefunctionkeysthatperformmorecomplexoperations.Forexample,somecalculatorshaveabuttonforcalculatingthesquarerootofanumber,andothersevenprovidestatisticalfunctions,suchasthecalculationofanaverage.Mostofthesefunctionscouldbedonewiththebasicmathematicaloperationsofadd,subtract,multiply,anddivide,butthatmighttakealotofsteps—it’smuchsimplerfortheuserifsheonlyneedstopressonebutton.Allsheneedstodoisprovidethedata—numbersinthiscase—andthefunctionkeydoestherest.

FunctionsinJavaScriptworkalittlelikethefunctionbuttonsonapocketcalculator:Theyencapsulateablockofcodethatperformsacertaintask.Overthecourseofthebooksofar,youhavecomeacrossanumberofhandybuilt-infunctionsthatperformacertaintask,suchastheparseInt()andparseFloat()functions,whichconvertstringstonumbers,andtheisNaN()function,whichtellsyouwhetheraparticularvaluecanbeconvertedtoanumber.Someofthesefunctionsreturndata,suchasparseInt(),whichreturnsanintegernumber;otherssimplyperformanactionbutreturnnodata.You’llalsonoticethatsomefunctionscanbepasseddata,whereasotherscannot.Forexample,theisNaN()functionneedstobepassedsomedata,whichitcheckstoseeifitisNaN.Thedatathatafunctionrequirestobepassedareknownasitsparameter(s).

Asyouworkyourwaythroughthebook,you’llbecomingacrossmanymoreusefulbuilt-infunctions,butwouldn’titbegreattobeabletowriteyourownfunctions?Afteryou’veworkedout,written,anddebuggedablockofcodetoperformacertaintask,itwouldbenicetobeabletocallitagainandagainwhenyouneedit.JavaScriptenablesustodojustthat,andthisiswhatyou’llbeconcentratingoninthissection.

CREATINGYOUROWNFUNCTIONSCreatingandusingyourownfunctionsisverysimple.Figure4.1showsanexampleofafunctiondeclaration.

Figure4.1

You’veprobablyalreadyrealizedwhatthisfunctiondoesandhowthecodeworks.Yes,it’stheinfamousFahrenheit-to-centigradeconversioncodeagain.

EachfunctionyoudefineinJavaScriptmustbegivenauniquenameforthatparticularpage.Thenamecomesimmediatelyafterthefunctionkeyword.Tomakelifeeasierforyourself,tryusingmeaningfulnamessothatwhenyouseethembeingusedlaterinyourcode,you’llknowexactlywhattheydo.Forexample,afunctionthattakesasitsparameterssomeone’sbirthdayandtoday’sdateandreturnstheperson’sagecouldbecalledgetAge().However,thenamesyoucanusearelimited,muchasvariablenamesare.Forexample,youcan’tusewordsreservedbyJavaScript,soyoucan’tcallyourfunctionif()orwhile().

Theparametersforthefunctionaregiveninparenthesesafterthefunction’sname.Aparameterisjustanitemofdatathatthefunctionneedstobegiveninordertodoitsjob.Usually,notpassingtherequiredparameterswillresultinanerror.Afunctioncanhavezeroormoreparameters,thoughevenifithasnoparameters,youmuststillputtheopenandcloseparenthesesafteritsname.Forexample,thetopofyourfunctiondefinitionmustlooklikethefollowing:

functionmyNoParamFunction()

Youthenwritethecode,whichthefunctionwillexecutewhencalledontodoso.Allthefunctioncodemustbeputinablockwithapairofcurlybraces.

Functionsalsoenableyoutoreturnavaluefromafunctiontothecodethatcalledit.Youusethereturnstatementtoreturnavalue.Intheexamplefunctiongivenearlier,youreturnthevalueofthevariabledegCent,whichyouhavejustcalculated.Youdon’thavetoreturnavalueifyoudon’twantto,butit’simportanttonotethateveryfunctionreturnsavalueevenifyoudon’tusethereturnstatement.Functionsthatdonotexplicitlyreturnavalue—thatis,returnavaluewiththereturnstatement—returnundefined.

WhenJavaScriptcomesacrossareturnstatementinafunction,ittreatsitabitlikeabreakstatementinaforloop—itexitsthefunction,returninganyvaluespecifiedafterthereturnkeyword.

You’llprobablyfinditusefultobuildupa“library”offunctionsthatyouusefrequentlyinJavaScriptcode,whichyoucanreferenceinyourpages.

Havingcreatedyourfunctions,howdoyouusethem?Unlikethecodeyou’veseensofar,whichexecuteswhenJavaScriptreachesthatline,functionsonlyexecuteifyouaskthemto,whichistermedcallingorinvokingthefunction.Youcallafunctionbywritingitsnameatthepointwhereyouwantittobecalledandmakingsurethatyoupassanyparametersitneeds,separatedbycommas.Forexample:

myTemp=convertToCentigrade(212);

ThislinecallstheconvertToCentigrade()functionyousawearlier,passing212astheparameterandstoringthereturnvaluefromthefunction(thatis,100)inthemyTempvariable.

Haveagoatcreatingyourownfunctionsnow,takingacloserlookathowparametersarepassed.Parameterpassingcanbeabitconfusing,soyou’llfirstcreateasimplefunctionthattakesjustoneparameter(theuser’sname)andwritesittothepageinafriendlywelcomestring.First,youneedtothinkofanameforyourfunction.AshortbutdescriptivenameiswriteUserWelcome().Nowyouneedtodefinewhatparametersthefunctionexpectstobepassed.There’sonlyoneparameter—theusername.Definingparametersisalittlelikedefiningvariables—youneedtosticktothesamerulesfornaming,sothatmeansnospaces,specialcharacters,orreservedwords.Let’scallyourparameteruserName.Youneedtoadditinsideparenthesestotheendofthefunctionname(notethatyoudon’tputasemicolonattheendoftheline):

functionwriteUserWelcome(userName)

Okay,nowyouhavedefinedyourfunctionnameanditsparameters;allthat’sleftistocreatethefunctionbody—thatis,thecodethatwillbeexecutedwhenthefunctioniscalled.Youmarkoutthispartofthefunctionbywrappingitincurlybraces:

functionwriteUserWelcome(userName){

document.write("Welcometomywebsite"+userName+"<br/>");

document.write("Hopeyouenjoyit!");

}

Thecodeissimpleenough;youwriteoutamessagetothewebpageusingdocument.write().YoucanseethatuserNameisusedjustasyou’duseanynormalvariable;infact,it’sbesttothinkofparametersasnormalvariables.ThevaluethattheparameterhaswillbethatspecifiedbytheJavaScriptcodewherethefunctionwascalled.

Let’sseehowyouwouldcallthisfunction:

writeUserWelcome("Paul");

Simple,really—justwritethenameofthefunctionyouwanttocall,andtheninparenthesesaddthedatatobepassedtoeachoftheparameters,herejustonepiece.When

thecodeinthefunctionisexecuted,thevariableuserName,usedinthebodyofthefunctioncode,willcontainthetext"Paul".

Supposeyouwantedtopasstwoparameterstoyourfunction—whatwouldyouneedtochange?Well,firstyou’dhavetoalterthefunctiondefinition.Imaginethatthesecondparameterwillholdtheuser’sage—youcouldcallituserAgebecausethatmakesitprettyclearwhattheparameter’sdatarepresents.Hereisthenewcode:

functionwriteUserWelcome(userName,userAge){

document.write("Welcometomywebsite"+userName+"<br/>");

document.write("Hopeyouenjoyit<br/>");

document.write("Yourageis"+userAge);

}

You’veaddedalinetothebodyofthefunctionthatusestheparameteryouhaveadded.Tocallthefunction,you’dwritethefollowing:

writeUserWelcome("Paul",31);

Thesecondparameterisanumber,sothereisnoneedforquotesaroundit.HeretheuserNameparameterwillbePaul,andthesecondparameter,userAge,willbe31.

TRYITOUTFahrenheittoCentigradeFunctionLet’srewritethetemperatureconverterpageusingfunctions.Youcancutandpastemostofthiscodefromch3_example4.html—thepartsthathavechangedhavebeenhighlighted.Whenyou’vefinished,saveitasch4_example1.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter4,Example1</title>

</head>

<body>

<script>

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

vardegFahren=[212,32,-459.15];

vardegCent=[];

varloopCounter;

for(loopCounter=0;loopCounter<=2;loopCounter++){

degCent[loopCounter]=

convertToCentigrade(degFahren[loopCounter]);

}

for(loopCounter=2;loopCounter>=0;loopCounter−−){

document.write("Value"+loopCounter+

"was"+degFahren[loopCounter]+

"degreesFahrenheit");

document.write("whichis"+degCent[loopCounter]+

"degreescentigrade<br/>");

}

</script>

</body>

</html>

Whenyouloadthispageintoyourbrowser,youshouldseeexactlythesameresultsthatyouhadwithch3_example4.html.

AtthetopofthescriptblockyoudeclareyourconvertToCentigrade()function.Yousawthisfunctionearlier:

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

Ifyou’reusinganumberofseparatescriptblocksinapage,it’sveryimportantthatthefunctionbedefinedbeforeanyscriptcallsit.Ifyouhaveanumberoffunctions,youmaywanttoputthemallintheirownscriptfileandloaditbeforeallotherscripts.Thatwayyouknowwheretofindallyourfunctions,andyoucanbesurethattheyhavebeendeclaredbeforetheyhavebeenused.

Youshouldbeprettyfamiliarwithhowthecodeinthefunctionworks.YoudeclareavariabledegCent,doyourcalculation,andthenreturndegCentbacktothecallingcode.Thefunction’sparameterisdegFahren,whichprovidestheinformationthecalculationneeds.

Followingthefunctiondeclarationisthecodethatexecuteswhenthepageloads.Firstyoudefinethevariablesyouneed,andthenyouhavethetwoloopsthatcalculateandthenoutputtheresults.Thisismostlythesameasbefore,apartfromthefirstforloop:

for(loopCounter=0;loopCounter<=2;loopCounter++){

degCent[loopCounter]=convertToCentigrade(degFahren[loopCounter]);

}

ThecodeinsidethefirstforloopputsthevaluereturnedbythefunctionconvertToCentigrade()intothedegCentarray.

Thereisasubtlepointtothecodeinthisexample.NoticethatyoudeclarethevariabledegCentwithinyourfunctionconvertToCentigrade(),andyoualsodeclareitasanarrayafterthefunctiondefinition.

Surelythisisn’tallowed?

Well,thisleadsneatlytothenexttopicofthischapter—scope.

SCOPEANDLIFETIMEWhatismeantbyscope?Well,putsimply,it’sthescopeorextentofavariable’sorfunction’savailability—whichpartsofyourcodecanaccessavariableandthedataitcontains.Scopeisimportanttoanyprogramminglanguage—evenmoresoinJavaScript—soit’simperativethatyouunderstandhowscopeworksinJavaScript.

GlobalScopeAnyvariablesorfunctionsdeclaredoutsideofafunctionwillbeavailabletoallJavaScriptcodeonthepage,whetherthatcodeisinsideafunctionorotherwise—wecallthisglobalscope.Lookatthefollowingexample:

vardegFahren=12;

functionconvertToCentigrade(){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

Inthiscode,thedegFahrenvariableisaglobalvariablebecauseitiscreatedoutsideofafunction,andbecauseitisglobal,itcanbeusedanywhereinthepage.TheconvertToCentigrade()functionaccessesthedegFahrenvariable,usingitaspartofthecalculationtoconvertFahrenheittocentigrade.

Thisalsomeansyoucanchangethevalueofaglobalvariable,andthefollowingcodedoesjustthat:

vardegFahren=12;

functionconvertToCentigrade(){

degFahren=20;

vardegCent=5/9*(degFahren-32);

returndegCent;

}

ThisnewlineofcodechangesthevalueofdegFahrento20;sotheoriginalvalueof12isnolongerusedinthecalculation.Thischangeinvalueisn’tseenonlyinsideoftheconvertToCentigrade()function.ThedegFahrenvariableisaglobalvariable,andthusitsvalueis20everywhereitisused.

Additionally,thecovertToCentigrade()functionisaglobalfunctionbecauseitisdefinedoutsideofanotherfunction(yes,youcancreateafunctionwithinafunction…funception!),andtheytoocanbeaccessedanywhereinthepage.

Inpractice,youwanttoavoidcreatingglobalvariablesandfunctionsbecausetheycanbeeasilyandunintentionallymodified.Youcanusesometrickstoavoidglobals,andyouwillseethemthroughoutthisbook,buttheyallboildowntocreatingvariablesand

functionsinfunctionalscope.

FunctionalScopeVariablesandfunctionsdeclaredinsideafunctionarevisibleonlyinsidethatfunction—nocodeoutsidethefunctioncanaccessthem.Forexample,considerourstandardconvertToCentigrade()function:

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

ThedegCentvariableisdefinedinsidetheconvertToCentigrade()function.Therefore,itcanonlybeaccessedfromwithinconvertToCentigrade().Thisiscommonlyreferredtoasfunctionalorlocalscope,anddegCentiscommonlycalledalocalvariable.

Functionparametersaresimilartovariables;theyhavelocalscope,andthuscanonlybeaccessedfromwithinthefunction.SointhecaseofthepreviousconvertToCentigrade()function,degFahrenanddegCentarelocalvariables.

Sowhathappenswhenthecodeinsideafunctionendsandexecutionreturnstothepointatwhichthecodewascalled?Dothevariablesdefinedwithinthefunctionretaintheirvaluewhenyoucallthefunctionthenexttime?

Theanswerisno:Variablesnotonlyhavethescopeproperty—wheretheyarevisible—buttheyalsohavealifetime.Whenthefunctionfinishesexecuting,thevariablesinthatfunctiondieandtheirvaluesarelost,unlessyoureturnoneofthemtothecallingcode.EverysooftenJavaScriptperformsgarbagecollection(whichwetalkedaboutinChapter2),wherebyitscansthroughthecodeandseesifanyvariablesarenolongerinuse;ifso,thedatatheyholdarefreedfrommemorytomakewayforthedataofothervariables.

IdentifierLookupWhathappensifyouusethesamevariablenameforbothaglobalandlocalvariable?JavaScripthandlesthisseeminglycatastrophiceventwithaprocesscalledidentifierlookup.Anidentifierissimplythenameyougiveavariableorfunction.So,identifierlookupistheprocessthattheJavaScriptengineusestofindavariableorfunctionwithagivenname.Considerthefollowingcode:

vardegCent=10;

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

ThiscodecontainstwodegCentvariables:Oneisglobal,andtheotherislocaltoconvertToCentigrade().Whenyouexecutethefunction,theJavaScriptenginecreates

thelocaldegCentvariableandassignsittheresultoftheFahrenheit-to-centigradeconversion—theglobaldegCentvariableisleftaloneandstillcontains10.Butwhatvaluedoesthereturnstatementreturn:theglobalorlocaldegCent?

TheJavaScriptenginebeginstheidentifierlookupprocessinthecurrentlevelofscope.Therefore,itstartslookingwithinthefunctionalscopeofconvertToCentigrade()foravariableorfunctionwiththenamedegCent,itfindsthelocalvariable,andusesitsvalueinthereturnstatement.

ButifdegCentwasnotcreatedwithinconvertToCentigrade(),theJavaScriptenginewouldthenlookinthenextlevelofscope—theglobalscopeinthiscase—forthedegCentidentifier.Itwouldfindtheglobalvariableanduseitsvalue.

Sonowthatyouunderstandhowscopeworks,revisitExample1inthe“FahrenheittoCentigradeFunction”TryItOut.EventhoughithastwodegCentvariables—oneglobalandonelocaltoconvertToCentigrade()—thecodeexecuteswithoutaproblem.Insidethefunction,thelocaldegCentvariabletakesprecedenceovertheglobal.Andoutsideofthefunction,thelocalvariableisnolongerinscope;therefore,theglobaldegCentisused.

Althoughit’sperfectlyvalidtousethesameidentifierforglobalandlocalvariables,itishighlyrecommendedthatyouavoiddoingso.Itaddsextra,andoftenunnecessary,complexityandconfusiontoyourcode.Itcanalsomakeiteasiertointroducebugsthataredifficulttofindandfix.Imaginethat,withinafunction,youmodifiedalocalvariablewhenyoumeanttomodifyaglobalvariable.Thatisabug,andifyoureplicateditinmanyotherfunctions,youwillspendprecioustimefindingandfixingthoseerrors.

FUNCTIONSASVALUESJavaScriptisapowerfullanguage,andalotofthatpowercomesfromfunctions.Unlikemanyotherlanguages,functionsarefirst-classcitizensinJavaScript;inotherwords,wecantreatfunctionsjustlikeanyothertypeofvalue.Forexample,let’staketheconvertToCentigrade()functionandassignittoavariable:

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

varmyFunction=convertToCentigrade;

ThiscodeassignstheconvertToCentigrade()functiontothemyFunctionvariable,butlookcloselyattheright-handsideoftheassignment—theopeningandclosingparenthesesaremissingattheendoftheconvertToCentigradeidentifier.Itlooksalotlikeavariable!

Inthisstatement,wearenotexecutingconvertToCentigrade();wearereferringtotheactualfunctionitself.Thismeansthatwenowhavetwowaysofexecutingthesamefunction.WecancallitnormallybyexecutingconvertToCentigrade(),orwecanexecutemyFunction(),likethis:

vardegCent=myFunction(75);//23.88888889

vardegCent2=convertToCentigrade(75);//23.88888889

Thisalsomeanswecanpassafunctiontoanotherfunction’sparameter.Takealookatthefollowingcode:

functiondoSomething(fn){

fn("Hello,World");

}

doSomething(alert);

ThiscodedefinesafunctioncalleddoSomething(),andithasasingleparametercalledfn.Insidethefunction,thefnvariableisusedasafunction;it’sexecutedbyusingthefnidentifierfollowedbyapairofparentheses.ThefinallineofcodeexecutesthedoSomething()functionandpassesthealertfunctionastheparameter.Whenthiscodeexecutes,analertboxdisplaysthemessage"Hello,World".

TRYITOUTPassingFunctions

Let’srewritethetemperatureconverterpagetousemorefunctions.Youcancutandpastesomeofthecodefromch4_example1.html,butthemajorityofthisexamplewillbenewcode.Whenyou’vefinished,saveitasch4_example2.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter4,Example2</title>

</head>

<body>

<script>

functiontoCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

document.write(degFahren+"Fahrenheitis"+

degCent+"Celsius.<br/>");

}

functiontoFahrenheit(degCent){

vardegFahren=9/5*degCent+32;

document.write(degCent+"Celsiusis"+

degFahren+"Fahrenheit.<br/>");

}

functionconvert(converter,temperature){

converter(temperature);

}

convert(toFahrenheit,23);

convert(toCentigrade,75);

</script>

</body>

</html>

Whenyouloadthispageintoyourbrowser,youshouldseetheresultsshowninFigure4.2.

Figure4.2

AtthetopofthescriptblockisthetoCentigrade()function.ItissomewhatsimilartotheconvertToCentigrade()functionfromch4_example1.html;insteadofreturningtheconvertedvalue,itsimplywritestheconversioninformationtothedocument:

functiontoCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

document.write(degFahren+"Fahrenheitis"+

degCent+"Celsius.<br/>");

}

Thenextfunction,toFahrenheit(),issimilartotoCentigrade()exceptthatitconvertsthesuppliedvaluetoFahrenheit.Itthenwritestheconversioninformationtothedocument:

functiontoFahrenheit(degCent){

vardegFahren=9/5*degCent+32;

document.write(degCent+"Celsiusis"+

degFahren+"Fahrenheit.<br/>");

}

Admittedly,youcouldusethesefunctionsasiswithoutanyproblem,butthatwouldn’tresultinaveryinterestingexample.Instead,thethirdfunction,convert(),willbeusedtoexecutetoCentigrade()andtoFahrenheit():

functionconvert(converter,temperature){

returnconverter(temperature);

}

Thisfunctiontakesthefirstparameter,converter,andusesitasafunction.Thesecondparameter,temperature,isthenpassedtoconverter()toperformtheconversionandwritetheresultstothedocument.

Thefinaltwolinesofcodeuseconvert()andpassittheappropriateconverterfunctionandtemperaturevalue:

convert(toFahrenheit,23);

convert(toCentigrade,75);

Althoughthisiscertainlyamorecomplexsolutiontoarelativelysimpleproblem,itdemonstratesthefactthatfunctionsarevaluesinJavaScript.Wecanassignthemtovariablesandpassthemtootherfunctions.Thisisanextremelyimportantconcepttounderstand,andyou’llseewhyinChapter10whenyoulearnaboutevents.

SUMMARYInthischapteryouconcludedyourlookatthecoreoftheJavaScriptlanguageanditssyntax.Everythingfromnowonbuildsonthesefoundations,andwiththelessinterestingsyntaxunderyourbelt,youcanmoveontomoreinterestingthingsintheremainderofthebook.

Thechapterlookedatthefollowing:

Functionsarereusablebitsofcode.JavaScripthasalotofbuilt-infunctionsthatprovideprogrammersservices,suchasconvertingastringtoanumber.However,JavaScriptalsoenablesyoutodefineanduseyourownfunctionsusingthefunctionkeyword.Functionscanhavezeroormoreparameterspassedtothemandcanreturnavalueifyousowish.

Variablescopeandlifetime:Variablesdeclaredoutsideafunctionareavailableglobally—thatis,anywhereinthepage.Anyvariablesdefinedinsideafunctionareprivatetothatfunctionandcan’tbeaccessedoutsideofit.Variableshavealifetime,thelengthofwhichdependsonwherethevariablewasdeclared.Ifit’saglobalvariable,itslifetimeisthatofthepage—whilethepageisloadedinthebrowser,thevariableremainsalive.Forvariablesdefinedinafunction,thelifetimeislimitedtotheexecutionofthatfunction.Whenthefunctionisfinishedexecuting,thevariablesdie,andtheirvaluesarelost.Ifthefunctioniscalledagainlaterinthecode,thevariableswillbeempty.

Identifierlookup:Whenyouuseavariableorfunction,theJavaScriptenginegoesthroughtheidentifierlookupprocesstofindthevalueassociatedwiththeidentifier.

Functionsarefirst-classcitizensinJavaScript.Youcanassignfunctionstovariablesandpassthemtootherfunctions.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. ChangethecodeofQuestion2fromChapter3sothatit’safunctionthattakesasparametersthetimestablerequiredandthevaluesatwhichitshouldstartandend.Forexample,youmighttrythe4timestabledisplayedstartingwith4*4andendingat4*9.

2. ModifythecodeofQuestion1torequestthetimestabletobedisplayedfromtheuser;thecodeshouldcontinuetorequestanddisplaytimestablesuntiltheuserenters-1.Additionally,doachecktomakesurethattheuserisenteringavalidnumber;ifthenumberisnotvalid,asktheusertore-enterit.

5JavaScript—AnObject-BasedLanguageWHATYOUWILLLEARNINTHISCHAPTER:

UsingJavaScript’sbuilt-inobjectstoworkwithcomplexdata

Creatingcustomobjectstorepresentcomplexideasanddata

Definingcustomreferencetypes

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Inthischapter,youlookataconceptthatiscentraltoJavaScript,namelyobjects.Butwhatareobjects,andwhyaretheyuseful?

First,wehavetobreakittoyou:Youhavebeenusingobjectsthroughoutthisbook(forexample,anarrayisanobject).JavaScriptisanobject-basedlanguage,andthereforemostofwhatyoudoinvolvesmanipulatingobjects.You’llseethatwhenyoumakefulluseoftheseobjects,therangeofthingsyoucandowithJavaScriptexpandsimmensely.

We’llstartthischapterbytakingalookattheideaofwhatobjectsareandwhytheyareimportant.We’llmoveontowhatkindsofobjectsareusedinJavaScript,howtocreatethemandusethem,andhowtheysimplifymanyprogrammingtasksforyou.Finally,you’llseeinmoredetailsomeofthemostusefulobjectsthatJavaScriptprovidesandhowtousetheseinpracticalsituations.

NotonlydoestheJavaScriptlanguageconsistofanumberofthesethingscalledobjects(whicharealsocallednativeJavaScriptobjects),butalsothebrowseritselfismodeledasacollectionofobjectsavailableforyouruse.YoulearnabouttheseobjectsinparticularinChapter8.

OBJECT-BASEDPROGRAMMINGObject-basedprogrammingisaslightlyscarierwayofsaying“programmingusingobjects.”Butwhataretheseobjectsthatyouwillbeprogrammingwith?Wherearetheyandhowandwhywouldyouwanttoprogramwiththem?Inthissection,youlookattheanswerstothesequestions,bothingeneralprogrammingtermsandmorespecificallywithinJavaScript.

WhatAreObjects?Tostarttheintroductiontoobjects,let’sthinkaboutwhatismeantbyanobjectinthe“realworld”outsidecomputing.Theworldiscomposedofthings,orobjects,suchastables,chairs,andcars(tonamejustafew!).Let’stakeacarasanexample,toexplorewhatanobjectreallyis.

Howwouldyoudefinethecar?Youmightsayit’sabluecarwithfour-wheeldrive.Youmightspecifythespeedatwhichit’straveling.Whenyoudothis,youarespecifyingpropertiesoftheobject.Forexample,thecarhasacolorproperty,whichinthisinstancehasthevalueblue.

Howdoyouusethecar?Youturntheignitionkey,pressthegaspedal,beepthehorn,changethegear(thatis,choosebetween1,2,3,4,andreverseonamanualcar,ordriveandreverseonanautomatic),andsoon.Whenyoudothis,youareusingmethodsoftheobject.

Youcanthinkofmethodsasbeingabitlikefunctions.Sometimes,youmayneedtousesomeinformationwiththemethod,orpassitaparameter,togetittowork.Forexample,whenyouusethechanging-gearsmethod,youneedtosaywhichgearyouwanttochangeto.Othermethodsmaypassinformationbacktotheowner.Forexample,thedipstickmethodwilltelltheownerhowmuchoilisleftinthecar.

Sometimesusingoneormoreofthemethodsmaychangeoneormoreoftheobject’sproperties.Forexample,usingtheacceleratormethodwillprobablychangethecar’sspeedproperty.Otherpropertiescan’tbechanged:forexample,thebody-shapepropertyofthecar(unlessyouhitabrickwallwiththespeedpropertyat100milesperhour!).

Youcouldsaythatthecarisdefinedbyitscollectionofmethodsandproperties.Inobject-basedprogramming,theideaistomodelreal-worldsituationsbyobjects,whicharedefinedbytheirmethodsandproperties.

ObjectsinJavaScriptYoushouldnowhaveabasicideaofwhatanobjectis—a“thing”withmethodsandproperties.ButhowdoyouusethisconceptinJavaScript?

Inthepreviouschaptersyouhave(forthemostpart)beendealingwithprimitivedata(thatis,you’vebeenworkingwithactualdata).Thistypeofdataisnottoocomplexandisfairlyeasytodealwith.However,notallinformationisassimpleasprimitivedata.Let’s

lookatanexampletoclarifythingsalittle.

Supposeyouhadwrittenawebapplicationthatdisplayedtimetableinformationforbusesortrains.Oncetheuserhasselectedajourney,youmightwanttolethimknowhowlongthatjourneywilltake.Todothat,youneedtosubtractthearrivaltimefromthedeparturetime.

However,that’snotquiteassimpleasitmayappearatfirstglance.Forexample,consideradeparturetimeof14:53(for2:53p.m.)andanarrivaltimeof15:10(for3:10p.m.).IfyoutellJavaScripttoevaluatetheexpression15.10–14.53,yougettheresult0.57,whichis57minutes.However,youknowthattherealdifferenceintimeis17minutes.Usingthenormalmathematicaloperatorsontimesdoesn’twork!

Whatwouldyouneedtodotocalculatethedifferencebetweenthesetwotimes?Youwouldfirstneedtoseparatethehoursfromtheminutesineachtime.Then,togetthedifferenceinminutesbetweenthetwotimes,youwouldneedtocheckwhethertheminutesofthearrivaltimeweregreaterthantheminutesofthedeparture.Ifso,youcouldsimplysubtractthedeparturetimeminutesfromthearrivaltimeminutes.Ifnot,you’dneedtoadd60tothearrivaltimeminutesandsubtractonefromthearrivaltimehourstocompensate,beforetakingthedeparturetimeminutesfromthearrivaltimeminutes.You’dthenneedtosubtractthedeparturetimehoursfromthearrivaltimehours,beforeputtingtheminutesandhoursthatyouhavearrivedatbacktogether.

Thiswouldworkokaysolongasthetwotimeswereinthesameday.Itwouldn’twork,forexample,withthetimes23:45and04:32.

Thiswayofworkingoutthetimedifferenceobviouslyhasitsproblems,butitalsoseemsverycomplex.Isthereaneasierwaytodealwithmorecomplexdatasuchastimesanddates?

Thisiswhereobjectscomein.YoucandefineyourdepartureandarrivaltimesasDateobjects.BecausetheyareDateobjects,theycomewithavarietyofpropertiesandmethodsthatyoucanusewhenyouneedtomanipulateorcalculatetimes.Forexample,youcanusethegetTime()methodtogetthenumberofmillisecondsbetweenthetimeintheDateobjectandJanuary1,1970,00:00:00.Onceyouhavethesemillisecondvaluesforthearrivalanddeparturetimes,youcansimplysubtractonefromtheotherandstoretheresultinanotherDateobject.Toretrievethehoursandminutesofthistime,yousimplyusethegetHours()andgetMinutes()methodsoftheDateobject.Youseemoreexamplesofthislaterinthechapter.

TheDateobjectisnottheonlytypeofobjectthatJavaScripthastooffer.AnotherobjecttypewasintroducedinChapter2,buttokeepthingssimple,wedidn’ttellyouwhatitwasatthetime:theArrayobject.Recallthatanarrayisawayofholdinganumberofpiecesofdataatthesametime.

Arrayobjectshaveapropertycalledlengththattellsyouhowmanypiecesofdata,orratherhowmanyelements,thearrayholds.Theyalsohaveanumberofmethods.Oneexampleisthesort()method,whichyoucanusetosorttheelementswithinthearrayintoalphabeticalorder.

YoushouldnowhaveanideawhyobjectsareusefulinJavaScript.YouhaveseentheDate

andArrayobjects,butJavaScriptmakesavailablemanyothertypesofobjectssothatyoucanachievemorewithyourcode.TheseincludetheMathandStringobjects,whichwetalkmoreaboutlaterinthechapter.

UsingJavaScriptObjectsNowthatyouhaveseenthewhyofJavaScriptobjects,youneedtolookatthewhatandthehow.

EachofJavaScript’sobjectshasacollectionofrelatedpropertiesandmethodsthatyoucanusetomanipulateacertainkindofdata.Forexample,theArrayobjectconsistsofmethodstomanipulatearraysandpropertiestofindoutinformationfromthem.Inmostcases,tomakeuseofthesemethodsandproperties,youneedtodefineyourdataasoneoftheseobjects.Inotherwords,youneedtocreateanobject.

Inthissection,youlookathowtogoaboutcreatinganobjectand,havingdonethat,howyouuseitspropertiesandmethods.

CreatinganObjectTocreatemanytypesofobjects,youusethenewoperator.ThefollowingstatementcreatesaDateobject:

varmyDate=newDate();

Thefirsthalfofthestatementisfamiliartoyou.YouusethevarkeywordtodefineavariablecalledmyDate.Thisvariableisinitialized,usingtheequalssignassignmentoperator(=),totheright-handsideofthestatement.

Theright-handsideofthestatementconsistsoftwoparts.Firstyouhavetheoperatornew.ThistellsJavaScriptthatyouwanttocreateanewobject.NextyouhaveDate().ThisistheconstructorforaDateobject.It’safunctionthattellsJavaScriptwhattypeofobjectyouwanttocreate.Mostobjectshaveconstructorslikethis.Forexample,theArrayobjecthastheArray()constructor(butremember,wetypicallydon’tuseitinfavoroftheliteral[]).TheonlyexceptionyouseeinthisbookistheMathobject,andthisisexplainedinalaterpartofthechapter.

Becauseaconstructorisafunction,youcanpassparameterstotheconstructortoadddatatoyourobject.Forexample,thefollowingcodecreatesaDateobjectcontainingthedate1January2014:

varmyDate=newDate("1Jan2014");

Howobjectdataisstoredinvariablesdiffersfromhowprimitivedata,suchastextandnumbers,isstored.(PrimitivedataisthemostbasicdatapossibleinJavaScript.)Withprimitivedata,thevariableholdsthedata’sactualvalue.Forexample:

varmyNumber=23;

ThiscodemeansthatthevariablemyNumberholdsthedata23.However,variablesassignedtoobjectsdon’tholdtheactualdata,butratherareferencetothememoryaddress

wherethedatacanbefound.Thisdoesn’tmeanyoucangetholdofthememoryaddress—thisissomethingonlyJavaScripthasdetailsofandkeepstoitselfinthebackground.Allyouneedtorememberisthatwhenyousaythatavariablereferencesanobject,youmeanitreferencesamemoryaddress.Thisisshowninthefollowingexample:

varmyArrayRef=[0,1,2];

varmySecondArrayRef=myArrayRef;

myArrayRef[0]=100;

alert(mySecondArrayRef[0]);

FirstyousetthemyArrayRefvariabletoreferencethenewarrayobject,andthenyousetmySecondArrayReftothesamereference—forexample,nowmySecondArrayRefissettoreferencethesamearrayobject.Sowhenyousetthefirstelementofthearrayto100,asshownhere:

myArrayRef[0]=100;

anddisplaythecontentsofthefirstelementofthearrayreferencedinmySecondArrayRefasfollows:

alert(mySecondArrayRef[0]);

you’llseeithasalsomagicallychangedto100!However,asyounowknow,it’snotmagic;it’sbecausebothvariablesreferencethesamearrayobject—whenitcomestoobjects,it’sareferencetotheobjectandnottheobjectitselfthatisstoredinavariable.Whenyoudidtheassignment,itdidn’tmakeacopyofthearrayobject,itsimplycopiedthereference.Contrastthatwiththefollowing:

varmyVariable="ABC";

varmySecondVariable=myVariable;

myVariable="DEF";

alert(mySecondVariable);

Inthiscaseyou’redealingwithastring,whichisaprimitivedatatype,asarenumbers.Thistimetheactualvaluesarestoredinthevariable,sowhenyoudothis:

varmySecondVariable=myVariable;

mySecondVariablegetsitsownseparatecopyofthedatainmyVariable.SothealertattheendwillstillshowmySecondVariableasholding"ABC".

Tosummarizethissection,youcreateJavaScriptobjectsusingthefollowingbasicsyntax:

varmyVariable=newConstructorName(optionalparameters);

UsinganObject’sPropertiesAccessingthevaluescontainedinanobject’spropertiesisverysimple.Youwritethenameofthevariablecontaining(orreferencing)yourobject,followedbyadot,andthenthenameoftheobject’sproperty.

Forexample,ifyoudefinedanArrayobjectcontainedinthevariablemyArray,youcouldaccessitslengthpropertylikethis:

myArray.length

Butwhatcanyoudowiththispropertynowthatyouhaveit?Youcanuseitasyouwouldanyotherpieceofdataandstoreitinavariable:

varmyVariable=myArray.length;

Oryoucanshowittotheuser:

alert(myArray.length);

Insomecases,youcanevenchangethevalueoftheproperty,likethis:

myArray.length=12;

However,unlikevariables,somepropertiesareread-only—youcangetinformationfromthem,butyoucan’tchangeinformationinsidethem.

CallinganObject’sMethodsMethodsareverymuchlikefunctionsinthattheycanbeusedtoperformusefultasks,suchasgettingthehoursfromaparticulardateorgeneratingarandomnumber.Againlikefunctions,somemethodsreturnavalue,suchasaDateobject’sgetHours()method,whereasothersperformatask,butreturnnodata,suchasanArrayobject’ssort()method.

Usingthemethodsofanobjectisverysimilartousingproperties,inthatyouputtheobject’svariablenamefirst,thenadot,andthenthenameofthemethod.Forexample,tosorttheelementsofanArrayinthevariablemyArray,youcanusethefollowingcode:

myArray.sort();

Justaswithfunctions,youcanpassparameterstosomemethodsbyplacingtheparametersbetweentheparenthesesfollowingthemethod’sname.However,whetherornotamethodtakesparameters,youmuststillputparenthesesafterthemethod’sname,justasyoudidwithfunctions.Asageneralrule,anywhereyoucanuseafunction,youcanuseamethodofanobject.

PrimitivesandObjectsYoushouldnowhaveagoodideaaboutthedifferencebetweenprimitivedata,suchasnumbersandstrings,andobjectdata,suchasDatesandArrays.However,aswasmentionedearlier,thereisalsoaStringobject.Wheredoesthisfitin?

Infact,thereareString,Number,andBooleanobjectscorrespondingtothestring,number,andbooleanprimitivedatatypes.Forexample,tocreateaStringobjectcontainingthetext"I'maStringobject"youcanusethefollowingcode:

varmyString=newString("I'maStringobject");

StringobjectshavethelengthpropertyjustasArrayobjectsdo.ThisreturnsthenumberofcharactersintheStringobject.Forexample,

varlengthOfString=myString.length;

wouldstorethevalue19inthevariablelengthOfString(rememberthatspacesarereferredtoascharacters,too).

ButwhatifyouhaddeclaredaprimitivestringcalledmySecondStringholdingthetext"I'maprimitivestring"likethis:

varmySecondString="I'maprimitivestring";

andwantedtoknowhowmanycharacterscouldbefoundinthisprimitivestring?

ThisiswhereJavaScripthelpsyouout.RecallfrompreviouschaptersthatJavaScriptcanhandletheconversionofonedatatypetoanotherautomatically.Forexample,ifyoutriedtoaddastringprimitivetoanumberprimitive,likethis:

theResult="23"+23;

JavaScriptwouldassumethatyouwanttotreatthenumberasastringandconcatenatethetwotogether,thenumberbeingconvertedtotextautomatically.ThevariabletheResultwouldcontain"2323"—theconcatenationof23and23,andnotthesumof23and23,whichwouldbe46.

Thesameappliestoobjects.Ifyoudeclareaprimitivestringandthentreatitasanobject,suchasbytryingtoaccessoneofitsmethodsorproperties,JavaScriptwillknowthattheoperationyou’retryingtodowon’twork.Theoperationwillonlyworkwithanobject;forexample,itwouldbevalidwithaStringobject.Inthiscase,JavaScriptconvertstheplaintextstringintoatemporaryStringobject,justforthatoperation,anddestroystheobjectwhenit’sfinishedtheoperation.

So,foryourprimitivestringmySecondString,youcanusethelengthpropertyoftheStringobjecttofindoutthenumberofcharactersitcontains.Forexample:

varlengthOfSecondString=mySecondString.length;

Thiswouldstorethedata22inthevariablelengthOfSecondString.

ThesameideasexpressedherearealsotruefornumberandbooleanprimitivesandtheircorrespondingNumberandBooleanobjects.However,theseobjectsarenotusedveryoften,sowewillnotbediscussingthemfurtherinthisbook.

JAVASCRIPT’SNATIVEOBJECTTYPESSofar,youhavejustbeenlookingatwhatobjectsare,howtocreatethem,andhowtousethem.NowtakealookatsomeofthemoreusefulobjectsthatarenativetoJavaScript—thatis,thosethatarebuiltintotheJavaScriptlanguage.

Youwon’tbelookingatallofthenativeJavaScriptobjects,justsomeofthemorecommonlyusedones,namelytheStringobject,theMathobject,theArrayobject,andtheDateobject.

StringObjectsLikemostobjects,Stringobjectsneedtobecreatedbeforetheycanbeused.TocreateaStringobject,youcanwritethis:

varstring1=newString("Hello");

varstring2=newString(123);

varstring3=newString(123.456);

However,asyouhaveseen,youcanalsodeclareastringprimitiveanduseitasifitwereaStringobject,lettingJavaScriptdotheconversiontoanobjectforyoubehindthescenes.Forexample:

varstring1="Hello";

Usingthistechniqueispreferable.TheadvantagestodoingitthiswayarethatthereisnoneedtocreateaStringobjectitself,andyouavoidthetroubleswithcomparingstringobjects.Whenyoutrytocomparestringobjectswithprimitivestringvalues,theactualvaluesarecompared,butwithStringobjects,theobjectreferencesarecompared.

TheStringobjecthasavastnumberofmethodsandproperties.Inthissection,youlookonlyatsomeofthelesscomplexandmorecommonlyusedmethods.However,inChapter6youlookatsomeofthetrickierbutverypowerfulmethodsassociatedwithstringsandtheregularexpressionobject(RegExp).Regularexpressionsprovideaverypowerfulmeansofsearchingstringsforpatternsofcharacters.Forexample,ifyouwanttofind"Paul"whereitexistsasawholewordinthestring"Pauline,Paul,Paula",youneedtouseregularexpressions.However,theycanbealittletrickytouse,sowewon’tdiscussthemfurtherinthischapter—wewanttosavesomefunforlater!

WithmostoftheStringobject’smethods,ithelpstorememberthatastringisjustaseriesofindividualcharactersandthat,aswitharrays,eachcharacterhasaposition,orindex.Alsoaswitharrays,thefirstposition,orindex,islabeled0andnot1.So,forexample,thestring"HelloWorld"hasthecharacterpositionsshowninthefollowingtable:

CHARACTERINDEX 0 1 2 3 4 5 6 7 8 9 10Character H e l l o W o r l d

ThelengthPropertyThelengthpropertysimplyreturnsthenumberofcharactersinthestring.Forexample,

varmyName="Jeremy";

document.write(myName.length);

willwritethelengthofthestring"Jeremy"(thatis,6)tothepage.

FindingaStringInsideAnotherString—TheindexOf()andlastIndexOf()MethodsThemethodsindexOf()andlastIndexOf()areusedforsearchingfortheoccurrenceofonestringinsideanother.Astringcontainedinsideanotherisusuallytermedasubstring.Theyareusefulwhenyouhaveastringofinformationbutonlywantasmallpartofit.Forexample,inthetriviaquiz,whensomeoneentersatextanswer,youwanttocheckifcertainkeywordsarepresentwithinthestring.

BothindexOf()andlastIndexOf()taketwoparameters:

Thestringyouwanttofind

Thecharacterpositionyouwanttostartsearchingfrom(optional)

Characterpositionsstartat0.Ifyoudon’tincludethesecondparameter,searchingstartsfromthebeginningofthestring.

ThereturnvalueofindexOf()andlastIndexOf()isthecharacterpositioninthestringatwhichthesubstringwasfound.Again,it’szero-based,soifthesubstringisfoundatthestartofthestring,then0isreturned.Ifthereisnomatch,thevalue-1isreturned.

Forexample,tosearchforthesubstring"Jeremy"inthestring"Hellojeremy.HowareyouJeremy",youcanusethefollowingcode:

varmyString="Hellojeremy.HowareyouJeremy";

varfoundAtPosition=myString.indexOf("Jeremy");

alert(foundAtPosition);

Thiscodeshouldresultinamessageboxcontainingthenumber26,whichisthecharacterpositionof"Jeremy".Youmightbewonderingwhyit’s26,whichclearlyreferstothesecond"Jeremy"inthestring,ratherthan6forthefirst"jeremy".

Thisisduetocasesensitivity.JavaScripttakescasesensitivityveryseriously,bothinitssyntaxandwhenmakingcomparisons.IfyoutypeIndexOf()insteadofindexOf(),JavaScriptwillcomplain.Similarly,"jeremy"isnotthesameas"Jeremy".Rememberthatmistakeswithcaseareverycommonandsoeasytomake,evenforexperts,andit’sbesttobeveryawareofcasewhenprogramming.

You’veseenindexOf()inaction,buthowdoeslastIndexOf()differ?Well,whereasindexOf()startssearchingfromthebeginningofthestring,orthepositionyouspecifiedinthesecondparameter,andworkstowardtheend,lastIndexOf()startsattheendofthestring,orthepositionyouspecified,andworkstowardthebeginningofthestring.Let’smodifythepreviousexampletothefollowingcode:

varmyString="HelloJeremy.HowareyouJeremy";

varfoundAtPosition=myString.indexOf("Jeremy");

alert(foundAtPosition);

foundAtPosition=myString.lastIndexOf("Jeremy");

alert(foundAtPosition);

First,noticethestringvalueassignedtomyString;bothinstancesof"Jeremy"nowbeginwithacapitalletter.Thefirstalertboxdisplaystheresultof6becausethatisthepositionofthefirstoccurrenceof"Jeremy".Thesecondalertboxdisplays26becauselastIndexOf()startssearchingattheendofthestring,andthepositionofthefirstoccurrenceof"Jeremy"fromtheendofthestringis26.

TRYITOUTCountingOccurrencesofSubstringsInthisexample,youlookathowtousethe“startcharacterposition”parameterofindexOf().HereyouwillcounthowmanytimesthewordWroxappearsinthestring:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example1</title>

</head>

<body>

<script>

varmyString="WelcometoWroxbooks."+

"TheWroxwebsiteiswww.wrox.com."+

"VisittheWroxwebsitetoday.Thanksforbuying

Wrox";

varfoundAtPosition=0;

varwroxCount=0;

while(foundAtPosition!=-1){

foundAtPosition=myString.indexOf("Wrox",

foundAtPosition);

if(foundAtPosition!=-1){

wroxCount++;

foundAtPosition++;

}

}

document.write("Thereare"+wroxCount+"occurrencesofthe

wordWrox");

</script>

</body>

</html>

Savethisexampleasch5_example1.html.Whenyouloadthepageintoyourbrowser,youshouldseethefollowingsentence:Thereare4occurrencesofthewordWrox.

Atthetopofthescriptblock,youbuiltupastringinsidethevariablemyString,whichyouthenwanttosearchfortheoccurrenceofthewordWrox.Youalsodefinetwovariables:wroxCountwillcontainthenumberoftimesWroxisfoundinthestring,andfoundAtPositionwillcontainthepositioninthestringofthecurrentoccurrenceofthesubstringWrox.

Youthenusedawhileloop,whichcontinuesloopingallthewhileyouarefindingthewordWroxinthestring—thatis,whilethevariablefoundAtPositionisnotequalto-1.Insidethewhileloop,youhavethisline:

foundAtPosition=myString.indexOf("Wrox",foundAtPosition);

HereyousearchforthenextoccurrenceofthesubstringWroxinthestringmyString.Howdoyoumakesurethatyougetthenextoccurrence?YouusethevariablefoundAtPositiontogiveyouthestartingpositionofyoursearch,becausethiscontainstheindexaftertheindexpositionofthelastoccurrenceofthesubstringWrox.YouassignthevariablefoundAtPositiontotheresultofyoursearch,theindexpositionofthenextoccurrenceofthesubstringWrox.

EachtimeWroxisfound(thatis,eachtimefoundAtPositionisnot-1)youincreasethevariablewroxCount,whichcountshowmanytimesyouhavefoundthesubstring,andyouincreasefoundAtPositionsothatyoucontinuethesearchatthenextpositioninthestring:

if(foundAtPosition!=-1){

wroxCount++;

foundAtPosition++;

}

Finally,youdocument.write()thevalueofthevariablewroxCounttothepage.

Chapter3talkedaboutthedangerofinfiniteloops,andyoucanseethatthereisadangerofonehere.IffoundAtPosition++wereremoved,you’dkeepsearchingfromthesamestartingpointandnevermovetofindthenextoccurrenceofthewordWrox.

TheindexOf()andlastIndexOf()methodsaremoreusefulwhencoupledwiththesubstr()andsubstring()methods,whichyoulookatinthenextsection.Usingacombinationofthesemethodsenablesyoutocutsubstringsoutofastring.

CopyingPartofaString—Thesubstr()andsubstring()MethodsIfyouwantedtocutoutpartofastringandassignthatcut-outparttoanothervariableoruseitinanexpression,youwouldusethesubstr()andsubstring()methods.Bothmethodsprovidethesameendresult—thatis,apartofastring—buttheydifferintheparameterstheyrequire.

Themethodsubstring()acceptstwoparameters:thecharacterstartpositionandthepositionafterthelastcharacterdesiredinthesubstring.Thesecondparameterisoptional;

ifyoudon’tincludeit,allcharactersfromthestartpositiontotheendofthestringareincluded.

Forexample,ifyourstringis"JavaScript"andyouwantjustthetext"Java",youcouldcallthemethodlikeso:

varmyString="JavaScript";

varmySubString=myString.substring(0,4);

alert(mySubString);

Thecharacterpositionsforthestring“JavaScript”are:

CHARACTERPOSITION 0 1 2 3 4 5 6 7 8 9Character J a v a S c r i p t

Likesubstring(),themethodsubstr()againtakestwoparameters,thefirstbeingthestartpositionofthefirstcharacteryouwantincludedinyoursubstring.However,thistimethesecondparameterspecifiesthelengthofthestringofcharactersthatyouwanttocutoutofthelongerstring.Forexample,youcouldrewritetheprecedingcodelikethis:

varmyString="JavaScript";

varmySubString=myString.substr(0,4);

alert(mySubString);

Aswiththesubstring()method,thesecondparameterisoptional.Ifyoudon’tincludeit,allthecharactersfromthestartpositiononwardwillbeincluded.

NOTEThesubstring()methodwasintroducedlongbeforesubstr().Mostofthetime,youwillusethesubstr()method.

Let’slookattheuseofthesubstr()andlastIndexOf()methodstogether.Laterinthebook,youseehowyoucanretrievethefilepathandnameofthecurrentlyloadedwebpage.However,thereisnowayofretrievingthefilenamealone.Soif,forexample,yourfileishttp://mywebsite/temp/myfile.html,youmayneedtoextractthemyfile.htmlpart.Thisiswheresubstr()andlastIndexOf()areuseful:

varfileName=window.location.href;

fileName=fileName.substr(fileName.lastIndexOf("/")+1);

document.write("Thefilenameofthispageis"+fileName);

ThefirstlinesetsthevariablefileNametothecurrentfilepathandname,suchas/mywebsite/temp/myfile.html.Don’tworryaboutunderstandingthislinerightnow;you’llseeitlater.

Thesecondlineiswheretheinterestingactionis.YoucanseethatthiscodeusesthereturnvalueofthelastIndexOf()methodasaparameterforanothermethod,somethingthat’sperfectlycorrectandveryuseful.ThegoalinusingfileName.lastIndexOf("/")istofindthepositionofthefinalforwardslash(/),whichwillbethelastcharacterbeforethenameofthefile.Youaddonetothisvalue,becauseyoudon’twanttoincludethatcharacter,andthenpassthisnewvaluetothesubstr()method.There’snosecond

parameterhere(thelength),becauseyoudon’tknowit.Asaresult,substr()willreturnallthecharactersrighttotheendofthestring,whichiswhatyouwant.

NOTEThisexampleretrievesthenameofthepageonthelocalmachine,becauseyou’renotaccessingthepagefromawebserver.However,don’tletthismisleadyouintothinkingthataccessingfilesonalocalharddrivefromawebpageissomethingyou’llbeabletodowithJavaScriptalone.Toprotectusersfrommalicioushackers,JavaScript’saccesstotheuser’ssystem,suchasaccesstofiles,isverylimited.Youlearnmoreaboutthislaterinthebook.

ConvertingCase—ThetoLowerCase()andtoUpperCase()MethodsIfyouwanttochangethecaseofastring(forexample,toremovecasesensitivitywhencomparingstrings),youneedthetoLowerCase()andtoUpperCase()methods.It’snothardtoguesswhatthesetwomethodsdo.BothofthemreturnastringthatisthevalueofthestringintheStringobject,butwithitscaseconvertedtoeitherupperorlowerdependingonthemethodinvoked.Anynon-alphabeticalcharactersremainunchangedbythesefunctions.

Inthefollowingexample,youcanseethatbychangingthecaseofbothstringsyoucancomparethemwithoutcasesensitivitybeinganissue:

varmyString="IDon'tCareAboutCase";

if(myString.toLowerCase()=="idon'tcareaboutcase"){

alert("Whocaresaboutcase?");

}

EventhoughtoLowerCase()andtoUpperCase()don’ttakeanyparameters,youmustremembertoputthetwoemptyparentheses—thatis,()—attheend,ifyouwanttocallamethod.

SelectingaSingleCharacterfromaString—ThecharAt()andcharCodeAt()MethodsIfyouwanttofindoutinformationaboutasinglecharacterwithinastring,youneedthecharAt()andcharCodeAt()methods.Thesemethodscanbeveryusefulforcheckingthevalidityofuserinput,somethingyouseemoreofinChapter11whenyoulookatHTMLforms.

ThecharAt()methodacceptsoneparameter:theindexpositionofthecharacteryouwantinthestring.Itthenreturnsthatcharacter.charAt()treatsthepositionsofthestringcharactersasstartingat0,sothefirstcharacterisatindex0,thesecondatindex1,andsoon.

Forexample,tofindthelastcharacterinastring,youcouldusethiscode:

varmyString=prompt("Entersometext","HelloWorld!");

vartheLastChar=myString.charAt(myString.length-1);

document.write("Thelastcharacteris"+theLastChar);

Inthefirstline,youprompttheuserforastring,withthedefaultof"HelloWorld!",andstorethisstringinthevariablemyString.

Inthenextline,youusethecharAt()methodtoretrievethelastcharacterinthestring.Youusetheindexpositionof(myString.length-1).Why?Let’stakethestring"HelloWorld!"asanexample.Thelengthofthisstringis12,butthelastcharacterpositionis11becausetheindexingstartsat0.Therefore,youneedtosubtractonefromthelengthofthestringtogetthelastcharacter’sposition.

Inthefinalline,youwritethelastcharacterinthestringtothepage.

ThecharCodeAt()methodissimilarinusetothecharAt()method,butinsteadofreturningthecharacteritself,itreturnsanumberthatrepresentsthedecimalcharactercodeforthatcharacterintheUnicodecharacterset.Recallthatcomputersonlyunderstandnumbers—tothecomputer,allyourstringsarejustnumericdata.Whenyourequesttextratherthannumbers,thecomputerdoesaconversionbasedonitsinternalunderstandingofeachnumberandprovidestherespectivecharacter.

Forexample,tofindthecharactercodeofthefirstcharacterinastring,youcouldwritethis:

varmyString=prompt("Entersometext","HelloWorld!");

vartheFirstCharCode=myString.charCodeAt(0);

document.write("Thefirstcharactercodeis"+theFirstCharCode);

Thiswillgetthecharactercodeforthecharacteratindexposition0inthestringgivenbytheuser,andwriteitouttothepage.

Charactercodesgoinorder,so,forexample,theletterAhasthecode65,B66,andsoon.Lowercaselettersstartat97(ais97,bis98,andsoon).Digitsgofrom48(forthenumber0)to57(forthenumber9).Youcanusethisinformationforvariouspurposes,asyouseeinthenextexample.

TRYITOUTCheckingaCharacter’sCaseThisisanexamplethatdetectsthetypeofthecharacteratthestartofagivenstring—thatis,whetherthecharacterisuppercase,lowercase,numeric,orother:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example2</title>

</head>

<body>

<script>

functioncheckCharType(charToCheck){

varreturnValue="O";

varcharCode=charToCheck.charCodeAt(0);

if(charCode>="A".charCodeAt(0)&&charCode<=

"Z".charCodeAt(0)){

returnValue="U";

}elseif(charCode>="a".charCodeAt(0)&&

charCode<="z".charCodeAt(0)){

returnValue="L";

}elseif(charCode>="0".charCodeAt(0)&&

charCode<="9".charCodeAt(0)){

returnValue="N";

}

returnreturnValue;

}

varmyString=prompt("Entersometext","HelloWorld!");

switch(checkCharType(myString)){

case"U":

document.write("Firstcharacterwasuppercase");

break;

case"L":

document.write("Firstcharacterwaslowercase");

break;

case"N":

document.write("Firstcharacterwasanumber");

break;

default:

document.write("Firstcharacterwasnotacharacteror

anumber");

}

</script>

</body>

</html>

Typethecodeandsaveitasch5_example2.html.Whenyouloadthepageintoyourbrowser,youwillbepromptedforastring.Amessagewillthenbewrittentothepageinformingyouofthetypeofthefirstcharacterthatyouentered—whetheritisuppercase,lowercase,anumber,orsomethingelse,suchasapunctuationmark.

Tostartwith,youdefineafunctioncheckCharType().YoustartthisfunctionbydeclaringthevariablereturnValueandinitializingittothecharacter"O"toindicateit’ssomeothercharacterthanalowercaseletter,uppercaseletter,ornumericalcharacter:

functioncheckCharType(charToCheck){

varreturnValue="O";

Youusethisvariableasthevaluetobereturnedattheendofthefunction,indicatingthetypeofcharacter.ItwilltakethevaluesUforuppercase,Lforlowercase,Nfornumber,andOforother.

ThenextlineinthefunctionusesthecharCodeAt()methodtogetthecharactercodeofthefirstcharacterinthestringstoredincharToCheck,whichisthefunction’sonlyparameter.ThecharactercodeisstoredinthevariablecharCode:

varcharCode=charToCheck.charCodeAt(0);

Inthefollowinglines,youhaveaseriesofifstatements,whichcheckwithinwhatrangeofvaluesthecharactercodefalls.YouknowthatifitfallsbetweenthecharactercodesforAandZ,it’suppercase,andsoyouassignthevariablereturnValuethevalueU.Ifthecharactercodefallsbetweenthecharactercodesforaandz,it’slowercase,andsoyouassignthevalueLtothevariablereturnValue.Ifthecharactercodefallsbetweenthecharactercodesfor0and9,it’sanumber,andyouassignthevalueNtothevariablereturnValue.Ifthevaluefallsintononeoftheseranges,thevariableretainsitsinitializationvalueofOforother,andyoudon’thavetodoanything.

if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0))

{

returnValue="U";

}elseif(charCode>="a".charCodeAt(0)&&

charCode<="z".charCodeAt(0)){

returnValue="L";

}elseif(charCode>="0".charCodeAt(0)&&

charCode<="9".charCodeAt(0)){

returnValue="N";

}

Thisprobablyseemsabitweirdatfirst,solet’sseewhatJavaScriptisdoingwithyourcode.Whenyouwrite

"A".charCodeAt(0)

itappearsthatyouaretryingtouseamethodoftheStringobjectonastringliteral,whichisthesameasaprimitivestringinthatit’sjustcharactersandnotanobject.However,JavaScriptrealizeswhatyouaredoinganddoesthenecessaryconversionofliteralcharacter"A"intoatemporaryStringobjectcontaining"A".Then,andonlythen,doesJavaScriptperformthecharCodeAt()methodontheStringobjectithascreatedinthebackground.Whenithasfinished,theStringobjectisdisposedof.Basically,thisisashorthandwayofwritingthefollowing:

varmyChar=newString("A");

myChar.charCodeAt(0);

Ineithercase,thefirst(and,inthisstring,theonly)character’scodeisreturnedtoyou.Forexample,"A".charCodeAt(0)willreturnthenumber65.

Finally,youcometotheendofthefunctionandreturnthereturnValuevariabletowherethefunctionwascalled:

returnreturnValue;

}

YoumightwonderwhyyoubotherusingthevariablereturnValueatall,insteadofjustreturningitsvalue.Forexample,youcouldwritethecodeasfollows:

if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0)){

return"U";

}elseif(charCode>="a".charCodeAt(0)&&

charCode<="z".charCodeAt(0)){

return"L";

}elseif(charCode>="0".charCodeAt(0)&&

charCode<="9".charCodeAt(0)){

return"N";

}

return"O";

Thiswouldworkfine,sowhynotdoitthisway?Thedisadvantageofthiswayisthatit’sdifficulttofollowtheflowofexecutionofthefunction,whichisnotthatbadinasmallfunctionlikethis,butcangettrickyinbiggerfunctions.Withtheoriginalcodeyoualwaysknowexactlywherethefunctionexecutionstops:Itstopsattheendwiththeonlyreturnstatement.Theversionofthefunctionjustshownfinisheswhenanyofthereturnstatementsisreached,sotherearefourpossibleplaceswherethefunctionmightend.

Thenextchunkofcodechecksthatthefunctionworks.YoufirstusethevariablemyString,initializedto"HelloWorld!"orwhatevertheuserentersintothepromptbox,asyourteststring.

varmyString=prompt("Entersometext","HelloWorld!");

Next,theswitchstatementusesthecheckCharType()functionthatyoudefinedearlierinitscomparisonexpression.Dependingonwhatisreturnedbythefunction,oneofthecasestatementswillexecuteandlettheuserknowwhatthecharactertypewas:

switch(checkCharType(myString)){

case"U":

document.write("Firstcharacterwasuppercase");

break;

case"L":

document.write("Firstcharacterwaslowercase");

break;

case"N":

document.write("Firstcharacterwasanumber");

break;

default:

document.write("Firstcharacterwasnotacharacterora

number");

}

Thatcompletestheexample,butbeforemovingon,it’sworthnotingthatthisexampleisjustthat—anexampleofusingcharCodeAt().Inpractice,itwouldbemucheasiertojustwrite

if(char>="A"&&char<="Z")

ratherthan

if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0))

whichyouhaveusedhere.

ConvertingCharacterCodestoaString—ThefromCharCode()MethodYoucanthinkofthemethodfromCharCode()astheoppositeofcharCodeAt(),inthatyoupassitaseriesofcomma-separatednumbersrepresentingcharactercodes,anditconvertsthemtoasinglestring.

However,thefromCharCode()methodisunusualinthatit’sastaticmethod—youdon’tneedtohavecreatedaStringobjecttouseitwith;it’salwaysavailabletoyou.

Forexample,thefollowinglinesputthestring"ABC"intothevariablemyString:

varmyString=String.fromCharCode(65,66,67);

ThefromCharCode()methodcanbeveryusefulwhenusedwithvariables.Forexample,tobuildupastringconsistingofalltheuppercaselettersofthealphabet,youcouldusethefollowingcode:

varmyString="";

varcharCode;

for(charCode=65;charCode<=90;charCode++){

myString=myString+String.fromCharCode(charCode);

}

document.write(myString);

YouusetheforlooptoselecteachcharacterfromAtoZinturnandconcatenatethistomyString.Notethatalthoughthisisfineasanexample,itismoreefficientandlessmemory-hungrytosimplywritethisinstead:

varmyString="ABCDEFGHIJKLMNOPQRSTUVWXYZ";

RemovingLeadingandTrailingWhitespace—Thetrim()MethodWhenworkingwithuser-provideddata,you’reneverguaranteedthattheusersinputtheirdataexactlyhowyouwantthemto.Therefore,it’salwaysbesttoassumeuserinputisincorrect,andit’syourjobtomakeitcorrect.

Theprocessofscrubbingdataisdependentonthespecificneedsofyourapplication,butyou’llcommonlywanttotrimthewhitespacefromthestartandendofthestring.Forthis,Stringobjectshavethetrim()method.Itreturnsanewstringwithallleadingandtrailingwhitespaceremoved.Forexample:

varname=prompt("Pleaseenteryourname");

name=name.trim();

alert("Hello,"+name);

Thiscodepromptsuserstoentertheirname.Youthentrimtheirinputofwhitespaceandusetheresultingvalueinagreetingthatisdisplayedinanalertbox.So,iftheuserentered"Jim",he’dstillonlysee"Hello,Jim"inthealertboxbecauseyoutrimmedhisinput.

ArrayObjectsYousawhowtocreateandusearraysinChapter2,andthischaptermentionedearlierthattheyareactuallyobjects.

Inadditiontostoringdata,Arrayobjectsprovideanumberofusefulpropertiesandmethodsyoucanusetomanipulatethedatainthearrayandfindoutinformationsuchasthesizeofthearray.

Again,thisisnotanexhaustivelookateverypropertyandmethodofArrayobjects,butratherjustsomeofthemoreusefulones.

FindingOutHowManyElementsAreinanArray—ThelengthPropertyThelengthpropertygivesyouthenumberofelementswithinanarray.Sometimesyouknowexactlyhowlongthearrayis,butinsomesituationsyoumayhavebeenaddingnewelementstoanarraywithnoeasywayofkeepingtrackofhowmanyhavebeenadded.

Youcanusethelengthpropertytofindtheindexofthelastelementinthearray.Thisisillustratedinthefollowingexample:

varnames=[];

names[0]="Paul";

names[1]="Jeremy";

names[11]="Nick";

document.write("Thelastnameis"+names[names.length-1]);

NOTENotethatyouhaveinserteddataintheelementswithindexpositions0,1,and11.Thearrayindexstartsat0,sothelastelementisatindexlength-1,whichis11,ratherthanthevalueofthelengthproperty,whichis12.

AnothersituationinwhichthelengthpropertyprovesusefuliswhereaJavaScriptmethodreturnsanarrayithasbuiltitself.Forexample,inthenextchapter,youseethattheStringobjecthasthesplit()method,whichsplitstextintopiecesandpassesbacktheresultasanArrayobject.BecauseJavaScriptcreatedthearray,thereisnowayforyoutoknow,withoutthelengthproperty,whattheindexisofthelastelementinthearray.

AddingElements—Thepush()MethodYou’llfindthatArrayobjectshavemanyusefulmethods,butyouwillprobablyusethepush()methodmorethananyother.Itspurposeissimple—addelementstothearray—anditletsyoudosowithoutneedingtospecifyanindex,likethis:

varnames=[];

names.push("Jeremy");

names.push("Paul");

Itsusageissimple—simplypassthevalueyouwanttoaddtothearray,andthatvaluewillbepushedtotheendofthearray.Sointhepreviousnamesarray,"Jeremy"and"Paul"are

inindexpositionsof0and1,respectively.

JoiningArrays—Theconcat()MethodIfyouwanttotaketwoseparatearraysandjointhemintoonebigarray,youcanusetheArrayobject’sconcat()method.Theconcat()methodreturnsanewarray,whichisthecombinationofthetwoarrays:theelementsofthefirstarray,thentheelementsofthesecondarray.Todothis,youusethemethodonyourfirstarrayandpassthenameofthesecondarrayasitsparameter.

Forexample,sayyouhavetwoarrays,namesandages,andseparatelytheylooklikethefollowingtables:

namesarrayELEMENTINDEX 0 1 2VALUE Paul Jeremy Nick

agesarrayELEMENTINDEX 0 1 2VALUE 31 30 31

Ifyoucombinethemusingnames.concat(ages),youwillgetanarrayliketheoneinthefollowingtable:

ELEMENTINDEX 0 1 2 3 4 5VALUE Paul Jeremy Nick 31 30 31

Inthefollowingcode,thisisexactlywhatyouaredoing:

varnames=["Paul","Jeremy","Nick"];

varages=[31,30,31];

varconcatArray=names.concat(ages);

It’salsopossibletocombinetwoarraysintoonebutassignthenewarraytothenameoftheexistingfirstarray,usingnames=names.concat(ages).

Ifyouweretouseages.concat(names),whatwouldbethedifference?Well,asyoucanseeinthefollowingtable,thedifferenceisthatnowtheagesarrayelementsarefirst,andtheelementsfromthenamesarrayareconcatenatedontheend:

ELEMENTINDEX 0 1 2 3 4 5VALUE 31 30 31 Paul Jeremy Nick

CopyingPartofanArray—Theslice()MethodWhenyoujustwanttocopyaportionofanarray,youcanusetheslice()method.Usingtheslice()method,youcansliceoutaportionofthearrayandassignittoanewvariablename.Theslice()methodhastwoparameters:

Theindexofthefirstelementyouwantcopied

Theindexoftheelementmarkingtheendoftheportionyouareslicingout(optional)

Justaswithstringcopyingwithsubstring(),thestartpointisincludedinthecopy,buttheendpointisnot.Again,ifyoudon’tincludethesecondparameter,allelementsfromthestartindexonwardarecopied.

Supposeyouhavethearraynamesshowninthefollowingtable:

INDEX 0 1 2 3 4VALUE Paul Sarah Jeremy Adam Bob

Ifyouwanttocreateanewarraywithelements1,Sarah,and2,Jeremy,youwouldspecifyastartindexof1andanendindexof3.Thecodewouldlooksomethinglikethis:

varnames=["Paul","Sarah","Jeremy","Adam","Bob"];

varslicedArray=names.slice(1,3);

WhenJavaScriptcopiesthearray,itcopiesthenewelementstoanarrayinwhichtheyhaveindexes0and1,nottheiroldindexesof1and2.

Afterslicing,theslicedArraylookslikethefollowingtable:

INDEX 0 1VALUE Sarah Jeremy

Thefirstarray,names,isunaffectedbytheslicing.

ConvertinganArrayintoaSingleString—Thejoin()MethodThejoin()methodconcatenatesalltheelementsinanarrayandreturnsthemasastring.Italsoenablesyoutospecifyanycharactersyouwanttoinsertbetweenelementsastheyarejoinedtogether.Themethodhasonlyoneparameter,andthat’sthestringyouwantbetweenelements.

Anexamplewillhelpexplainthings.Imaginethatyouhaveyourweeklyshoppingliststoredinanarray,whichlookssomethinglikethis:

INDEX 0 1 2 3 4VALUE Eggs Milk Potatoes Cereal Banana

Nowyouwanttowriteoutyourshoppinglisttothepageusingdocument.write().Youwanteachitemtobeonadifferentline,andyoucandothisbyusingthe<br/>tagbetweeneachelementinthearray.The<br/>tagisanHTMLlinebreak,avisualcarriagereturnforbreakingtextintodifferentlines.First,youneedtodeclareyourarray:

varmyShopping=["Eggs","Milk","Potatoes","Cereal","Banana"];

Next,convertthearrayintoonestringwiththejoin()method:

varmyShoppingList=myShopping.join("<br/>");

NowthevariablemyShoppingListwillholdthefollowingtext:

"Eggs<br/>Milk<br/>Potatoes<br/>Cereal<br/>Banana"

whichyoucanwriteouttothepagewithdocument.write():

document.write(myShoppingList);

Theshoppinglistwillappearinthepagewitheachitemonanewline,asshowninFigure5.1.

Figure5.1

PuttingYourArrayinOrder—Thesort()MethodIfyouhaveanarraythatcontainssimilardata,suchasalistofnamesoralistofages,youmaywanttoputtheminalphabeticalornumericalorder.Thisissomethingthatthesort()methodmakesveryeasy.Inthefollowingcode,youdefineyourarrayandthenputitinascendingalphabeticalorderusingnames.sort().Finally,yououtputitsothatyoucanseethatit’sinorder:

varnames=["Paul","Sarah","Jeremy","Adam","Bob"];

names.sort();

document.write("Nowthenamesagaininorder<br/>");

for(varindex=0;index<names.length;index++){

document.write(names[index]+"<br/>");

}

Don’tforgetthatthesortingiscasesensitive,soPaulwillcomebeforepaul.RememberthatJavaScriptstoreslettersencodedintheirequivalentUnicodenumber,andthatsortingisdonebasedonUnicodenumbersratherthanactualletters.ItjusthappensthatUnicode

numbersmatchtheorderinthealphabet.However,lowercaselettersaregivenadifferentsequenceofnumbers,whichcomeaftertheuppercaseletters.SothearraywithelementsAdam,adam,Zoë,zoë,willbesortedtotheorderAdam,Zoë,adam,zoë.

Notethatinyourforstatementyou’veusedtheArrayobject’slengthpropertyintheconditionstatement,ratherthaninsertingthelengthofthearray(5),likethis:

for(varindex=0;index<5;index++)

Whydothis?Afterall,youknowinadvancethatyouhavefiveelementsinthearray.Well,whatwouldhappenifyoualteredthenumberofelementsinthearraybyaddingtwomorenames?

varnames=["Paul","Sarah","Jeremy","Adam","Bob","Karen","Steve"];

Ifyouhadinserted5ratherthannames.length,yourloopcodewouldn’tworkasyouwantitto.Itwouldn’tdisplaythelasttwoelementsunlessyouchangedtheconditionpartoftheforloopto7.Byusingthelengthproperty,you’vemadelifeeasier,becausenowthereisnoneedtochangecodeelsewhereifyouaddarrayelements.

Okay,you’veputthingsinascendingorder,butwhatifyouwanteddescendingorder?Thatiswherethereverse()methodcomesin.

PuttingYourArrayintoReverseOrder—Thereverse()MethodThenextmethodfortheArrayobjectisthereverse()method,which,noprizesforguessing,reversestheorderofthearraysothattheelementsatthebackaremovedtothefront.Let’staketheshoppinglistagainasanexample:

INDEX 0 1 2 3 4VALUE Eggs Milk Potatoes Cereal Banana

Ifyouusethereverse()method

varmyShopping=["Eggs","Milk","Potatoes","Cereal","Banana"];

myShopping.reverse();

youget

INDEX 0 1 2 3 4VALUE Banana Cereal Potatoes Milk Eggs

Toprovethis,youcouldwriteittothepagewiththejoin()methodyousawearlier.

varmyShoppingList=myShopping.join("<br/>")

document.write(myShoppingList);

TRYITOUTSortinganArrayWhenusedinconjunctionwiththesort()method,thereverse()methodcanbe

usedtosortanarraysothatitselementsappearinreversealphabeticalornumericalorder.Thisisshowninthefollowingexample:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example3</title>

</head>

<body>

<script>

varmyShopping=["Eggs","Milk","Potatoes","Cereal",

"Banana"];

varord=prompt("Enter1foralphabeticalorder,"+

"and-1forreverseorder",1);

if(ord==1){

myShopping.sort();

document.write(myShopping.join("<br/>"));

}elseif(ord==-1){

myShopping.sort();

myShopping.reverse();

document.write(myShopping.join("<br/>"));

}else{

document.write("Thatisnotavalidinput");

}

</script>

</body>

</html>

Savetheexampleasch5_example3.html.Whenyouloadthisintoyourbrowser,youwillbeaskedtoentersomeinputdependingonwhetheryouwantthearraytobeorderedinforwardorbackwardorder.Ifyouenter1,thearraywillbedisplayedinforwardorder.Ifyouenter–1,thearraywillbedisplayedinreverseorder.Ifyouenterneitherofthesevalues,youwillbetoldthatyourinputwasinvalid.

Atthetopofthescriptblock,youdefinethearraycontainingyourshoppinglist.Nextyoudefinethevariableordtobethevalueenteredbytheuserinapromptbox:

varord=prompt("Enter1foralphabeticalorder,"+

"and-1forreverseorder",1);

Thisvalueisusedintheconditionsoftheifstatementsthatfollow.Thefirstifcheckswhetherthevalueofordis1—thatis,whethertheuserwantsthearrayinalphabeticalorder.Ifso,thefollowingcodeisexecuted:

myShopping.sort();

document.write(myShopping.join("<br/>"));

Thearrayissortedandthendisplayedtotheuseronseparatelinesusingthejoin()method.Next,intheelseifstatement,youcheckwhetherthevalueofordis-1—thatis,whethertheuserwantsthearrayinreversealphabeticalorder.Ifso,thefollowingcodeisexecuted:

myShopping.sort();

myShopping.reverse();

document.write(myShopping.join("<br/>"));

Here,yousortthearraybeforereversingitsorder.Againthearrayisdisplayedtotheuserbymeansofthejoin()method.

Finally,ifordhasneitherthevalue1northevalue-1,youtelltheuserthathisinputwasinvalid:

document.write("Thatisnotavalidinput");

FindingArrayElements—TheindexOf()andlastIndexOf()MethodsAsyoucanprobablyguess,theArrayobject’sindexOf()andlastIndexOf()methodsbehavesimilarlytotheStringobject’smethods—theyreturntheindexofanitem’sfirstandlastoccurrenceinanarray.Considerthefollowingcode:

varcolors=["red","blue","green","blue"];

alert(colors.indexOf("red"));

alert(colors.lastIndexOf("blue"));

Thefirstlineofcodecreatesanarraycalledcolors.Ithasfourelements(twoofwhichareblue).Thesecondlinealerts0totheuser,becauseredisthefirstelementofthearray.Thethirdlinereturnsthevalueof3becausethelastIndexOf()methodbeginsitssearchattheveryendofthearray.

BoththeindexOf()andlastIndexOf()methodsreturn-1iftheprovidedvaluecannotbefoundinthearray.

IteratingthroughanArraywithoutLoopsTheremainingfivemethodsarecallediterativemethodsbecausetheyiterate,orloop,throughthearray.Inaddition,thesemethodsexecuteafunctionthatyoudefineoneveryelementwhiletheyiteratethroughthearray.Thefunctionthesemethodsusemustfollowonerule—itmustacceptthreeargumentslikethefollowingcode:

functionfunctionName(value,index,array){

//dosomethinghere

}

Whenexecuted,JavaScriptpassesthreeargumentstoyourfunction.Thefirstisthevalueoftheelement,thesecondistheindexoftheelement,andthethirdisthearrayitself.Thesethreeparametersenableyoutoperformjustaboutanyoperationorcomparisonyoumightneedinrelationtothearrayanditselements.

TestingEachElement—Theevery(),some(),andfilter()MethodsLet’slookattheevery()andsome()methodsfirst.Thesearetestingmethods.Theevery()methodtestswhetherallelementsinthearraypassthetestinyourfunction.Considerthefollowingcode:

varnumbers=[1,2,3,4,5];

functionisLessThan3(value,index,array){

varreturnValue=false;

if(value<3){

returnValue=true;

}

returnreturnValue;

}

alert(numbers.every(isLessThan3));

Thefirstlineshowsthecreationofanarraycallednumbers;itselementsholdthevalues1through5.ThenextlinedefinestheisLessThan3()function.Itacceptsthethreemandatoryargumentsanddeterminesifthevalueofeachelementislessthan3.Thelastlinealertstheoutcomeoftheevery()test.Becausenoteveryvalueinthearrayislessthan3,theresultoftheevery()testisfalse.

Contrastthiswiththesome()method.Unlikeevery(),thesome()testonlycaresifsomeoftheelementspassthetestinyourfunction.UsingthesamenumbersarrayandisLessThan3()function,considerthislineofcode:

alert(numbers.some(isLessThan3));

Theresultistruebecausesomeoftheelementsinthearrayarelessthan3.It’seasytokeepthesetwomethodsstraight.Justremembertheevery()methodreturnstrueif,andonlyif,allelementsinthearraypassthetestinyourfunction;thesome()methodreturnstrueif,andonlyif,someoftheelementsinthearraypassyourfunction’stest.

Let’sassumeyouwanttoretrievetheelementsthathaveavaluelessthan3.Youalreadyknowsomeelementsmeetthiscriterion,buthowdoyouidentifythoseelementsandretrievethem?Thisiswherethefilter()methodbecomesuseful.

Thefilter()methodexecutesyourfunctiononeveryelementinthearray,andifyourfunctionreturnstrueforaparticularelement,thatelementisaddedtoanewarraythatthefilter()methodreturns.Keepingthatinmind,lookatthefollowingcode:

varnumbers=[1,2,3,4,5];

functionisLessThan3(value,index,array){

varreturnValue=false;

if(value<3){

returnValue=true;

}

returnreturnValue;

}

if(numbers.some(isLessThan3)){

varresult=numbers.filter(isLessThan3);

alert("Thesenumbersarelessthan3:"+result);

}

ThiscoderedefinesthenumbersarrayandtheisLessThan3functionusedinpreviousexamples.Thehighlightedcodedeterminesifanyelementsinthenumbersarraycontainavaluelessthan3,andifso,callsthefilter()methodtoplacethoseelementsintoanewarray.TheresultofthiscodeisshowninFigure5.2.

Figure5.2

OperatingonElements—TheforEach()andmap()MethodsThefinaltwomethodsaretheforEach()andmap()methods.Unlikethepreviousiterativemethods,thesetwomethodsdonottesteachelementinthearraywithyourfunction;instead,thefunctionyouwriteshouldperformsomekindofoperationthatusestheelementinsomeway.Lookatthefollowingcode:

varnumbers=[1,2,3,4,5];

for(vari=0;i<numbers.length;i++){

varresult=numbers[i]*2;

alert(result);

}

Asaprogrammer,you’lloftenseeandusethistypeofcode.Itdefinesanarrayandloopsthroughitinordertoperformsomekindofoperationoneachelement.Inthiscase,thevalueofeachelementisdoubled,andtheresultisshowninanalertboxtotheuser.

ThiscodecanberewrittentousetheforEach()method.Asitsnameimplies,itdoessomethingforeachelementinthearray.Allyouneedtodoiswriteafunctiontodoubleagivenvalueandoutputtheresultinanalertbox,likethis:

varnumbers=[1,2,3,4,5];

functiondoubleAndAlert(value,index,array){

varresult=value*2;

alert(result);

}

numbers.forEach(doubleAndAlert);

NoticethatthedoubleAndAlert()functiondoesn’treturnavaluelikethetestingmethods.Itcannotreturnavalue;itsonlypurposeistoperformanoperationoneveryelementinthearray.Thisisusefulinmanycases,butyou’llwanttousethemap()methodwhenyouneedtostoretheresultsofthefunction.

Thepremiseofthemap()methodissimilartothatofforEach().Itexecutesagivenfunctiononeveryelementinanarray,butitalsoreturnsanewarraythatcontainstheresultsofthefunction.

Let’smodifythepreviousexampleandwriteanewfunctioncalleddoubleAndReturn().Itwillstilldoubleeachelementinthearray,butitwillreturnthedoubledvalueinsteadofalertingit.ThefollowingcodepassesthedoubleAndReturn()functiontotheArrayobject’smap()method:

varnumbers=[1,2,3,4,5];

functiondoubleAndReturn(value,index,array){

varresult=value*2;

returnresult;

}

vardoubledNumbers=numbers.map(doubleAndReturn);

alert("Thedoublednumbersare:"+doubledNumbers);

Figure5.3showstheresultsofthiscode.It’simportanttonotethatthemap()methoddoesnotaltertheoriginalarray.

Figure5.3

TheMathObjectTheMathobjectprovidesanumberofusefulmathematicalfunctionsandnumbermanipulationmethods.Youtakealookatsomeofthemhere,butyou’llfindtherestdescribedindetailattheMozillaDeveloperNetwork:https://developer.mozilla.org/en-

US/docs/Web/JavaScript/Reference/Global_Objects/Math.

TheMathobjectisalittleunusualinthatJavaScriptcreatesitforyouautomatically.There’snoneedtodeclareavariableasaMathobjectordefineanewMathobjectbeforebeingabletouseit,makingitalittlebiteasiertouse.

ThepropertiesoftheMathobjectincludesomeusefulmathconstants,suchasthePIproperty(givingthevalue3.14159andsoon).Youaccesstheseproperties,asusual,byplacingadotaftertheobjectname(Math)andthenwritingthepropertyname.Forexample,tocalculatetheareaofacircle,youcanusethefollowingcode:

varradius=prompt("Givetheradiusofthecircle","");

vararea=Math.PI*radius*radius;

document.write("Theareais"+area);

ThemethodsoftheMathobjectincludesomeoperationsthatareimpossible,orcomplex,toperformusingthestandardmathematicaloperators(+,–,*,and/).Forexample,thecos()methodreturnsthecosineofthevaluepassedasaparameter.Youlookatafewofthesemethodsnow.

Theabs()MethodTheabs()methodreturnstheabsolutevalueofthenumberpassedasitsparameter.Essentially,thismeansthatitreturnsthepositivevalueofthenumber.So-1isreturnedas

1,-4as4,andsoon.However,1wouldbereturnedas1becauseit’salreadypositive.

Forexample,thefollowingcodewritesthenumber101tothepage:

varmyNumber=-101;

document.write(Math.abs(myNumber));

FindingtheLargestandSmallestNumbers—Themin()andmax()MethodsLet’ssayyouhavetwonumbers,andyouwanttofindeitherthelargestorsmallestofthetwo.Toaidyouinthistask,theMathobjectprovidesthemin()andmax()methods.Thesemethodsbothacceptatleasttwoarguments,allofwhichmustobviouslybenumbers.Lookatthisexamplecode:

varmax=Math.max(21,22);//resultis22

varmin=Math.min(30.1,30.2);//resultis30.1

Themin()methodreturnsthenumberwiththelowestvalue,andmax()returnsthenumberwiththehighestvalue.Thenumbersyoupasstothesetwomethodscanbewholeorfloating-pointnumbers.

NOTEThemax()andmin()methodscanacceptmanynumbers;you’renotlimitedtotwo.

RoundingNumbersTheMathobjectprovidesafewmethodstoroundnumbers,eachwithitsownspecificpurpose.

Theceil()MethodTheceil()methodalwaysroundsanumberuptothenextlargestwholenumberorinteger.So10.01becomes11,and–9.99becomes–9(because–9isgreaterthan–10).Theceil()methodhasjustoneparameter,namelythenumberyouwantroundedup.

Usingceil()isdifferentfromusingtheparseInt()functionyousawinChapter2,becauseparseInt()simplychopsoffanynumbersafterthedecimalpointtoleaveawholenumber,whereasceil()roundsthenumberup.

Forexample,thefollowingcodewritestwolinesinthepage,thefirstcontainingthenumber102andthesecondcontainingthenumber101:

varmyNumber=101.01;

document.write(Math.ceil(myNumber)+"<br/>");

document.write(parseInt(myNumber,10));

Thefloor()MethodLiketheceil()method,thefloor()methodremovesanynumbersafterthedecimalpoint,andreturnsawholenumberorinteger.Thedifferenceisthatfloor()alwaysroundsthenumberdown.Soifyoupass10.01youwillbereturned10,andifyoupass–9.99youwillsee–10returned.

Theround()MethodTheround()methodisverysimilartoceil()andfloor(),exceptthatinsteadofalwaysroundinguporalwaysroundingdown,itroundsuponlyifthedecimalpartis.5orgreater,androundsdownotherwise.

Forexample:

varmyNumber=44.5;

document.write(Math.round(myNumber)+"<br/>");

myNumber=44.49;

document.write(Math.round(myNumber));

Thiscodewouldwritethenumbers45and44tothepage.

SummaryofRoundingMethodsAsyouhaveseen,theceil(),floor(),andround()methodsallremovethenumbersafteradecimalpointandreturnjustawholenumber.However,whichwholenumbertheyreturndependsonthemethodused:floor()returnsthelowest,ceil()thehighest,andround()thenearestequivalentinteger.Thiscanbealittleconfusing,sothefollowingisatableofvaluesandwhatwholenumberwouldbereturnedifthesevalueswerepassedtotheparseInt()function,andceil(),floor(),andround()methods:

PARAMETER PARSEINT()RETURNS

CEIL()RETURNS

FLOOR()RETURNS

ROUND()RETURNS

10.25 10 11 10 1010.75 10 11 10 1110.5 10 11 10 11−10.25 −10 −10 −11 −10−10.75 −10 −10 −11 −11−10.5 −10 −10 −11 −10

NOTERememberthatparseInt()isanativeJavaScriptfunction,notamethodoftheMathobject,liketheothermethodspresentedinthistable.

TRYITOUTRoundingMethodsResultsCalculatorIfyou’restillnotsureaboutroundingnumbers,thisexampleshouldhelp.Here,youlookatacalculatorthatgetsanumberfromtheuser,andthenwritesoutwhattheresultwouldbewhenyoupassthatnumbertoparseInt(),ceil(),floor(),andround():

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example4</title>

</head>

<body>

<script>

varmyNumber=prompt("Enterthenumbertoberounded","");

document.write("<h3>Thenumberyouenteredwas"+myNumber+

"</h3>");

document.write("<p>Theroundingresultsforthisnumber

are</p>");

document.write("<tablewidth='150'border='1'>");

document.write("<tr><th>Method</th><th>Result</th></tr>");

document.write("<tr><td>parseInt()</td><td>"+

parseInt(myNumber,10)+"</td></tr>");

document.write("<tr><td>ceil()</td><td>"+Math.ceil(myNumber)

+

"</td></tr>");

document.write("<tr><td>floor()</td><td>"+Math.floor(myNumber)

+

"</td></tr>");

document.write("<tr><td>round()</td><td>"+

Math.round(myNumber)+

"</td></tr>");

document.write("</table>");

</script>

</body>

</html>

Savethisasch5_example4.htmlandloaditintoawebbrowser.Inthepromptbox,enteranumber(forexample,12.354),andclickOK.TheresultsofthisnumberbeingpassedtoparseInt(),ceil(),floor(),andround()willbedisplayedinthepageformattedinsideatable,asshowninFigure5.4.

Figure5.4

Thefirsttaskistogetthenumbertoberoundedfromtheuser:

varmyNumber=prompt("Enterthenumbertoberounded","");

Thenyouwriteoutthenumberandsomedescriptivetext:

document.write("<h3>Thenumberyouenteredwas"+myNumber+"</h3>");

document.write("<p>Theroundingresultsforthisnumberare</p>");

NoticehowthistimesomeHTMLtagsforformattinghavebeenincluded—themainheaderbeingin<h3>tags,andthedescriptionofwhatthetablemeansbeinginsideaparagraph<p>tag.

Nextyoucreatethetableofresults:

document.write("<tablewidth='150'border='1'>");

document.write("<tr><th>Method</th><th>Result</th></tr>");

document.write("<tr><td>parseInt()</td><td>"+

parseInt(myNumber,10)+"</td></tr>");

document.write("<tr><td>ceil()</td><td>"+Math.ceil(myNumber)+

"</td></tr>");

document.write("<tr><td>floor()</td><td>"+Math.floor(myNumber)+

"</td></tr>");

document.write("<tr><td>round()</td><td>"+Math.round(myNumber)+

"</td></tr>");

document.write("</table>");

Youcreatethetableheaderfirstbeforeactuallydisplayingtheresultsofeach

roundingfunctiononaseparaterow.TheprinciplesarethesameaswithHTMLinapage:Youmustmakesureyourtag’ssyntaxisvalidorotherwisethingswillappearstrangeornotappearatall.

Eachrowfollowsthesameprinciplebutusesadifferentroundingfunction.Let’slookatthefirstrow,whichdisplaystheresultsofparseInt():

document.write("<tr><td>parseInt()</td><td>"+

parseInt(myNumber,10)+"</td></tr>");

Insidethestringtobewrittenouttothepage,youstartbycreatingthetablerowwiththe<tr>tag.Thenyoucreateatablecellwitha<td>tagandinsertthenameofthemethodfromwhichtheresultsarebeingdisplayedonthisrow.Thenyouclosethecellwith</td>andopenanewonewith<td>.InsidethisnextcellyouareplacingtheactualresultsoftheparseInt()function.AlthoughanumberisreturnedbyparseInt(),becauseyouareconcatenatingittoastring,JavaScriptautomaticallyconvertsthenumberreturnedbyparseInt()intoastringbeforeconcatenating.Allthishappensinthebackgroundwithoutyouneedingtodoathing.Finally,youclosethecellandtherowwith</td></tr>.

Therandom()MethodTherandom()methodreturnsarandomfloating-pointnumberintherangebetween0and1,where0isincludedand1isnot.ThiscanbeveryusefulfordisplayingrandombannerimagesorforwritingaJavaScriptgame.

Let’slookathowyouwouldmimictherollofasingledie.Inthefollowingpage,10randomnumbersarewrittentothepage.Clickthebrowser’sRefreshbuttontogetanothersetofrandomnumbers.

<!DOCTYPEhtml>

<htmllang="en">

<body>

<script>

vardiceThrow;

for(varthrowCount=0;throwCount<10;throwCount++){

diceThrow=(Math.floor(Math.random()*6)+1);

document.write(diceThrow+"<br>");

}

</script>

</body>

</html>

YouwantdiceThrowtobebetween1and6.Therandom()functionreturnsafloating-pointnumberbetween0andjustunder1.Bymultiplyingthisnumberby6,yougetanumberbetween0andjustunder6.Thenbyadding1,yougetanumberbetween1andjustunder7.Byusingfloor()toalwaysrounditdowntothenextlowestwholenumber,youcanensurethatyou’llendupwithanumberbetween1and6.

Ifyouwantedarandomnumberbetween1and100,youwouldjustchangethecodeso

thatMath.random()ismultipliedby100ratherthan6.

Thepow()MethodThepow()methodraisesanumbertoaspecifiedpower.Ittakestwoparameters,thefirstbeingthenumberyouwantraisedtoapower,andthesecondbeingthepoweritself.Forexample,toraise2tothepowerof8(thatis,tocalculate2*2*2*2*2*2*2*2),youwouldwriteMath.pow(2,8)—theresultbeing256.Unlikesomeoftheothermathematicalmethods,likesin(),cos(),andacos(),whicharenotcommonlyusedinwebprogrammingunlessit’sascientificapplicationyou’rewriting,thepow()methodcanoftenproveveryuseful.

TRYITOUTUsingpow()Inthisexample,youwriteafunctionusingpow(),whichfixesthenumberofdecimalplacesinanumber:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter<5,Example5</title>

</head>

<body>

<script>

functionfix(fixNumber,decimalPlaces){

vardiv=Math.pow(10,decimalPlaces);

fixNumber=Math.round(fixNumber*div)/div;

returnfixNumber;

}

varnumber1=prompt("Enterthenumberwithdecimalplacesyou

"+

"wanttofix","");

varnumber2=prompt("Howmanydecimalplacesdoyouwant?",

"");

document.write(number1+"fixedto"+number2+"decimal

placesis:");

document.write(fix(number1,number2));

</script>

</body>

</html>

Savethepageasch5_example5.html.Whenyouloadthepageintoyourbrowser,youwillbepresentedwithtwopromptboxes.Inthefirst,enterthenumberforwhichyouwanttofixthenumberofdecimalplaces(forexample,2.2345).Inthesecond,enterthenumberofdecimalplacesyouwantfixed(forexample,2).Thentheresultoffixingthenumberyouhaveenteredtothenumberofdecimalplacesyouhavechosenwillbewrittentothepage,asshowninFigure5.5.Fortheexamplenumbers,

thiswillbe2.23.

Figure5.5

Youfirstdefinethefunctionfix().ThisfunctionwillfixitsfixNumberparametertoamaximumofitsdecimalPlacesparameter’snumberofdigitsafterthedecimalplace.Forexample,fixing34.76459toamaximumofthreedecimalplaceswillreturn34.765.

Thefirstlineofcodeinthefunctionsetsthevariabledivtothenumber10raisedtothepowerofthenumberofdecimalplacesyouwant:

functionfix(fixNumber,decimalPlaces){

vardiv=Math.pow(10,decimalPlaces);

Then,inthenextline,youcalculatethenewnumber:

fixNumber=Math.round(fixNumber*div)/div;

WhatthecodeMath.round(fixNumber*div)doesismovethedecimalpointinthenumberthatyouareconvertingtoafterthepointinthenumberthatyouwanttokeep.Sofor2.2345,ifyouwanttokeeptwodecimalplaces,youconvertitto223.45.TheMath.round()methodroundsthisnumbertothenearestinteger(inthiscase223)andsoremovesanyundesireddecimalpart.

Youthenconvertthisnumberbackintothefractionitshouldbe,butofcourseonlythefractionalpartyouwantisleft.Youdothisbydividingbythesamenumber(div)thatyoumultipliedby.Inthisexample,youdivide223by100,whichleaves2.23.Thisis2.2345fixedtotwodecimalplaces.Thisvalueisreturnedtothecallingcodeintheline:

returnfixNumber;

}

Next,youusetwopromptboxestogetnumbersfromtheuser.Youthendisplaytheresultsofusingthesenumbersinyourfix()functiontotheuserusingdocument.write().

Thisexampleisjustthat—anexample.Inafewminutes,youlearnabouttheNumberobject’stoFixed()method,whichdoesthesamethingasthefix()function.

NumberObjectsAswiththeStringobject,Numberobjectsneedtobecreatedbeforetheycanbeused.TocreateaNumberobject,youcanwritethefollowing:

varfirstNumber=newNumber(123);

varsecondNumber=newNumber('123');

However,asyouhaveseen,youcanalsodeclareanumberasprimitiveanduseitasifitwereaNumberobject,lettingJavaScriptdotheconversiontoanobjectforyoubehindthescenes.Forexample:

varmyNumber=123.765;

AswiththeStringobject,thistechniqueispreferablesolongasit’scleartoJavaScriptwhatobjectyouexpecttohavecreatedinthebackground.So,forexample,

varmyNumber="123.567";

willleadJavaScripttoassume,quiterightly,thatit’sastring,andanyattemptstousetheNumberobject’smethodswillfail.

YoulookatjustthetoFixed()methodoftheNumberobjectbecausethat’sthemostusefulmethodforregularuse.

ThetoFixed()MethodThetoFixed()methodcutsanumberoffafteracertainpoint.Let’ssayyouwanttodisplayapriceaftersalestax.Ifyourpriceis$9.99andsalestaxis7.5percent,thatmeanstheafter-taxcostwillbe$10.73925.Well,thisisratheranoddamountforamoneytransaction—whatyoureallywanttodoisfixthenumbertonomorethantwodecimalplaces.Let’screateanexample:

varitemCost=9.99;

varitemCostAfterTax=9.99*1.075;

document.write("Itemcostis$"+itemCostAfterTax+"<br/>");

itemCostAfterTax=itemCostAfterTax.toFixed(2);

document.write("Itemcostfixedto2decimalplacesis"+

"$"+itemCostAfterTax);

Thefirstdocument.write()outputsthefollowingtothepage:

Itemcostis$10.73925

However,thisisnottheformatyouwant;insteadyouwanttwodecimalplaces,soonthenextline,enterthis:

itemCostAfterTax=itemCostAfterTax.toFixed(2);

YouusethetoFixed()methodoftheNumberobjecttofixthenumbervariablethatitemCostAfterTaxholdstotwodecimalplaces.Themethod’sonlyparameteristhenumberofdecimalplacesyouwantyournumberfixedto.Thislinemeansthatthenextdocument.writedisplaysthis:

Itemcostfixedto2decimalplacesis$10.74

Thefirstthingyoumightwonderiswhy10.74andnot10.73?Well,thetoFixed()methoddoesn’tjustchopoffthedigitsnotrequired;italsoroundsupordown.Inthiscase,thenumberwas10.739,whichroundsupto10.74.Ifit’dbeen10.732,itwouldhavebeenroundeddownto10.73.

Notethatyoucanonlyfixanumberfrom0to20decimalplaces.

DateObjectsTheDateobjecthandleseverythingtodowithdateandtimeinJavaScript.Usingit,youcanfindoutthecurrentdateandtime,storeyourowndatesandtimes,docalculationswiththesedates,andconvertthedatesintostrings.

TheDateobjecthasalotofmethodsandcanbealittletrickytouse,whichiswhyChapter7isdedicatedtothedate,time,andtimersinJavaScript.However,inthissectionyoufocusonhowtocreateaDateobjectandsomeofitsmorecommonlyusedmethods.

CreatingaDateObjectYoucandeclareandinitializeaDateobjectinfourways.Inthefirstmethod,yousimplydeclareanewDateobjectwithoutinitializingitsvalue.Inthiscase,thedateandtimevaluewillbesettothecurrentdateandtimeonthePConwhichthescriptisrun:

vartheDate1=newDate();

Secondly,youcandefineaDateobjectbypassingthenumberofmillisecondssinceJanuary1,1970,at00:00:00GMT.Inthefollowingexample,thedateis31January200000:20:00GMT(thatis,20minutespastmidnight):

vartheDate2=newDate(949278000000);

It’sunlikelythatyou’llbeusingthiswayofdefiningaDateobjectveryoften,butthisishowJavaScriptactuallystoresthedates.Theotherformatsforgivingadatearesimplyforconvenience.

ThethirdwayforyoutodeclareaDateobjectistopassastringrepresentingadate,oradateandtime.Inthefollowingexample,youhave"31January2014":

vartheDate3=newDate("31January2014");

However,youcouldhavewritten31Jan2014,Jan312014,oranyofanumberofvalidvariationsyou’dcommonlyexpectwhenwritingdownadatenormally—ifindoubt,tryitout.

Ifyouarewritingyourwebpagesforaninternationalaudience,youneedtobeawareofthedifferentwaysofspecifyingdates.IntheUnitedKingdomandmanyotherplaces,thestandardisday,month,year,whereasintheUnitedStatesthestandardismonth,day,year.Thiscancauseproblemsifyouspecifyonlynumbers—JavaScriptmaythinkyou’rereferringtoadaywhenyoumeanamonth.

InthefourthandfinalwayofdefiningaDateobject,youinitializeitbypassingthefollowingparametersseparatedbycommas:year,month,day,hours,minutes,seconds,andmilliseconds.Forexample:

vartheDate4=newDate(2014,0,31,15,35,20,20);

Thisdateisactually31January2014at15:35:20and20milliseconds.Youcanspecifyjustthedatepartifyouwantandignorethetime.SomethingtobeawareofisthatinthisinstanceJanuaryismonth0,notmonth1,asyou’dexpect,andDecemberismonth11.

TIPIt’sveryeasytomakeamistakewhenspecifyingamonthusingeitherthethirdorfourthmethodofdeclaringaDateobject.Theeasiestwaytoavoidsuchheadachesistoalwaysusethenameofthemonthwherepossible.Thatwaytherecanbenoconfusion.

GettingDateValuesIt’sallverynicehavingstoredadate,buthowdoyougettheinformationoutagain?Well,youjustusethegetmethods.Thesearesummarizedinthefollowingtable:

METHOD RETURNSgetDate() ThedayofthemonthgetDay() Thedayoftheweekasaninteger,withSundayas0,Mondayas1,and

soongetMonth() Themonthasaninteger,withJanuaryas0,Februaryas1,andsoongetFullYear() Theyearasafour-digitnumbertoDateString() Returnsthefulldatebasedonthecurrenttimezoneasahuman-

readablestring,forexample,“Wed31Dec2003”

Forexample,ifyouwanttogetthemonthinourDateObj,youcansimplywritethefollowing:

theMonth=myDateObject.getMonth();

Allthemethodsworkinaverysimilarway,andallvaluesreturnedarebasedonlocaltime,meaningtimelocaltothemachineonwhichthecodeisrunning.It’salsopossibletouseUniversalTime,previouslyknownasGMT,whichwediscussinChapter7.

TRYITOUTUsingtheDateObjecttoRetrievetheCurrentDateInthisexample,youusethegetdatetypemethodsyouhavebeenlookingattowritethecurrentday,month,andyeartoawebpage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example6</title>

</head>

<body>

<script>

varmonths=["January","February","March","April","May",

"June","July","August","September",

"October","November","December"];

vardateNow=newDate();

varyearNow=dateNow.getFullYear();

varmonthNow=months[dateNow.getMonth()];

vardayNow=dateNow.getDate();

vardaySuffix;

switch(dayNow){

case1:

case21:

case31:

daySuffix="st";

break;

case2:

case22:

daySuffix="nd";

break;

case3:

case23:

daySuffix="rd";

break;

default:

daySuffix="th";

break;

}

document.write("Itisthe"+dayNow+daySuffix+"day");

document.write("inthemonthof"+monthNow);

document.write("intheyear"+yearNow);

</script>

</body>

</html>

Savethecodeasch5_example6.html.Whenyouloadthepageinyourbrowser,youshouldseeacorrectlyformattedsentencetellingyouthecurrentdate.

Thefirstthingyoudointhecodeisdeclareanarrayandpopulateitwiththemonthsofayear.Whydothis?Well,thereisnomethodoftheDateobjectthat’llgiveyouthemonthbynameinsteadofasanumber.However,thisposesnoproblem;youjustdeclareanarrayofmonthsandusethemonthnumberasthearrayindextoselectthecorrectmonthname:

varmonths=["January","February","March","April","May","June",

"July",

"August","September","October","November",

"December"];

NextyoucreateanewDateobject,andbynotinitializingitwithyourownvalue,youallowittoinitializeitselftothecurrentdateandtime:

vardateNow=newDate();

FollowingthisyousettheyearNowvariabletothecurrentyear,asreturnedbythegetFullYear()method:

varyearNow=dateNow.getFullYear();

YouthenpopulateyourmonthNowvariablewiththevaluecontainedinthearrayelementwithanindexofthenumberreturnedbygetMonth().RememberthatgetMonth()returnsthemonthasanintegervalue,startingwith0forJanuary—thisisabonusbecausearraysalsostartat0,sonoadjustmentisneededtofindthecorrectarrayelement:

varmonthNow=months[dateNow.getMonth()];

Finally,youputthecurrentdayofthemonthintothevariabledayNow:

vardayNow=dateNow.getDate();

Nextyouuseaswitchstatement,whichyoulearnedaboutinChapter3.Thisisausefultechniqueforaddingthecorrectsuffixtothedatethatyoualreadyhave.Afterall,yourapplicationwilllookmoreprofessionalifyoucansay"itisthe1stday",ratherthan"itisthe1day".Thisisalittletricky,however,becausethesuffixyouwanttoadddependsonthenumberthatprecedesit.So,forthefirst,twenty-first,andthirty-firstdaysofthemonth,youhavethis:

switch(dayNow){

case1:

case21:

case31:

daySuffix="st";

break;

Forthesecondandtwenty-seconddays,youhavethis:

case2:

case22:

daySuffix="nd";

break;

andforthethirdandtwenty-thirddays,youhavethis:

case3:

case23:

daySuffix="rd";

break;

Finally,youneedthedefaultcaseforeverythingelse.Asyouwillhaveguessedbynow,thisissimply"th":

default:

daySuffix="th";

break;

}

InthefinallinesyousimplywritetheinformationtotheHTMLpage,usingdocument.write().

SettingDateValuesTochangepartofthedateinaDateobject,youhaveagroupofsetfunctions,whichprettymuchreplicatethegetfunctionsdescribedearlier,exceptthatyouaresetting,notgetting,thevalues.Thesefunctionsaresummarizedinthefollowingtable:

METHOD DESCRIPTIONsetDate() Thedateofthemonthispassedinastheparametertosetthedate.setMonth() Themonthoftheyearispassedinasanintegerparameter,where0is

January,1isFebruary,andsoon.setFullYear() Thissetstheyeartothefour-digitintegernumberpassedinasa

parameter.

NOTEthatforsecurityreasons,thereisnowayforweb-basedJavaScripttochangethecurrentdateandtimeonauser’scomputer.

So,tochangetheyearto2016,thecodewouldbeasfollows:

myDateObject.setFullYear(2016);

Settingthedateandmonthtothe27thofFebruarylookslikethis:

myDateObject.setDate(27);

myDateObject.setMonth(1);

OneminorpointtonotehereisthatthereisnodirectequivalentofthegetDay()method.Aftertheyear,date,andmonthhavebeendefined,thedayisautomaticallysetforyou.

CalculationsandDatesTakealookatthefollowingcode:

varmyDate=newDate("1Jan2010");

myDate.setDate(32);

document.write(myDate);

Surelythereissomeerror—sincewhenhasJanuaryhad32days?Theansweristhatofcourseitdoesn’t,andJavaScriptknowsthat.InsteadJavaScriptsetsthedateto32daysfromthefirstofJanuary—thatis,itsetsittothe1stofFebruary.

ThesamealsoappliestothesetMonth()method.Ifyousetittoavaluegreaterthan11,thedateautomaticallyrollsovertothenextyear.SoifyouusesetMonth(12),thatwillsetthedatetoJanuaryofthenextyear,andsimilarlysetMonth(13)isFebruaryofthenextyear.

HowcanyouusethisfeatureofsetDate()andsetMonth()toyouradvantage?Well,let’ssayyouwanttofindoutwhatdateitwillbe28daysfromnow.Giventhatdifferentmonthshavedifferentnumbersofdaysandthatyoucouldrollovertoadifferentyear,it’snotassimpleataskasitmightfirstseem.OratleastthatwouldbethecaseifitwerenotforsetDate().Thecodetoachievethistaskisasfollows:

varnowDate=newDate();

varcurrentDay=nowDate.getDate();

nowDate.setDate(currentDay+28);

FirstyougetthecurrentsystemdatebysettingthenowDatevariabletoanewDateobjectwithnoinitializationvalue.Inthenextline,youputthecurrentdayofthemonthintoavariablecalledcurrentDay.Why?Well,whenyouusesetDate()andpassitavalueoutsideofthemaximumnumberofdaysforthatmonth,itstartsfromthefirstofthemonthandcountsthatmanydaysforward.So,iftoday’sdateisJanuary15andyouusesetDate(28),it’snot28daysfromthe15thofJanuary,but28daysfromthe1stofJanuary.Whatyouwantis28daysfromthecurrentdate,soyouneedtoaddthecurrentdatetothenumberofdaysaheadyouwant.SoyouwantsetDate(15+28).Inthethirdline,yousetthedatetothecurrentdate,plus28days.YoustoredthecurrentdayofthemonthincurrentDay,sonowyoujustadd28tothattomove28daysahead.

Ifyouwantthedate28dayspriortothecurrentdate,youjustpassthecurrentdateminus28.Notethatthiswillmostoftenbeanegativenumber.Youneedtochangeonlyoneline,andthat’sthethirdone,whichyouchangetothefollowing:

nowDate.setDate(currentDay-28);

YoucanuseexactlythesameprinciplesforsetMonth()asyouhaveusedforsetDate().

GettingTimeValuesThemethodsyouusetoretrievetheindividualpiecesoftimedataworkmuchlikethegetmethodsfordatevalues.Themethodsyouusehereare:

getHours()

getMinutes()

getSeconds()

getMilliseconds()

toTimeString()

Thesemethodsreturn,respectively,thehours,minutes,seconds,milliseconds,andfulltimeofthespecifiedDateobject,wherethetimeisbasedonthe24-hourclock:0formidnightand23for11p.m.ThelastmethodissimilartothetoDateString()methodinthatitreturnsaneasilyreadablestring,exceptthatinthiscaseitcontainsthetime(forexample,"13:03:51UTC").

TRYITOUTWritingtheCurrentTimeintoaWebPageLet’slookatanexamplethatwritesoutthecurrenttimetothepage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example7</title>

</head>

<body>

<script>

vargreeting;

varnowDate=newDate();

varnowHour=nowDate.getHours();

varnowMinute=nowDate.getMinutes();

varnowSecond=nowDate.getSeconds();

if(nowMinute<10){

nowMinute="0"+nowMinute;

}

if(nowSecond<10){

nowSecond="0"+nowSecond;

}

if(nowHour<12){

greeting="GoodMorning";

}elseif(nowHour<17){

greeting="GoodAfternoon";

}else{

greeting="GoodEvening";

}

document.write("<h4>"+greeting+"andwelcometomy

website</h4>");

document.write("Accordingtoyourclockthetimeis");

document.write(nowHour+":"+nowMinute+":"+nowSecond);

</script>

</body>

</html>

Savethispageasch5_example7.html.Whenyouloaditintoawebbrowser,itwritesagreetingbasedonthetimeofdayaswellasthecurrenttime,asshowninFigure5.6.

Figure5.6

Thefirsttwolinesofcodedeclaretwovariables—greetingandnowDate:

vargreeting;

varnowDate=newDate();

Thegreetingvariablewillbeusedshortlytostorethewelcomemessageonthewebsite,whetherthisis"GoodMorning","GoodAfternoon",or"GoodEvening".ThenowDatevariableisinitializedtoanewDateobject.NotethattheconstructorfortheDateobjectisempty,soJavaScriptwillstorethecurrentdateandtimeinit.

Next,yougettheinformationonthecurrenttimefromnowDateandstoreitinvariousvariables.Youcanseethatgettingtimedataisverysimilartogettingdatedata,justusingdifferentmethods:

varnowHour=nowDate.getHours();

varnowMinute=nowDate.getMinutes();

varnowSecond=nowDate.getSeconds();

Youmaywonderwhythefollowinglinesareincludedintheexample:

if(nowMinute<10){

nowMinute="0"+nowMinute;

}

if(nowSecond<10){

nowSecond="0"+nowSecond;

}

Theselinesaretherejustforformattingreasons.Ifthetimeisnineminutespast10,thenyouexpecttoseesomethinglike10:09.Youdon’texpect10:9,whichiswhatyouwouldgetifyouusedthegetMinutes()methodwithoutaddingtheextrazero.Thesamegoesforseconds.Ifyou’rejustusingthedataincalculations,youdon’tneedtoworryaboutformattingissues—youdoherebecauseyou’reinsertingthetimethecodeexecutedintothewebpage.

Next,inaseriesofifstatements,youdecide(basedonthetimeofday)whichgreetingtocreatefordisplayingtotheuser:

if(nowHour<12){

greeting="GoodMorning";

}elseif(nowHour<17){

greeting="GoodAfternoon";

}else{

greeting="GoodEvening";

}

Finally,youwriteoutthegreetingandthecurrenttimetothepage:

document.write("<h4>"+greeting+"andwelcometomywebsite</h4>");

document.write("Accordingtoyourclockthetimeis");

document.write(nowHour+":"+nowMinute+":"+nowSecond);

SettingTimeValuesWhenyouwanttosetthetimeinyourDateobjects,youhaveaseriesofmethodssimilartothoseusedforgettingthetime:

setHours()

setMinutes()

setSeconds()

setMilliseconds()

Theseworkmuchlikethemethodsyouusetosetthedate,inthatifyousetanyofthetimeparameterstoanillegalvalue,JavaScriptassumesyoumeanthenextorprevioustimeboundary.Ifit’s9:57andyousetminutesto64,thetimewillbesetto10:04—thatis,64minutesfrom9:00.

Thisisdemonstratedinthefollowingcode:

varnowDate=newDate();

nowDate.setHours(9);

nowDate.setMinutes(57);

alert(nowDate);

nowDate.setMinutes(64);

alert(nowDate);

FirstyoudeclarethenowDatevariableandassignittoanewDateobject,whichwillcontainthecurrentdateandtime.Inthefollowingtwolines,yousetthehoursto9andthe

minutesto57.Youshowthedateandtimeusinganalertbox,whichshouldshowatimeof9:57.Theminutesarethensetto64andagainanalertboxisusedtoshowthedateandtimetotheuser.Nowtheminuteshaverolledoverthehoursothetimeshownshouldbe10:04.

Ifthehoursweresetto23insteadof9,settingtheminutesto64wouldnotjustmovethetimetoanotherhour,butalsocausethedaytochangetothenextdate.

CREATINGYOUROWNCUSTOMOBJECTSWe’vespentalotoftimediscussingobjectsbuiltintoJavaScript,butJavaScript’srealpowercomesfromthefactthatyoucancreateyourownobjectstorepresentcomplexdata.Forexample,imaginethatyouneedtorepresentanindividualpersoninyourcode.Youcouldsimplyusetwovariablesforanindividualperson’sfirstnameandlastname,likethis:

varfirstName="John";

varlastName="Doe";

Butwhatifyouneededtorepresentmultiplepeople?Creatingtwovariablesforeverypersonwouldgetunwieldyveryquickly,andkeepingtrackofeveryvariableforeverypersonwouldcauseheadachesforeventhebestprogrammersintheworld.Instead,youcouldcreateanobjecttorepresenteachindividualperson.Eachoftheseobjectswouldcontainthenecessaryinformationthatmakesonepersonuniquefromother(suchasaperson’sfirstandlastnames).

TocreateanobjectinJavaScript,simplyusethenewoperatorinconjunctionwiththeObjectconstructor,likethis:

varjohnDoe=newObject();

Butlikearrays,JavaScriptprovidesaliteralsyntaxtosignifyanobject:apairofcurlybraces({}).Soyoucanrewritethepreviouscodelikethis:

varjohnDoe={};

Today’sJavaScriptdevelopersfavorthisliteralsyntaxinsteadofcallingtheObjectconstructor.

Onceyouhaveanobject,youcanbegintopopulateitwithproperties.Itissimilartocreatingavariable,exceptyoudonotusethevarkeyword.Simplyusethenameoftheobject,followedbyadot,thenthenameoftheproperty,andassignitavalue.Forexample:

johnDoe.firstName="John";

johnDoe.lastName="Doe";

ThesetwolinesofcodecreatethefirstNameandlastNamepropertiesonthejohnDoeobjectandassigntheirrespectivevalues.JavaScriptdoesnotcheckifthesepropertiesexistbeforethey’recreated;itsimplycreatesthem.Thisfreepropertycreationmightsoundgreat(anditis!),butitdoeshavedrawbacks.TheprimaryissueisthatJavaScriptwon’ttellyouifyouaccidentallymisspellapropertyname;it’lljustcreateanewpropertywiththemisspelledname,somethingthatcanmakeitdifficulttotrackbugs.Soalwaysbecarefulwhencreatingproperties.

Youcanassignmethodsinthesameway,exceptyouassignafunctioninsteadofanothertypeofvalue,likethis:

johnDoe.greet=function(){

alert("Mynameis"+this.firstName+""+this.lastName;

};

Thiscodecreatesamethodcalledgreet(),whichsimplyalertsagreeting.Afewimportantthingsareimportanttonoteinthiscode.

First,noticethereisnonamebetweenfunctionand().Afunctionthathasnonameiscalledananonymousfunction.Anonymousfunctions,inandofthemselves,areasyntaxerrorunlessyouassignthatfunctiontoavariable.Onceyouassignananonymousfunctiontoavariable,thatfunction’snamebecomesthenameofthevariable.SoyoucanexecutetheanonymousfunctionassignedtojohnDoe.greetlikethis:

johnDoe.greet();

Next,noticetheuseofthisinsideofthefunction:this.firstNameandthis.lastName.InJavaScript,thisisaspecialvariablethatreferstothecurrentobject—thejohnDoeobjectinthiscase.Itliterallymeans“thisobject.”Soyoucouldrewritegreet()likethefollowing:

johnDoe.greet=function(){

alert("Mynameis"+johnDoe.firstName+""+johnDoe.lastName;

};

However,youwon’talwayshavethenameofobjecttouseinplaceofthis.Therefore,itispreferredtorefertothecurrentobjectinsideofamethodbyusingthisratherthantheactualnameoftheobject.

ThefullcodeforcreatingthisjohnDoeobjectlookslikethis:

varjohnDoe={};

johnDoe.firstName="John";

johnDoe.lastName="Doe";

johnDoe.greet=function(){

alert("Mynameis"+johnDoe.firstName+""+johnDoe.lastName;

};

ThisisperfectlyvalidJavaScript,butittakesfourstatementstocreatethecompleteobject.Thesefourstatementscanbereducedtoonestatementbydefiningtheentireobjectusingliteralnotation.Admittedly,itwilllookalittleweirdatfirst,butyou’llsoongetusedtoit:

varjohnDoe={

firstName:"John",

lastName:"Doe",

greet:function(){

alert("Mynameis"+

this.firstName+""+

this.lastName;

}

};

Takeamomentandstudythiscode.First,noticethiscodeusescurlybracestoenclosethe

entireobject.Thennoticethateachpropertyandmethodisdefinedbyspecifyingthenameoftheproperty/method,followedbyacolon,andthenitsvalue.So,assigningthefirstNamepropertylookslikethis:

firstName:"John"

Thereisnoequalsignusedhere.Inobjectliteralnotation,thecolonsetsthevalueoftheproperty.

Finally,noticethateachpropertyandmethoddefinitionisseparatedbyacomma—verymuchlikehowyouseparateindividualelementsinanarrayliteral.

TRYITOUTUsingObjectLiteralsItisveryimportantforyoutounderstandobjectliterals—theyareusedextremelyliberallybyJavaScriptdevelopers.Let’slookatanexamplethatusesafunctiontocreateacustomobject:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Example8</title>

</head>

<body>

<script>

functioncreatePerson(firstName,lastName){

return{

firstName:firstName,

lastName:lastName,

getFullName:function(){

returnthis.firstName+""+this.lastName

},

greet:function(person){

alert("Hello,"+person.getFullName()+

".I'm"+this.getFullName());

}

};

}

varjohnDoe=createPerson("John","Doe");

varjaneDoe=createPerson("Jane","Doe");

johnDoe.greet(janeDoe);

</script>

</body>

</html>

Savethispageasch5_example8.html.Whenyouloadthepageintoawebbrowser,itdisplaysthemessage:"Hello,JaneDoe.I'mJohnDoe".

First,thiscodecreatesafunctioncalledcreatePerson()thatacceptsaperson’sfirstandlastnamesasparameters.Thisfunctioncreatesanobjectwiththeperson’sfirst

andlastnamesusingobjectliteralnotation:

functioncreatePerson(firstName,lastName){

return{

ThefirstpropertycreatedisthefirstNameproperty,anditisassignedthevalueofthefirstNameparameter:

firstName:firstName,

NextisthelastNameproperty,whichreceivesitsvaluefromthecreatePerson()function’slastNameparameter:

lastName:lastName,

ThenamethodcalledgetFullName()iscreated.Itspurposeistoreturnthefirstandlastnameofthepersontothecaller:

getFullName:function(){

returnthis.firstName+""+this.lastName

},

Thismethodusesthethisvariabletoaccessthisobject’sfirstNameandlastNameproperties.Notethatthethisvariableistheonlywaytoretrievetheseproperties—theobjectdoesn’thaveaname;itisananonymousobjectthatiscreatedandthenreturnedtothecaller.

Thefinalmethodofthisobjectisgreet().ItacceptsanotherpersonobjectasaparameterandusesitsgetFullName()inordertogreetthatperson:

greet:function(person){

alert("Hello,"+person.getFullName()+

".I'm"+this.getFullName());

}

};

}

Thenexttwolinescreatetwoobjectstworepresenttwoindividualpeople:

varjohnDoe=createPerson("John","Doe");

varjaneDoe=createPerson("Jane","Doe");

Noticetheabsenceofthenewkeyword.ThecreatePerson()functionisnotaconstructorfunction(youlearnhowtowriteconstructorfunctionslater).It’ssimplyafunctionthatcreatesandreturnsanobject.

Finally,JohnDoegreetsJaneDoebycallingthegreet()methodandpassingthejaneDoeobjecttoit:

johnDoe.greet(janeDoe);

CREATINGNEWTYPESOFOBJECTS(REFERENCETYPES)Thissection’sfocusisonsomeadvancedstuff.It’snotessentialstuff,soyoumaywanttomoveonandcomebacktoitlater.

You’veseenthatJavaScriptprovidesanumberofobjectsbuiltintothelanguageandreadyforustouse.You’vealsobuiltcustomobjectsthatyoucanusetorepresentmorecomplexdata,butJavaScriptalsoenablesyoutocreateyourowntypeofobjects.Forexample,youcreatedanobjectthatrepresentedanindividualperson,butyoucanalsocreateanobjectthatisaPersonobject.

It’sabitlikeahousethat’sbuiltalreadyandyoucanjustmoveonin.However,whatifyouwanttocreateyourownhouse,todesignitforyourownspecificneeds?Inthatcaseyou’lluseanarchitecttocreatetechnicaldrawingsandplansthatprovidethetemplateforthenewhouse—thebuildersusetheplanstotellthemhowtocreatethehouse.

SowhatdoesanyofthishavetodowithJavaScriptandobjects?Well,JavaScriptenablesyoutobeanarchitectandcreatethetemplatesforyourownobjectstoyourownspecification,tofityourspecificneeds.Goingbacktothepersonobjectexample,JavaScriptdoesn’tcomewithbuilt-inpersonobjects,soyou’dhavetodesignyourown.

Justasabuilderofahouseneedsanarchitect’splanstoknowwhattobuildandhowitshouldbelaidout,youneedtoprovideblueprintstellingJavaScripthowyourobjectshouldlook.YousomewhatdidthiswiththecreatePerson()functioninch5 _ example8.html,butyouonlycreatedplainobjectswithcustompropertiesandmethods—youdidn’tcreateanactualPersonobject.

ButJavaScriptsupportsthedefinitionofreferencetypes.Referencetypesareessentiallytemplatesforanobject,asthearchitect’sdrawingsarethetemplateusedtobuildahouse.Beforeyoucanuseyournewobjecttype,youneedtodefineitalongwithitsmethodsandproperties.Theimportantdistinctionisthatwhenyoudefineyourreferencetype,noobjectbasedonthattypeiscreated.It’sonlywhenyoucreateaninstanceofyourreferencetypeusingthenewkeywordthatanobjectofthattype,basedonyourblueprintorprototype,iscreated.

Beforeyoustart,animportantdistinctionmustbemade.Manydevelopersrefertoreferencetypesasclassesandusethetwotermsinterchangeably.Althoughthisiscorrectformanyobject-orientedlanguagessuchasJava,C#,andC++,itisnotcorrectforJavaScript.JavaScriptdoesnotyetsupportaclassconstruct,althoughthenextversionofJavaScriptwillprovideformalclasses.JavaScriptdoes,however,fullysupportthelogicalequivalent,referencetypes.

It’salsoimportanttopointoutthatthebuilt-inobjectsdiscussedthusfarinthischapterarealsoreferencetypes.String,Array,Number,Date,andevenObjectareallreferencetypes,andtheobjectsyoucreatedareinstancesofthesetypes.

Areferencetypeconsistsofthreethings:

Aconstructor

Methoddefinitions

Properties

Aconstructorisafunctionthatiscalledeverytimeoneofyourobjectsbasedonthisreferencetypeiscreated.It’susefulwhenyouwanttoinitializepropertiesortheobjectinsomeway.Youneedtocreateaconstructorevenifyoudon’tpassanyparameterstoitorifitcontainsnocode.(Inthatcaseit’djustbeanemptydefinition.)Aswithallfunctions,aconstructorcanhavezeroormoreparameters.

You’vecreatedobjectstorepresentindividualpeople.Nextyoucreateasimplereference,calledPerson,todothesamething—exceptthattheseobjectswillbeactualPersonobjects.

DefiningaReferenceTypeThefirstthingyouneedtodoiscreatetheconstructor,whichisshownhere:

functionPerson(firstName,lastName){

this.firstName=firstName;

this.lastName=lastName;

}

Yourfirstthoughtmightbethatwhatyouhavehereissimplyafunction,andyou’dberight.It’snotuntilyoustartdefiningthepropertiesandmethodsthatitbecomessomethingmorethanafunction.Thisisincontrasttosomeprogramminglanguages,whichhaveamoreformalwayofdefiningtypes.

NOTETypically,areferencetypeisdefinedwithanuppercaseletter.Doingsomakesiteasytodifferentiateafunctionfromareferencetypeeasilyandquickly.

Insidethefunction,noticetheuseofthethisvariable.Onceagain,itliterallymeans“thisobject,”anditistheonlywaytoaccesstheobjectthatisbeingcreated.SotocreatethefirstNameandlastNameproperties,youwritethefollowingcode:

this.firstName=firstName;

this.lastName=lastName;

NowyouneedtodefinegetFullName()andgreet()methods.Youcandefinetheminsideoftheconstructor,butitismoreefficienttodefinethemonPerson’sprototype,likethis:

Person.prototype.getFullName=function(){

returnthis.firstName+""+this.lastName;

};

Person.prototype.greet=function(person){

alert("Hello,"+person.getFullName()+

".I'm"+this.getFullName());

};

ThefirstthingyounoticeisPerson.prototype.RememberfromChapter4thatfunctions

areobjectsinJavaScript,andinthischapteryoulearnedthatobjectshavepropertiesandmethods.Soit’seasytoassumethatfunctionshavepropertiesandmethods.

Everyfunctionobjecthasaprototypeproperty,butitisonlyusefulforconstructorfunctions.YoucanthinkofthePerson.prototypepropertyasanactualprototypeforPersonobjects.AnypropertiesandmethodsyouassigntoPerson.prototypeareusableonallPersonobjects.Infact,they’remorethanusable—they’reshared!

ThefunctionsassignedtoPerson.prototype.getFullNameandPerson.prototype.greetaresharedbetweenallobjects,orinstances,ofPerson.ThismeansthatthefunctionobjectofonePersonobject’sgetFullNameistheexactsamefunctionobjectonanotherPersonobject’sgetFullName.Toexpressthatincode:

varareSame=person1.getFullName==person2.getFullName;//true

ButwhywerefirstNameandlastNameassignedintheconstructorinsteadofPerson.prototype?ThefirstNameandlastNamepropertiesarecalledinstancedata.Instancedataisuniquetoeachindividualobject,orinstance.SobecausefirstNameandlastNameareinstancedata,wedefinethemintheconstructor—theyshouldn’tbesharedbetweenallPersonobjects.

CreatingandUsingReferenceTypeInstancesYoucreateinstancesofyourreferencetypeinthesamewayyoucreatedinstancesofJavaScript’sbuilt-intypes:usingthenewkeyword.SotocreateanewinstanceofPerson,you’dwritethis:

varjohnDoe=newPerson("John","Doe");

varjaneDoe=newPerson("Jane","Doe");

Here,aswithaDateobject,youhavecreatedtwonewobjectsandstoredtheminvariables,johnDoeandjaneDoe,butthistimeit’sanewobjectbasedonthePersontype.

NOTETheuseofthenewkeywordisveryimportantwhencreatinganobjectwithaconstructor.Thebrowserdoesnotthrowanerrorifyoudonotusethenewkeyword,butyourscriptwillnotworkcorrectly.Insteadofcreatinganewobject,youactuallyaddpropertiestotheglobalwindowobject.Theproblemscausedbynotusingthenewkeywordcanbehardtodiagnose,somakesureyouspecifythenewkeywordwhencreatingobjectswithaconstructor.

Youusetheseobjectsjustlikeyoudidinch5 _ example8.html.Inthefollowingcode,JaneDoegreetsJohnDoe:

janeDoe.greet(johnDoe);

EventhoughgetFullName()andgreet()aredefinedonPerson.prototype,youstillcallthemlikenormalmethods.JavaScriptisintelligentenoughtolookatPerson.prototypeforthosemethods.

Nowforthemilliondollarquestion:Whydefineareferencetypeinsteadofcreatingplain,

butcustom,objects?It’savalidquestion.Boththeobjectscreatedinch5_example8.htmlandfromthePersonconstructorservethesamepurpose:torepresentanindividualperson.Themaindifferenceishowtheobjectsarecreated.Objectscreatedfromaconstructortypicallyconsumelessofthecomputer’smemorythanliteralobjects.

Frankly,it’saquestionyoudon’thavetoworryaboutatthispointintime.It’smoreimportanttoknowhowtocreateobjectsthanusingthecorrectapproach.Sopracticebothmethods;createyourowncustomobjectsandreferencetypes!

SUMMARYInthischapteryou’vetakenalookattheconceptofobjectsandseenhowvitaltheyaretoanunderstandingofJavaScript,whichrepresentsvirtuallyeverythingwithobjects.YoualsolookedatsomeofthevariousnativereferencetypesthattheJavaScriptlanguageprovidestoaddtoitsfunctionality.

Yousawthat:

JavaScriptisobject-based—itrepresentsthings,suchasstrings,dates,andarrays,usingtheconceptofobjects.

Objectshavepropertiesandmethods.Forexample,anArrayobjecthasthelengthpropertyandthesort()method.

Tocreateanewobject,yousimplywritenewObjectType().Youcanchoosetoinitializeanobjectwhenyoucreateit.

Tosetanobject’spropertyvalueorgetthatvalue,yousimplywriteobjectName.objectProperty.

Callingthemethodsofanobjectissimilartocallingfunctions.Parametersmaybepassed,andreturnvaluesmaybepassedback.Accessingthemethodsofanobjectisidenticaltoaccessingaproperty,exceptthatyoumustremembertoaddparenthesesattheend,evenwhenithasnoparameters.Forexample,youwouldwriteobjectName.objectMethod().

TheStringtypeprovideslotsofhandyfunctionalityfortextandgivesyouwaysoffindingouthowlongthetextis,searchingfortextinsidethestring,andselectingpartsofthetext.

TheMathtypeiscreatedautomaticallyandprovidesanumberofmathematicalpropertiesandmethods.Forexample,toobtainarandomnumberbetween0and1,youusethemethodMath.random().

TheArraytypeprovideswaysofmanipulatingarrays.Someofthethingsyoucandoarefindthelengthofanarray,sortitselements,andjointwoarraystogether.

TheDatetypeprovidesawayofstoring,calculatingwith,andlateraccessingdatesandtimes.

JavaScriptletsyoucreateyourowncustomobjects,givingthemthepropertiesandmethodsthatyouwantthemtohave.

JavaScriptenablesyoutocreateyourowntypesofobjectsusingreferencetypes.Thesecanbeusedtomodelreal-worldsituationsandformakingcodeeasiertocreateandmoremaintainable,thoughtheydorequireextraeffortatthestart.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. UsingtheDatetype,calculatethedate12monthsfromnowandwritethisintoawebpage.

2. Obtainalistofnamesfromtheuser,storingeachnameenteredinanarray.Keepgettinganothernameuntiltheuserentersnothing.Sortthenamesinascendingorderandthenwritethemouttothepage,witheachnameonitsownline.

3. ch5_example8.htmlusesafunctiontocreateobjectsusingliteralnotation.ModifythisexampletousethePersondatatype.

6StringManipulationWHATYOUWILLLEARNINTHISCHAPTER:

UsingtheStringobject’sadvancedmethodstomanipulatestrings

Matchingsubstringsfollowaspecificpattern

Validatingusefulpiecesofinformation,suchastelephonenumbers,e-mailaddresses,andpostalcodes

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

InChapter5youlookedattheStringobject,whichisoneofthenativeobjectsthatJavaScriptmakesavailabletoyou.Yousawanumberofitspropertiesandmethods,includingthefollowing:

length—Thelengthofthestringincharacters

charAt()andcharCodeAt()—Themethodsforreturningthecharacterorcharactercodeatacertainpositioninthestring

indexOf()andlastIndexOf()—Themethodsthatallowyoutosearchastringfortheexistenceofanotherstringandthatreturnthecharacterpositionofthestringiffound

substr()andsubstring()—Themethodsthatreturnjustaportionofastring

toUpperCase()andtoLowerCase()—Themethodsthatreturnastringconvertedtoupper-orlowercase

InthischapteryoulookatfournewmethodsoftheStringobject,namelysplit(),match(),replace(),andsearch().Thelastthree,inparticular,giveyousomeverypowerfultext-manipulationfunctionality.However,tomakefulluseofthisfunctionality,youneedtolearnaboutaslightlymorecomplexsubject.

Themethodssplit(),match(),replace(),andsearch()canallmakeuseofregularexpressions,somethingJavaScriptwrapsupinanobjectcalledtheRegExpobject.Regularexpressionsenableyoutodefineapatternofcharacters,whichyoucanusefortextsearchingorreplacement.Say,forexample,thatyouhaveastringinwhichyouwanttoreplaceallsinglequotesenclosingtextwithdoublequotes.Thismayseemeasy—justsearchthestringfor'andreplaceitwith"—butwhatifthestringisBobO'Harasaid"Hello"?Youwouldnotwanttoreplacethesingle-quotecharacterinO'Hara.Youcanperformthistextreplacementwithoutregularexpressions,butitwouldtakemorethanthetwolinesofcodeneededifyoudouseregularexpressions.

Althoughsplit(),match(),replace(),andsearch()areattheirmostpowerfulwithregularexpressions,theycanalsobeusedwithjustplaintext.Youtakealookathowtheyworkinthissimplercontextfirst,tobecomefamiliarwiththemethods.

ADDITIONALSTRINGMETHODSInthissectionyoutakealookatthesplit(),replace(),search(),andmatch()methods,andseehowtheyworkwithoutregularexpressions.

Thesplit()MethodTheStringobject’ssplit()methodsplitsasinglestringintoanarrayofsubstrings.Wherethestringissplitisdeterminedbytheseparationparameterthatyoupasstothemethod.Thisparameterissimplyacharacterortextstring.

Forexample,tosplitthestring"A,B,C"sothatyouhaveanarraypopulatedwiththelettersbetweenthecommas,thecodewouldbeasfollows:

varmyString="A,B,C";

varmyTextArray=myString.split(",");

JavaScriptcreatesanarraywiththreeelements.InthefirstelementitputseverythingfromthestartofthestringmyStringuptothefirstcomma.Inthesecondelementitputseverythingfromafterthefirstcommatobeforethesecondcomma.Finally,inthethirdelementitputseverythingfromafterthesecondcommatotheendofthestring.So,yourarraymyTextArraywilllooklikethis:

ABC

If,however,yourstringwere"A,B,C,"JavaScriptwouldsplititintofourelements,thelastelementcontainingeverythingfromthelastcommatotheendofthestring;inotherwords,thelaststringwouldbeanemptystring:

ABC

Thisissomethingthatcancatchyouoffguardifyou’renotawareofit.

TRYITOUTReversingtheOrderofTextLet’screateashortexampleusingthesplit()method,inwhichyoureversethelineswrittenina<textarea>element:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example1</title>

</head>

<body>

<script>

varvalues=prompt("Pleaseenterasetofcommaseparated

values.",

"Apples,Oranges,Bananas");

functionsplitAndReverseText(csv){

varparts=csv.split(",");

parts.reverse();

varreversedString=parts.join(",");

alert(reversedString);

}

splitAndReverseText(values);

</script>

</body>

</html>

Savethisasch6 _ example1.htmlandloaditintoyourbrowser.Usethedefaultvalueinthepromptbox,clickOK,andyoushouldseethescreenshowninFigure6.1.

Figure6.1

Tryothercomma-separatedvaluestotestitfurther.

ThekeytohowthiscodeworksisthefunctionsplitAndReverseText().Itacceptsastringvaluethatshouldcontainoneormorecommas.Youstartbysplittingthevaluecontainedwithincsvusingthesplit()methodandputtingtheresultingarrayinsidethepartsvariable:

functionsplitAndReverseText(csv){

varparts=csv.split(",");

Thisusesacommaastheseparator.YouthenreversethearrayofstringpartsusingtheArrayobject’sreverse()method:

parts.reverse();

Withthearraynowreversed,it’sjustasimplematterofcreatingthenewstring.YoucaneasilyaccomplishthiswiththeArrayobject’sjoin()method:

varreversedString=parts.join(",");

RememberfromChapter5thatthejoin()methodconvertsanarrayintoastring,separatingeachelementwiththespecifiedseparator.

Finally,youdisplaythenewstringinanalertbox:

alert(reversedString);

}

Afteryou’velookedatregularexpressions,you’llrevisitthesplit()method.

Thereplace()MethodThereplace()methodsearchesastringforoccurrencesofasubstring.Whereitfindsamatchforthissubstring,itreplacesthesubstringwithathirdstringthatyouspecify.

Let’slookatanexample.SayyouhaveastringwiththewordMayinit,asshowninthefollowing:

varmyString="TheeventwillbeinMay,the21stofJune";

Now,sayyouwanttoreplaceMaywithJune.Youcanusethereplace()methodlikeso:

VarmyCleanedUpString=myString.replace("May","June");

ThevalueofmyStringwillnotbechanged.Instead,thereplace()methodreturnsthevalueofmyStringbutwithMayreplacedwithJune.YouassignthisreturnedstringtothevariablemyCleanedUpString,whichwillcontainthecorrectedtext:

"TheeventwillbeinJune,the21stofJune"

Thesearch()MethodThesearch()methodenablesyoutosearchastringforaparticularpieceoftext.Ifthetextisfound,thecharacterpositionatwhichitwasfoundisreturned;otherwise,-1isreturned.Themethodtakesonlyoneparameter,namelythetextyouwanttosearchfor.

Whenusedwithplaintext,thesearch()methodprovidesnorealbenefitovermethodslikeindexOf(),whichyou’vealreadyseen.However,youseelaterthatthepowerofthismethodbecomesapparentwhenyouuseregularexpressions.

Inthefollowingexample,youwanttofindoutifthewordJavaiscontainedwithinthestringcalledmyString:

varmyString="BeginningJavaScript,BeginningJava,"+

"ProfessionalJavaScript";

alert(myString.search("Java"));

Thealertboxthatoccurswillshowthevalue10,whichisthecharacterpositionoftheJinthefirstoccurrenceofJava,aspartofthewordJavaScript.

Thematch()MethodThematch()methodisverysimilartothesearch()method,exceptthatinsteadofreturningthepositionatwhichamatchwasfound,itreturnsanarray.Eachelementofthearraycontainsthetextofeachmatchthatisfound.

Althoughyoucanuseplaintextwiththematch()method,itwouldbecompletelypointlesstodoso.Forexample,takealookatthefollowing:

varmyString="1997,1998,1999,2000,2000,2001,2002";

myMatchArray=myString.match("2000");

alert(myMatchArray.length);

ThiscoderesultsinmyMatchArrayholdinganelementcontainingthevalue2000.Giventhatyoualreadyknowyoursearchstringis2000,youcanseeit’sbeenaprettypointlessexercise.

However,thematch()methodmakesalotmoresensewhenyouuseitwithregularexpressions.Thenyoumightsearchforallyearsinthetwenty-firstcentury—thatis,thosebeginningwith2.Inthiscase,yourarraywouldcontainthevalues2000,2000,2001,and2002,whichismuchmoreusefulinformation!

REGULAREXPRESSIONSBeforeyoulookatthesplit(),match(),search(),andreplace()methodsoftheStringobjectagain,youneedtolookatregularexpressionsandtheRegExpobject.Regularexpressionsprovideameansofdefiningapatternofcharacters,whichyoucanthenusetosplit,searchfor,orreplacecharactersinastringwhentheyfitthedefinedpattern.

JavaScript’sregularexpressionsyntaxborrowsheavilyfromtheregularexpressionsyntaxofPerl,anotherscriptinglanguage.Mostmodernprogramminglanguagessupportregularexpressions,asdolotsofapplications,suchasWebMatrix,SublimeText,andDreamweaver,inwhichtheFindfacilityallowsregularexpressionstobeused.You’llfindthatyourregularexpressionknowledgewillproveusefulevenoutsideJavaScript.

RegularexpressionsinJavaScriptareusedthroughtheRegExpobject,whichisanativeJavaScriptobject,asareString,Array,andsoon.YouhavetwowaysofcreatinganewRegExpobject.Theeasieriswitharegularexpressionliteral,suchasthefollowing:

varmyRegExp=/\b'|'\b/;

Theforwardslashes(/)markthestartandendoftheregularexpression.ThisisaspecialsyntaxthattellsJavaScriptthatthecodeisaregularexpression,muchasquotemarksdefineastring’sstartandend.Don’tworryabouttheactualexpression’ssyntaxyet(the\b'|'\b)—thatisexplainedindetailshortly.

Alternatively,youcouldusetheRegExpobject’sconstructorfunctionRegExp()andtypethefollowing:

varmyRegExp=newRegExp("\\b'|'\\b");

Eitherwayofspecifyingaregularexpressionisfine,thoughtheformermethodisashorter,moreefficientoneforJavaScripttouseandthereforeisgenerallypreferred.Formuchoftheremainderofthechapter,youusethefirstmethod.Themainreasonforusingthesecondmethodisthatitallowstheregularexpressiontobedeterminedatruntime(asthecodeisexecutingandnotwhenyouarewritingthecode).Thisisusefulif,forexample,youwanttobasetheregularexpressiononuserinput.

Onceyougetfamiliarwithregularexpressions,youwillcomebacktothesecondwayofdefiningthem,usingtheRegExp()constructor.Asyoucansee,thesyntaxofregularexpressionsisslightlydifferentwiththesecondmethod,sowe’llreturntothissubjectlater.

Althoughyou’llbeconcentratingontheuseoftheRegExpobjectasaparameterfortheStringobject’ssplit(),replace(),match(),andsearch()methods,theRegExpobjectdoeshaveitsownmethodsandproperties.Forexample,thetest()methodenablesyoutotesttoseeifthestringpassedtoitasaparametercontainsapatternmatchingtheonedefinedintheRegExpobject.Youseethetest()methodinuseinanexampleshortly.

SimpleRegularExpressions

Definingpatternsofcharactersusingregularexpressionsyntaxcangetfairlycomplex.Inthissectionyouexplorejustthebasicsofregularexpressionpatterns.Thebestwaytodothisisthroughexamples.

Let’sstartbylookingatanexampleinwhichyouwanttodoasimpletextreplacementusingthereplace()methodandaregularexpression.Imagineyouhavethefollowingstring:

varmyString="Paul,Paula,Pauline,paul,Paul";

andyouwanttoreplaceanyoccurrenceofthename“Paul”with“Ringo.”

Well,thepatternoftextyouneedtolookforissimplyPaul.Representingthisasaregularexpression,youjusthavethis:

varmyRegExp=/Paul/;

Asyousawearlier,theforward-slashcharactersmarkthestartandendoftheregularexpression.Nowlet’susethisexpressionwiththereplace()method:

myString=myString.replace(myRegExp,"Ringo");

Youcanseethatthereplace()methodtakestwoparameters:theRegExpobjectthatdefinesthepatterntobesearchedandreplaced,andthereplacementtext.

Ifyouputthisalltogetherinanexample,youhavethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Figure2</title>

</head>

<body>

<script>

varmyString="Paul,Paula,Pauline,paul,Paul";

varmyRegExp=/Paul/;

myString=myString.replace(myRegExp,"Ringo");

alert(myString);

</script>

</body>

</html>

Youcansaveandrunthiscode.YouwillseethescreenshowninFigure6.2.

Figure6.2

YoucanseethatthishasreplacedthefirstoccurrenceofPaulinyourstring.ButwhatifyouwantedalltheoccurrencesofPaulinthestringtobereplaced?Thetwoatthefarendofthestringarestillthere,sowhathappened?

Bydefault,theRegExpobjectlooksonlyforthefirstmatchingpattern,inthiscasethefirstPaul,andthenstops.ThisisacommonandimportantbehaviorforRegExpobjects.Regularexpressionstendtostartatoneendofastringandlookthroughthecharactersuntilthefirstcompletematchisfound,thenstop.

Whatyouwantisaglobalmatch,whichisasearchforallpossiblematchestobemadeandreplaced.Tohelpyouout,theRegExpobjecthasthreeattributesyoucandefine,aslistedinthefollowingtable:

ATTRIBUTECHARACTER

DESCRIPTION

G Globalmatch.Thislooksforallmatchesofthepatternratherthanstoppingafterthefirstmatchisfound.

I Patterniscase-insensitive.Forexample,Paulandpaulareconsideredthesamepatternofcharacters.

M Multi-lineflag.Thisspecifiesthatthespecialcharacters^and$canmatchthebeginningandtheendoflinesaswellasthebeginningandendofthestring.

Youlearnmoreabouttheseattributecharacterslaterinthechapter.

IfyouchangetheRegExpobjectinthecodetothefollowing,aglobalcase-insensitivematchwillbemade:

varmyRegExp=/Paul/gi;

RunningthecodenowproducestheresultshowninFigure6.3.

Figure6.3

Thislooksasifithasallgonehorriblywrong.TheregularexpressionhasmatchedthePaulsubstringsatthestartandtheendofthestring,andthepenultimatepaul,justasyouwanted.However,thePaulsubstringsinsidePaulineandPaulahavealsobeenreplaced.

TheRegExpobjecthasdoneitsjobcorrectly.YouaskedforallpatternsofthecharactersPaultobereplacedandthat’swhatyougot.WhatyouactuallymeantwasforalloccurrencesofPaul,whenit’sasinglewordandnotpartofanotherword,suchasPaula,tobereplaced.Thekeytomakingregularexpressionsworkistodefineexactlythepatternofcharactersyoumean,sothatonlythatpatterncanmatchandnoother.Solet’sdothat.

1. YouwantpaulorPaultobereplaced.

2. Youdon’twantitreplacedwhenit’sactuallypartofanotherword,asinPauline.

Howdoyouspecifythissecondcondition?Howdoyouknowwhenthewordisjoinedtoothercharacters,ratherthanjustjoinedtospacesorpunctuationorthestartorendofthestring?

Toseehowyoucanachievethedesiredresultwithregularexpressions,youneedtoenlistthehelpofregularexpressionspecialcharacters.Youlookattheseinthenextsection,bytheendofwhichyoushouldbeabletosolvetheproblem.

RegularExpressions:SpecialCharactersYoulookatthreetypesofspecialcharactersinthissection.

Text,Numbers,andPunctuationThefirstgroupofspecialcharacterscontainsthecharacterclass’sspecialcharacters.

Characterclassmeansdigits,letters,andwhitespacecharacters.Thespecialcharactersaredisplayedinthefollowingtable:

CHARACTERCLASS

CHARACTERSITMATCHES EXAMPLE

\d Anydigitfrom0to9 \d\dmatches72,butnotaaor7a.

\D Anycharacterthatisnotadigit \D\D\Dmatchesabc,butnot123or8ef.

\w Anywordcharacter;thatis,A–Z,a–z,0–9,andtheunderscorecharacter(_)

\w\w\w\wmatchesAb_2,butnot£$%*orAb_@.

\W Anynon-wordcharacter \Wmatches@,butnota.\s Anywhitespacecharacter \smatchestab,return,

formfeed,andverticaltab.\S Anynon-whitespacecharacter \SmatchesA,butnotthe

tabcharacter.. Anysinglecharacterotherthanthenewline

character(\n).matchesaor4or@.

[...] Anyoneofthecharactersbetweenthebrackets[a-z]matchesanycharacterintherangeatoz

[abc]matchesaorborc,butnothingelse.

[^...] Anyonecharacter,butnotoneofthoseinsidethebrackets

[^abc]matchesanycharacterexceptaorborc.

[^a-z]matchesanycharacterthatisnotintherangeatoz

.

Notethatuppercaseandlowercasecharactersmeanverydifferentthings,soyouneedtobeextracarefulwithcasewhenusingregularexpressions.

Let’slookatanexample.Tomatchatelephonenumberintheformat1-800-888-5474,theregularexpressionwouldbeasfollows:

\d-\d\d\d-\d\d\d-\d\d\d\d

Youcanseethatthere’salotofrepetitionofcharactershere,whichmakestheexpressionquiteunwieldy.Tomakethissimpler,regularexpressionshaveawayofdefiningrepetition.Youseethisalittlelaterinthechapter,butfirstlet’slookatanotherexample.

TRYITOUTCheckingaPassphraseforAlphanumericCharactersYouusewhatyou’velearnedsofaraboutregularexpressionsinafullexampleinwhichyoucheckthatapassphrasecontainsonlylettersandnumbers—thatis,alphanumericcharacters,notpunctuationorsymbolslike@,%,andsoon:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example2</title>

</head>

<body>

<script>

varinput=prompt("Pleaseenterapassphrase.","");

functionisValid(text){

varmyRegExp=/[^a-z\d]/i;

return!(myRegExp.test(text));

}

if(isValid(input)){

alert("Yourpassphrasecontainsonlyvalidcharacters");

}else{

alert("Yourpassphrasecontainsoneormoreinvalid

characters");

}

</script>

</body>

</html>

Savethepageasch6 _ example2.html,andthenloaditintoyourbrowser.Typejustletters,numbers,andspacesintothepromptbox,clickOK,andyou’llbetoldthatthephrasecontainsvalidcharacters.Tryputtingpunctuationorspecialcharacterslike@,^,$,andsoonintothetextbox,andyou’llbeinformedthatyourpassphraseisinvalid.

Let’sstartbylookingattheisValid()function.Asitsnameimplies,itchecksthevalidityofthepassphrase:

functionisValid(text){

varmyRegExp=/[^a-z\d]/i;

return!(myRegExp.test(text));

}

Thefunctiontakesjustoneparameter:thetextyouwanttovalidate.Youthendeclareavariable,myRegExp,andsetittoanewregularexpression,whichimplicitlycreatesanewRegExpobject.

Theregularexpressionitselfisfairlysimple,butfirstthinkaboutwhatpatternyouare

lookingfor.WhatyouwanttofindoutiswhetheryourpassphrasestringcontainsanycharactersthatarenotlettersbetweenAandZorbetweenaandz,numbersbetween0and9,orspaces.Let’sseehowthistranslatesintoaregularexpression:

1. Youusesquarebracketswiththe^symbol:

[^]

Thismeansyouwanttomatchanycharacterthatisnotoneofthecharactersspecifiedinsidethesquarebrackets.

2. Youadda-z,whichspecifiesanycharacterintherangeathroughz:

[^a-z]

Sofar,yourregularexpressionmatchesanycharacterthatisnotbetweenaandz.Notethat,becauseyouaddedtheitotheendoftheexpressiondefinition,you’vemadethepatterncase-insensitive.SoyourregularexpressionactuallymatchesanycharacternotbetweenAandZoraandz.

3. Youadd\dtoindicateanydigitcharacter,oranycharacterbetween0and9:

[^a-z\d]

4. Yourexpressionmatchesanycharacterthatisnotbetweenaandz,AandZ,or0and9.Youdecidethataspaceisvalid,soyouaddthatinsidethesquarebrackets:

[^a-z\d]

Puttingthisalltogether,youhavearegularexpressionthatmatchesanycharacterthatisnotaletter,adigit,oraspace.

5. Onthesecondandfinallineofthefunction,youusetheRegExpobject’stest()methodtoreturnavalue:

return!(myRegExp.test(text));

Thetest()methodoftheRegExpobjectchecksthestringpassedasitsparametertoseeifthecharactersspecifiedbytheregularexpressionsyntaxmatchanythinginsidethestring.Iftheydo,trueisreturned;ifnot,falseisreturned.Yourregularexpressionmatchesthefirstinvalidcharacterfound,soifyougetaresultoftrue,youhaveaninvalidpassphrase.However,it’sabitillogicalforanis _ validfunctiontoreturntruewhenit’sinvalid,soyoureversetheresultreturnedbyaddingtheNOToperator(!).

Previouslyyousawthetwo-linevalidity-checkerfunctionusingregularexpressions.Justtoshowhowmuchmorecodingisrequiredtodothesamethingwithoutregularexpressions,hereisasecondfunctionthatdoesthesamethingasisValid()butwithoutregularexpressions:

functionisValid2(text){

varreturnValue=true;

varvalidChars="abcdefghijklmnopqrstuvwxyz1234567890";

for(varcharIndex=0;charIndex<text.length;charIndex++){

if(validChars.indexOf(text.charAt(charIndex).toLowerCase())<0)

{

returnValue=false;

break;

}

}

returnreturnValue;

}

Thisisprobablyassmallasthenon-regularexpressionversioncanbe,andyetit’sstillseverallineslongerthanisValid().

Theprincipleofthisfunctionissimilartothatoftheregularexpressionversion.Youhaveavariable,validChars,whichcontainsallthecharactersyouconsidertobevalid.YouthenusethecharAt()methodinaforlooptogeteachcharacterinthepassphrasestringandcheckwhetheritexistsinyourvalidCharsstring.Ifitdoesn’t,youknowyouhaveaninvalidcharacter.

Inthisexample,thenon-regularexpressionversionofthefunctionis10lines,butwithamorecomplexproblemyoucouldfindittakes20or30linestodothesamethingaregularexpressioncandoinjustafew.

Backtoyouractualcode:youuseanif…elsestatementtodisplaytheappropriatemessagetotheuser.Ifthepassphraseisvalid,analertboxtellstheuserthatallisfine:

if(isValid(input)){

alert("Yourpassphrasecontainsonlyvalidcharacters");

}

Ifitisn’t,anotheralertboxtellsusersthattheirtextwasinvalid:

else{

alert("Yourpassphrasecontainsoneormoreinvalidcharacters");

}

RepetitionCharactersRegularexpressionsincludesomethingcalledrepetitioncharacters,whichareameansofspecifyinghowmanyofthelastitemorcharacteryouwanttomatch.Thisprovesveryuseful,forexample,ifyouwanttospecifyaphonenumberthatrepeatsacharacteraspecificnumberoftimes.Thefollowingtablelistssomeofthemostcommonrepetitioncharactersandwhattheydo:

SPECIALCHARACTER

MEANING EXAMPLE

{n} Matchnofthepreviousitem. x{2}matchesxx.{n,} Matchnormoreoftheprevious

item.x{2,}matchesxx,xxx,xxxx,xxxxx,andsoon.

{n,m} Matchatleastnandatmostmofthepreviousitem.

x{2,4}matchesxx,xxx,andxxxx.

? Matchthepreviousitemzerooronetime.

x?matchesnothingorx.

+ Matchthepreviousitemoneormoretimes.

x+matchesx,xx,xxx,xxxx,xxxxx,andsoon.

* Matchthepreviousitemzeroormoretimes.

x*matchesnothing,orx,xx,xxx,xxxx,andsoon.

Yousawearlierthattomatchatelephonenumberintheformat1-800-888-5474,theregularexpressionwouldbe\d-\d\d\d-\d\d\d-\d\d\d\d.Let’sseehowthiswouldbesimplifiedwiththeuseoftherepetitioncharacters.

Thepatternyou’relookingforstartswithonedigitfollowedbyadash,soyouneedthefollowing:

\d-

Nextarethreedigitsfollowedbyadash.Thistimeyoucanusetherepetitionspecialcharacters—\d{3}willmatchexactlythree\d,whichistheany-digitcharacter:

\d-\d{3}-

Next,youhavethreedigitsfollowedbyadashagain,sonowyourregularexpressionlookslikethis:

\d-\d{3}-\d{3}-

Finally,thelastpartoftheexpressionisfourdigits,whichis\d{4}:

\d-\d{3}-\d{3}-\d{4}

You’ddeclarethisregularexpressionlikethis:

varmyRegExp=/\d-\d{3}-\d{3}-\d{4}/

Rememberthatthefirst/andlast/tellJavaScriptthatwhatisinbetweenthosecharactersisaregularexpression.JavaScriptcreatesaRegExpobjectbasedonthisregularexpression.

Asanotherexample,whatifyouhavethestringPaulPaulaPauline,andyouwanttoreplacePaulandPaulawithGeorge?Todothis,youwouldneedaregularexpressionthatmatchesbothPaulandPaula.

Let’sbreakthisdown.YouknowyouwantthecharactersPaul,soyourregularexpression

startsas:

Paul

NowyoualsowanttomatchPaula,butifyoumakeyourexpressionPaula,thiswillexcludeamatchonPaul.Thisiswherethespecialcharacter?comesin.Itenablesyoutospecifythatthepreviouscharacterisoptional—itmustappearzero(notatall)oronetime.So,thesolutionis:

Paula?

whichyou’ddeclareas:

varmyRegExp=/Paula?/

PositionCharactersThethirdgroupofspecialcharactersincludesthosethatenableyoutospecifyeitherwherethematchshouldstartorendorwhatwillbeoneithersideofthecharacterpattern.Forexample,youmightwantyourpatterntoexistatthestartorendofastringorline,oryoumightwantittobebetweentwowords.Thefollowingtablelistssomeofthemostcommonpositioncharactersandwhattheydo:

POSITIONCHARACTER

DESCRIPTION

^ Thepatternmustbeatthestartofthestring,orifit’samulti-linestring,thenatthebeginningofaline.Formulti-linetext(astringthatcontainscarriagereturns),youneedtosetthemulti-lineflagwhendefiningtheregularexpressionusing/myregex/m.NotethatthisisonlyapplicabletoIE5.5andlaterandNN6andlater.

$ Thepatternmustbeattheendofthestring,orifit’samulti-linestring,thenattheendofaline.Formulti-linetext(astringthatcontainscarriagereturns),youneedtosetthemulti-lineflagwhendefiningtheregularexpressionusing/myregex/m.NotethatthisisonlyapplicabletoIE5.5andlaterandNN6andlater.

\b Thismatchesawordboundary,whichisessentiallythepointbetweenawordcharacterandanon-wordcharacter.

\B Thismatchesapositionthat’snotawordboundary.

Forexample,ifyouwantedtomakesureyourpatternwasatthestartofaline,youwouldtypethefollowing:

^myPattern

ThiswouldmatchanoccurrenceofmyPatternifitwasatthebeginningofaline.

Tomatchthesamepattern,butattheendofaline,youwouldtypethefollowing:

myPattern$

Theword-boundaryspecialcharacters\band\Bcancauseconfusion,becausetheydonotmatchcharactersbutthepositionsbetweencharacters.

Imagineyouhadthestring"Helloworld!,let'slookatboundariessaid007."definedinthecodeasfollows:

varmyString="Helloworld!,let'slookatboundariessaid007.";

Tomakethewordboundaries(thatis,theboundariesbetweenthewords)ofthisstringstandout,let’sconvertthemtothe|character:

varmyRegExp=/\b/g;

myString=myString.replace(myRegExp,"|");

alert(myString);

You’vereplacedallthewordboundaries,\b,witha|,andyourmessageboxlooksliketheoneinFigure6.4.

Figure6.4

Youcanseethatthepositionbetweenanywordcharacter(letters,numbers,ortheunderscorecharacter)andanynon-wordcharacterisawordboundary.You’llalsonoticethattheboundarybetweenthestartorendofthestringandawordcharacterisconsideredtobeawordboundary.Theendofthisstringisafullstop.Sotheboundarybetweenthefullstopandtheendofthestringisanon-wordboundary,andthereforeno|hasbeeninserted.

Ifyouchangetheregularexpressionintheexample,sothatitreplacesnon-wordboundariesasfollows:

varmyRegExp=/\B/g;

yougettheresultshowninFigure6.5.

Figure6.5

Nowthepositionbetweenaletter,number,orunderscoreandanotherletter,number,orunderscoreisconsideredanon-wordboundaryandisreplacedbyan|intheexample.However,whatisslightlyconfusingisthattheboundarybetweentwonon-wordcharacters,suchasanexclamationmarkandacomma,isalsoconsideredanon-wordboundary.Ifyouthinkaboutit,itactuallydoesmakesense,butit’seasytoforgetwhencreatingregularexpressions.

You’llrememberthisexamplefromwhenyoustartedlookingatregularexpressions:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Figure2</title>

</head>

<body>

<script>

varmyString="Paul,Paula,Pauline,paul,Paul";

varmyRegExp=/Paul/gi;

myString=myString.replace(myRegExp,"Ringo");

alert(myString);

</script>

</body>

</html>

YouusedthiscodetoconvertallinstancesofPaulorpaultoRingo.

However,youfoundthatthiscodeactuallyconvertsallinstancesofPaultoRingo,evenwhenthewordPaulisinsideanotherword.

OnewaytosolvethisproblemwouldbetoreplacethestringPaulonlywhereitis

followedbyanon-wordcharacter.Thespecialcharacterfornon-wordcharactersis\W,soyouneedtoaltertheregularexpressiontothefollowing:

varmyRegExp=/Paul\W/gi;

ThisgivestheresultshowninFigure6.6.

Figure6.6

It’sgettingbetter,butit’sstillnotwhatyouwant.NoticethatthecommasafterthesecondandthirdPaulsubstringshavealsobeenreplacedbecausetheymatchedthe\Wcharacter.Also,you’restillnotreplacingPaulattheveryendofthestring.That’sbecausethereisnocharacteraftertheletterlinthelastPaul.WhatisafterthelinthelastPaul?Nothing,justtheboundarybetweenawordcharacterandanon-wordcharacter,andthereinliestheanswer.WhatyouwantasyourregularexpressionisPaulfollowedbyawordboundary.Let’saltertheregularexpressiontocopewiththatbyenteringthefollowing:

varmyRegExp=/Paul\b/gi;

Nowyougettheresultyouwant,asshowninFigure6.7.

Figure6.7

Atlastyou’vegotitright,andthisexampleisfinished.

CoveringAllEventualitiesPerhapsthetrickiestthingaboutaregularexpressionismakingsureitcoversalleventualities.Inthepreviousexampleyourregularexpressionworkswiththestringasdefined,butdoesitworkwiththefollowing?

varmyString="Paul,Paula,Pauline,paul,Paul,JeanPaul";

HerethePaulsubstringinJeanPaulwillbechangedtoRingo.YoureallyonlywanttoconvertthesubstringPaulwhereitisonitsown,withawordboundaryoneitherside.Ifyouchangeyourregularexpressioncodeto:

varmyRegExp=/\bPaul\b/gi;

youhaveyourfinalanswerandcanbesureonlyPaulorpaulwilleverbematched.

GroupingRegularExpressionsThefinaltopicunderregularexpressions,beforeyoulookatexamplesusingthematch(),replace(),andsearch()methods,ishowyoucangroupexpressions.Infact,it’squiteeasy.Ifyouwantanumberofexpressionstobetreatedasasinglegroup,youjustenclosetheminparentheses,forexample,/(\d\d)/.Parenthesesinregularexpressionsarespecialcharactersthatgrouptogethercharacterpatternsandarenotthemselvespartofthecharacterstobematched.

Whywouldyouwanttodothis?Well,bygroupingcharactersintopatterns,youcanusethespecialrepetitioncharacterstoapplytothewholegroupofcharacters,ratherthanjustone.

Let’stakethefollowingstringdefinedinmyStringasanexample:

varmyString="JavaScript,VBScriptandPHP";

HowcouldyoumatchbothJavaScriptandVBScriptusingthesameregularexpression?TheonlythingtheyhaveincommonisthattheyarewholewordsandtheybothendinScript.Well,aneasywaywouldbetouseparenthesestogroupthepatternsJavaandVB.Thenyoucanusethe?specialcharactertoapplytoeachofthesegroupsofcharacterstomakethepatternmatchanywordhavingzerooroneinstanceofthecharactersJavaorVB,andendinginScript:

varmyRegExp=/\b(VB)?(Java)?Script\b/gi;

Breakingdownthisexpression,youcanseethepatternitrequiresisasfollows:

1. Awordboundary:\b

2. ZerooroneinstanceofVB:(VB)?

3. ZerooroneinstanceofJava:(Java)?

4. ThecharactersScript:Script

5. Awordboundary:\b

Puttingthesetogether,yougetthis:

varmyString="JavaScript,VBScriptandPHP";

varmyRegExp=/\b(VB)?(Java)?Script\b/gi;

myString=myString.replace(myRegExp,"xxxx");

alert(myString);

TheoutputofthiscodeisshowninFigure6.8.

Figure6.8

Ifyoulookbackatthespecialrepetitioncharacterstable,you’llseethattheyapplytotheitemprecedingthem.Thiscanbeacharacter,or,wheretheyhavebeengroupedbymeansofparentheses,thepreviousgroupofcharacters.

However,thereisapotentialproblemwiththeregularexpressionyoujustdefined.AswellasmatchingVBScriptandJavaScript,italsomatchesVBJavaScript.Thisisclearlynotexactlywhatyoumeant.

Togetaroundthisyouneedtomakeuseofbothgroupingandthespecialcharacter|,whichisthealternationcharacter.Ithasanor-likemeaning,similarto||inifstatements,andwillmatchthecharactersoneithersideofitself.

Let’sthinkabouttheproblemagain.YouwantthepatterntomatchVBScriptorJavaScript.ClearlytheyhavetheScriptpartincommon.SowhatyouwantisanewwordstartingwithJavaorstartingwithVB;eitherway,itmustendinScript.

First,youknowthatthewordmuststartwithawordboundary:

\b

NextyouknowthatyouwanteitherVBorJavatobeatthestartoftheword.You’vejustseenthatinregularexpressions|providesthe“or”youneed,soinregularexpressionsyntaxyouwantthefollowing:

\b(VB|Java)

ThismatchesthepatternVBorJava.NowyoucanjustaddtheScriptpart:

\b(VB|Java)Script\b

Yourfinalcodelookslikethis:

varmyString="JavaScript,VBScriptandPerl";

varmyRegExp=/\b(VB|Java)Script\b/gi;

myString=myString.replace(myRegExp,"xxxx");

alert(myString);

ReusingGroupsofCharactersYoucanreusethepatternspecifiedbyagroupofcharacterslateronintheregularexpression.Torefertoapreviousgroupofcharacters,youjusttype\andanumberindicatingtheorderofthegroup.Forexample,youcanrefertothefirstgroupas\1,thesecondas\2,andsoon.

Let’slookatanexample.Sayyouhavealistofnumbersinastring,witheachnumberseparatedbyacomma.Forwhateverreason,youarenotallowedtohavetwoinstancesofthesamenumberinarow,soalthough

009,007,001,002,004,003

wouldbeokay,thefollowing:

007,007,001,002,002,003

wouldnotbevalid,becauseyouhave007and002repeatedafterthemselves.

HowcanyoufindinstancesofrepeateddigitsandreplacethemwiththewordERROR?Youneedtousetheabilitytorefertogroupsinregularexpressions.

First,let’sdefinethestringasfollows:

varmyString="007,007,001,002,002,003,002,004";

Nowyouknowyouneedtosearchforaseriesofoneormorenumbercharacters.Inregularexpressionsthe\dspecifiesanydigitcharacter,and+meansoneormoreofthepreviouscharacter.Sofar,thatgivesyouthisregularexpression:

\d+

Youwanttomatchaseriesofdigitsfollowedbyacomma,soyoujustaddthecomma:

\d+,

Thiswillmatchanyseriesofdigitsfollowedbyacomma,buthowdoyousearchforanyseriesofdigitsfollowedbyacomma,thenfollowedagainbythesameseriesofdigits?Becausethedigitscouldbeanydigits,youcan’taddthemdirectlyintotheexpressionlikeso:

\d+,007

Thiswouldnotworkwiththe002repeat.Whatyouneedtodoisputthefirstseriesofdigitsinagroup;thenyoucanspecifythatyouwanttomatchthatgroupofdigitsagain.Youcandothiswith\1,whichsays,“Matchthecharactersfoundinthefirstgroupdefinedusingparentheses.”Putallthistogether,andyouhavethefollowing:

(\d+),\1

Thisdefinesagroupwhosepatternofcharactersisoneormoredigitcharacters.Thisgroupmustbefollowedbyacommaandthenbythesamepatternofcharactersasinthefirstgroup.PutthisintosomeJavaScript,andyouhavethefollowing:

varmyString="007,007,001,002,002,003,002,004";

varmyRegExp=/(\d+),\1/g;

myString=myString.replace(myRegExp,"ERROR");

alert(myString);

Thealertboxwillshowthismessage:

ERROR,1,ERROR,003,002,004

Thatcompletesyourbrieflookatregularexpressionsyntax.Becauseregularexpressionscangetalittlecomplex,it’softenagoodideatostartsimpleandbuildthemupslowly,asinthepreviousexample.Infact,mostregularexpressionsarejusttoohardtogetrightinonestep—atleastforusmeremortalswithoutabrainthesizeofaplanet.

Ifit’sstilllookingabitstrangeandconfusing,don’tpanic.Inthenextsections,youlookattheStringobject’ssplit(),replace(),search(),andmatch()methodswithplentymoreexamplesofregularexpressionsyntax.

THESTRINGOBJECTThemainfunctionsmakinguseofregularexpressionsaretheStringobject’ssplit(),replace(),search(),andmatch()methods.You’vealreadyseentheirsyntax,sointhissectionyouconcentrateontheirusewithregularexpressionsandatthesametimelearnmoreaboutregularexpressionsyntaxandusage.

Thesplit()MethodYou’veseenthatthesplit()methodenablesyoutosplitastringintovariouspieces,withthesplitbeingmadeatthecharacterorcharactersspecifiedasaparameter.Theresultofthismethodisanarraywitheachelementcontainingoneofthesplitpieces.Forexample,thefollowingstring:

varmyListString="apple,banana,peach,orange"

couldbesplitintoanarrayinwhicheachelementcontainsadifferentfruit,likethis:

varmyFruitArray=myListString.split(",");

Howaboutifyourstringisthisinstead?

varmyListString="apple,0.99,banana,0.50,peach,0.25,orange,0.75";

Thestringcould,forexample,containboththenamesandpricesofthefruit.Howcouldyousplitthestring,butretrieveonlythenamesofthefruitandnottheprices?Youcoulddoitwithoutregularexpressions,butitwouldtakemanylinesofcode.Withregularexpressionsyoucanusethesamecodeandjustamendthesplit()method’sparameter.

TRYITOUTSplittingtheFruitStringLet’screateanexamplethatsolvestheproblemjustdescribed—itmustsplityourstring,butincludeonlythefruitnames,nottheprices:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example3</title>

</head>

<body>

<script>

varmyListString="apple,0.99,banana,0.50,peach,0.25,

orange,0.75";

vartheRegExp=/[^a-z]+/i;

varmyFruitArray=myListString.split(theRegExp);

document.write(myFruitArray.join("<br/>"));

</script>

</body>

</html>

Savethefileasch6 _ example3.htmlandloaditinyourbrowser.Youshouldseethefourfruitsfromyourstringwrittenouttothepage,witheachfruitonaseparateline.

Withinthescriptblock,firstyouhaveyourstringwithfruitnamesandprices:

varmyListString="apple,0.99,banana,0.50,peach,0.25,orange,

0.75";

Howdoyousplititinsuchawaythatonlythefruitnamesareincluded?Yourfirstthoughtmightbetousethecommaasthesplit()method’sparameter,butofcoursethatmeansyouendupwiththeprices.Whatyouhavetoaskis,“Whatisitthat’sbetweentheitemsIwant?”Orinotherwords,whatisbetweenthefruitnamesthatyoucanusetodefineyoursplit?Theansweristhatvariouscharactersarebetweenthenamesofthefruit,suchasacomma,aspace,numbers,afullstop,morenumbers,andfinallyanothercomma.Whatisitthatthesethingshaveincommonandmakesthemdifferentfromthefruitnamesthatyouwant?Whattheyhaveincommonisthatnoneofthemarelettersfromathroughz.Ifyousay“Splitthestringatthepointwherethereisagroupofcharactersthatarenotbetweenaandz,”thenyougettheresultyouwant.Nowyouknowwhatyouneedtocreateyourregularexpression.

Youknowthatwhatyouwantisnotthelettersathroughz,soyoustartwiththis:

[^a-z]

The^says“Matchanycharacterthatdoesnotmatchthosespecifiedinsidethesquarebrackets.”Inthiscaseyou’vespecifiedarangeofcharactersnottobematched—allthecharactersbetweenaandz.Asspecified,thisexpressionwillmatchonlyonecharacter,whereasyouwanttosplitwhereverthereisasinglegroupofoneormorecharactersthatarenotbetweenaandz.Todothisyouneedtoaddthe+specialrepetitioncharacter,whichsays“Matchoneormoreoftheprecedingcharacterorgroupspecified”:

[^a-z]+

Thefinalresultisthis:

vartheRegExp=/[^a-z]+/i

The/and/charactersmarkthestartandendoftheregularexpressionwhoseRegExpobjectisstoredasareferenceinthevariabletheRegExp.Youaddtheiontheendtomakethematchcase-insensitive.

Don’tpanicifcreatingregularexpressionsseemslikeafrustratingandless-than-obviousprocess.Atfirst,ittakesalotoftrialanderrortogetitright,butasyougetmoreexperienced,you’llfindcreatingthembecomesmucheasierandwillenableyoutodothingsthatwithoutregularexpressionswouldbeeitherveryawkwardorvirtuallyimpossible.

InthenextlineofscriptyoupasstheRegExpobjecttothesplit()method,whichusesittodecidewheretosplitthestring:

varmyFruitArray=myListString.split(theRegExp);

Afterthesplit,thevariablemyFruitArraywillcontainanArraywitheachelementcontainingthefruitname,asshownhere:

ARRAYELEMENTINDEX 0 1 2 3Elementvalue apple banana peach orange

YouthenjointhestringtogetheragainusingtheArrayobject’sjoin()methods,whichyousawinChapter4:

document.write(myFruitArray.join("<br/>"))

Thereplace()MethodYou’vealreadylookedatthesyntaxandusageofthereplace()method.However,somethinguniquetothereplace()methodisitsabilitytoreplacetextbasedonthegroupsmatchedintheregularexpression.Youdothisusingthe$signandthegroup’snumber.Eachgroupinaregularexpressionisgivenanumberfrom1to99;anygroupsgreaterthan99arenotaccessible.Torefertoagroup,youwrite$followedbythegroup’sposition.Forexample,ifyouhadthefollowing:

varmyRegExp=/(\d)(\W)/g;

then$1referstothegroup(\d),and$2referstothegroup(\W).You’vealsosettheglobalflaggtoensurethatallmatchingpatternsarereplaced—notjustthefirstone.

Youcanseethismoreclearlyinthenextexample.Sayyouhavethefollowingstring:

varmyString="2012,2013,2014";

Ifyouwantedtochangethisto"theyear2012,theyear2013,theyear2014",howcouldyoudoitwithregularexpressions?

First,youneedtoworkoutthepatternasaregularexpression,inthiscasefourdigits:

varmyRegExp=/\d{4}/g;

Butgiventhattheyearisdifferenteverytime,howcanyousubstitutetheyearvalueintothereplacedstring?

Well,youchangeyourregularexpressionsothatit’sinsideagroup,asfollows:

varmyRegExp=/(\d{4})/g;

Nowyoucanusethegroup,whichhasgroupnumber1,insidethereplacementstringlikethis:

myString=myString.replace(myRegExp,"theyear$1");

ThevariablemyStringnowcontainstherequiredstring"theyear2012,theyear2013,theyear2014".

Let’slookatanotherexampleinwhichyouwanttoconvertsinglequotesintexttodoublequotes.Yourteststringisthis:

Hethensaid'MyNameisO'Connerly,yesthat'sright,O'Connerly'.

Oneproblemthattheteststringmakesclearisthatyouwanttoreplacethesingle-quotemarkwithadoubleonlywhereitisusedinpairsaroundspeech,notwhenitisactingasanapostrophe,suchasinthewordthat's,orwhenit’spartofsomeone’sname,suchasinO'Connerly.

Let’sstartbydefiningtheregularexpression.First,youknowthatitmustincludeasinglequote,asshowninthefollowingcode:

varmyRegExp=/'/;

However,asitisthiswouldreplaceeverysinglequote,whichisnotwhatyouwant.

Lookingatthetext,youshouldalsonoticethatquotesarealwaysatthestartorendofaword—thatis,ataboundary.Onfirstglanceitmightbeeasytoassumethatitwouldbeawordboundary.However,don’tforgetthatthe'isanon-wordcharacter,sotheboundarywillbebetweenitandanothernon-wordcharacter,suchasaspace.Sotheboundarywillbeanon-wordboundaryor,inotherwords,\B.

Therefore,thecharacterpatternyouarelookingforiseitheranon-wordboundaryfollowedbyasinglequoteorasinglequotefollowedbyanon-wordboundary.Thekeyisthe“or,”forwhichyouuse|inregularexpressions.Thisleavesyourregularexpressionasthefollowing:

varmyRegExp=/\B'|'\B/g;

Thiswillmatchthepatternontheleftofthe|orthecharacterpatternontheright.Youwanttoreplaceallthesinglequoteswithdoublequotes,sotheghasbeenaddedattheend,indicatingthataglobalmatchshouldtakeplace.

TRYITOUTReplacingSingleQuoteswithDoubleQuotesLet’slookatanexampleusingtheregularexpressionjustdefined:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example4</title>

</head>

<body>

<script>

vartext="Hethensaid'MyNameisO'Connerly,yes"+

"that'sright,O'Connerly'";

document.write("Original:"+text+"<br/>");

varmyRegExp=/\B'|'\B/g;

text=text.replace(myRegExp,'"');

document.write("Corrected:"+text);

</script>

</body>

</html>

Savethepageasch6_example4.html.LoadthepageintoyourbrowserandyoushouldseewhatisshowninFigure6.9.

Figure6.9

Youcanseethatbyusingregularexpressions,youhavecompletedataskinacoupleoflinesofsimplecode.Withoutregularexpressions,itwouldprobablytakefourorfivetimesthatamount.

Theworkhorsesofthiscodearetwosimplelines:

varmyRegExp=/\B'|'\B/g;

text=text.replace(myRegExp,'"');

Youdefineyourregularexpression(asdiscussedpreviously),whichmatchesanynon-wordboundaryfollowedbyasinglequoteoranysinglequotefollowedbyanon-wordboundary.Forexample,'Hwillmatch,aswillH',butO'Rwon’t,becausethequoteisbetweentwowordboundaries.Don’tforgetthatawordboundaryisthepositionbetweenthestartorendofawordandanon-wordcharacter,suchasaspaceorpunctuationmark.

Thesecondlineofcodeusesthereplace()methodtodothecharacterpatternsearchandreplace,andassignsthenewvaluetothetextvariable.

Thesearch()MethodThesearch()methodenablesyoutosearchastringforapatternofcharacters.Ifthepatternisfound,thecharacterpositionatwhichitwasfoundisreturned;otherwise,-1isreturned.Themethodtakesonlyoneparameter,theRegExpobjectyouhavecreated.

AlthoughforbasicsearchestheindexOf()methodisfine,ifyouwantmorecomplexsearches,suchasasearchforapatternofanydigitsoroneinwhichawordmustbeinbetweenacertainboundary,search()providesamuchmorepowerfulandflexible,butsometimesmorecomplex,approach.

Inthefollowingexample,youwanttofindoutifthewordJavaiscontainedwithinthestring.However,youwanttolookjustforJavaasawholeword,notpartofanotherwordsuchasJavaScript:

varmyString="BeginningJavaScript,BeginningJava2,"+

"ProfessionalJavaScript";

varmyRegExp=/\bJava\b/i;

alert(myString.search(myRegExp));

First,youhavedefinedyourstring,andthenyou’vecreatedyourregularexpression.YouwanttofindthecharacterpatternJavawhenit’sonitsownbetweentwowordboundaries.You’vemadeyoursearchcase-insensitivebyaddingtheiaftertheregularexpression.Notethatwiththesearch()method,thegforglobalisnotrelevant,anditsusehasnoeffect.

Onthefinalline,yououtputthepositionatwhichthesearchhaslocatedthepattern,inthiscase32.

Thematch()MethodThematch()methodisverysimilartothesearch()method,exceptthatinsteadofreturningthepositionatwhichamatchwasfound,itreturnsanarray.Eachelementofthearraycontainsthetextofamatchmade.

Forexample,ifyouhadthestring:

varmyString="Theyearswere2012,2013and2014";

andwantedtoextracttheyearsfromthisstring,youcoulddosousingthematch()method.Tomatcheachyear,youarelookingforfourdigitsinbetweenwordboundaries.Thisrequirementtranslatestothefollowingregularexpression:

varmyRegExp=/\b\d{4}\b/g;

Youwanttomatchalltheyears,sotheghasbeenaddedtotheendforaglobalsearch.

Todothematchandstoretheresults,youusethematch()methodandstoretheArrayobjectitreturnsinavariable:

varresultsArray=myString.match(myRegExp);

Toproveithasworked,let’susesomecodetooutputeachiteminthearray.You’veadded

anifstatementtodouble-checkthattheresultsarrayactuallycontainsanarray.Ifnomatchesweremade,theresultsarraywillcontainnull—doingif(resultsArray)willreturntrueifthevariablehasavalueandnotnull:

if(resultsArray){

for(varindex=0;index<resultsArray.length;index++){

alert(resultsArray[index]);

}

}

Thiswouldresultinthreealertboxescontainingthenumbers2012,2013,and2014.

TRYITOUTSplittingHTMLInthisexample,youwanttotakeastringofHTMLandsplititintoitscomponentparts.Forexample,youwanttheHTML<p>Hello</p>tobecomeanarray,withtheelementshavingthefollowingcontents:

<p> Hello </p>

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example5</title>

</head>

<body>

<divid="output"></div>

<script>

varhtml="<h2>HelloWorld!</h2>"+

"<p>WeloveJavaScript!</p>";

varregex=/<[^>\r\n]+>|[^<>\r\n]+/g;

varresults=html.match(regex);

document.getElementById("output").innerText=

results.join("\r\n");

</script>

</body>

</html>

Savethisfileasch6 _ example5.html.Whenyouloadthepageintoyourbrowseryou’llseethatthestringofHTMLissplit,witheachelement’stagsandcontentdisplayedonseparatelines,asshowninFigure6.10.

Figure6.10

Onceagain,thecodethatmakesallofthisworkconsistsofjustafewlines.YoufirstcreateaRegExpobjectandinitializeittoyourregularexpression:

varregex=/<[^>\r\n]+>|[^<>\r\n]+/g;

Let’sbreakitdowntoseewhatpatternyou’retryingtomatch.First,notethatthepatternisbrokenupbyanalternationsymbol:|.Thismeansthatyouwantthepatternontheleftortherightofthissymbol.Lookatthesepatternsseparately.Ontheleft,youhavethefollowing:

Thepatternmuststartwitha<.

In[^>\r\n]+,youspecifythatyouwantoneormoreofanycharacterexceptthe>ora\r(carriagereturn)ora\n(linefeed).

>specifiesthatthepatternmustendwitha>.

Ontheright,youhaveonlythefollowing:

[^<>\r\n]+specifiesthatthepatternisoneormoreofanycharacter,solongasthatcharacterisnota<,>,\r,or\n.Thiswillmatchplaintext.

Aftertheregularexpressiondefinitionyouhaveag,whichspecifiesthatthisisaglobalmatch.

Sothe<[^>\r\n]+>regularexpressionwillmatchanystartorclosetags,suchas<p>or</p>.Thealternativepatternis[^<>\r\n]+,whichwillmatchanycharacterpatternthatisnotanopeningorclosingtag.

Inthefollowingline,youassigntheresultsvariabletotheArrayobjectreturnedbythematch()method:

varresults=html.match(regex);

Theremainderofthecodepopulatesa<div/>elementwiththesplitHTML:

document.getElementById("output").innerText=results.join("\r\n");

Thiscodeusesfeaturesyouhaven’tyetseen.Itessentiallyretrievestheelementthathasanidvalueofoutput;thisisthe<div/>elementatthetopofthebody.TheinnerTextpropertyenablesyoutosetthetextinsideofthe<div/>element.Youlearnmoreinlaterchapters.

YouthenusetheArrayobject’sjoin()methodtojoinallthearray’selementsintoonestringwitheachelementseparatedbya\r\ncharacter,sothateachtagorpieceoftextgoesonaseparateline.

USINGTHEREGEXPOBJECT’SCONSTRUCTORSofaryou’vebeencreatingRegExpobjectsusingthe/and/characterstodefinethestartandendoftheregularexpression,asshowninthefollowingexample:

varmyRegExp=/[a-z]/;

Althoughthisisthegenerallypreferredmethod,itwasbrieflymentionedthataRegExpobjectcanalsobecreatedbymeansoftheRegExp()constructor.Youmightusethefirstwaymostofthetime.However,onsomeoccasionsthesecondwayofcreatingaRegExpobjectisnecessary(forexample,whenaregularexpressionistobeconstructedfromuserinput).

Asanexample,theprecedingregularexpressioncouldequallywellbedefinedas:

varmyRegExp=newRegExp("[a-z]");

HereyoupasstheregularexpressionasastringparametertotheRegExp()constructorfunction.

Averyimportantdifferencewhenyouareusingthismethodisinhowyouusespecialregularexpressioncharacters,suchas\b,thathaveabackwardslashinfrontofthem.TheproblemisthatthebackwardslashindicatesanescapecharacterinJavaScriptstrings—forexample,youmayuse\b,whichmeansabackspace.Todifferentiatebetween\bmeaningabackspaceinastringandthe\bspecialcharacterinaregularexpression,youhavetoputanotherbackwardslashinfrontoftheregularexpressionspecialcharacter.So\bbecomes\\bwhenyoumeantheregularexpression\bthatmatchesawordboundary,ratherthanabackspacecharacter.

Forexample,sayyouhavedefinedyourRegExpobjectusingthefollowing:

varmyRegExp=/\b/;

TodeclareitusingtheRegExp()constructor,youwouldneedtowritethis:

varmyRegExp=newRegExp("\\b");

andnotthis:

varmyRegExp=newRegExp("\b");

Allspecialregularexpressioncharacters,suchas\w,\b,\d,andsoon,musthaveanextra\infrontwhenyoucreatethemusingRegExp().

Whenyoudefineregularexpressionswiththe/and/method,afterthefinal/youcouldaddthespecialflagsm,g,anditoindicatethatthepatternmatchingshouldbemulti-line,global,orcase-insensitive,respectively.WhenusingtheRegExp()constructor,howcanyoudothesamething?

Easy.TheoptionalsecondparameteroftheRegExp()constructortakestheflagsthatspecifyaglobalorcase-insensitivematch.Forexample,thiswilldoaglobalcase-insensitivepatternmatch:

varmyRegExp=newRegExp("hello\\b","gi");

Youcanspecifyjustoneoftheflagsifyouwant—suchasthefollowing:

varmyRegExp=newRegExp("hello\\b","i");

or

varmyRegExp=newRegExp("hello\\b","g");

TRYITOUTFormValidationModuleInthisTryItOut,youcreateasetofusefulJavaScriptfunctionsthatuseregularexpressionstovalidatethefollowing:

Telephonenumbers

Postalcodes

E-mailaddresses

Thevalidationonlycheckstheformat.So,forexample,itcan’tcheckthatthetelephonenumberactuallyexists,onlythatitwouldbevalidifitdid.

Firstisthe.jscodefilewiththeinputvalidationcode.Pleasenotethatthelinesofcodeinthefollowingblockaretoowideforthebook—makesureeachregularexpressioniscontainedononeline:

functionisValidTelephoneNumber(telephoneNumber){

vartelRegExp=/^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})

?\d{3}?\d{0,7}((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-

5})?$/i;

returntelRegExp.test(telephoneNumber);

}

functionisValidPostalCode(postalCode){

varpcodeRegExp=/^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-

z])

?\d[a-z][a-z])$/i;

returnpcodeRegExp.test(postalCode);

}

functionisValidEmail(emailAddress){

varemailRegExp=/^(([^<>()\[\]\\.,;:@"\x00-\x20\x7F]|\\.)+|("""

([^\x0A\x0D"\\]

|\\\\)+"""))@(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]

|#\d+?)\.)+([a-z]{2,4})$/i;

returnemailRegExp.test(emailAddress);

}

Savethisasch6_example6.js.

Totestthecode,youneedasimplepage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6,Example6</title>

</head>

<body>

<scriptsrc="ch6_example6.js"></script>

<script>

varphoneNumber=prompt("Pleaseenteraphonenumber.",

"");

if(isValidTelephoneNumber(phoneNumber)){

alert("ValidPhoneNumber");

}else{

alert("InvalidPhoneNumber");

}

varpostalCode=prompt("Pleaseenterapostalcode.","");

if(isValidPostalCode(postalCode)){

alert("ValidPostalCode");

}else{

alert("InvalidPostalCode");

}

varemail=prompt("Pleaseenteranemailaddress.","");

if(isValidEmail(email)){

alert("ValidEmailAddress");

}else{

alert("InvalidEmailAddress");

}

</script>

</body>

</html>

Savethisasch6 _ example6.htmlandloaditintoyourbrowser,andyou’llbepromptedtoenteraphonenumber.Enteravalidtelephonenumber(forexample,+1(123)1234567),andyou’llseeamessagethatstateswhetherornotthephonenumberisvalid.

You’llthenbepromptedtoenterapostalcodeandane-mail.Enterthosevaluestotestthosefunctions.Thisisprettybasic,butit’ssufficientfortestingyourcode.

Theactualcodeisverysimple,buttheregularexpressionsaretrickytocreate,solet’slookatthoseindepthstartingwithtelephonenumbervalidation.

TelephoneNumberValidationTelephonenumbersaremoreofachallengetovalidate.Theproblemsare:

Phonenumbersdifferfromcountrytocountry.

Avalidnumbercanbeenteredindifferentways(forexample,withorwithoutthenationalorinternationalcode).

Forthisregularexpression,youneedtospecifymorethanjustthevalidcharacters;youalsoneedtospecifytheformatofthedata.Forexample,allofthefollowingarevalid:

+1(123)1234567

+1123123456

+44(123)1234567

+44(123)1234567ext123

+442078934567

Thevariationsthatyourregularexpressionneedstodealwith(optionallyseparatedbyspaces)areshowninthefollowingtable:

Theinternationalnumber

“+”followedbyonetothreedigits(optional)

Thelocalareacode Twotofivedigits,sometimesinparentheses(compulsory)Theactualsubscribernumber

Threeto10digits,sometimeswithspaces(compulsory)

Anextensionnumber

Twotofivedigits,precededbyx,xtn,extn,pax,pbx,orextension,andsometimesinparentheses

Obviously,thiswon’tworkinsomecountries,whichissomethingyou’dneedtodealwithbasedonwhereyourcustomersandpartnerswouldbe.Thefollowingregularexpressionisrathercomplex(itslengthmeantithadtobesplitacrosstwolines;makesureyoutypeitinononeline):

^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})?\d{3}?\d{0,7}

((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-5})?$

Youwillneedtosetthecase-insensitiveflagwiththis,aswellastheexplicitcaptureoption.Althoughthisseemscomplex,ifbrokendown,it’squitestraightforward.

Let’sstartwiththepatternthatmatchesaninternationaldialingcode:

(\+\d{1,3}?)?

Sofar,you’rematchingaplussign(\+)followedbyonetothreedigits(\d{1,3})andanoptionalspace(?).Rememberthatbecausethe+characterisaspecialcharacter,youadda\characterinfrontofittospecifythatyoumeananactual+character.Thecharactersarewrappedinsideparenthesestospecifyagroupofcharacters.Youallowanoptionalspaceandmatchthisentiregroupofcharacterszerooronetime,asindicatedbythe?characteraftertheclosingparenthesisofthegroup.

Nextisthepatterntomatchanareacode:

(\(\d{1,5}\)|\d{1,5})

Thispatterniscontainedinparentheses,whichdesignateitasagroupofcharacters,andmatcheseitheronetofivedigitsinparentheses((\d{1,5}))orjustonetofivedigits(\d{1,5}).Again,becausetheparenthesischaractersarespecialcharactersinregular

expressionsyntaxandyouwanttomatchactualparentheses,youneedthe\characterinfrontofthem.Alsonotetheuseofthepipesymbol(|),whichmeans“OR”or“matcheitherofthesetwopatterns.”

Next,let’smatchthesubscribernumber:

?\d{3,4}?\d{0,7}

NOTETheinitialspaceand?mean“matchzerooronespace.”Thisisfollowedbythreeorfourdigits(\d{3,4})—althoughU.S.numbersalwayshavethreedigits,UKnumbersoftenhavefour.Thenthere’sanother“zerooronespace,”and,finally,betweenzeroandsevendigits(\d{0,7}).

Finally,addtheparttocopewithanoptionalextensionnumber:

((x|xtn|ext|extn|extension)?\.??\d{2-5})?

Thisgroupisoptionalbecauseitsparenthesesarefollowedbyaquestionmark.Thegroupitselfchecksforaspace,optionallyfollowedbyx,ext,xtn,extn,orextension,followedbyzerooroneperiod(notethe\character,because.isaspecialcharacterinregularexpressionsyntax),followedbyzerooronespace,followedbybetweentwoandfivedigits.Puttingthesefourpatternstogether,youcanconstructtheentireregularexpression,apartfromthesurroundingsyntax.Theregularexpressionstartswith^andendswith$.The^characterspecifiesthatthepatternmustbematchedatthebeginningofthestring,andthe$characterspecifiesthatthepatternmustbematchedattheendofthestring.Thismeansthatthestringmustmatchthepatterncompletely;itcannotcontainanyothercharactersbeforeorafterthepatternthatismatched.

Therefore,withtheregularexpressionexplained,let’slookonceagainattheisValidTelephoneNumber()functioninch6_example6.js:

functionisValidTelephoneNumber(telephoneNumber){

vartelRegExp=/^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})?\d{3}

?\d{0,7}((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-5})?$/i;

returntelRegExp.test(telephoneNumber);

}

Noteinthiscasethatitisimportanttosetthecase-insensitiveflagbyaddinganiontheendoftheexpressiondefinition;otherwise,theregularexpressioncouldfailtomatchtheextparts.Pleasealsonotethattheregularexpressionitselfmustbeononelineinyourcode—it’sshowninmultiplelineshereduetothepage-widthrestrictionsofthisbook.

ValidatingaPostalCodeWejustaboutmanagedtocheckworldwidetelephonenumbers,butdoingthesameforpostalcodeswouldbesomethingofamajorchallenge.Instead,you’llcreateafunctionthatonlychecksforU.S.ZIPcodesandUKpostcodes.Ifyouneededtocheckforothercountries,thecodewouldneedmodifying.Youmayfindthatcheckingmorethanoneortwopostalcodesinoneregularexpressionbeginstogetunmanageable,anditmaywellbe

easiertohaveanindividualregularexpressionforeachcountry’spostalcodeyouneedtocheck.Forthispurposethough,let’scombinetheregularexpressionfortheUnitedKingdomandtheUnitedStates:

^(\d{5}(-\d{4})?|[a-z][a-z]?\d\d??\d[a-z][a-z])$

Thisisactuallyintwoparts.ThefirstpartchecksforZIPcodes,andthesecondpartchecksforUKpostcodes.StartbylookingattheZIPcodepart.

ZIPcodescanberepresentedinoneoftwoformats:asfivedigits(12345),orfivedigitsfollowedbyadashandfourdigits(12345-1234).TheZIPcoderegularexpressiontomatchtheseisasfollows:

\d{5}(-\d{4})?

Thismatchesfivedigits,followedbyanoptionalnon-capturinggroupthatmatchesadash,followedbyfourdigits.

ForaregularexpressionthatcoversUKpostcodes,let’sconsidertheirvariousformats.UKpostcodeformatsareoneortwolettersfollowedbyeitheroneortwodigits,followedbyanoptionalspace,followedbyadigit,andthentwoletters.Additionally,somecentralLondonpostcodeslooklikeSE2V3ER,withaletterattheendofthefirstpart.Currently,onlysomeofthosepostcodesstartwithSE,WC,andW,butthatmaychange.ValidexamplesofUKpostcodesinclude:CH39DR,PR291XX,M271AE,WC1V2ER,andC273AH.

Basedonthis,therequiredpatternisasfollows:

([a-z][a-z]?\d\d?|[a-z]{2}\d[a-z])?\d[a-z][a-z]

Thesetwopatternsarecombinedusingthe|characterto“matchoneortheother”andgroupedusingparentheses.Youthenaddthe^characteratthestartandthe$characterattheendofthepatterntobesurethattheonlyinformationinthestringisthepostalcode.Althoughpostalcodesshouldbeuppercase,itisstillvalidforthemtobelowercase,soyoualsosetthecase-insensitiveoptionasfollowswhenyouusetheregularexpression:

^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-z])?\d[a-z][a-z])$

Justforreference,let’slookonceagainattheisValidPostalCode()function:

functionisValidPostalCode(postalCode){

varpcodeRegExp=/^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-z])

?\d[a-z][a-z])$/i;

returnpcodeRegExp.test(postalCode);

}

Again,rememberthattheregularexpressionmustbeononelineinyourcode.

ValidatinganE-mailAddressBeforeworkingonaregularexpressiontomatche-mailaddresses,youneedtolookatthetypesofvalide-mailaddressesyoucanhave.Forexample:

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

Also,ifyouexaminetheSMTPRFC(http://www.ietf.org/rfc/rfc0821.txt),youcanhavethefollowing:

[email protected]

"""PaulWilton"""@somedomain.com

That’squitealist,anditcontainsmanyvariationstocopewith.It’sbesttostartbybreakingitdown.First,notethatthelattertwoversionsareexceptionallyrareandnotprovidedforintheregularexpressionyou’llcreate.

Second,youneedtobreakupthee-mailaddressintoseparateparts.Let’slookatthepartafterthe@symbolfirst.

ValidatingaDomainNameEverythinghasbecomemorecomplicatedsinceUnicodedomainnameshavebeenallowed.However,thee-mailRFCstilldoesn’tallowthese,solet’sstickwiththetraditionaldefinitionofhowadomaincanbedescribedusingASCII.Adomainnameconsistsofadot-separatedlistofwords,withthelastwordbeingbetweentwoandfourcharacterslong.Itwasoftenthecasethatifatwo-lettercountrywordwasused,therewouldbeatleasttwopartstothedomainnamebeforeit:agroupingdomain(.co,.ac,andsoon)andaspecificdomainname.However,withtheadventofthe.tvnames,thisisnolongerthecase.Youcouldmakethisveryspecificandprovidefortheallowedtop-leveldomains(TLDs),butthatwouldmaketheregularexpressionverylarge,anditwouldbemoreproductivetoperformaDNSlookupinstead.

Eachpartofadomainnamemustfollowcertainrules.Itcancontainanyletterornumberorahyphen,butitmuststartwithaletter.Theexceptionisthat,atanypointinthedomainname,youcanusea#,followedbyanumber,whichrepresentstheASCIIcodeforthatletter,orinUnicode,the16-bitUnicodevalue.Knowingthis,let’sbegintobuilduptheregularexpression,firstwiththenamepart,assumingthatthecase-insensitiveflagwillbesetlaterinthecode:

([a-z]|#\d+)([a-z0-9-]|#\d+)*([a-z0-9]|#\d+)

Thisbreaksthedomainintothreeparts.TheRFCdoesn’tspecifyhowmanydigitscanbe

containedhere,soneitherwillwe.ThefirstpartmustonlycontainanASCIIletter;thesecondmustcontainzeroormoreofaletter,number,orhyphen;andthethirdmustcontaineitheraletterornumber.Thetop-leveldomainhasmorerestrictions,asshownhere:

[a-z]{2,4}

Thisrestrictsyoutoatwo-,three-,orfour-lettertop-leveldomain.So,puttingitalltogether,withtheperiodsyouendupwiththis:

^(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]|#\d+?)\.)+([a-z]{2,4})$

Again,thedomainnameisanchoredatthebeginningandendofthestring.Thefirstthingistoaddanextragrouptoallowoneormorename.portionsandthenanchoratwo-tofour-letterdomainnameattheendinitsowngroup.Wehavealsomademostofthewildcardslazy.Becausemuchofthepatternissimilar,itmakessensetodothis;otherwise,itwouldrequiretoomuchbacktracking.However,wehaveleftthesecondgroupwitha“greedy”wildcard:Itwillmatchasmuchasitcan,upuntilitreachesacharacterthatdoesnotmatch.Thenitwillonlybacktrackonepositiontoattemptthethirdgroupmatch.Thisismoreresource-efficientthanalazymatchisinthiscase,becauseitcouldbeconstantlygoingforwardtoattemptthematch.Onebacktrackpernameisanacceptableamountofextraprocessing.

ValidatingaPerson’sAddressYoucannowattempttovalidatethepartbeforethe@sign.TheRFCspecifiesthatitcancontainanyASCIIcharacterwithacodeintherangefrom33to126.YouareassumingthatyouarematchingagainstASCIIonly,soyoucanassumethattheenginewillmatchagainstonly128characters.Thisbeingthecase,itissimplertojustexcludetherequiredvaluesasfollows:

[^<>()\[\],;:@"\x00-\x20\x7F]+

Usingthis,you’resayingthatyouallowanynumberofcharacters,aslongasnoneofthemarethosecontainedwithinthesquarebrackets.Thesquarebracketandbackslashcharacters([,],and\)havetobeescaped.However,theRFCallowsforotherkindsofmatches.

ValidatingtheCompleteAddressNowthatyouhaveseenalltheprevioussections,youcanbuilduparegularexpressionfortheentiree-mailaddress.First,here’severythinguptoandincludingthe@sign:

^([^<>()\[\],;:@"\x00-\x20\x7F]|\\.)+@

Thatwasstraightforward.Nowforthedomainnamepart:

^([^<>()\[\],;:@"\x00-\x20\x7F]|\\.)+@(([a-z]|#\d+?)([a-z0-9-]

|#\d+?)*([a-z0-9]|#\d+?)\.)+([a-z]{2,4})$

We’vehadtoputitontwolinestofitthisbook’spagewidth,butinyourcodethismust

allbeononeline.

Finally,here’stheisValidEmail()functionforreference:

functionisValidEmail(emailAddress){

varemailRegExp=

/^(([^<>()\[\]\\.,;:@"\x00-\x20\x7F]|\\.)+|("""

([^\x0A\x0D"\\]|\\\\)+"""))

@(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]|#\d+?)\.)

+([a-z]{2,4})$/i;

returnemailRegExp.test(emailAddress);

}

Again,notetheregularexpressionmustallbeononelineinyourcode.

SUMMARYInthischapteryou’velookedatsomemoreadvancedmethodsoftheStringobjectandhowyoucanoptimizetheirusewithregularexpressions.

Torecap,thechaptercoveredthefollowingpoints:

Thesplit()methodsplitsasinglestringintoanarrayofstrings.Youpassastringoraregularexpressiontothemethodthatdetermineswherethesplitoccurs.

Thereplace()methodenablesyoutoreplaceapatternofcharacterswithanotherpatternthatyouspecifyasasecondparameter.

Thesearch()methodreturnsthecharacterpositionofthefirstpatternmatchingtheonegivenasaparameter.

Thematch()methodmatchespatterns,returningthetextofthematchesinanarray.

Regularexpressionsenableyoutodefineapatternofcharactersthatyouwanttomatch.Usingthispattern,youcanperformsplits,searches,textreplacement,andmatchesonstrings.

InJavaScript,theregularexpressionsareintheformofaRegExpobject.YoucancreateaRegExpobjectusingeithermyRegExp=/myRegularExpression/ormyRegExp=newRegExp(“myRegularExpression”).Thesecondformrequiresthatcertainspecialcharactersthatnormallyhaveasingle\infrontnowhavetwo.

Thegandicharactersattheendofaregularexpression(asin,forexample,myRegExp=/Pattern/gi;)ensurethataglobalandcase-insensitivematchismade.

Aswellasspecifyingactualcharacters,regularexpressionshavecertaingroupsofspecialcharactersthatallowanyofcertaingroupsofcharacters,suchasdigits,words,ornon-wordcharacters,tobematched.

Youcanalsousespecialcharacterstospecifypatternorcharacterrepetition.Additionally,youcanspecifywhatthepatternboundariesmustbe—forexample,atthebeginningorendofthestring,ornexttoawordornon-wordboundary.

Finally,youcandefinegroupsofcharactersthatcanbeusedlaterintheregularexpressionorintheresultsofusingtheexpressionwiththereplace()method.

Inthenextchapter,youtakealookatusingandmanipulatingdatesandtimesusingJavaScript,andtimeconversionbetweendifferentworldtimezones.Alsocoveredishowtocreateatimerthatexecutescodeatregularintervalsafterthepageisloaded.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. Whatproblemdoesthefollowingcodesolve?

varmyString="Thissentencehashasafaultandandweneedtofix

it."

varmyRegExp=/(\b\w+\b)\1/g;

myString=myString.replace(myRegExp,"$1");

Nowimaginethatyouchangethatcode,sothatyoucreatetheRegExpobjectlikethis:

varmyRegExp=newRegExp("(\b\w+\b)\1");

Whywouldthisnotwork,andhowcouldyourectifytheproblem?

2. Writearegularexpressionthatfindsalloftheoccurrencesoftheword“a”inthefollowingsentenceandreplacesthemwith“the”:

“adogwalkedinoffastreetandorderedafinestbeer”

Thesentenceshouldbecome:

“thedogwalkedinoffthestreetandorderedthefinestbeer”

3. Imagineyouhaveawebsitewithamessageboard.Writearegularexpressionthatwouldremovebarredwords.(Youcanmakeupyourownwords!)

7Date,Time,andTimersWHATYOUWILLLEARNINTHISCHAPTER:

RetrievingspecificdateandtimeinformationfromaDateobject

ModifyingthedateandtimeofaDateobject

Delayingtheexecutionofafunction

Executingafunctionatasetintervaloftime

Chapter5discussedthattheconceptsofdateandtimeareembodiedinJavaScriptthroughtheDateobject.YoulookedatsomeofthepropertiesandmethodsoftheDateobject,includingthefollowing:

ThemethodsgetDate(),getDay(),getMonth(),andgetFullYear()enableyoutoretrievedatevaluesfrominsideaDateobject.

ThesetDate(),setMonth(),andsetFullYear()methodsenableyoutosetthedatevaluesofanexistingDateobject.

ThegetHours(),getMinutes(),getSeconds(),andgetMilliseconds()methodsretrievethetimevaluesinaDateobject.

ThesetHours(),setMinutes(),setSeconds(),andsetMilliseconds()methodsenableyoutosetthetimevaluesofanexistingDateobject.

Onethingnotcoveredinthatchapteristheideathatthetimedependsonyourlocationaroundtheworld.Inthischapteryoucorrectthatomissionbylookingatdateandtimeinrelationtoworldtime.

Forexample,imagineyouhaveachatroomonyourwebsiteandwanttoorganizeachatforacertaindateandtime.Simplystating15:30isnotgoodenoughifyourwebsiteattractsinternationalvisitors.Thetime15:30couldbeEasternStandardTime,PacificStandardTime,thetimeintheUnitedKingdom,oreventhetimeinKualaLumpur.Youcould,ofcourse,say15:30ESTandletyourvisitorsworkoutwhatthatmeans,buteventhatisn’tfoolproof.ThereisanESTinAustraliaaswellasintheUnitedStates.Wouldn’titbegreatifyoucouldautomaticallyconvertthetimetotheuser’stimezone?Inthischapter,youseehow.

Inadditiontolookingatworldtime,youalsolookathowtocreateatimerinawebpage.You’llseethatbyusingthetimeryoucantriggercode,eitheratregularintervalsorjustonce(forexample,fivesecondsafterthepagehasloaded).You’llseehowyoucanusetimerstoaddareal-timeclocktoawebpage.Timerscanalsobeusefulforcreatinganimationsorspecialeffectsinyourwebapplications,whichyouexploreinlaterchapters.

WORLDTIMETheconceptofnowmeansthesamepointintimeeverywhereintheworld.However,whenthatpointintimeisrepresentedbynumbers,thosenumbersdifferdependingonwhereyouare.Whatisneededisastandardnumbertorepresentthatmomentintime.ThisisachievedthroughCoordinatedUniversalTime(UTC),whichisaninternationalbasisofcivilandscientifictimeandwasimplementedin1964.ItwaspreviouslyknownasGMT(GreenwichMeanTime),and,indeed,at0:00UTCitismidnightinGreenwich,London.

Thefollowingtableshowslocaltimesaroundtheworldat0:00UTCtime:

SANFRANCISCO

NEWYORK(EST)

GREENWICH,LONDON

BERLIN,GERMANY

TOKYO,JAPAN

4:00pm 7:00pm 0:00(midnight) 1:00am 9:00am

NOTEthatthetimesgivenarewintertimes—nodaylightsavingshoursaretakenintoaccount.

ThesupportforUTCinJavaScriptcomesfromanumberofmethodsoftheDateobjectthataresimilartothoseyouhavealreadyseen.Foreachoftheset-dateandget-date–typemethodsyou’veseensofar,thereisaUTCequivalent.Forexample,setHours()setsthelocalhourinaDateobject,andsetUTCHours()doesthesamethingforUTCtime.Youlookatthesemethodsinmoredetailinthenextsection.

Inaddition,threemoremethodsoftheDateobjectinvolveworldtime.

YouhavethemethodstoUTCString()andtoLocaleString(),whichreturnthedateandtimestoredintheDateobjectasastringbasedoneitherUTCorlocaltime.Mostmodernbrowsersalsohavetheseadditionalmethods:toLocaleTimeString(),toTimeString(),toLocaleDateString(),andtoDateString().

Ifyousimplywanttofindoutthedifferenceinminutesbetweenthecurrentlocale’stimeandUTC,youcanusethegetTimezoneOffset()method.IfthetimezoneisbehindUTC,suchasintheUnitedStates,itwillreturnapositivenumber.Ifthetimezoneisahead,suchasinAustraliaorJapan,itwillreturnanegativenumber.

TRYITOUTTheWorldTimeMethodoftheDateObject

InthefollowingcodeyouusethetoLocaleString(),toUTCString(),getTimezoneOffset(),toLocaleTimeString(),toTimeString(),toLocaleDateString(),andtoDateString()methodsandwritetheirvaluesouttothepage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Example1</title>

</head>

<body>

<script>

varlocalTime=newDate();

varhtml="<p>UTCTimeis"+localTime.toUTCString()+"

</p>";

html+="LocalTimeis"+localTime.toLocaleString()+"</p>";

html+="<p>TimeZoneOffsetis"+

localTime.getTimezoneOffset()+"</p>";

html+="<p>UsingtoLocalTimeString()gives:"+

localTime.toLocaleTimeString()+"</p>";

html+="<p>UsingtoTimeString()gives:"+

localTime.toTimeString()+"</p>";

html+="<p>UsingtoLocaleDateString()gives:"+

localTime.toLocaleDateString()+"</p>";

html+="<p>UsingtoDateString()gives::"+

localTime.toDateString()+"</p>";

document.write(html);

</script>

</body>

</html>

Savethisasch7_example1.htmlandloaditintoyourbrowser.Whatyousee,ofcourse,dependsonwhichtimezoneyourcomputerissetto,butyourbrowsershouldshowsomethingsimilartoFigure7.1.

Figure7.1

Herethecomputer’stimeissetto09:28:318PMonMarch30,2014,inAmerica’sEasternDaylightTime(forexample,NewYork).

Sohowdoesthiswork?Atthetopofthepage’sscriptblock,youhavejust:

varlocalTime=newDate();

ThiscreatesanewDateobjectandinitializesittothecurrentdateandtimebasedontheclientcomputer’sclock.(NotethattheDateobjectsimplystoresthenumberofmillisecondsbetweenthedateandtimeonyourcomputer’sclockandmidnightUTConJanuary1,1970.)

Withintherestofthescriptblock,youobtaintheresultsfromvarioustimeanddatefunctions.Theresultsarestoredinvariablehtml,andthisisthendisplayedinthepage.

Inthefollowingline,youstorethestringreturnedbythetoUTCString()methodinthehtmlvariable:

varhtml="<p>UTCTimeis"+localTime.toUTCString()+"</p>";

ThisconvertsthedateandtimestoredinsidethelocalTimeDateobjecttotheequivalentUTCdateandtime.

Thenthefollowinglinestoresastringwiththelocaldateandtimevalue:

html+="LocalTimeis"+localTime.toLocaleString()+"</p>";

Becausethistimeisjustbasedontheuser’sclock,thestringreturnedbythismethodalsoadjustsfordaylightsavingstime(aslongastheclockadjustsforit).

Next,thiscodestoresastringwiththedifference,inminutes,betweenthelocaltime

zone’stimeandthatofUTC:

html+="<p>TimeZoneOffsetis"+localTime.getTimezoneOffset()+"

</p>";

YoumaynoticeinFigure7.1thatthedifferencebetweenNewYorktimeandUTCtimeiswrittentobe240minutes,or4hours.Yetintheprevioustable,yousawthatNewYorktimeis5hoursbehindUTC.Sowhatishappening?

Well,inNewYorkonMarch30,daylightsavingshoursareinuse.Whereasinthesummerit’s8:00p.m.inNewYorkwhenit’s0:00UTC,inthewinterit’s7:00p.m.inNewYorkwhenit’s0:00UTC.Therefore,inthesummerthegetTimezoneOffset()methodreturns240,whereasinthewinterthegetTimezoneOffset()methodreturns300.

Toillustratethis,compareFigure7.1toFigure7.2,wherethedateonthecomputer’sclockhasbeenadvancedtoDecember,whichisinthewinterwhendaylightsavingsisnotineffect.

Figure7.2

ThenexttwomethodsaretoLocaleTimeString()andtoTimeString(),asfollows:

html+="<p>UsingtoLocalTimeString()gives:"+

localTime.toLocaleTimeString()+"</p>";

html+="<p>UsingtoTimeString()gives:"+

localTime.toTimeString()+"</p>";

ThesemethodsdisplayjustthetimepartofthedateandtimeheldintheDateobject.ThetoLocaleTimeString()methoddisplaysthetimeasspecifiedbytheuseronhiscomputer.Thesecondmethoddisplaysthetimebutalsogivesanindicationofthetimezone(intheexample,ESTforEasternStandardTimeinAmerica).

Thefinaltwomethodsdisplaythedatepartofthedateandtime.ThetoLocaleDateString()displaysthedateintheformattheuserhasspecifiedonhiscomputer.OnWindowsoperatingsystems,thisissetintheregionalsettingsofthePC’sControlPanel.However,becauseitreliesontheuser’sPCsetup,thelookofthedatevariesfromcomputertocomputer.ThetoDateString()methoddisplaysthecurrentdatecontainedinthePCdateinastandardformat.

Ofcourse,thisexamplereliesonthefactthattheuser’sclockissetcorrectly,notsomethingyoucanbe100percentsureof—it’samazinghowmanyusershavetheirlocaltimezonesettingssetcompletelywrong.

SettingandGettingaDateObject’sUTCDateandTimeWhenyoucreateanewDateobject,youcaneitherinitializeitwithavalueorletJavaScriptsetittothecurrentdateandtime.Eitherway,JavaScriptassumesyouaresettingthelocaltimevalues.IfyouwanttospecifyUTCtime,youneedtousethesetUTCtypemethods,suchassetUTCHours().

FollowingarethesevenmethodsforsettingUTCdateandtime:

setUTCDate()

setUTCFullYear()

setUTCHours()

setUTCMilliseconds()

setUTCMinutes()

setUTCMonth()

setUTCSeconds()

Thenamesprettymuchgiveawayexactlywhateachmethoddoes,solet’slaunchstraightintoasimpleexample,whichsetstheUTCtime.

TRYITOUTWorkingwithUTCDateandTimeLet’slookataquickexample.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Example2</title>

</head>

<body>

<script>

varmyDate=newDate();

myDate.setUTCHours(12);

myDate.setUTCMinutes(0);

myDate.setUTCSeconds(0);

varhtml="<p>"+myDate.toUTCString()+"</p>";

html+="<p>"+myDate.toLocaleString()+"</p>";

document.write(html);

</script>

</body>

</html>

Savethisasch7_example2.html.Whenyouloaditinyourbrowser,youshouldseesomethinglikewhatisshowninFigure7.3inyourwebpage,althoughtheactualdatewilldependonthecurrentdateandwhereyouareintheworld.

Figure7.3

Youmightwanttochangeyourcomputer’stimezoneandtimeofyeartoseehowitvariesindifferentregionsandwithdaylightsavingschanges.InWindowsyoucanmakethechangesbyopeningtheControlPanelandthendouble-clickingtheDate/Timeicon.

Sohowdoesthisexamplework?Youdeclareavariable,myDate,andsetittoanewDateobject.Becauseyouhaven’tinitializedtheDateobjecttoanyvalue,itcontainsthelocalcurrentdateandtime.

Then,usingthesetUTCmethods,yousetthehours,minutes,andsecondssothatthetimeis12:00:00UTC(midday,notmidnight).

Now,whenyouwriteoutthevalueofmyDateasaUTCstring,youget12:00:00andtoday’sdate.WhenyouwriteoutthevalueoftheDateobjectasalocalstring,yougettoday’sdateandatimethatistheUTCtime12:00:00convertedtotheequivalentlocaltime.Thelocalvaluesyou’llsee,ofcourse,dependonyourtimezone.For

example,NewYorkerswillsee08:00:00duringthesummerand07:00:00duringthewinterbecauseofdaylightsavings.IntheUnitedKingdom,inthewinteryou’llsee12:00:00,butinthesummeryou’llsee13:00:00.

ForgettingUTCdatesandtimes,youhavethesamefunctionsyouwoulduseforsettingUTCdatesandtimes,exceptthatthistime,forexample,it’sgetUTCHours(),notsetUTCHours():

getUTCDate()

getUTCDay()

getUTCFullYear()

getUTCHours()

getUTCMilliseconds()

getUTCMinutes()

getUTCMonth()

getUTCSeconds()

toISOString()

Noticethatthistimeyouhavetwoadditionalmethods,getUTCDay()andtoISOString().ThegetUTCDay()methodworksinthesamewayasthegetDay()methodandreturnsthedayoftheweekasanumber,from0forSundayto6forSaturday.Becausethedayoftheweekisdecidedbythedayofthemonth,themonth,andtheyear,thereisnosetUTCDay()method.

ThetoISOString()methodisrelativelynewtoJavaScript,anditreturnsthedateandtimeinanISO-formattedstring.Theformatis:

YYYY-MM-DDTHH:mm:ss.sssZ

TheISOformatseparatesthedatefromthetimewiththeliteralcharacterT.SoYYYY-MM-DDisthedate,andHH:mm:ss.sssisthetime.TheZattheenddenotestheUTCtimezone.TheISOformattedstringforMarch30,2014at3:10PMUTCis:

2014-03-30T15:10:00Z

WhenyoulearnaboutformsinChapter11,you’llrevisitdatesandtimestobuildatimeconverter.

TIMERSINAWEBPAGEYoucancreatetwotypesoftimers:one-shottimersandcontinuallyfiringtimers.Theone-shottimertriggersjustonceafteracertainperiodoftime,andthesecondtypeoftimercontinuallytriggersatsetintervals.Youinvestigateeachofthesetypesoftimersinthenexttwosections.

Withinreasonablelimits,youcanhaveasmanytimersasyouwantandcansetthemgoingatanypointinyourcode,suchaswhentheuserclicksabutton.Commonusesfortimersincludeanimatingelements,creatingadvertisementbannerpicturesthatchangeatregularintervals,anddisplayingthechangingtimeinawebpage.

One-ShotTimerSettingaone-shottimerisveryeasy;youjustusethesetTimeout()function:

vartimerId=setTimeout(yourFunction,millisecondsDelay)

ThesetTimeout()methodtakestwoparameters.Thefirstisafunctionyouwantexecuted,andthesecondisthedelay,inmilliseconds(thousandthsofasecond),untilthecodeisexecuted.

Themethodreturnsavalue(aninteger),whichisthetimer’suniqueID.Ifyoudecidelaterthatyouwanttostopthetimerfiring,youusethisIDtotellJavaScriptwhichtimeryouarereferringto.

TRYITOUTDelayingaMessageInthisexample,yousetatimerthatfiresthreesecondsafterthepagehasloaded:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Example3</title>

</head>

<body>

<script>

functiondoThisLater(){

alert("Time'sup!");

}

setTimeout(doThisLater,3000);

</script>

</body>

</html>

Savethisfileasch7_example3.html,andloaditintoyourbrowser.

ThispagedisplaysamessageboxthreesecondsafterthebrowserexecutestheJavaScriptcodeinthebodyofthepage.Let’slookatthatcodestartingwiththedoThisLater()function:

functiondoThisLater(){

alert("Time'sup!");

}

Thisfunction,whencalled,simplydisplaysamessageinanalertbox.YoudelaythecallofthisfunctionbyusingsetTimeout():

setTimeout(doThisLater,3000);

TakenotehowdoThisLater()ispassedtosetTimeout()—theparenthesesareomitted.YoudonotwanttocalldoThisLater()here;yousimplywanttorefertothefunctionobject.

ThesecondparametertellsJavaScripttoexecutedoThisLater()after3,000milliseconds,or3seconds,havepassed.

It’simportanttonotethatsettingatimerdoesnotstopthescriptfromcontinuingtoexecute.Thetimerrunsinthebackgroundandfireswhenitstimeisup.Inthemeantimethepagerunsasusual,andanyscriptafteryoustartthetimer’scountdownwillrunimmediately.So,inthisexample,thealertboxtellingyouthatthetimerhasbeensetappearsimmediatelyafterthecodesettingthetimerhasbeenexecuted.

Whatifyoudecidedthatyouwantedtostopthetimerbeforeitfired?

ToclearatimeryouusetheclearTimeout()function.Thistakesjustoneparameter:the

uniquetimerIDreturnedbythesetTimeout()function.

TRYITOUTStoppingaTimerInthisexample,you’llaltertheprecedingexampleandprovideabuttonthatyoucanclicktostopthetimer:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Example4</title>

</head>

<body>

<script>

functiondoThisLater(){

alert("Time'sup!");

}

vartimerId=setTimeout(doThisLater,3000);

clearTimeout(timerId);

</script>

</body>

</html>

Savethisasch7_example4.htmlandloaditintoyourbrowser.YouwillnotseeanalertboxdisplayingtheTime'sup!messagebecauseyoucalledclearTimeout()andpassedthetimerIDbeforethetimeoutcouldexpire.

SettingaTimerthatFiresatRegularIntervalsThesetInterval()andclearInterval()functionsworksimilarlytosetTimeout()andclearTimeout(),exceptthatthetimerfirescontinuallyatregularintervalsratherthanjustonce.

ThesetInterval()functiontakesthesameparametersassetTimeout(),exceptthatthesecondparameternowspecifiestheinterval,inmilliseconds,betweeneachfiringofthetimer,ratherthanjustthelengthoftimebeforethetimerfires.

Forexample,tosetatimerthatfiresthefunctionmyFunction()everyfiveseconds,thecodewouldbeasfollows:

varmyTimerID=setInterval(myFunction,5000);

AswithsetTimeout(),thesetInterval()methodreturnsauniquetimerIDthatyou’llneedifyouwanttoclearthetimerwithclearInterval(),whichworksidenticallytoclearTimeout().Sotostopthetimerstartedintheprecedingcode,youwouldusethefollowing:

clearInterval(myTimerID);

TRYITOUTACountingClockInthisexample,youwriteasimplepagethatdisplaysthecurrentdateandtime.That’snotveryexciting,soyou’llalsomakeitupdateeverysecond:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Example5</title>

</head>

<body>

<divid="output"></div>

<script>

functionupdateTime(){

document.getElementById("output").innerHTML=new

Date();

}

setInterval(updateTime,1000);

</script>

</body>

</html>

Savethisfileasch7_example5.html,andloaditintoyourbrowser.

Inthebodyofthispageisa<div/>element,anditsidattributehasthevalueofoutput:

<divid="output"></div>

Theupdateddateandtimewillbedisplayedinsidethiselement,andthecontentsofthiselementareupdatedbytheupdateTime()function:

functionupdateTime(){

document.getElementById("output").innerText=newDate();

}

Thisfunctionusesthedocument.getElementById()methodtoretrievetheaforementioned<div/>element,anditusestheinnerTextpropertytosettheelement’stexttoanewDateobject.Whendisplayedinthebrowser,JavaScriptconvertstheDateobjecttoahuman-readablestringcontainingboththedateandtime.

Tochangethedateandtime,youusethesetInterval()function,passingitareferencetotheupdateTime()function,andsettingittoexecuteeverysecond(1,000milliseconds).This,inturn,changesthetextinsideofthe<div/>element,thusshowingthecurrentdateandtimeeverysecond.

Thatcompletesyourlookatthisexampleandalsoyourintroductiontotimers.YouusethesetInterval()andclearInterval()functionsinlaterchapters.

SUMMARYYoustartedthechapterbylookingatCoordinatedUniversalTime(UTC),whichisaninternationalstandardtime.Youthenlookedathowtocreatetimersinwebpages.

Theparticularpointscoveredwerethefollowing:

TheDateobjectenablesyoutosetandgetUTCtimeinawaysimilartosettingaDateobject’slocaltimebyusingmethods(suchassetUTCHours()andgetUTCHours())forsettingandgettingUTChourswithsimilarmethodsformonths,years,minutes,seconds,andsoon.

AusefultoolininternationaltimeconversionisthegetTimezoneOffset()method,whichreturnsthedifference,inminutes,betweentheuser’slocaltimeandUTC.Onepitfallofthisisthatyouareassumingtheuserhascorrectlysethistimezoneonhiscomputer.Ifnot,getTimezoneOffset()isrendereduseless,aswillbeanylocaldateandtimemethodsiftheuser’sclockisincorrectlyset.

UsingthesetTimeout()method,youfoundyoucouldstartatimerthatwouldfirejustonceafteracertainnumberofmilliseconds.setTimeout()takestwoparameters:Thefirstisthefunctionyouwantexecuted,andthesecondisthedelaybeforethatcodeisexecuted.Itreturnsavalue,theuniquetimerIDthatyoucanuseifyoulaterwanttoreferencethetimer;forexample,tostopitbeforeitfires,youusetheclearTimeout()method.

Tocreateatimerthatfiresatregularintervals,youusedthesetInterval()method,whichworksinthesamewayassetTimeout(),exceptthatitkeepsfiringunlesstheuserleavesthepageoryoucalltheclearInterval()method.

Inthenextchapter,youturnyourattentiontothewebbrowseritselfand,particularly,thevariousobjectsthatitmakesavailableforyourJavaScriptprogramming.Youseethattheuseofbrowserobjectsiskeytocreatingpowerfulwebpages.

EXERCISES1. Createapagethatgetstheuser’sdateofbirth.Then,usingthatinformation,tellher

onwhatdayoftheweekshewasborn.

2. CreateawebpagesimilartoExample5inthe“ACountingClock”TryItOut,butmakeitdisplayonlythehour,minutes,andseconds.

8ProgrammingtheBrowserWHATYOUWILLLEARNINTHISCHAPTER:

Workingwiththebrowser’snativewindowobject

SendingthebrowsertoaURL

Manipulatingimagesaftertheyareloadedinthepage

Retrievingthebrowser’scurrentgeographicalposition

Detectingtheuser’sbrowser

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Overthepastfewchapters,you’veexaminedthecoreJavaScriptlanguage.You’veseenhowtoworkwithvariablesanddata,performoperationsonthatdata,makedecisionsinyourcode,looprepeatedlyoverthesamesectionofcode,andevenhowtowriteyourownfunctions.YoumovedontolearnhowJavaScriptisanobject-basedlanguage,andyousawhowtoworkwiththenativeJavaScriptobjects.However,youarenotinterestedonlyinthelanguageitself;youwanttofindouthowtowritescriptsforthewebbrowser.Usingthisability,youcanstarttocreatemoreimpressivewebpages.

NotonlyisJavaScriptobject-based,butthebrowserisalsomadeupofobjects.WhenJavaScriptisrunninginthebrowser,youcanaccessthebrowser’sobjectsinexactlythesamewaythatyouusedJavaScript’snativeobjects.Butwhatkindsofobjectsdoesthebrowserprovide?

Thebrowsermakesavailablearemarkablenumberofobjects.Forexample,thereisawindowobjectcorrespondingtothewindowofthebrowser.Youhavealreadybeenusingtwomethodsofthisobject,namelythealert()andprompt()methods.Forsimplicity,wepreviouslyreferredtotheseasfunctions,buttheyare,infact,methodsofthebrowser’swindowobject.

Anotherobjectmadeavailablebythebrowseristhepageitself,representedbythedocumentobject.Again,youhavealreadyusedmethodsandpropertiesofthisobject.Recallfrompreviouschaptersthatyouusedthedocumentobject’swrite()methodtowriteinformationtothepage.

Avarietyofotherobjectsexist,representativeoftheHTMLyouwriteinthepage.Forexample,thereisanimgobjectforeach<img/>elementthatyouusetoinsertanimageintoyourdocument.

ThecollectionofobjectsthatthebrowsermakesavailabletoyouforusewithJavaScript

isgenerallycalledthebrowserobjectmodel(BOM).

NOTEYouwilloftenseethistermedthedocumentobjectmodel(DOM);itisincorrecttodoso.Throughoutthisbook,we’llusethetermDOMtorefertotheW3C’sstandarddocumentobjectmodel,whichisdiscussedinthenextchapter.

AllthisaddedfunctionalityofJavaScriptcomeswithapotentialdownside:ThereisnostandardBOMimplementation(althoughsomeattemptisbeingmadewiththeHTML5specification).Whichcollectionsofobjectsaremadeavailabletoyouishighlydependentonthebrandandversionofthebrowserthatyouareusing.Someobjectsaremadeavailableinsomebrowsersandnotinothers,whereasotherobjectshavedifferentpropertiesandmethodsindifferentbrowsers.Thegoodnewsisthatbrowsermakerstypicallydonotchangemuchoftheirbrowser’sBOM,becausedoingsowouldcreateariftininteroperability.ThismeansifyousticktothecorefunctionalityoftheBOM(thecommonobjectsinallbrowsers),yourcodeismorelikelytoworkbetweenthedifferentbrowsersandversions.Thischapter’sfocusistheBOMcorefunctionality.YoucanachievealotinJavaScriptbyjuststickingtothecore.

INTRODUCTIONTOTHEBROWSER’SOBJECTSThissectionintroducestheobjectsoftheBOMthatarecommontoallbrowsers.

InChapter5,yousawthatJavaScripthasanumberofnativeobjectsthatyoucanaccessanduse.Mostoftheobjectsarethosethatyouneedtocreateyourself,suchastheStringandDateobjects.Others,suchastheMathobject,existwithoutyouneedingtocreatethemandarereadyforuseimmediatelywhenthepagestartsloading.

WhenJavaScriptisrunninginawebpage,ithasaccesstoalargenumberofotherobjectsmadeavailablebythewebbrowser.LiketheMathobject,thesearecreatedforyouratherthanyourneedingtocreatethemexplicitly.Asmentioned,theobjects,theirmethods,properties,andeventsareallmappedoutintheBOM.

TheBOMisverylargeandpotentiallyoverwhelmingatfirst.However,you’llfindthatinitiallyyouwon’tbeusingmorethan10percentoftheavailableobjects,methods,andpropertiesintheBOM.YoustartinthischapterbylookingatthemorecommonlyusedpartsoftheBOM,asshowninFigure8.1.ThesepartsoftheBOMare,toacertainextent,commonacrossallbrowsers.Laterchaptersbuildonthissothatbytheendofthebookyou’llbeabletoreallymaketheBOMworkforyou.

Figure8.1

TheBOMhasahierarchy.Attheverytopofthishierarchyisthewindowobject.Youcanthinkofthisasrepresentingtheframeofthebrowserandeverythingassociatedwithit,suchasthescrollbars,navigatorbaricons,andsoon.

Containedinsidethewindowframeisthepage.ThepageisrepresentedintheBOMbythedocumentobject.YoucanseethesetwoobjectsrepresentedinFigure8.2.

Figure8.2

Nowlet’slookateachoftheseobjectsinmoredetail.

ThewindowObjectThewindowobjectrepresentsthebrowser’sframeorwindow,inwhichyourwebpageiscontained.Tosomeextent,italsorepresentsthebrowseritselfandincludesanumberofpropertiesthataretheresimplybecausetheydon’tfitanywhereelse.Forexample,viathepropertiesofthewindowobject,youcanfindoutwhatbrowserisrunning,thepagestheuserhasvisited,thesizeofthebrowserwindow,thesizeoftheuser’sscreen,andmuchmore.Youcanalsousethewindowobjecttoaccessandchangethetextinthebrowser’sstatusbar,changethepagethatisloaded,andevenopennewwindows.

Thewindowobjectisaglobalobject,whichmeansyoudon’tneedtouseitsnametoaccessitspropertiesandmethods.Infact,theglobalfunctionsandvariables(theonesaccessibleforyoutoscriptanywhereinapage)areallcreatedaspropertiesoftheglobalobject.Forexample,thealert()functionyouhavebeenusingsincethebeginningofthebookis,infact,thealert()methodofthewindowobject.Althoughyouhavebeenusingthissimplyasthis:

alert("Hello!");

Youcouldwritethiswiththesame,exactresults:

window.alert("Hello!");

However,becausethewindowobjectistheglobalobject,itisperfectlycorrecttousethefirstversion.

Someofthepropertiesofthewindowobjectarethemselvesobjects.Thosecommontoallbrowsersincludethedocument,navigator,history,screen,andlocationobjects.Thedocumentobjectrepresentsyourpage,thehistoryobjectcontainsthehistoryofpagesvisitedbytheuser,thenavigatorobjectholdsinformationaboutthebrowser,thescreen

objectcontainsinformationaboutthedisplaycapabilitiesoftheclient,andthelocationobjectcontainsdetailsonthecurrentpage’slocation.Youlookattheseimportantobjectsindividuallylaterinthechapter.

Atthispointit’sworthhighlightingthefactthat,withinawebpage,youshouldn’tusenamesforyourfunctionsorvariablesthatconflictwithnamesofBOMobjectsortheirpropertiesandmethods.Ifyoudo,youmaynotgetanerror,butinsteadgetunexpectedresults.Forexample,thefollowingcodedeclaresavariablenamedhistory,andtriestousethehistorypropertyofthewindowobjecttogobacktothepreviouspage.This,however,won’tworkbecausehistoryhasbeenchangedtoholdadifferentvalue:

varhistory="Hello,BOM!";

window.history.back();//error;stringobjectsdon'thaveaback()method

Inthissituationyouneedtouseadifferentvariablename.Thishappensbecauseanyfunctionorvariableyoudefinewithintheglobalscopeactuallygetsappendedtothewindowobject.Lookatthiscodeasanexample:

varmyVariable="Hello,World!";

alert(window.myVariable);

Ifyouweretoexecutethiscodeinabrowser,thealertwindowwoulddisplaythemessage“Hello,World.”

AswithalltheBOMobjects,youcanlookatlotsofpropertiesandmethodsforthewindowobject.However,inthischapteryouconcentrateonthehistory,location,navigator,screen,anddocumentproperties.Allfiveofthesepropertiescontainobjects(thehistory,location,navigator,screen,anddocumentobjects),eachwithitsownpropertiesandmethods.Inthenextfewpages,youlookateachoftheseobjectsinturnandfindouthowtheycanhelpyoumakefulluseoftheBOM.

ThehistoryObjectThehistoryobjectkeepstrackofeachpagethattheuservisits.Thislistofpagesiscommonlycalledthehistorystackforthebrowser.Itenablestheusertoclickthebrowser’sBackandForwardbuttonstorevisitpages.Youhaveaccesstothisobjectviathewindowobject’shistoryproperty.

LikethenativeJavaScriptArraytype,thehistoryobjecthasalengthproperty.Youcanusethistofindouthowmanypagesareinthehistorystack.

Asyoumightexpect,thehistoryobjecthastheback()andforward()methods.Whentheyarecalled,thelocationofthepagecurrentlyloadedinthebrowserischangedtothepreviousornextpagethattheuserhasvisited.

Thehistoryobjectalsohasthego()method.Thistakesoneparameterthatspecifieshowfarforwardorbackwardinthehistorystackyouwanttogo.Forexample,ifyouwantedtoreturntheusertothepagebeforethepreviouspage,you’dwritethis:

history.go(-2);

Togoforwardthreepages,you’dwritethis:

history.go(3);.

Notethatgo(-1)andback()areequivalent,asarego(1)andforward().

ThelocationObjectThelocationobjectcontainslotsofpotentiallyusefulinformationaboutthecurrentpage’slocation.Notonlydoesitcontaintheuniformresourcelocator(URL)forthepage,butalsotheserverhostingthepage,theportnumberoftheserverconnection,andtheprotocolused.Thisinformationismadeavailablethroughthelocationobject’shref,hostname,port,andprotocolproperties.However,manyofthesevaluesareonlyreallyrelevantwhenyouareloadingthepagefromaserverandnot,asyouaredoinginthepresentexamples,loadingthepagedirectlyfromalocalharddrive.

Inadditiontoretrievingthecurrentpage’slocation,youcanusethemethodsofthelocationobjecttochangethelocationandrefreshthecurrentpage.

Youcannavigatetoanotherpageintwoways.Youcaneithersetthelocationobject’shrefpropertytopointtoanotherpage,oryoucanusethelocationobject’sreplace()method.Theeffectofthetwoisthesame;thepagechangeslocation.However,theydifferinthatthereplace()methodremovesthecurrentpagefromthehistorystackandreplacesitwiththenewpageyouaremovingto,whereasusingthehrefpropertysimplyaddsthenewpagetothetopofthehistorystack.Thismeansthatifthereplace()methodhasbeenusedandtheuserclickstheBackbuttoninthebrowser,theusercan’tgobacktotheoriginalpageloaded.Ifthehrefpropertyhasbeenused,theusercanusetheBackbuttonasnormal.

Forexample,toreplacethecurrentpagewithanewpagecalledmyPage.html,you’dusethereplace()methodandwritethefollowing:

location.replace("myPage.html");

ThisloadsmyPage.htmlandreplacesanyoccurrenceofthecurrentpageinthehistorystackwithmyPage.html.

Toloadthesamepageandtoaddittothehistoryofpagesnavigatedto,youusethehrefproperty:

location.href="myPage.html";

Thisaddsthecurrentlyloadedpagetothehistory.Inbothoftheprecedingcases,windowisinfrontoftheexpression,butbecausethewindowobjectisglobalthroughoutthepage,youcouldhavewrittenoneofthefollowing:

location.replace("myPage.html");

location.href="myPage.html";

ThenavigatorObjectThenavigatorobjectisanotherobjectthatisapropertyofwindowandisavailableinallbrowsers.Itsnameismorehistoricalthandescriptive.Perhapsabetternamewouldbethe

“browserobject,”becausethenavigatorobjectcontainslotsofinformationaboutthebrowserandtheoperatingsysteminwhichit’srunning.

Historically,themostcommonuseofthenavigatorobjectisforhandlingbrowserdifferences.Usingitsproperties,youcanfindoutwhichbrowser,version,andoperatingsystemtheuserhas.Youcanthenactonthatinformationandmakesureyourcodeworksonlyinbrowsersthatsupportit.Thisisreferredtoasbrowsersniffing,andthoughithasitsuses,itdoeshavelimitations.

Abetteralternativetobrowsersniffingisfeaturedetection,theactofdeterminingifabrowsersupportsaparticularfeature.Wewon’tgointothesesubjectshere;latersectionsofthischapteraredevotedtobrowsersniffingandfeaturedetection.

ThegeolocationObjectTheHTML5specificationaddsthegeolocationpropertytonavigator.Itspurposeissimple:toenabledeveloperstoobtainandusethepositionofthedeviceorcomputer.Thatsoundslikeascaryproposition,butusersmustgivepermissionforthatinformationtoberetrievedandused.

AttheheartofthegeolocationobjectisitsgetCurrentPosition()method.Whenyoucallthismethod,youmustpassitacallbackfunction,whichisafunctionthatexecuteswhengetCurrentPosition()successfullycompletesitswork.InChapter4,youlearnedthatfunctionsarevalues.Youcanassignthemtovariablesandpassthemtootherfunctions,andthelatteriswhatyoudowiththegetCurrentPosition()method.Forexample:

functionsuccess(position){

alert("Ihaveyounow!");

}

navigator.geolocation.getCurrentPosition(success);

Inthiscode,success()isthecallbackfunctionthatexecuteswhennavigator.geolocation.getCurrentPosition()determinesthecomputer’sordevice’slocation.Theparameter,position,isanobjectthatcontainstheEarthlypositionandaltitudeofthecomputerordevice,andyoucanretrievethesepiecesofinformationthroughitscoordsproperty,likethis:

functionsuccess(position){

varlatitude=position.coords.latitude;

varlongitude=position.coords.longitude;

varaltitude=position.coords.altitude;

varspeed=position.coords.speed;

}

Thelatitude,longitude,andaltitudepropertiesareself-explanatory;theyaresimplynumericvaluesrepresentingthelatitude,longitude,andaltitudeofthedeviceorcomputer,respectively.Thespeedpropertyretrievesthespeed,orratherthevelocity,ofthedevice/computerinmeterspersecond.

Ifyouneedtoretrievemorethanoneofthesevalues,itmakessensetoassign

position.coordstoavariableandthenusethevariabletoretrievethepositionalvalues.Forexample:

functionsuccess(position){

varcrds=position.coords;

varlatitude=crds.latitude;

varlongitude=crds.longitude;

varaltitude=crds.altitude;

varspeed=crds.speed;

}

Thisreducestheamountofcodeyouhavetotype.Italsohastheadvantageofreducingthesizeofyourcode,resultinginaslightlyfasterdownloadtime.

ThegetCurrentPosition()methodacceptsasecondparameter,anothercallbackfunctionthatexecuteswhenanerroroccurs:

functiongeoError(errorObj){

alert("Uhoh,somethingwentwrong");

}

navigator.geolocation.getCurrentPosition(success,geoError);

TheerrorcallbackfunctionhasasingleparameterthatrepresentsthereasonforgetCurrentPosition()’sfailure.Itisanobjectcontainingtwoproperties.Thefirst,code,isanumericvalueindicatingthereasonoffailure.Thefollowingtableliststhepossiblevaluesandtheirmeanings:

VALUE DESCRIPTION1 Failureoccurredbecausethepagedidnothavepermissiontoacquirethe

positionofthedevice/computer.2 Aninternalerroroccurred.3 Thetimeallowedtoretrievethedevice’s/computer’spositionwasreached

beforethepositionwasobtained.

Thesecondpropertyiscalledmessage;it’sahuman-readablemessagethatdescribestheerror.

TRYITOUTUsingGeolocationInthisexample,youusethegeolocationobjecttoretrievethelatitudeandlongitudeofthedevice/computer:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Example1</title>

</head>

<body>

<script>

functiongeoSuccess(position){

varcoords=position.coords;

varlatitude=coords.latitude;

varlongitude=coords.longitude;

varmessage="You'reat"+latitude+","+

longitude

alert(message);

}

functiongeoError(errorObj){

alert(errorObj.message);

}

navigator.geolocation.getCurrentPosition(geoSuccess,

geoError);

</script>

</body>

</html>

Savethepageasch8_example1.htmlandloaditintoyourbrowser.

Thepagerequirestheuser’sconsentinordertoretrievehisorhergeographicalposition.Sothefirstthingyouwillseeisapromptaskingyoutoallowordenythepagepermissiontoretrievethatinformation.Everybrowserdisplaysthisrequestdifferently;Figure8.3isChrome’srequest.

Figure8.3

Ifyouallowthepagetoaccessyourposition,you’llseethelatitudeandlongitudeofyourdeviceorcomputerdisplayedinanalertbox.Ifyouchoosetodenyaccess,

you’llseeamessagesimilartothatshowninFigure8.4.

Figure8.4

Twofunctionsinthispageareresponsiblefortheaforementionedbehavior.Thefirstfunction,geoSuccess(),isthecallbackfunctionthatexecuteswhenthebrowsercansuccessfullyretrieveyourdevice’s/computer’sposition:

functiongeoSuccess(position){

varcoords=position.coords;

varlatitude=coords.latitude;

varlongitude=coords.longitude;

Thefirststatementinthisfunctionstoresposition.coordsinthecoordsvariabletoaccessthepositionalinformationwithfewerkeystrokes.Thesecondandthirdstatementsretrievethelatitudeandlongitude,respectively.

Nowthatyouhavethelatitudeandlongitude,youassembleamessagethatcontainsthisinformationanddisplayittotheuser:

varmessage="You'reat"+latitude+","+longitude

alert(message);

}

Ifyoudeniedthepageaccesstoyourposition,orifthebrowsercannotobtainyourposition,thegeoError()callbackfunctionexecutes:

functiongeoError(errorObj){

alert(errorObj.message);

}

Thissimplefunctionsimplyusestheerrorobject’smessagepropertytotelltheuserwhygetCurrentPosition()failed.

ThescreenObjectThescreenobjectpropertyofthewindowobjectcontainsalotofinformationaboutthedisplaycapabilitiesoftheclientmachine.Itspropertiesincludetheheightandwidthproperties,whichindicatetheverticalandhorizontalrangeofthescreen,respectively,in

pixels.

Anotherpropertyofthescreenobject,whichyouuseinanexamplelater,isthecolorDepthproperty.Thistellsyouthenumberofbitsusedforcolorsontheclient’sscreen.

ThedocumentObjectAlongwiththewindowobject,thedocumentobjectisprobablyoneofthemostimportantandcommonlyusedobjectsintheBOM.ViathisobjectyoucangainaccesstotheHTMLelements,theirproperties,andtheirmethodsinsideyourpage.

Thischapterconcentratesonthebasicpropertiesandmethodsthatarecommontoallbrowsers.MoreadvancedmanipulationofthedocumentobjectiscoveredinChapter9.

Thedocumentobjecthasanumberofpropertiesassociatedwithit,whicharealsoarray-likestructurescalledcollections.Themaincollectionsaretheforms,images,andlinkscollections.InternetExplorersupportsanumberofothercollectionproperties,suchastheallcollectionproperty,whichisanarrayofalltheelementsrepresentedbyobjectsinthepage.However,you’llconcentrateonusingobjectsthathavestandardcross-browsersupport,sothatyouarenotlimitingyourwebpagestojustonebrowser.

Youlookattheimagesandlinkscollectionsshortly.Athirdcollection,theformscollection,isoneofthetopicsofChapter11whenyoulookatformsinwebbrowsers.First,though,youlookatanice,simpleexampleofhowtousethedocumentobject’smethodsandproperties.

UsingthedocumentObjectYou’vealreadycomeacrosssomeofthedocumentobject’spropertiesandmethods—forexample,thewrite()methodandthebgColorproperty.

TRYITOUTSettingColorsAccordingtotheUser’sScreenColorDepth

Inthisexample,yousetthebackgroundcolorofthepageaccordingtohowmanycolorstheuser’sscreensupports.Thisistermedscreencolordepth.Iftheuserhasadisplaythatsupportsjusttwocolors(blackandwhite),there’snopointinyousettingthebackgroundcolortobrightred.YouaccommodatedifferentdepthsbyusingJavaScripttosetacolortheusercanactuallysee.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Example2</title>

</head>

<body>

<script>

varcolorDepth=window.screen.colorDepth;

switch(colorDepth){

case1:

case4:

document.bgColor="white";

break;

case8:

case15:

case16:

document.bgColor="blue";

break;

case24:

case32:

document.bgColor="skyblue";

break;

default:

document.bgColor="white";

}

document.write("Yourscreensupports"+colorDepth+

"bitcolor");

</script>

</body>

</html>

Savethepageasch8_example2.html.Whenyouloaditintoyourbrowser,thebackgroundcolorofthepagewillbedeterminedbyyourcurrentscreencolordepth.Also,amessageinthepagewilltellyouwhatthecolordepthcurrentlyis.

Youcantestthatthecodeisworkingproperlybychangingthecolorssupportedbyyourscreen.Byrefreshingthebrowser,youcanseewhatdifferencethismakestothecolorofthepage.

NOTEInFirefox,Safari,andChromebrowsers,it’snecessarytoshutdownandrestartthebrowsertoobserveanyeffect.

Asyousawearlier,thewindowobjecthasthescreenobjectproperty.OneofthepropertiesofthisobjectisthecolorDepthproperty,whichreturnsavalueof1,4,8,15,16,24,or32.Thisrepresentsthenumberofbitsassignedtoeachpixelonyourscreen.(Apixelisjustoneofthemanydotsthatmakeupyourscreen.)Toworkouthowmanycolorsyouhave,youjustcalculatethevalueof2tothepowerofthecolorDepthproperty.Forexample,acolorDepthof1meansthattwocolorsareavailable,acolorDepthof8meansthat256colorsareavailable,andsoon.Currently,mostpeoplehaveascreencolordepthofatleast8,butusually24or32.

Thefirsttaskofthescriptblockistosetthecolorofthebackgroundofthepagebasedonthenumberofcolorstheusercanactuallysee.Youdothisinabigswitchstatement.TheconditionthatischeckedforintheswitchstatementisthevalueofthecolorDepthvariable,whichissettowindow.screen.colorDepth:

varcolorDepth=window.screen.colorDepth;

switch(colorDepth){

Youdon’tneedtosetadifferentcolorforeachcolorDepthpossible,becausemanyofthemaresimilarwhenitcomestogeneralwebuse.Instead,yousetthesamebackgroundcolorfordifferent,butsimilar,colorDepthvalues.ForacolorDepthof1or4,yousetthebackgroundtowhite.Youdothisbydeclaringthecase1:statement,butyoudon’tgiveitanycode.IfthecolorDepthmatchesthiscasestatement,itwillfallthroughtothecase4:statementbelowit,whereyoudosetthebackgroundcolortowhite.Youthencallabreakstatement,sothatthecasematchingwillnotfallanyfurtherthroughtheswitchstatement:

case1:

case4:

document.bgColor="white";

break;

YoudothesamewithcolorDepthvaluesof8,15,and16,settingthebackgroundcolortoblueasfollows:

case8:

case15:

case16:

document.bgColor="blue";

break;

Finally,youdothesameforcolorDepthvaluesof24and32,settingthebackgroundcolortoskyblue:

case24:

case32:

document.bgColor="skyblue";

break;

Youendtheswitchstatementwithadefaultcase,justincasetheothercasestatementsdidnotmatch.Inthisdefaultcase,youagainsetthebackgroundcolortowhite:

default:

document.bgColor="white";

}

Inthenextbitofscript,youusethedocumentobject’swrite()method,somethingyou’vebeenusingintheseexamplesforawhilenow.Youuseittowritetothedocument—thatis,thepage—thenumberofbitsatwhichthecolordepthiscurrentlyset,asfollows:

document.write("Yourscreensupports"+colorDepth+

"bitcolor")

You’vealreadybeenusingthedocumentobjectintheexamplesthroughoutthebook.YouuseditsbgColorpropertyinChapter1tochangethebackgroundcolorofthepage,andyou’vealsomadegooduseofitswrite()methodintheexamplestowrite

HTMLandtextouttothepage.

Nowlet’slookatsomeoftheslightlymorecomplexpropertiesofthedocumentobject.Thesepropertieshaveincommonthefactthattheyallcontaincollections.Thefirstoneyoulookatisacollectioncontaininganobjectforeachimageinthepage.

TheimagesCollectionAsyouknow,youcaninsertanimageintoanHTMLpageusingthefollowingtag:

<imgalt="USA"name="myImage"src="usa.gif"/>

ThebrowsermakesthisimageavailableforyoutomanipulatewithJavaScriptbycreatinganimgobjectforitwiththenamemyImage.Infact,eachimageonyourpagehasanimgobjectcreatedforit.

Eachoftheimgobjectsinapageisstoredintheimagescollection,whichisapropertyofthedocumentobject.Youusethis,andothercollections,asyouwouldanarray.Thefirstimageonthepageisfoundintheelementdocument.images[0],thesecondindocument.images[1],andsoon.

Ifyouwantto,youcanassignavariabletoreferenceanimgobjectintheimagescollection.Itcanmakecodeeasiertotypeandread.Forexample,thefollowingcodeassignsareferencetotheimgobjectatindexposition1tothemyImage2variable:

varmyImage2=document.images[1];

NowyoucanwritemyImage2insteadofdocument.images[1]inyourcode,withexactlythesameeffect.

Becausethedocument.imagespropertyisacollection,ithaspropertiessimilartothenativeJavaScriptArraytype,suchasthelengthproperty.Forexample,ifyouwanttoknowhowmanyimagesareonthepage,thecodedocument.images.lengthwilltellyou.

TRYITOUTImageSelectionTheimgobjectitselfhasanumberofusefulproperties.Themostimportantoftheseisitssrcproperty.Bychangingthis,youcanchangetheimagethat’sloaded.Thisexampledemonstratesthis:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Example3</title>

</head>

<body>

<imgsrc=""width="200"height="150"alt="MyImage"/>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

varimgIndex=prompt("Enteranumberfrom0to3","");

document.images[0].src=myImages[imgIndex];

</script>

</body>

</html>

Savethisasch8_example3.html.Youwillalsoneedfourimagefiles,calledusa.gif,canada.gif,jamaica.gif,andmexico.gif.Youcancreatetheseimagesyourselforobtaintheonesprovidedwiththecodedownloadforthebook.

Apromptboxasksyoutoenteranumberfrom0to3whenthispageloadsintothebrowser.Adifferentimageisdisplayeddependingonthenumberyouenter.

AtthetopofthepageyouhaveyourHTML<img/>element.Noticethatthesrcattributeisleftempty:

<imgsrc=""width="200"height="150"alt="MyImage"/>

Nextyoucometothescriptblockwheretheimagetobedisplayedisdecided.Onthefirstline,youdefineanarraycontainingalistofimagesources.Inthisexample,theimagesareinthesamedirectoryastheHTMLfile,soapathisnotspecified.Ifyoursarenot,makesureyouenterthefullpath(forexample,C:\myImages\mexico.gif).

Thenyouasktheuserforanumberfrom0to3,whichwillbeusedasthearrayindextoaccesstheimagesourceinthemyImagesarray:

varimgIndex=prompt("Enteranumberfrom0to3","");

Finally,yousetthesrcpropertyoftheimgobjecttothesourcetextinsidethemyImagesarrayelementwiththeindexnumberprovidedbytheuser:

document.images[0].src=myImages[imgIndex];

Don’tforgetthatwhenyouwritedocument.images[0],youareaccessingtheimgobjectstoredintheimagescollection.It’sanindexpositionof0,becauseit’sthefirst(andonly)imageonthispage.

ThelinksCollectionForeachhyperlinkelement<a/>definedwithanhrefattribute,thebrowsercreatesanaobject.Themostimportantpropertyoftheaobjectisthehrefproperty,correspondingtothehrefattributeofthetag.Usingthis,youcanfindoutwherethelinkpointsto,andyoucanchangethisevenafterthepagehasloaded.

Thecollectionofallaobjectsinapageiscontainedwithinthelinkscollection,muchastheimgobjectsarecontainedintheimagescollection,asyousawearlier.

DETERMININGTHEUSER’SBROWSERManybrowsers,versionsofthosebrowsers,andoperatingsystemsareoutthereontheInternet,eachwithitsownversionoftheBOM,itsownsetoffeatures,anditsownparticularquirks.It’sthereforeimportantthatyoumakesureyourpageswillworkcorrectlyonallbrowsers,oratleastdegradegracefully,suchasbydisplayingamessagesuggestingthattheuserupgradehisorherbrowser.

Youhavetwowaystotestifthebrowsercanexecuteyourcode:featuredetectionandbrowsersniffing.Theyshareasimilarendgoal(toexecutecodeforagivenbrowser),buttheyareusedfordifferentpurposes.

FeatureDetectionNotallbrowserssupportthesamefeatures(althoughtoday’smodernbrowsersdoaverygoodjobofit).Whenwesay“feature,”we’renotreferringtotabbedbrowsing,downloadmanagers,andsoon.Wemeanfeaturesthatwe,asJavaScriptdevelopers,canaccessanduseinourcode.

Featuredetectionistheprocessofdeterminingifabrowsersupportsagivenfeature,anditisthepreferredmethodofbrowserdetection.Itrequireslittlemaintenance,anditisusedtoexecutecodeacrossallbrowsersthatimplement(ordon’timplement)aspecificfeature.

Forexample,allmodernbrowserssupportnavigator.geolocation.Youcanuseitinyourpage,andvisitorsusingthosebrowserswillnotexperienceanyissues.However,visitorsusingInternetExplorer8wouldexperiencescripterrorsbecauseIE8doesnotsupportgeolocation.

Thisisacommonproblembecauseeventhelatestversionsofbrowsersdon’talwayssupportthesamefeatures,butyoucanavoidthesetypesofissueswithfeaturedetection.Thepatternissimple:Checkifthefeatureexists,andonlyusethefeatureifitdoes.Therefore,allyouneedisanifstatement,likethis:

if(navigator.geolocation){

//usegeolocation

}

Whoa!Waitaminute!Thiscodeusesnavigator.geolocationastheifstatement’scondition!Isn’ttheifstatementsupposedtoworkontrueorfalsevalues?Yes,butJavaScriptcantreatanyvalueastrueorfalse.Wecallthesetruthyandfalsey.Theyaren’ttruebooleanvalues,buttheyevaluatetotrueandfalsewhenusedinaconditionalstatement.

Here’showthisworks;thefollowingvaluesarefalsey:

0

""(anemptystring)

null

undefined

[](anemptyarray)

false

Justabouteverythingelseistruthy.

Inbrowsersthatdon’tsupportgeolocation,navigator.geolocationisundefinedandisthereforefalsey.

Weknowthatthiscanbeconfusing,anditcanaddsomeambiguitytoyourcode.SomanyJavaScriptdevelopersliketoavoidusingtruthy/falseystatements,andoptforaclearercomparisonbyusingthetypeofoperator,likethis:

if(typeofnavigator.geolocation!="undefined"){

//usegeolocation

}

Thetypeofoperatorreturnsastringthattellsyouthetypeofavalueorobject.Inthiscode,thetypeofoperatorisusedonnavigator.geolocation.Inbrowsersthatsupportgeolocation,thetypeis"object";inbrowsersthatdon’t,it’s"undefined".

Youcanusethetypeofoperatoronanyobjectorvalue.Refertothefollowingtableforthepossiblevaluesreturnedbytypeof:

STATEMENT RESULTtypeof1 numbertypeof"hello" stringtypeoftrue booleantypeof[](oranyarray) objecttypeof{}(oranyobject) objecttypeofundefined undefinedtypeofnull object

TRYITOUTUsingFeatureDetectionInthisexample,youmodifych8_example1.htmlandensurethatthepageworksinbrowsersthatdonotsupportgeolocation.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Example4</title>

</head>

<body>

<script>

functiongeoSuccess(position){

varcoords=position.coords;

varlatitude=coords.latitude;

varlongitude=coords.longitude;

varmessage="You'reat"+latitude+","+

longitude

alert(message);

}

functiongeoError(errorObj){

alert(errorObj.message);

}

if(typeofnavigator.geolocation!="undefined"){

navigator.geolocation.getCurrentPosition(geoSuccess,

geoError);

}else{

alert("Thispageusesgeolocation,andyour"+

"browserdoesn'tsupportit.");

}

</script>

</body>

</html>

Savethisexampleasch8_example4.html.

Thekeydifferenceinthisexampleistheif…elsestatementatthebottomoftheJavaScriptcode:

if(typeofnavigator.geolocation!="undefined"){

navigator.geolocation.getCurrentPosition(geoSuccess,geoError);

}else{

alert("Thispageusesgeolocation,andyour"+

"browserdoesn'tsupportit.");

}

Here,youusethetypeofoperatoronnavigator.geolocationtodetermineifthebrowsersupportsthatfeature.Ifitdoes,thegetCurrentPosition()methodiscalled.

Ifthebrowserdoesn’tsupportgeolocation,thecodedisplaysamessagetotheuserstatingthathisorherbrowserdoesn’tsupportthenecessaryfeature.Ifyouhadattemptedtousegeolocationwithoutensuringthatthebrowsersupportsit,thebrowserwouldthrowanerror.

Featuredetectionisextremelyuseful,anditenablesyoutoisolatebrowsersbasedonthefeaturestheydoordon’tsupport.Butbrowsermakersarenotperfect,andtheysometimesreleaseaversionofabrowserthatexhibitsuniqueandquirkybehavior.Inthesecases,youneedtoisolateanindividualbrowser,andfeaturedetectionrarelygivesyouthatfinelevelofcontrol.

BrowserSniffingFirst,letusreiteratethispoint:Mostofthetime,youwanttousefeaturedetection.Browsersniffinghasmanydrawbacks,oneofwhichisthatsomelesscommonbrowsersmayfalselyidentifythemselvesasamorecommonbrowser.Anotherproblemisthatbrowsersniffingreliesonthebrowser’suser-agentstring,whichisastringthatidentifiesthebrowser,andbrowsermakerscandrasticallychangetheuser-agentstringbetween

differentversions(youseeanexampleofthislater).Youshouldusethetechniquescontainedinthissectiononlywhenyouneedtotargetasinglebrowserforitsownquirkybehavior.

Thenavigatorobjectexposestwopropertiesthatareusefulinidentifyingabrowser:appNameanduserAgent.TheappNamepropertyreturnsthemodelofthebrowser,suchas“MicrosoftInternetExplorer”forIEor“Netscape”forFirefox,Chrome,andSafari.

TheuserAgentpropertyreturnsastringcontainingvariousbitsofinformation,suchasthebrowserversion,operatingsystem,andbrowsermodel.However,thevaluereturnedbythispropertyvariesfrombrowsertobrowser,soyouhavetobevery,verycarefulwhenusingit.Forexample,thebrowser’sversionisembeddedindifferentlocationsofthestring.

TRYITOUTCheckingforandDealingwithDifferentBrowsersInthisexample,youcreateapagethatusestheaforementionedpropertiestodiscovertheclient’sbrowserandbrowserversion.Thepagecanthentakeactionbasedontheclient’sspecifications.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Example5</title>

</head>

<body>

<script>

functiongetBrowserName(){

varlsBrowser=navigator.userAgent;

if(lsBrowser.indexOf("MSIE")>=0){

return"MSIE";

}elseif(lsBrowser.indexOf("Firefox")>=0){

return"Firefox";

}elseif(lsBrowser.indexOf("Chrome")>=0){

return"Chrome";

}elseif(lsBrowser.indexOf("Safari")>=0){

return"Safari";

}elseif(lsBrowser.indexOf("Opera")>=0){

return"Opera";

}else{

return"UNKNOWN";

}

}

functiongetBrowserVersion(){

varua=navigator.userAgent;

varbrowser=getBrowserName();

varfindIndex=ua.indexOf(browser)+browser.length+1;

varbrowserVersion=parseFloat(

ua.substring(findIndex,findIndex+3));

returnbrowserVersion;

}

varbrowserName=getBrowserName();

varbrowserVersion=getBrowserVersion();

if(browserName=="MSIE"){

if(browserVersion<9){

document.write("YourversionofIEistooold");

}else{

document.write("YourversionofIEisfully

supported");

}

}elseif(browserName=="Firefox"){

document.write("Firefoxisfullysupported");

}elseif(browserName=="Safari"){

document.write("Safariisfullysupported");

}elseif(browserName=="Chrome"){

document.write("Chromeisfullysupported");

}elseif(browserName=="Opera"){

document.write("Operaisfullysupported");

}else{

document.write("Sorrythisbrowserversionisnot

supported");

}

</script>

</body>

</html>

Savethisfileasch8_example5.html.

IfthebrowserisFirefox,IE9or10,Safari,Chrome,orOpera,amessageappearstellingusersthatthebrowserissupported.Ifit’sanearlierversionofIE,theuserseesamessagetellinghimorhertheversionofthatbrowserisnotsupported.

Ifit’snotoneofthosebrowsers(includingIE11+),theuserseesamessagesayingthebrowserisunsupported.

Atthetopofthescriptblockaretwoimportantfunctions.ThegetBrowserName()functionfindsoutthenameofthebrowserandthegetBrowserVersion()functionfindsoutthebrowserversion.

Thekeytothebrowser-checkingcodeisthevaluereturnedbythenavigator.userAgentproperty.Hereareafewexampleuser-agentstringsfromcurrentbrowsers:

1. Mozilla/5.0(WindowsNT6.3;WOW64;Trident/7.0;.NET4.0E;.NET4.0C;.NETCLR3.5.30729;.NETCLR2.0.50727;.NETCLR

3.0.30729;rv:11.0)likeGecko

2. Mozilla/5.0(compatible;MSIE10.0;WindowsNT6.3;WOW64;Trident/7.0;.NET4.0E;.NET4.0C;.NETCLR3.5.30729;.NETCLR

2.0.50727;.NETCLR3.0.30729)

3. Mozilla/5.0(WindowsNT6.3;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/34.0.1847.131Safari/537.36

4. Mozilla/5.0(WindowsNT6.3;WOW64;rv:32.0)Gecko/20100101Firefox/32.0

HereeachlineoftheuserAgentstringshasbeennumbered.Lookingcloselyateachline,it’snothardtoguesswhichbrowsereachagentstringrelatesto.Inorder:

1. MicrosoftIE11

2. MicrosoftIE10

3. Chrome34.0.1847.131

4. Firefox32

Usingthisinformation,let’sstartonthefirstfunction,getBrowserName().Firstyougetthenameofthebrowser,asfoundinnavigator.userAgent,andstoreitinthevariablelsBrowser:

functiongetBrowserName(){

varlsBrowser=navigator.userAgent;

Thestringreturnedbythispropertytendstobequitelonganddoesvary.However,bycheckingfortheexistenceofcertainkeywords,suchasMSIEorFirefox,youcanusuallydeterminethebrowsername.Startwiththefollowinglines:

if(lsBrowser.indexOf("MSIE")>=0){

return"MSIE";

}

TheselinessearchthelsBrowserstringforMSIE.IftheindexOfvalueofthissubstringis0orgreater,youknowyouhavefoundit,andsoyousetthereturnvaluetoMSIE.

Thefollowingelseifstatementdoesthesame,exceptthatitismodifiedforFirefox:

elseif(lsBrowser.indexOf("Firefox")>=0){

return"Firefox";

}

Thisprinciplecarriesonforanotherthreeifstatements,inwhichyoualsocheckforChrome,Safari,andOpera.Ifyouhaveabrowseryouwanttocheckfor,thisistheplacetoadditsifstatement.Justviewthestringitreturnsinnavigator.userAgentandlookforitsnameorsomethingthatuniquelyidentifiesit.

Ifnoneoftheifstatementsmatch,youreturnUNKNOWNasthebrowsername:

else{

return"UNKNOWN";

}

Nowturntothefinalfunction,getBrowserVersion().

ThebrowserversiondetailsoftenappearintheuserAgentstringrightafterthenameofthebrowser.Forthesereasons,yourfirsttaskinthefunctionistofindoutwhichbrowseryouaredealingwith.Youdeclareandinitializethebrowservariabletothenameofthebrowser,usingthegetBrowserName()functionyoujustwrote:

functiongetBrowserVersion(){

varua=navigator.userAgent;

varbrowser=getBrowserName();

IfthebrowserisMSIE(InternetExplorer),youneedtousetheuserAgentpropertyagain.UnderIE,theuserAgentpropertyalwayscontainsMSIEfollowedbythebrowserversion.SowhatyouneedtodoissearchforMSIE,andthengetthenumberfollowingthat.

YousetfindIndextothecharacterpositionofthebrowsernameplusthelengthofthename,plusone.Doingthisensuresyoutogetthecharacterafterthenameandjustbeforetheversionnumber.browserVersionissettothefloating-pointvalueofthatnumber,whichyouobtainusingthesubstring()method.ThisselectsthecharactersstartingatfindIndexandendingwiththeonebeforefindIndex,plusthree.Thisensuresthatyoujustselectthreecharactersfortheversionnumber:

varfindIndex=ua.indexOf(browser)+browser.length+1;

varbrowserVersion=parseFloat(ua.substring(findIndex,findIndex+

3));

IfyoulookbacktotheuserAgentstrings,youseethatIE10’sissimilartothis:

Mozilla/5.0(compatible;MSIE10.0;WindowsNT6.3;WOW64;Trident/7.0)

SofindIndexwillbesettothecharacterindexofthenumber10followingthebrowsername.browserVersionwillbesettothreecharactersfromandincludingthe10,givingtheversionnumberas10.0.

Attheendofthefunction,youreturnbrowserVersiontothecallingcode,asshownhere:

returnbrowserVersion;

}

You’veseenthesupportingfunctions,buthowdoyoumakeuseofthem?Well,inthefollowingcodeyouobtaintwobitsofinformation—browsernameandversion—andusethesetofilterwhichbrowsertheuserisrunning:

varbrowserName=getBrowserName();

varbrowserVersion=getBrowserVersion();

if(browserName=="MSIE"){

if(browserVersion<9){

document.write("YourversionofInternetExploreristooold");

}else{

document.write("YourversionofInternetExplorerisfully

supported");

}

}

ThefirstoftheifstatementsisshownintheprecedingcodeandcheckstoseeiftheuserhasIE.Iftrue,itthencheckstoseeiftheversionislowerthan9.Ifitis,theuserseesthemessagestatinghisorherbrowseristooold.Ifitis9or10,themessagetellstheuserthathisorherbrowserisfullysupported.Somethinggoeswrongwiththis

codewithIE11,andyou’llfindoutwhatthatisshortly.

YoudothisagainforFirefox,Chrome,Safari,andOpera.Theversionsofthesebrowsersaren’tcheckedinthisexample,butyoucandosoifyouwantto:

elseif(browserName=="Firefox"){

document.write("Firefoxisfullysupported");

}elseif(browserName=="Safari"){

document.write("Safariisfullysupported");

}elseif(browserName=="Chrome"){

document.write("Chromeisfullysupported");

}elseif(browserName=="Opera"){

document.write("Operaisfullysupported");

}else{

document.write("Sorrythisbrowserversionisnotsupported.");

}

Onthefinalpartoftheifstatementsistheelsestatementthatcoversallotherbrowsersandtellstheuserthebrowserisnotsupported.

IfyourunthispageinIE11,you’llseethemessage“Sorrythisbrowserversionisnotsupported.”Atfirstglance,thisappearstobeanerror,butlookatIE11’suser-agentstring:

Mozilla/5.0(WindowsNT6.3;WOW64;Trident/7.0;rv:11.0)likeGecko

ThereisnomentionofMSIEanywhere,butforthoseversedinthebrowsermaker’scodewords,weknowthatTridentisMicrosoft’srenderingengineandtheversionis11.0.Microsofthadverygoodreasonsforchangingitsuser-agentstringwithversion11,butthisjustdrivesthepointhome:Youcannotrelyonbrowsersniffingbeyondtargetingasinglebrowser.

SUMMARYYou’vecoveredalotinthischapter,butnowyouhaveallthegroundingyouneedtomoveontomoreusefulthings,suchasinteractingwiththepageandformsandhandlinguserinput.

Youturnedyourattentiontothebrowser,theenvironmentinwhichJavaScriptexists.JustasJavaScripthasnativeobjects,sodowebbrowsers.Theobjectswithinthewebbrowser,andthehierarchyinwhichtheyareorganized,aredescribedbysomethingcalledthebrowserobjectmodel(BOM).Thisisessentiallyamapofabrowser’sobjects.Usingit,youcannavigateyourwayaroundeachoftheobjectsmadeavailablebythebrowser,togetherwiththeirproperties,methods,andevents.

Thefirstofthemainobjectsyoulookedatwasthewindowobject.ThissitsattheverytopoftheBOM’shierarchy.Thewindowobjectcontainsanumberofimportantsub-objects,includingthelocationobject,thenavigatorobject,thehistoryobject,thescreenobject,andthedocumentobject.

Thelocationobjectcontainsinformationaboutthecurrentpage’slocation,suchasitsfilename,theserverhostingthepage,andtheprotocolused.Eachoftheseisapropertyofthelocationobject.Somepropertiesareread-only,butothers,suchasthehrefproperty,notonlyenableyoutofindthelocationofthepage,butcanbechangedsothatyoucannavigatethepagetoanewlocation.

Thehistoryobjectisarecordofallthepagestheuserhasvisitedsinceopeninghisorherbrowser.Sometimespagesarenotnoted(forexample,whenthelocationobject’sreplace()methodisusedfornavigation).Youcanmovethebrowserforwardandbackwardinthehistorystackanddiscoverwhatpagestheuserhasvisited.

Thenavigatorobjectrepresentsthebrowseritselfandcontainsusefuldetailsofwhattypeofbrowser,version,andoperatingsystemtheuserhas.Thesedetailsenableyoutowritepagesdealingwithvarioustypesofbrowsers,evenwheretheymaybeincompatible.

Thescreenobjectcontainsinformationaboutthedisplaycapabilitiesoftheuser’scomputer.

Thedocumentobjectisoneofthemostimportantobjects.It’sanobjectrepresentationofyourpageandcontainsalltheelements,alsorepresentedbyobjects,withinthatpage.Thedifferencesbetweenthevariousbrowsersareparticularlyprominenthere,butsimilaritiesexistbetweenthebrowsersthatenableyoutowritecross-browsercode.

Thedocumentobjectcontainsthreepropertiesthatareactuallycollections.Thesearethelinks,images,andformscollections.Eachcontainsalltheobjectscreatedbythe<a/>,<img/>,and<form/>elementsonthepage,andit’sawayofaccessingthoseelements.

Theimagescollectioncontainsanimgobjectforeach<img/>elementonthepage.

Youfoundthatevenafterthepagehasloaded,youcanchangethepropertiesofimages.Forexample,youcanmaketheimagechangewhenclicked.Thesameprinciplesforusingtheimagescollectionapplytothelinkscollection.

Finally,youlookedathowyoucancheckwhattypeofbrowsertheuserhas,therebygivingyouthepowertousenewfeatureswithoutcausingerrorsinolderbrowsers.Youalsolearnedhowtosniffthebrowserwiththenavigatorobject’sappNameanduserAgentproperties,andhowunreliablethatinformationcanbe.

That’sitforthischapter.Inthenextchapter,youmoveontothemoreexcitingdocumentobjectmodel,whereyoucanaccessandmanipulatetheelementsinyourpage.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. Createtwopages,onecalledlegacy.htmlandtheothercalledmodern.html.Eachpageshouldhaveaheadingtellingyouwhatpageisloaded.Forexample:

<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>

Usingfeaturedetectionandthelocationobject,sendbrowsersthatdonotsupportgeolocationtolegacy.html;sendbrowsersthatdosupportgeolocationtomodern.html.

2. ModifyExample3fromthe“ImageSelection”TryItOuttodisplayoneofthefourimagesrandomly.Hint:refertoChapter5andtheMath.random()method.

9DOMScriptingWHATYOUWILLLEARNINTHISCHAPTER:

Findingelementsinthepage

Creatingandinsertingelementsintothepagedynamically

Navigatingthewebpage,travellingfromoneelementtoanother

Changingelements’styleaftertheyareloadedinthepage

Animatingelementsbymanipulatingtheirpositioning

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

JavaScript’sprimaryroleinwebdevelopmentistointeractwiththeuser,toaddsomekindofbehaviortoyourwebpage.JavaScriptenablesyoutocompletelychangeallaspectsofawebpageafterit’sloadedinthebrowser.WhatgivesJavaScriptthispoweroverawebpageisthedocumentobjectmodel(DOM),atree-likerepresentationofthewebpage.

TheDOMisoneofthemostmisunderstoodstandardssetforthbytheWorldWideWebConsortium(W3C),abodyofdeveloperswhorecommendstandardsforbrowsermakersandwebdeveloperstofollow.TheDOMgivesdevelopersawayofrepresentingeverythingonawebpagesothatitisaccessibleviaacommonsetofpropertiesandmethodsinJavaScript.Byeverything,wemeaneverything.Youcanliterallychangeanythingonthepage:thegraphics,tables,forms,style,andeventextitselfbyalteringarelevantDOMpropertywithJavaScript.

TheDOMshouldnotbeconfusedwiththebrowserobjectmodel(BOM)thatwasintroducedinChapter8.You’llseethedifferencesbetweenthetwoindetailshortly.Fornow,though,thinkoftheBOMasabrowser-dependentrepresentationofeveryfeatureofthebrowser,fromthebrowserbuttons,URLaddressline,andtitlebartothebrowserwindowcontrols,aswellaspartsofthewebpage,too.TheDOM,however,dealsonlywiththecontentsofthebrowserwindoworwebpage(inotherwords,theHTMLdocument).Itmakesthedocumentavailableinsuchawaythatanybrowsercanuseexactlythesamecodetoaccessandmanipulatethecontentofthedocument.Tosummarize,theBOMgivesyouaccesstothebrowserandsomeofthedocument,whereastheDOMgivesyouaccesstoallofthedocument,butonlythedocument.

ThegreatthingabouttheDOMisthatitisbrowser-andplatform-independent.ThismeansthatdeveloperscanwriteJavaScriptcodethatdynamicallyupdatesthepage,andthatwillworkonanyDOM-compliantbrowserwithoutanytweaking.Youshouldnotneedtocodefordifferentbrowsersortakeexcessivecarewhencoding.

TheDOMachievesthisindependencebyrepresentingthecontentsofthepageasagenerictreestructure.WhereasintheBOMyoumightexpecttoaccesssomethingbylookingupapropertyrelevanttothatpartofthebrowserandadjustingit,theDOMrequiresnavigationthroughitsrepresentationofthepagethroughnodesandpropertiesthatarenotspecifictothebrowser.Youexplorethisstructurealittlelater.

However,tousetheDOMstandard,ultimatelydevelopersrequirebrowsersthatcompletelyimplementthestandard,somethingthatnobrowserdoes100percentefficiently,unfortunately.Tomakemattersworse,noonebrowserimplementstheexactsameDOMfeaturesthatotherbrowserssupport,butdon’tbescaredoffyet.AllmodernbrowserssupportmanyofthesamefeaturesoutlinedbytheDOMstandard.

ToprovideatrueperspectiveonhowtheDOMfitsin,weneedtotakeabrieflookatitsrelationshipwithsomeoftheothercurrentlyexistingwebstandards.WeshouldalsotalkaboutwhythereismorethanoneversionoftheDOMstandard,aswellasdifferentsectionswithinthestandarditself.Afterunderstandingtherelationships,youcanlookatusingJavaScripttonavigatetheDOMandtodynamicallychangeawebpage’scontentinmorethanonebrowser.Thefollowingitemsareonyouragenda:

TheHTMLandECMAScriptstandards

TheDOMstandards

ManipulatingtheDOM

Writingcross-browserJavaScript

NOTERememberthattheexampleswithinthischapteraretargetedonlyattheDOM(withveryfewexceptions)andwillbesupportedbymodernbrowsers(IE9+,Chrome,Firefox,Opera,andSafari).Legacybrowsers(IE8andbelow,earlierversionsofChrome,andsimilarearlybrowsers)mayormaynotsupportthem.

THEWEBSTANDARDSWhenTimBerners-LeecreatedHTMLin1991,heprobablyhadlittleideathatthistechnologyformarkingupscientificpapersviaasetoftagsforhisownglobalhypertextproject,knownastheWorldWideWeb,would,withinamatterofyears,becomeabattlegroundbetweenthetwogiantsofthesoftwarebusinessofthemid-1990s.HTMLwasasimplederivationfromthemeta-languageStandardGeneralizedMarkupLanguage(SGML)thathadbeenkickingaroundacademicinstitutionsfordecades.Itspurposewastopreservethestructureofthedocumentscreatedwithit.HTMLdependsonaprotocol,HyperTextTransferProtocol(HTTP),totransmitdocumentsbackandforthbetweentheresourceandtheviewer(forexample,theserverandtheclientcomputer).Thesetwotechnologiesformedthefoundationoftheweb,anditquicklybecameobviousintheearly1990sthatthereneededtobesomesortofpolicingofbothspecificationstoensureacommonimplementationofHTMLandHTTPsothatcommunicationscouldbeconductedworldwide.

In1994,TimfoundedtheWorldWideWebConsortium(W3C),abodythatsetouttooverseethetechnicalevolutionoftheweb.Ithasthreemainaims:

Toprovideuniversalaccess,sothatanybodycanusetheweb

Todevelopasoftwareenvironmenttoallowuserstomakeuseoftheweb

Toguidethedevelopmentoftheweb,takingintoconsiderationthelegal,social,andcommercialissuesthatarise

EachnewversionofaspecificationofawebtechnologyhastobecarefullyvettedbyW3Cbeforeitcanbecomeastandard.TheHTMLandHTTPspecificationsaresubjecttothisprocess,andeachnewsetofupdatestothesespecificationsyieldsanewversionofthestandard.Eachstandardhastogothroughaworkingdraft,acandidaterecommendation,andaproposedrecommendationstagebeforeitcanbeconsideredafullyoperationalstandard.Ateachstageoftheprocess,membersoftheW3Cconsortiumvoteonwhichamendmentstomake,orevenonwhethertocancelthestandardcompletelyandsenditbacktosquareone.

Itsoundslikeaverypainfulandlaboriousmethodofcreatingastandardformat,andnotsomethingyou’dthinkofasspearheadingthecuttingedgeoftechnicalrevolution.Indeed,thesoftwarecompaniesofthemid-1990sfoundtheprocessesinvolvedtooslow,sotheysetthetonebyimplementingnewinnovationsthemselvesandthensubmittingthemtothestandardsbodyforapproval.Netscapestartedbyintroducingnewelementsinitsbrowser,suchasthe<font/>element,toaddpresentationalcontenttothewebpages.Thisprovedpopular,soNetscapeaddedawholeraftofelementsthatenableduserstoalteraspectsofpresentationandstyleonwebpages.Indeed,JavaScriptitselfwassuchaninnovationfromNetscape.

WhenMicrosoftenteredthefray,itwasplayingcatchupforthefirsttwoiterationsofitsInternetExplorerbrowser.However,withInternetExplorer3in1996,MicrosoftestablishedaroughlyequalsetoffeaturestocompetewithNetscapeandsowasabletoadditsownbrowser-specificelements.Veryquickly,thewebpolarizedbetweenthesetwo

browsers,andpagesviewableononebrowserquiteoftenwouldn’tworkonanother.OneproblemwasthatMicrosofthaduseditsmuchstrongerpositioninthemarkettogiveawayitsbrowserforfree,whereasNetscapestillneededtosellitsownbrowserbecauseitcouldn’taffordtofreelydistributeitsflagshipproduct.Tomaintainacompetitiveposition,NetscapeneededtooffernewfeaturestomaketheuserwanttopurchaseitsbrowserratherthanusethefreeMicrosoftbrowser.

Thingscametoaheadwithbothcompanies’version4browsers,whichintroduceddynamicpagefunctionality.Unfortunately,Netscapedidthisbythemeansofa<layer/>element,whereasMicrosoftchosetoimplementitviascriptinglanguagepropertiesandmethods.TheW3Cneededtotakeafirmstandhere,becauseoneofitsthreeprincipalaimshadbeencompromised:thatofuniversalaccess.Howcouldaccessbeuniversalifusersneededaspecificvendor’sbrowsertoviewaparticularsetofpages?TheydecidedonasolutionthatusedexistingstandardHTMLelementsandcascadingstylesheets,bothofwhichhadbeenadoptedaspartoftheMicrosoftsolution.Asaresult,Microsoftgainedadominantpositioninthebrowserwar,anditheldthatpositionformanyyears.Today,Microsoft’sInternetExplorerisstillthedominantbrowser,butithaslostalotofitsmarketsharetoChromeandFirefox.

WitharelativelystableversionoftheHTMLstandardinplacewithversion4.01,whichboastsasetoffeaturesthatwilltakeanybrowsermanufactureralongtimetoimplementcompletely,attentionwasturnedtootherareasoftheweb.Anewsetofstandardswasintroducedinthelate1990stogovernthemeansofpresentingHTML(stylesheets)andtherepresentationoftheHTMLdocumentinscript(theDOM).Otherstandardsemerged,suchasExtensibleMarkupLanguage(XML),whichoffersacommonformatforrepresentingdatainawaythatpreservesitsstructure.

TheW3Cwebsite(www.w3.org)hasahugenumberofstandardsinvaryingstagesofcreation.Notallofthesestandardsconcernus,andnotalloftheonesthatconcernuscanbefoundatthiswebsite.However,thevastmajorityofstandardsthatdoconcernuscanbefoundthere.

You’regoingtotakeabrieflooknowatthetechnologiesandstandardsthathaveanimpactonJavaScriptandfindoutalittlebackgroundinformationabouteach.Someofthetechnologiesmaybeunfamiliar,butyouneedtobeawareoftheirexistenceattheveryleast.

HTMLTheHTMLstandardismaintainedbyW3C.Thisstandardmightseemfairlystraightforward,giventhateachversionshouldhaveintroducedjustafewnewelements,butinrealitythelifeofthestandardsbodywasvastlycomplicatedbythebrowserwars.The1.0and2.0versionsofHTMLweresimple,smalldocuments,butwhentheW3CcametodebateHTMLversion3.0,theyfoundthatmuchofthenewfunctionalityitwasdiscussinghadalreadybeensupersededbynewadditions(suchasthe<applet/>and<style/>elements)totheversion3.0browser’sappletstyle.Version3.0wasdiscarded,andanewversion,3.2,becamethestandard.

However,alotofthefeaturesthatwentintoHTML3.2hadbeenintroducedatthebehest

ofthebrowsermanufacturersandrancontrarytothespiritofHTML,whichwasintendedsolelytodefinestructure.Thenewfeatures,stemmingfromthe<font/>element,justconfusedtheissueandaddedunnecessarypresentationalfeaturestoHTML.Thesefeaturesreallybecameredundantwiththeintroductionofstylesheets.Sosuddenly,intheversion3browsers,therewerethreedistinctwaystodefinethestyleofanitemoftext.Whichwasthecorrectway?Andifallthreewayswereused,whichstyledidthetextultimatelyassume?Version4.0oftheHTMLstandardwasleftwiththejobofunmuddlingthischaoticmessanddesignatedalotofelementsfordeprecation(removal)inthenextversionofthestandards.ItwasthelargestversionofthestandardsofarandincludedfeaturesthatlinkedittostylesheetsandtheDOM,andalsoaddedfacilitiesforthevisuallyimpairedandotherunfairlyneglectedminorityinterestareas.

In2004,theW3CwasfocusingonXHTML2.0,aspecificationthatmany,andperhapsmost,inthewebdevelopmentcommunitythoughttobethewrongdirectionfortheweb.Soanotherbody,theWebHypertextApplicationTechnologyWorkingGroup(WHATWG)startedworkingonHTML5.In2009,theW3CofficiallydroppedXHTML2.0,andtodaytheW3CandtheWHATWGworktogetherondevelopingHTML5.

HTML5introducesmanynewfeatures.Firstarenewelementsthatidentifyapage’snavigation,header,andfooterwiththe<nav/>,<header/>,and<footer/>elements.Italsoadds<audio/>and<video/>elementstoreplace<object/>.HTML5alsoremoveselementslike<font/>and<center/>,elementsthatarepurelyusedforpresentationpurposes.HTML5alsodefinesnativesupportfordraganddrop,geolocation,storage,andmuchmore.

NoteTheHTML5specificationisnotcompletelyfinalized,butmanyofitsindividualfeaturesaresaidtobecomplete.Asaresult,you’llfindmanyfeaturesimplementedintoday’smodernbrowsers.YoucanvisittheW3Cwebsiteathttp://www.w3.org/TR/html5/ortheWHATWGlivingstandardathttp://html.spec.whatwg.org/multipage/ifyouwanttoreadtheactualspecifications.

ECMAScriptJavaScriptitselffollowedatrajectorysimilartothatofHTML.ItwasfirstusedinNetscapeNavigatorandthenaddedtoInternetExplorer.TheInternetExplorerversionofJavaScriptwaschristenedJScriptandwasn’tfarremovedfromtheversionofJavaScriptfoundinNetscapeNavigator.However,onceagain,thereweredifferencesbetweenthetwoimplementationsandalotofcarehadtobetakeninwritingscriptforbothbrowsers.

Oddlyenough,itwaslefttotheEuropeanComputerManufacturersAssociation(ECMA)toproposeastandardspecificationforJavaScript.Thisdidn’tappearuntilafewversionsofJavaScripthadalreadybeenreleased.UnlikeHTML,whichhadbeendevelopedfromthestartwiththeW3Cconsortium,JavaScriptwasaproprietarycreation.Thisisthereasonthatitisgovernedbyadifferentstandardsbody.MicrosoftandNetscapebothagreedtouseECMAasthestandardsvehicle/debatingforum,becauseofitsreputationforfast-trackingstandardsandperhapsalsobecauseofitsperceivedneutrality.Thename

ECMAScriptwaschosensoasnottobebiasedtowardeithervendor’screationandalsobecausethe“Java”partofJavaScriptwasatrademarkofSunlicensedtoNetscape.Thestandard,namedECMA-262,laiddownaspecificationthatwasroughlyequivalenttotheJavaScript1.1specification.

Thatsaid,theECMAScriptstandardcoversonlycoreJavaScriptfeatures,suchastheprimitivedatatypesofnumbers,strings,andbooleans,nativeobjectsliketheDate,Array,andMathobjects,andtheproceduralstatementslikeforandwhileloops,andifandelseconditionals.Itmakesnoreferencetoclient-sideobjectsorcollections,suchaswindow,document,forms,links,andimages.So,althoughthestandardhelpstomakecoreprogrammingtaskscompatiblewhenbothJavaScriptandJScriptcomplywithit,itisofnouseinmakingthescriptingofclient-sideobjectscompatiblebetweenthemainbrowsers.Someincompatibilitiesremain.

AllcurrentimplementationsofJavaScriptareexpectedtoconformtothecurrentECMAScriptstandard,whichisECMAScriptedition5,publishedinDecember2009.

AlthoughthereusedtobequiteafewirregularitiesbetweenthedifferentdialectsofJavaScript,they’renowsimilarenoughtobeconsideredthesamelanguage.Thisisagoodexampleofhowstandardshaveprovidedauniformlanguageacrossbrowserimplementations,althoughadebatethatissimilartotheonethattookplaceoverHTMLstillragestoalesserdegreeoverJavaScript.

It’snowtimeforyoutoconsiderthedocumentobjectmodelitself.

THEDOCUMENTOBJECTMODELThedocumentobjectmodel(DOM)is,aspreviouslymentioned,awayofrepresentingthedocumentindependentofbrowsertype.Itallowsadevelopertoaccessthedocumentviaacommonsetofobjects,properties,methods,andevents,andtoalterthecontentsofthewebpagedynamicallyusingscripts.

YoushouldbeawarethatsomesmallvariationsareusuallyaddedtotheDOMbythebrowservendor.So,toguaranteethatyoudon’tfallafoulofaparticularimplementation,theW3Chasprovidedagenericsetofobjects,properties,andmethodsthatshouldbeavailableinallbrowsers,intheformoftheDOMstandard.

TheDOMStandardWehaven’ttalkedabouttheDOMstandardsofar,andforaparticularreason:It’snottheeasieststandardtofollow.Supportingagenericsetofpropertiesandmethodshasprovedtobeaverycomplextask,andtheDOMstandardhasbeenbrokendownintoseparatelevelsandsectionstodealwiththedifferentareas.Thedifferentlevelsofthestandardareallatdifferingstagesofcompletion.

Level0Level0isabitofamisnomer,becausetherewasn’treallyalevel0ofthestandard.Thisterminfactreferstothe“oldway”ofdoingthings—themethodsimplementedbythebrowservendorsbeforetheDOMstandard.Someonementioninglevel0propertiesisreferringtoamorelinearnotationofaccessingpropertiesandmethods.Forexample,typicallyyou’dreferenceitemsonaformwiththefollowingcode:

document.forms[0].elements[1].value="button1";

We’renotgoingtocoversuchpropertiesandmethodsinthischapter,becausetheyhavebeensupersededbynewermethods.

Level1Level1isthefirstversionofthestandard.Itissplitintotwosections:Oneisdefinedascore(objects,properties,andmethodsthatcanapplytobothXMLandHTML)andtheotherasHTML(HTML-specificobjects,properties,andmethods).Thefirstsectiondealswithhowtogoaboutnavigatingandmanipulatingthestructureofthedocument.Theobjects,properties,andmethodsinthissectionareveryabstract.ThesecondsectiondealswithHTMLonlyandoffersasetofobjectscorrespondingtoalltheHTMLelements.Thischaptermainlydealswiththesecondsection—level1ofthestandard.

In2000,level1wasrevampedandcorrected,thoughitonlymadeittoaworkingdraftandnottoafullW3Crecommendation.

Level2Level2iscompleteandmanyoftheproperties,methods,andeventshavebeen

implementedbytoday’sbrowsers.IthassectionsthataddspecificationsforeventsandstylesheetstothespecificationsforcoreandHTML-specificpropertiesandevents.(Italsoprovidessectionsonviewsandtraversalranges,neitherofwhichiscoveredinthisbook;youcanfindmoreinformationatwww.w3.org/TR/2000/PR-DOM-Level-2-Views-20000927/andwww.w3.org/TR/2000/PR-DOM-Level-2-Traversal-Range-20000927/.)

Level3Level3achievedrecommendationstatusin2004.Itisintendedtoresolvealotofthecomplicationsthatstillexistintheeventmodelinlevel2ofthestandard,andaddssupportforXMLfeatures,suchascontentmodelsandbeingabletosavetheDOMasanXMLdocument.

Level4InMay2014,DOMlevel4reachedcandidaterecommendationstatus.ItconsolidatesDOMlevel3withseveralindependentcomponents.Atthetimeofthiswriting,nomodernbrowsersupportsDOMlevel4,althoughthatwillchangeinthefuture.

BrowserCompliancewiththeStandardsAlmostnobrowserhas100percentcompliancewithanystandard.Therefore,thereisnoguaranteethatalltheobjects,properties,andmethodsoftheDOMstandardwillbeavailableinagivenversionofabrowser.However,allmodernbrowsersdoaverygoodjobofsupportingthestandardDOM.TheonlybrowsersyoutrulyhavetowatchoutforareIE8andbelow.

MuchofthematerialintheDOMstandardhasonlyrecentlybeenclarified,andalotofDOMfeaturesandsupporthavebeenaddedtoonlythelatestbrowserversions.Forthisreason,examplesinthischapterwillbeguaranteedtoworkononlythelatestversionsofIE,Chrome,Firefox,Opera,andSafari.Althoughcross-browserscriptingisarealisticgoal,backward-compatiblesupportisn’tatall.

Althoughthestandardsmightstillnotbefullyimplemented,theydogiveyouanideaastohowaparticularpropertyormethodshouldbeimplemented,andprovideaguidelineforallbrowsermanufacturerstoagreetoworktowardinlaterversionsoftheirbrowsers.TheDOMdoesn’tintroduceanynewHTMLelementsorstylesheetpropertiestoachieveitsends.TheideaoftheDOMistomakeuseoftheexistingtechnologies,andquiteoftentheexistingpropertiesandmethodsofoneorotherofthebrowsers.

DifferencesbetweentheDOMandtheBOMAsmentionedearlier,twomaindifferencesexistbetweenthedocumentobjectmodelandthebrowserobjectmodel.However,complicatingtheissueisthefactthataBOMissometimesreferredtounderthenameDOM.Lookoutforthisinanyliteratureonthesubject.

First,theDOMcoversonlythedocumentofthewebpage,whereastheBOMoffersscriptingaccesstoallareasofthebrowsers,fromthebuttonstothetitlebar,includingsomepartsofthepage.

Second,theBOMisuniquetoaparticularbrowser.Thismakessenseifyouthinkaboutit:youcan’texpecttostandardizebrowsers,becausetheyhavetooffercompetitivefeatures.Therefore,youneedadifferentsetofpropertiesandmethodsandevenobjectstobeabletomanipulatethemwithJavaScript.

RepresentingtheHTMLDocumentasaTreeStructureBecauseHTMLisstandardizedsothatwebpagescancontainonlythestandardfeaturessupportedinthelanguage,suchasforms,tables,images,andthelike,acommonmethodofaccessingthesefeaturesisneeded.ThisiswheretheDOMcomesin.ItprovidesauniformrepresentationoftheHTMLdocument,anditdoesthisbyrepresentingtheentireHTMLdocument/webpageasatreestructure.

Infact,itispossibletorepresentanyHTMLasatreestructure,andforbestresults,theHTMLdocumentshouldbewellformed.Browserstolerate,toagreaterorlesserextent,quirkssuchasunclosedtags,orHTMLformcontrolsnotbeingenclosedwithina<form/>element;however,forthestructureoftheHTMLdocumenttobeaccuratelydepicted,youneedtobeabletoalwayspredictthestructureofthedocument.TheabilitytoaccesselementsviatheDOMdependsontheabilitytorepresentthepageasahierarchy.

WhatIsaTreeStructure?Ifyou’renotfamiliarwiththeconceptoftrees,don’tworry.They’rejustadiagrammaticmeansofrepresentingahierarchicalstructure.

Let’sconsidertheexampleofabookwithseveralchapters.Ifinstructedto,youcouldfindthethirdlineonpage543afteralittlesearching.Ifanupdatededitionofthebookwereprintedwithextrachapters,morelikelythannotyou’dfailtofindthesametextifyoufollowedthosesameinstructions.However,iftheinstructionswerechangedto,say,“Findthechapteronstill-lifepainting,thesectiononusingwatercolors,andtheparagraphonpositioninglightsources,”you’dbeabletofindthateveninareprintededitionwithextrapagesandchapters,albeitwithperhapsalittlemoreeffortthanthefirstrequestrequired.

Booksaren’tparticularlydynamicexamples,butgivensomethinglikeawebpage,wheretheinformationcouldbechangeddaily,orevenhourly,canyouseewhyitwouldbeofmoreusetogivethesecondsetofdirectionsthanthefirst?ThesameprincipleapplieswiththeDOM.NavigatingtheDOMinahierarchicalfashion,ratherthaninastrictlylinearway,makesmuchmoresense.WhenyoutreattheDOMasatree,itbecomeseasytonavigatethepageinthisfashion.Considerhowyoulocatefilesonyourcomputer.Thefile/foldermanager(WindowsExplorerinWindows,FinderinMacOS,andsoon)createsatreeviewoffoldersthroughwhichyoucandrilldown.Insteadoflookingforafilealphabetically,youlocateitbygoingintoaparticularfolder.

Therulesforcreatingtreesaresimple.Youstartatthetopofthetreewiththedocumentandtheelementthatcontainsallotherelementsinthepage.Thedocumentistherootnode.Anodeisjustapointonthetreerepresentingaparticularelementorattributeofanelement,oreventhetextthatanelementcontains.Therootnodecontainsallothernodes,suchastheDTDdeclarationandtherootelement(theHTMLorXMLelementthatcontainsallotherelements).Therootelementshouldalwaysbethe<html/>elementinan

HTMLdocument.UnderneaththerootelementaretheHTMLelementsthattherootelementcontains.Typically,anHTMLpagewillhave<head/>and<body/>elementsinsidethe<html/>element.Theseelementsarerepresentedasnodesunderneaththerootelement’snode,whichitselfisunderneaththerootnodeatthetopofthetree(seeFigure9.1).

Figure9.1

Thetwonodesrepresentingthe<head/>and<body/>elementsareexamplesofchildnodes,andthe<html/>element’snodeabovethemisaparentnode.Becausethe<head/>and<body/>elementsarebothchildnodesofthe<html/>element,theybothgoonthesamelevelunderneaththeparentnode<html/>element.The<head/>and<body/>elementsinturncontainotherchildnodes/HTMLelements,whichwillappearatalevelunderneaththeirnodes.Sochildnodescanalsobeparentnodes.EachtimeyouencounterasetofHTMLelementswithinanotherelement,theyeachformaseparatenodeatthesamelevelonthetree.Theeasiestwayofexplainingthisclearlyiswithanexample.

AnExampleHTMLPageLet’sconsiderabasicHTMLpagesuchasthis:

<!DOCTYPEhtml>

<htmllang="en">

<head>

</head>

<body>

<h1>MyHeading</h1>

<p>Thisissometextinaparagraph.</p>

</body>

</html>

The<html/>elementcontains<head/>and<body/>elements.The<body/>elementcontainsan<h1/>elementanda<p/>element.The<h1/>elementcontainsthetextMyHeading.Whenyoureachanitem,suchastext,animage,oranelement,thatcontainsnoothers,thetreestructurewillterminateatthatnode.Suchanodeistermedaleafnode.Youthencontinuetothe<p/>node,whichcontainssometext,whichisalsoanodeinthedocument.YoucandepictthiswiththetreestructureshowninFigure9.2.

Figure9.2

Simple,eh?Thisexampleisalmosttoostraightforward,solet’smoveontoaslightlymorecomplexonethatinvolvesatableaswell:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Thisisatestpage</title>

</head>

<body>

<span>Belowisatable</span>

<table>

<tr>

<td>Row1Cell1</td>

<td>Row1Cell2</td>

</tr>

</table>

</body>

</html>

Thereisnothingoutoftheordinaryhere;thedocumentcontainsatablewithtworowswithtwocellsineachrow.Youcanonceagainrepresentthehierarchicalstructureofyourpage(forexample,thefactthatthe<html/>elementcontainsa<head/>anda<body/>element,andthatthe<head/>elementcontainsa<title/>element,andsoon)usingyourtreestructure,asshowninFigure9.3.

Figure9.3

Thetoplevelofthetreeissimpleenough;the<html/>elementcontains<head/>and<body/>elements.The<head/>elementinturncontainsa<title/>elementandthe<title/>elementcontainssometext.Thistextnodeisachildnodethatterminatesthebranch(aleafnode).Youcanthengobacktothenextnode,the<body/>elementnode,andgodownthatbranch.Hereyouhavetwoelementscontainedwithinthe<body/>element:the<span/>and<table/>elements.Althoughthe<span/>elementcontainsonlytextandterminatesthere,the<table/>elementcontainsonerow(<tr/>),anditcontainstwotablecell(<td/>)elements.Onlythendoyougettothebottomofthetreewiththetextcontainedineachtablecell.YourtreeisnowacompleterepresentationofyourHTMLcode.

TheCoreDOMObjectsWhatyouhaveseensofarhasbeenhighlytheoretical,solet’sgetalittlemorepracticalnow.

TheDOMprovidesyouwithaconcretesetofobjects,properties,andmethodsthatyoucanaccessthroughJavaScripttonavigatethetreestructureoftheDOM.Let’sstartwiththesetofobjects,withintheDOM,thatisusedtorepresentthenodes(elements,attributes,ortext)onyourtree.

BaseDOMObjectsThreeobjects,showninthefollowingtable,areknownasthebaseDOMobjects.

OBJECT DESCRIPTIONNode EachnodeinthedocumenthasitsownNodeobject.NodeList ThisisalistofNodeobjects.NamedNodeMap ThisprovidesaccessbynameratherthanbyindextoalltheNodeobjects.

ThisiswheretheDOMdiffersfromtheBOMquiteextensively.TheBOMobjectshavenamesthatrelatetoaspecificpartofthebrowser,suchasthewindowobject,ortheformsandimagescollections.Asmentionedearlier,tobeabletonavigateinthewebpageasthoughitwereatree,youhavetodoitabstractly.Youcanhavenopriorknowledgeofthestructureofthepage;everythingultimatelyisjustanode.TomovearoundfromHTMLelementtoHTMLelement,orelementtoattribute,youhavetogofromnodetonode.Thisalsomeansyoucanadd,replace,orremovepartsofyourwebpagewithoutaffectingthestructureasawhole,becauseyou’rejustchangingnodes.Thisiswhyyouhavethreeratherobscure-soundingobjectsthatrepresentyourtreestructure.

I’vealreadymentionedthatthetopofyourtreestructureistherootnode,andthattherootnodecontainstheDTDandrootelement.Therefore,youneedmorethanjustthesethreeobjectstorepresentyourdocument.Infact,therearedifferentobjectstorepresentthedifferenttypesofnodesonthetree.

High-LevelDOMObjectsBecauseeverythingintheDOMisanode,it’snowonderthatnodescomeinavarietyoftypes.Isthenodeanelement,anattribute,orjustplaintext?TheNodeobjecthasdifferentobjectstorepresenteachpossibletypeofnode.ThefollowingisacompletelistofallthedifferentnodetypeobjectsthatcanbeaccessedviatheDOM.Alotofthemwon’tconcernyouinthisbook,becausethey’rebettersuitedforXMLdocumentsandnotHTMLdocuments,butyoushouldnoticethatyourthreemaintypesofnodes,namelyelement,attribute,andtext,areallcovered.

OBJECT DESCRIPTIONDocument TherootnodeofthedocumentDocumentType TheDTDorschematypeoftheXMLdocumentDocumentFragment AtemporarystoragespaceforpartsofthedocumentEntityReference AreferencetoanentityintheXMLdocumentElement AnelementinthedocumentAttr AnattributeofanelementinthedocumentProcessingInstruction AprocessinginstructionComment AcommentinanXMLdocumentorHTMLdocumentText TextthatmustformachildnodeofanelementCDATASection ACDATAsectionwithintheXMLdocumentEntity AnunparsedentityintheDTDNotation AnotationdeclaredwithinaDTD

Wewon’tgoovermostoftheseobjectsinthischapter.

EachoftheseobjectsinheritsallthepropertiesandmethodsoftheNodeobject,butalsohassomepropertiesandmethodsofitsown.Youlookatsomeexamplesinthenextsection.

DOMObjectsandTheirPropertiesandMethodsIfyoutriedtolookatthepropertiesandmethodsofalltheobjectsintheDOM,itwouldtakeuphalfthebook.Insteadyou’regoingtoactivelyconsideronlythreeoftheobjects,namelytheNodeobject,theElementobject,andtheDocumentobject.Thisisallyou’llneedtobeabletocreate,amend,andnavigateyourtreestructure.Also,you’renotgoingtospendagestrawlingthrougheachofthepropertiesandmethodsoftheseobjects,butratherlookonlyatsomeofthemostusefulpropertiesandmethodsandusethemtoachievespecificends.

NOTEAppendixCcontainsarelativelycompletereferencetotheDOM,itsobjects,andtheirproperties.

TheDocumentObjectanditsMethodsTheDocumentreferencetypeexposesvariouspropertiesandmethodsthatareveryhelpfultosomeonescriptingtheDOM.Itsmethodsenableyoutofindindividualorgroupsofelementsandcreatenewelements,attributes,andtextnodes.AnyDOMscriptershouldknowthesemethodsandproperties,becausethey’reusedquitefrequently.

TheDocumentobject’smethodsareprobablythemostimportantmethodsyou’lllearn.Althoughmanytoolsareatyourdisposal,theDocumentobject’smethodsletyoufind,create,anddeleteelementsinyourpage.

FindingElementsoranElementLet’ssayyouhaveanHTMLwebpage—howdoyougoaboutgettingbackaparticularelementonthepageinscript?TheDocumentreferencetypeexposesthefollowingmethodstoperformthistask.

METHODSOFTHEDOCUMENTOBJECT

DESCRIPTION

getElementById(idValue) Returnsareference(anode)ofanelement,whensuppliedwiththevalueoftheidattributeofthatelement

getElementsByTagName(tagName) Returnsareference(anodelist)toasetofelementsthathavethesametagastheonesuppliedintheargument

querySelector(cssSelector) Returnsareference(anode)ofthefirstelementthatmatchesthegivenCSSselector

querySelectorAll(cssSelector) Returnsareference(anodelist)toasetofelementsthatmatchthegivenCSSselector

Thefirstofthesemethods,getElementById(),requiresyoutoensurethateveryelementyouwanttoquicklyaccessinthepageusesanidattribute,otherwiseanullvalue(awordindicatingamissingorunknownvalue)willbereturnedbyyourmethod.Let’sgobacktothefirstexampleandaddsomeidattributestotheelements.

<!DOCTYPEhtml>

<htmllang="en">

<head>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph.</p>

</body>

</html>

NowyoucanusethegetElementById()methodtoreturnareferencetoanyoftheHTMLelementswithidattributesonyourpage.Forexample,ifyouaddthefollowingcodeinthehighlightedsection,youcanfindandreferencethe<h1/>element:

<!DOCTYPEhtml>

<htmllang="en">

<head>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph.</p>

<script>

alert(document.getElementById("heading1"));

</script>

</body>

</html>

Figure9.4showstheresultofthiscodeinFirefox.

Figure9.4

NOTEHTMLHeadingElementisanobjectoftheHTMLDOM.AllHTMLelementshaveacorrespondingreferencetypeintheDOM.SeeAppendixCformoreobjectsoftheHTMLDOM.

Youmighthavebeenexpectingittoreturnsomethingalongthelinesof<h1/>or<h1id="heading1">,butallit’sactuallyreturningisareferencetothe<h1/>element.Thisreferencetothe<h1/>elementismoreusefulthough,becauseyoucanuseittoalterattributesoftheelement,suchasbychangingthecolororsize.Youcandothisviathestyleobject:

<!DOCTYPEhtml>

<htmllang="en">

<head>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph.</p>

<script>

varh1Element=document.getElementById("heading1");

h1Element.style.color="red";

</script>

</body>

</html>

Ifyoudisplaythisinthebrowser,youseethatyoucandirectlyinfluencetheattributesofthe<h1/>elementinscript,asyouhavedoneherebychangingitstextcolortored.

NOTEThestyleobjectpointstothestyleattributeofanelement;itenablesyoutochangetheCSSstyleassignedtoanelement.Thestyleobjectiscoveredlaterinthechapter.

Thesecondmethod,getElementsByTagName(),worksinthesameway,but,asitsnameimplies,itcanreturnmorethanoneelement.IfyouweretogobacktotheexampleHTMLdocumentwiththetableandusethismethodtoreturnthetablecells(<td/>)inyourcode,youwouldgetanodelistcontainingatotaloffourtables.You’dstillhaveonlyoneobjectreturned,butthisobjectwouldbeacollectionofelements.Rememberthatcollectionsarearray-likestructures,sospecifytheindexnumberforthespecificelementyouwantfromthecollection.Youcanusethesquarebracketsifyouwant;anotheralternativeistousetheitem()methodoftheNodeListobject,likethis:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Thisisatestpage</title>

</head>

<body>

<span>Belowisatable</span>

<table>

<tr>

<td>Row1Cell1</td>

<td>Row1Cell2</td>

</tr>

</table>

<script>

vartdElement=document.getElementsByTagName("td").item(0);

tdElement.style.color="red";

</script>

</body>

</html>

Ifyouranthisexample,onceagainusingthestyleobject,itwouldalterthestyleofthecontentsofthefirstcellinthetable.Ifyouwantedtochangethecolorofallthecellsinthisway,youcouldloopthroughthenodelist,likethis:

<script>

vartdElements=document.getElementsByTagName("td");

varlength=tdElements.length;

for(vari=0;i<length;i++){

tdElements[i].style.color="red";

}

</script>

OnethingtonoteaboutthegetElementsByTagName()methodisthatittakestheelementnameswithinquotationmarksandwithouttheanglebrackets(<>)thatnormallysurroundtags.

Thethirdmethod,querySelector(),retrievesthefirstelementthatmatchestheprovided

CSSselector.Thisisaconvenientwayofretrievinganelementthatdoesnothaveanidattribute(ifitdoeshaveanidattribute,youwanttousegetElementById()).

Forexample,considerthefollowingHTML:

<pclass="sub-title">Thisisa<span>special</span>paragraphelement

thatcontains<span>sometext</span></p>.

UsingthequerySelector()method,youcanretrievethefirst<span/>elementinthisHTMLwiththefollowingcode:

varfirstSpan=document.querySelector(".sub-titlespan");

TheprovidedCSSselectormatchesall<span/>elementscontainedwithinaparentelementwithaCSSclassofsub-title.ThisHTMLcontainstwosuch<span/>elements,butquerySelector()onlyreturnsthefirst:the<span/>elementcontainingthetext“special.”Justaswiththepreviousexamples,youcanmodifytheelement’stextcolorwithitsstyleproperty:

<script>

varfirstSpan=document.querySelector(".sub-titlespan");

firstSpan.style.color="red";

</script>

Ifyouwantedtoretrieveallofthe<span/>elementsinthisHTML,youwanttousethefourthmethod,querySelectorAll(),likethis:

varspans=document.querySelectorAll(".sub-titlespan");

AndjustaswiththegetElementsByTagName()example,youcanusealoopandmodifyalltheelementscontainedwithinthespansNodeList:

<script>

varspans=document.querySelectorAll(".sub-titlespan");

varlength=spans.length;

for(vari=0;i<length;i++){

spans[i].style.color="red";

}

</script>

NOTEThequerySelector()andquerySelectorAll()methodsaren’tactuallypartoftheDOMstandard.They’redefinedwithintheW3C’sSelectorsAPI,whichisoneofthecomponentstobeconsolidatedwithDOMlevel3intoDOMlevel4.YoucanusethesemethodsonElementobjects,too.

CreatingElementsandTextTheDocumentobjectalsoboastssomemethodsforcreatingelementsandtext,showninthefollowingtable.

METHODSOFTHEDOCUMENTOBJECT

DESCRIPTION

createElement(elementName) Createsanelementnodewiththespecifiedtagname.Returnsthecreatedelement

createTextNode(text) Createsandreturnsatextnodewiththesuppliedtext

Thefollowingcodedemonstratestheuseofthesemethods:

varpElement=document.createElement("p");

vartext=document.createTextNode("Thisissometext.");

Thiscodecreatesa<p/>elementandstoresitsreferenceinthepElementvariable.ItthencreatesatextnodecontainingthetextThisissometext.andstoresitsreferenceinthetextvariable.

It’snotenoughtocreatenodes,however;youhavetoaddthemtothedocument.We’lldiscusshowtodothisinjustabit.

PropertyoftheDocumentObject:GettingtheDocument’sRootElementYounowhaveareferencetoindividualelementsonthepage,butwhataboutthetreestructurementionedearlier?Thetreestructureencompassesalltheelementsandnodesonthepageandgivesthemahierarchicalstructure.Ifyouwanttoreferencethatstructure,youneedaparticularpropertyofthedocumentobjectthatreturnstheoutermostelementofyourdocument.InHTML,thisshouldalwaysbethe<html/>element.ThepropertythatreturnsthiselementisdocumentElement,asshowninthefollowingtable.

PROPERTYOFTHEDOCUMENTOBJECT

DESCRIPTION

documentElement Returnsareferencetotheoutermostelementofthedocument(therootelement;forexample,<html/>)

YoucanusedocumentElementasfollows.IfyougobacktothesimpleHTMLpage,youcantransferyourentireDOMintoonevariablelikethis:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title></title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varcontainer=document.documentElement;

</script>

</body>

</html>

Thevariablecontainernowcontainstherootelement,whichis<html/>.The

documentElementpropertyreturnedareferencetothiselementintheformofanobject,anElementobjecttobeprecise.TheElementobjecthasitsownsetofpropertiesandmethods.Ifyouwanttousethem,youcanrefertothembyusingthevariablename,followedbythemethodorpropertyname:

container.elementObjectProperty

Fortunately,theElementobjecthasonlyoneproperty.

TheElementObjectTheElementobjectisquitesimple,especiallycomparedtotheNodeobject(whichyouareintroducedtolater).Itexposesonlyahandfulofmembers(propertiesandmethods).

MEMBERNAME DESCRIPTIONtagName Getstheelement’stagnamegetAttribute() GetsthevalueofanattributesetAttribute() SetsanattributewithaspecifiedvalueremoveAttribute() Removesaspecificattributeanditsvaluefromtheelement

GettingtheElement’sTagName:ThetagNamePropertyThesolepropertyoftheElementobjectisareferencetothetagnameoftheelement:thetagNameproperty.

Inthepreviousexample,thevariablecontainercontainedthe<html/>element.Addthefollowinghighlightedline,whichmakesuseofthetagNameproperty:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title></title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varcontainer=document.documentElement;

alert(container.tagName);

</script>

</body>

</html>

Thiscodewillnowreturnproofthatyourvariablecontainerholdstheoutermostelement,andbyimplicationallotherelementswithinit(seeFigure9.5).

Figure9.5

MethodsoftheElementObject:GettingandSettingAttributesIfyouwanttosetanyelementattributes,otherthanthestyleattribute,youshouldusetheDOM-specificmethodsoftheElementobject.

ThethreemethodsyoucanusetoreturnandalterthecontentsofanHTMLelement’sattributesaregetAttribute(),setAttribute(),andremoveAttribute(),asshowninthefollowingtable.

METHODSOFTHEELEMENTOBJECT

DESCRIPTION

getAttribute(attributeName) ReturnsthevalueofthesuppliedattributeReturnsnulloranemptystringiftheattributedoesnotexist

setAttribute(attributeName,

value)

Setsthevalueofanattribute

removeAttribute(attributeName) Removesthevalueofanattributeandreplacesitwiththedefaultvalue

Let’stakeaquicklookathowthesemethodsworknow.

TRYITOUTPlayingwithAttributesOpenyourtexteditorandtypethefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example1</title>

</head>

<body>

<pid="paragraph1">Thisissometext.</p>

<script>

varpElement=document.getElementById("paragraph1");

pElement.setAttribute("align","center");

alert(pElement.getAttribute("align"));

pElement.removeAttribute("align");

</script>

</body>

</html>

Savethisasch9 _ example1.htmlandopenitinabrowser.You’llseethetextofthe<p/>elementinthecenterofthescreenandanalertboxdisplayingthetextcenter(Figure9.6).

Figure9.6

WhenyouclicktheOKbutton,you’llseethetextbecomeleft-aligned(Figure9.7).

Figure9.7

ThisHTMLpagecontainsone<p/>elementwithanidvalueofparagraph1.YouusethisvalueintheJavaScriptcodetofindtheelementnodeandstoreitsreferenceinthepElementvariablewiththegetElementById()method:

varpElement=document.getElementById("paragraph1");

Nowthatyouhaveareferencetotheelement,youusethesetAttribute()methodtosetthealignattributetocenter:

pElement.setAttribute("align","center");

Theresultofthiscodemovesthetexttothecenterofthebrowser’swindow.

YouthenusethegetAttribute()methodtogetthealignattribute’svalueanddisplayitinanalertbox:

alert(pElement.getAttribute("align"));

Thiscodedisplaysthevalue"center"inthealertbox.

Finally,youremovethealignattributewiththeremoveAttribute()method,effectivelymakingthetextleft-aligned.

NOTEStrictlyspeaking,thealignattributeisdeprecated,butyouuseditbecauseitworksandbecauseithasoneofthemosteasilydemonstrablevisualeffectsonawebpage.

TheNodeObjectYounowhaveyourelementorelementsfromthewebpage,butwhathappensifyouwant

tomovethroughyourpagesystematically,fromelementtoelementorfromattributetoattribute?Thisiswhereyouneedtostepbacktoalowerlevel.Tomoveamongelements,attributes,andtext,youhavetomoveamongnodesinyourtreestructure.Itdoesn’tmatterwhatiscontainedwithinthenode,orrather,whatsortofnodeitis.ThisiswhyyouneedtogobacktooneoftheobjectsofthecoreDOMspecification.Yourwholetreestructureismadeupofthesebase-levelNodeobjects.

TheNodeObject:NavigatingtheDOMThefollowingtablelistssomecommonpropertiesoftheNodeobjectthatprovideinformationaboutthenode,whetheritisanelement,attribute,ortext,andenableyoutomovefromonenodetoanother.

PROPERTIESOFTHENODEOBJECT

DESCRIPTIONOFPROPERTY

firstChild ReturnsthefirstchildnodeofanelementlastChild ReturnsthelastchildnodeofanelementpreviousSibling Returnsthepreviouschildnodeofanelementatthesame

levelasthecurrentchildnodenextSibling Returnsthenextchildnodeofanelementatthesamelevelas

thecurrentchildnodeownerDocument Returnstherootnodeofthedocumentthatcontainsthenode

(notethisisnotavailableinIE5or5.5)parentNode Returnstheelementthatcontainsthecurrentnodeinthetree

structurenodeName ReturnsthenameofthenodenodeType ReturnsthetypeofthenodeasanumbernodeValue Getsorsetsthevalueofthenodeinplaintextformat

Let’stakeaquicklookathowsomeofthesepropertieswork.Considerthisfamiliarexample:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title></title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varh1Element=document.getElementById("heading1");

h1Element.style.color="red";

</script>

</body>

</html>

Youcannowuseh1Elementtonavigateyourtreestructureandmakewhateverchangesyoudesire.Thefollowingcodeusesh1Elementasastartingpointtofindthe<p/>elementandchangeitstextcolor:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title></title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varh1Element=document.getElementById("heading1");

h1Element.style.color="red";

varpElement;

if(h1Element.nextSibling.nodeType==1){

pElement=h1Element.nextSibling;

}else{

pElement=h1Element.nextSibling.nextSibling;

}

pElement.style.color="red";

</script>

</body>

</html>

ThiscodedemonstratesafundamentaldifferencebetweentheDOMpresentinmodernbrowsersandthatinolderversionsofIE.TheDOMinmodernbrowserstreatseverythingasanodeintheDOMtree,includingthewhitespacebetweenelements.Ontheotherhand,olderversionsofIEstripoutthiswhitespace.Sotolocatethe<p/>elementinthepreviousexample,asiblingtothe<h1/>element,youmustcheckthenextsibling’snodeTypeproperty.Anelement’snodetypeis1(textnodesare3).IfthenextSibling’snodeTypeis1,youassignthatsibling’sreferencetopElement.Ifnot,yougetthenextsibling(the<p/>element)ofh1Element’ssibling(thewhitespacetextnode).

Ineffect,youarenavigatingthroughthetreestructureasshowninFigure9.8.

Figure9.8

Thesameprinciplesalsoworkinreverse.Youcangobackandchangethecodetonavigatefromthe<p/>elementtothe<h1/>element:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title></title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varpElement=document.getElementById("paragraph1");

pElement.style.color="red";

varh1Element;

if(pElement.previousSibling.nodeType==1){

h1Element=pElement.previousSibling;

}else{

h1Element=pElement.previousSibling.previousSibling;

}

h1Element.style.color="red";

</script>

</body>

</html>

Whatyou’redoinghereistheexactopposite;youfindthe<p/>bypassingthevalueofitsidattributetothegetElementById()methodandstoringthereturnedelementreferencetothepElementvariable.Youthenfindthecorrectprevioussiblingsothatyourcodeworksinallbrowsers,andyouchangeitstextcolortored.

TRYITOUTNavigatingYourHTMLDocumentUsingtheDOM

Upuntilnow,you’vebeencheating,becauseyouhaven’ttrulynavigatedyourHTMLdocument.You’vejustuseddocument.getElementById()toreturnanelementandnavigatedtodifferentnodesfromthere.Nowlet’susethedocumentElementpropertyofthedocumentobjectanddothisproperly.You’llstartatthetopofyourtreeandmovedownthroughthechildnodestogetatthoseelements;thenyou’llnavigatethroughyourchildnodesandchangethepropertiesinthesamewayasbefore.

Typethefollowingintoyourtexteditor:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example2</title>

</head>

<body>

<h1id="heading1">MyHeading</h1>

<pid="paragraph1">Thisissometextinaparagraph</p>

<script>

varhtmlElement;//htmlElementstoresreferenceto<html>

varheadElement;//headingElementstoresreferenceto<head>

varbodyElement;//bodyElementstoresreferenceto<body>

varh1Element;//h1Elementstoresreferenceto<h1>

varpElement;//pElementstoresreferenceto<p>

htmlElement=document.documentElement;

headElement=htmlElement.firstChild;

alert(headElement.tagName);

if(headElement.nextSibling.nodeType==3){

bodyElement=headElement.nextSibling.nextSibling;

}else{

bodyElement=headElement.nextSibling;

}

alert(bodyElement.tagName);

if(bodyElement.firstChild.nodeType==3){

h1Element=bodyElement.firstChild.nextSibling;

}else{

h1Element=bodyElement.firstChild;

}

alert(h1Element.tagName);

h1Element.style.fontFamily="Arial";

if(h1Element.nextSibling.nodeType==3){

pElement=h1Element.nextSibling.nextSibling;

}else{

pElement=h1Element.nextSibling;

}

alert(pElement.tagName);

pElement.style.fontFamily="Arial";

if(pElement.previousSibling.nodeType==3){

h1Element=pElement.previousSibling.previousSibling;

}else{

h1Element=pElement.previousSibling;

}

h1Element.style.fontFamily="Courier";

</script>

</body>

</html>

Savethisasch9 _ example2.htmlandopenitinyourbrowser.

ClickOKineachofthemessageboxesuntilyouseethepageshowninFigure9.9(unfortunately,IEdoesnotrenderthestylechangesuntilallalertboxeshavebeenopenedandclosed).

Figure9.9

You’vehopefullymadethisexampleverytransparentbyaddingseveralalertstodemonstratewhereyouarealongeachsectionofthetree.You’vealsonamedthevariableswiththeirvariouselements,togiveaclearerideaofwhatisstoredineachvariable.(Youcouldjustaseasilyhavenamedthema,b,c,d,ande,sodon’tthinkyouneedtobeboundbythisnamingconvention.)

YoustartatthetopofthescriptblockbyretrievingthewholedocumentusingthedocumentElementproperty:

varhtmlElement=document.documentElement;

Therootelementisthe<html/>element,hencethenameofyourfirstvariable.Nowifyourefertoyourtree,you’llseethattheHTMLelementmusthavetwochildnodes:onecontainingthe<head/>elementandtheothercontainingthe<body/>element.Youstartbymovingtothe<head/>element.YougetthereusingthefirstChildpropertyoftheNodeobject,whichcontainsyour<html/>element.Youuseyourfirstalerttodemonstratethatthisistrue:

alert(headingElement.tagName);

Your<body/>elementisyournextsiblingacrossfromthe<head/>element,soyounavigateacrossbycreatingavariablethatisthenextsiblingfromthe<head/>element:

if(headingElement.nextSibling.nodeType==3){

bodyElement=headingElement.nextSibling.nextSibling;

}else{

bodyElement=headingElement.nextSibling;

}

alert(bodyElement.tagName);

HereyouchecktoseewhatthenodeTypeofthenextSiblingofheadingElementis.Ifitreturns3,(nodeType3isatextnode),yousetbodyElementtobethenextSiblingofthenextSiblingofheadingElement;otherwise,youjustsetittobethenextSiblingofheadingElement.

Youuseanalerttoprovethatyouarenowatthe<body/>element:

alert(bodyElement.tagName);

The<body/>elementinthispagealsohastwochildren,the<h1/>and<p/>elements.UsingthefirstChildproperty,youmovedowntothe<h1/>element.Againyoucheckwhetherthechildnodeiswhitespaceforstandard-compliantbrowsers.Youuseanalertagaintoshowthatyouhavearrivedat<h1/>:

if(bodyElement.firstChild.nodeType==3){

h1Element=bodyElement.firstChild.nextSibling;

}else{

h1Element=bodyElement.firstChild;

}

alert(h1Element.tagName);

Afterthethirdalert,thestylewillbealteredonyourfirstelement,changingthefonttoArial:

h1Element.style.fontFamily="Arial";

Youthennavigateacrosstothe<p/>elementusingthenextSiblingproperty,againcheckingforwhitespace:

if(h1Element.nextSibling.nodeType==3){

pElement=h1Element.nextSibling.nextSibling;

}else{

pElement=h1Element.nextSibling;

}

alert(pElement.tagName);

Youchangethe<p/>element’sfonttoArialalso:

pElement.style.fontFamily="Arial";

Finally,youusethepreviousSiblingpropertytomovebackinyourtreetothe<h1/>elementandthistimechangethefonttoCourier:

if(pElement.previousSibling.nodeType==3){

h1Element=pElement.previousSibling.previousSibling;

}else{

h1Element=pElement.previousSibling;

}

h1Element.style.fontFamily="Courier";

Thisisafairlyeasyexampletofollowbecauseyou’reusingthesametreestructureyoucreatedwithdiagrams,butitdoesshowhowtheDOMeffectivelycreatesthishierarchyandthatyoucanmovearoundwithinitusingscript.

MethodsoftheNodeObjectWhereastheNodeobject’spropertiesenableyoutonavigatetheDOM,itsmethodsprovidethecompletelydifferentabilitytoaddandremovenodesfromtheDOM,thusfundamentallyalteringthestructureoftheHTMLdocument.Thefollowingtableliststhesemethods.

METHODSOFNODEOBJECTS

DESCRIPTION

appendChild(newNode) AddsanewNodeobjecttotheendofthelistofchildnodes.Thismethodreturnstheappendednode.

cloneNode(cloneChildren) Returnsaduplicateofthecurrentnode.Itacceptsabooleanvalue.Ifthevalueistrue,themethodclonesthecurrentnodeandallchildnodes.Ifthevalueisfalse,onlythecurrentnodeisclonedandchildnodesareleftoutoftheclone.

hasChildNodes() ReturnstrueifanodehasanychildnodesandfalseifnotinsertBefore(newNode,

referenceNode)

InsertsanewNodeobjectintothelistofchildnodesbeforethenodestipulatedbyreferenceNode.Returnstheinsertednode

removeChild(childNode) RemovesachildnodefromalistofchildnodesoftheNodeobject.Returnstheremovednode

TRYITOUTCreatingHTMLElementsandTextwithDOMMethodsInthisTryItOutyoucreateawebpagewithjustparagraph<p/>andheading<h1/>elements,butinsteadofHTMLyou’llusetheDOMpropertiesandmethodstoplacetheseelementsonthewebpage.Startupyourpreferredtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example3</title>

</head>

<body>

<script>

varnewText=document.createTextNode("MyHeading");

varnewElem=document.createElement("h1");

newElem.appendChild(newText);

document.body.appendChild(newElem);

newText=document.createTextNode("Thisissometextina

paragraph");

newElem=document.createElement("p");

newElem.appendChild(newText);

document.body.appendChild(newElem);

</script>

</body>

</html>

Savethispageasch9_example3.htmlandopenitinabrowser(Figure9.10).

Figure9.10

Italllooksabitdullandtedious,doesn’tit?Andyes,youcouldhavedonethismuchmoresimplywithHTML.Thatisn’tthepoint,though.TheideaisthatyouuseDOMpropertiesandmethods,accessedwithJavaScript,toinserttheseelements.Thefirsttwolinesofthescriptblockareusedtodefinethevariablesinyourscript,whichareinitializedtoholdthetextyouwanttoinsertintothepageandtheHTMLelementyouwanttoinsert:

varnewText=document.createTextNode("MyHeading");

varnewElem=document.createElement("h1");

Youstartatthebottomofyourtreefirst,bycreatingatextnodewiththecreateTextNode()method.ThenusethecreateElement()methodtocreateanHTMLheading.

Atthispoint,thetwovariablesareentirelyseparatefromeachother.Youhaveatextnode,andyouhavean<h1/>element,butthey’renotconnected.ThenextlineenablesyoutoattachthetextnodetoyourHTMLelement.YoureferencetheHTMLelementyouhavecreatedwiththevariablenamenewElem,usetheappendChild()methodofyournode,andsupplythecontentsofthenewTextvariableyoucreatedearlierasaparameter:

newElem.appendChild(newText);

Let’srecap.YoucreatedatextnodeandstoreditinthenewTextvariable.Youcreatedan<h1/>elementandstoreditinthenewElemvariable.Thenyouappendedthetextnodeasachildnodetothe<h1/>element.Thatstillleavesyouwithaproblem:You’vecreatedanelementwithavalue,buttheelementisn’tpartofyourdocument.Youneedtoattachtheentiretyofwhatyou’vecreatedsofartothedocumentbody.Again,youcandothiswiththeappendChild()method,butthistimecallitonthedocument.bodyobject(which,too,isaNode):

document.body.appendChild(newElem);

Thiscompletesthefirstpartofyourcode.Nowallyouhavetodoisrepeattheprocessforthe<p/>element:

newText=document.createTextNode("Thisissometextinaparagraph");

newElem=document.createElement("p");

newElem.appendChild(newText);

document.body.appendChild(newElem);

Youcreateatextnodefirst;thenyoucreateanelement.Youattachthetexttotheelement,andfinallyyouattachtheelementandtexttothebodyofthedocument.

It’simportanttonotethattheorderinwhichyoucreatenodesdoesnotmatter.Thisexamplehadyoucreatethetextnodesbeforetheelementnodes;ifyouwanted,youcouldhavecreatedtheelementsfirstandthetextnodessecond.

However,theorderinwhichyouappendnodesisveryimportantforperformancereasons.UpdatingtheDOMcanbeanexpensiveprocess,andperformancecansufferifyoumakemanychangestotheDOM.Forexample,thisexampleupdatedtheDOMonlytwotimesbyappendingthecompletedelementstothedocument’sbody.Itwouldrequirefourupdatesifyouappendedtheelementtothedocument’sbodyandthenappendedthetextnodetotheelement.Asaruleofthumb,onlyappendcompletedelementnodes(thatis,theelement,itsattributes,andanytext)tothedocumentwheneveryoucan.

NowthatyoucannavigateandmakechangestotheDOM,let’slookfurtherintomanipulatingDOMnodes.

MANIPULATINGTHEDOMDOMscriptingisthemanipulationofanHTMLpageafterit’sloadedintothebrowser.Uptothispoint,you’veexaminedthepropertiesandmethodsofthebasicDOMobjectsandlearnedhowtotraversetheDOMthroughJavaScript.

Throughouttheprevioussection,yousawsomeexamplesofmanipulatingtheDOM;morespecifically,yousawthatyoucanchangethecolorandfontfamilyoftextcontainedwithinanelement.Inthissection,youexpandonthatknowledge.

AccessingElementsAsyousawintheprevioussection,theDOMholdsthetoolsyouneedtofindandaccessHTMLelements;youusedthegetElementById()methodquitefrequently,andthroughexamplesyousawhoweasyitwastofindspecificelementsinthepage.

WhenscriptingtheDOM,chancesareyouhaveaprettygoodideaofwhatelementsyouwanttomanipulate.TheeasiestwaystofindthoseelementsarewiththegetElementById(),querySelector(),andquerySelectorAll()methods.Ifanelementhasanidattribute,usegetElementById()becauseitisthefastestwaytofindanelementinthepage.Otherwise,you’llneedtousethequerySelector()andquerySelectorAll()methods.

ChangingAppearancesProbablythemostcommonDOMmanipulationistochangethewayanelementlooks.Suchachangecancreateaninteractiveexperienceforvisitorstoyourwebsiteandcanevenbeusedtoalertthemtoimportantinformationorthatanactionisrequiredbythem.ChangingthewayanelementlooksconsistsalmostexclusivelyofchangingCSSpropertiesforanHTMLelement.YoucandothistwowaysthroughJavaScript:

ChangeeachCSSpropertywiththestyleproperty.

Changethevalueoftheelement’sclassattribute.

UsingthestylePropertyTochangespecificCSSproperties,youmustlooktothestyleproperty.Allbrowsersimplementthisobject,whichmapsdirectlytotheelement’sstyleattribute.ThisobjectcontainsCSSproperties,andbyusingityoucanchangeanyCSSpropertythatthebrowsersupports.You’vealreadyseenthestylepropertyinuse,buthere’saquickrefresher:

element.style.cssProperty=value;

TheCSSpropertynamesgenerallymatchthoseusedinaCSSstylesheet;therefore,changingthetextcolorofanelementrequirestheuseofthecolorproperty,likethis:

vardivAdvert=document.getElementById("divAdvert");

divAdvert.style.color="blue";

Insomecases,however,thepropertynameisalittledifferentfromtheoneseeninaCSSfile.CSSpropertiesthatcontainahyphen(-)areaperfectexampleofthisexception.Inthecaseoftheseproperties,youremovethehyphenandcapitalizethefirstletterofthewordthatfollowsthehyphen.Thefollowingcodeshowstheincorrectandcorrectwaystodothis:

divAdvert.style.background-color="gray";//wrong

divAdvert.style.backgroundColor="gray";//correct

Youcanalsousethestyleobjecttoretrievestylesthathavepreviouslybeendeclared.However,ifthestylepropertyyoutrytoretrievehasnotbeensetwiththestyleattribute(inlinestyles)orwiththestyleobject,youwillnotretrievetheproperty’svalue.ConsiderthefollowingHTMLcontainingastylesheetand<div/>element:

<style>

#divAdvert{

background-color:gray;

}

</style>

<divid="divAdvert"style="color:green">Iamanadvertisement.</div>

Whenthebrowserrendersthiselement,itwillhavegreentextonagraybackground.Ifyouhadusedthestyleobjecttoretrievethevalueofboththebackground-colorandcolorproperties,you’dgetthefollowingmixedresults:

vardivAdvert=document.getElementById("divAdvert");

alert(divAdvert.style.backgroundColor);//alertsanemptystring

alert(divAdvert.style.color);//alertsgreen

Yougettheseresultsbecausethestyleobjectmapsdirectlytothestyleattributeoftheelement.Ifthestyledeclarationissetina<style/>element,orinanexternalstylesheet,youcannotretrievethatproperty’svaluewiththestyleobject.

TRYITOUTUsingthestyleObjectLet’slookatasimpleexampleofchangingtheappearanceofsometextbyusingthestyleobject.Typethefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example4</title>

<style>

#divAdvert{

font:12ptarial;

}

</style>

</head>

<body>

<divid="divAdvert">

Hereisanadvertisement.

</div>

<script>

vardivAdvert=document.getElementById("divAdvert");

divAdvert.style.fontStyle="italic";

divAdvert.style.textDecoration="underline";

</script>

</body>

</html>

Savethisasch9_example4.html.Whenyourunthisinyourbrowser,youshouldseeasinglelineoftextthatisitalicizedandunderlined,asshowninFigure9.11.

Figure9.11

Inthepage’sbody,a<div/>elementisdefinedwithanidofdivAdvert.The<script/>elementappearsafterthe<div/>,anditcontainsthefollowingJavaScriptcode:

vardivAdvert=document.getElementById("divAdvert");

divAdvert.style.fontStyle="italic";

divAdvert.style.textDecoration="underline";

Beforeyoucandoanythingtothe<div/>element,youmustfirstretrieveit.YoudothissimplybyusingthegetElementById()method.Nowthatyouhavetheelement,youmanipulateitsstylebyfirstitalicizingthetextwiththefontStyleproperty.Next,youunderlinethetextbyusingthetextDecorationpropertyandassigningitsvaluetounderline.

It’sveryimportantthatthe<divid="divAdvert"/>elementisloadedintothebrowserbeforeyouretrieveitwithgetElementById().Thisiswhythe<script/>elementappearsafter<divid="divAdvert"/>.BythetimethebrowserloadsandexecutestheJavaScriptcode,the<div/>elementisloadedintotheDOM.

ChangingtheclassAttributeYoucanassignaCSSclasstoelementsbyusingtheelement’sclassattribute.ThisattributeisexposedintheDOMbytheclassNamepropertyandcanbechangedthroughJavaScripttoassociateadifferentstylerulewiththeelement:

element.className=sNewClassName;

UsingtheclassNamepropertytochangeanelement’sstyleisadvantageousintwoways:

ItreducestheamountofJavaScriptyouhavetowrite,whichnooneislikelytocomplainabout.

ItkeepsstyleinformationoutoftheJavaScriptfileandputsitintotheCSSfilewhereitbelongs.Makinganytypeofchangestothestylerulesiseasierbecauseyoudonothavetohaveseveralfilesopeninordertochangethem.

TRYITOUTUsingtheclassNamePropertyLet’srevisitthecodefromch9 _ example4.htmlfromtheprevioussectionandmakesomerevisions.Typethefollowingcode:

-transitional.dtd”>

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example5</title>

<style>

#divAdvert{

font:12ptarial;

}

.new-style{

font-style:italic;

text-decoration:underline;

}

</style>

</head>

<body>

<divid="divAdvert">

Hereisanadvertisement.

</div>

<script>

vardivAdvert=document.getElementById("divAdvert");

divAdvert.className="new-style";

</script>

</body>

</html>

Savethisasch9 _ example5.html.

Twokeydifferencesexistbetweench9 _ example4.htmlandch9 _ example5.html.ThefirstistheadditionofaCSSclasscallednew-style:

.newStyle{

font-style:italic;

text-decoration:underline;

}

Thisclasscontainsstyledeclarationstospecifyitalicizedandunderlinedtext.

ThesecondchangeisintheJavaScriptitself:

vardivAdvert=document.getElementById("divAdvert");

divAdvert.className="new-style";

}

Thefirststatementretrievesthe<div/>elementbyusingthegetElementById()method.ThesecondstatementchangestheclassNamepropertytothevaluenew-style.Withthisline,thedivAdvertelementtakesonanewstyleruleandthebrowserchangesthewayitlooks.

NOTEAlthoughitwasn’tdemonstratedhere,theHTMLclassattribute,andthustheclassNameproperty,cancontainmultipleCSSclassnames.YouseemoreaboutmultipleclassnamesinChapter16.

PositioningandMovingContentChangingtheappearanceofanelementisanimportantpatterninDOMscripting,anditfindsitsplaceinmanyscripts.However,thereismoretoDOMscriptingthanjustchangingthewaycontentappearsonthepage;youcanalsochangethepositionofanelementwithJavaScript.

MovingcontentwithJavaScriptisjustaseasyasusingthestyleobject.Youusethepositionpropertytochangethetypeofpositiondesired,andbyusingtheleftandtopproperties,youcanpositiontheelement:

vardivAdvert=document.getElementById("divAdvert");

divAdvert.style.position="absolute";

divAdvert.style.left="100px";//settheleftposition

divAdvert.style.top="100px";//settherightposition

ThiscodefirstretrievesthedivAdvertelement.Thenitsetstheelement’spositionto

absoluteandmovestheelement100pixelsfromtheleftandtopedges.Noticetheadditionofpxtothevalueassignedtothepositions.Youmustspecifyaunitwhenassigningapositionalvalue;otherwise,thebrowserwillnotpositiontheelement.

NOTEPositioningelementsrequiresthepositionofabsoluteorrelative.

Example:AnimatedAdvertisementPerhapsthemostcreativeuseofDOMscriptingisinanimatingcontentonthepage.Youcanperformavarietyofanimations:youcanfadetextelementsorimagesinandout,givethemaswipeanimation(makingitlooklikeasiftheyarewipedontothepage),andanimatethemtomovearoundonthepage.

Animationcangiveimportantinformationtheflairitneedstobeeasilyrecognizedbyyourreader,aswellasaddinga“that’scool”factor.PerforminganimationwithJavaScriptfollowsthesameprinciplesofanyothertypeofanimation:Youmakeseeminglyinsignificantchangesoneatatimeinasequentialorderuntilyoureachtheendoftheanimation.Essentially,withanyanimation,youhavethefollowingrequisites:

1. Thestartingstate

2. Themovementtowardthefinalgoal

3. Theendstate;stoppingtheanimation

Animatinganabsolutelypositionedelement,asyou’regoingtodointhissection,isnodifferent.First,withCSS,positiontheelementatthestartlocation.Thenperformtheanimationupuntilyoureachtheendpoint,whichsignalstheendoftheanimation.

Inthissection,youlearnhowtoanimatecontenttobouncebackandforthbetweentwopoints.Todothis,youneedoneimportantpieceofinformation:thecontent’scurrentlocation.

AreWeThereYet?TheDOMinmodernbrowsersexposestheoffsetTopandoffsetLeftpropertiesofanHTMLelementobject.Thesetwopropertiesreturnthecalculatedpositionrelativetotheelement’sparentelement:offsetToptellsyouthetoplocation,andoffsetLefttellsyoutheleftposition.Thevaluesreturnedbythesepropertiesarenumericalvalues,soyoucaneasilychecktoseewhereyourelementcurrentlyisintheanimation.Forexample:

varendPointX=394;

if(element.offsetLeft<endPointX){

//continueanimation

}

Theprecedingcodespecifiestheendpoint(inthiscase,394)andassignsittotheendPointXvariable.Youcanthenchecktoseeiftheelement’soffsetLeftvalueiscurrentlylessthanthatoftheendpoint.Ifitis,youcancontinuetheanimation.Thisexamplebringsustothenexttopicincontentmovement:performingtheanimation.

PerformingtheAnimationToperformananimation,youneedtomodifythetopandleftpropertiesofthestyleobjectincrementallyandquickly.Youdothiswithperiodicfunctionexecutionuntilit’stimetoendtheanimation.Todothis,useoneoftwomethodsofthewindowobject:setTimeout()orsetInterval().ThisexampleusesthesetInterval()methodtoperiodicallymoveanelement.

TRYITOUTAnimatingContentThispagemovesanelementacrossthepagefromrighttoleft.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Example6</title>

<style>

#divAdvert{

position:absolute;

font:12pxArial;

top:4px;

left:0px;

}

</style>

</head>

<body>

<divid="divAdvert">

Hereisanadvertisement.

</div>

<script>

varswitchDirection=false;

functiondoAnimation(){

vardivAdvert=document.getElementById("divAdvert");

varcurrentLeft=divAdvert.offsetLeft;

varnewLocation;

if(!switchDirection){

newLocation=currentLeft+2;

if(currentLeft>=400){

switchDirection=true;

}

}else{

newLocation=currentLeft-2;

if(currentLeft<=0){

switchDirection=false;

}

}

divAdvert.style.left=newLocation+"px";

}

setInterval(doAnimation,10);

</script>

</body>

</html>

Savethispageasch9 _ example6.htmlandloaditintoyourbrowser.Whenyouloadthepageintothebrowser,thecontentshouldstartmovingfromlefttoright,startingattheleftedgeoftheviewport.Whenthecontentreachesaleftpositionof400pixels,thecontentswitchesdirectionsandbeginstomovebacktowardtheleftedge.Thisanimationiscontinuous,soitshouldbouncebetweenthetwopoints(0and400)perpetually.

Insidethebodyofthepageisa<div/>element.ThiselementhasanidofdivAdvertsothatyoucanretrieveitwiththegetElementById()method,becausethisistheelementyouwanttoanimate:

<divid="divAdvert">

Hereisanadvertisement.

</div>

Thiselementhasnostyleattributesbecauseallthestyleinformationisinsidethestylesheetlocatedintheheadofthepage.Inthestylesheet,youdefineastartingpointforthis<div/>.Youwanttheanimationtogofirstfromlefttoright,andyouwantittostartattheleftedgeofthebrowser:

#divAdvert{

position:absolute;

font:12ptarial;

top:4px;

left:0px;

}

Thefirststyledeclarationpositionstheelementabsolutely,andthesecondspecifiesthefontas12-pointArial.Thenextdeclarationpositionstheelementfourpixelsfromthetopofthebrowser’sviewport.Settingthetoppositionawayfromthetopmostedgemakesthetextalittleeasiertoread.Finally,thelastlinepositionsthedivAdvertelementalongtheleftedgeoftheviewportwiththeleftproperty.

WithinthescriptblockisaglobalvariablecalledswitchDirection:

varswitchDirection=false;

Thisvariablekeepstrackofthedirectioninwhichthecontentiscurrentlygoing.IfswitchDirectionisfalse,thecontentismovingfromlefttoright,whichisthedefault.IfswitchDirectionistrue,thecontentismovingfromrighttoleft.

NextinthescriptblockisthedoAnimation()function,whichperformstheanimation:

functiondoAnimation(){

vardivAdvert=document.getElementById("divAdvert");

varcurrentLeft=divAdvert.offsetLeft;

varnewLocation;

First,youretrievethedivAdvertelementwiththegetElementById()method;youalsoretrievetheoffsetLeftpropertyandassignitsvaluetothecurrentLeftvariable.Youusethisvariabletocheckthecontent’scurrentposition.Next,createavariablecallednewLocationthatwillcontainthenewleftposition,butbeforeyouassignitsvalueyouneedtoknowthedirectioninwhichthecontentismoving:

if(!switchDirection){

newLocation=currentLeft+2;

if(currentLeft>=400){

switchDirection=true;

}

}

First,checkthedirectionbycheckingtheswitchDirectionvariable.Remember,ifitisfalse,theanimationismovingfromlefttoright;soassignnewLocationtocontainthecontent’scurrentpositionandadd2,thusmovingthecontenttwopixelstotheright.

Youthenneedtocheckifthecontenthasreachedtheleftpositionof400pixels.Ifithas,youneedtoswitchthedirectionoftheanimation,andyoudothisbychangingswitchDirectiontotrue.SothenexttimedoAnimation()runs,itwillbegintomovethecontentfromrighttoleft.

Thecodetomovetheelementinthisnewdirectionissimilartothepreviouscode,exceptforafewkeydifferences:

else{

newLocation=currentLeft-2;

if(currentLeft<=0){

switchDirection=false;

}

}

ThefirstdifferenceisthevalueassignedtonewLocation;insteadofadding2tothecurrentlocation,yousubtract2,thusmovingthecontenttwopixelstotheleft.Next,checkifcurrentLeftislessthanorequalto0.Ifitis,youknowyou’vereachedtheendingpointoftheright-to-leftmovementandneedtoswitchdirectionsagainbyassigningswitchDirectiontobefalse.

Finally,setthenewpositionofthecontent:

divAdvert.style.left=newLocation+"px";

}

Thisfinallineofthefunctionsetstheelement’sleftpropertytothevaluestoredinthenewLocationvariableplusthestring"px".

Toruntheanimation,usesetInterval()tocontinuouslyexecutedoAnimation().

ThefollowingcoderunsdoAnimation()every10milliseconds:

setInterval(doAnimation,10);

Atthisspeed,thecontentmovesatapacethatiseasilyseenbythoseviewingthepage.Ifyouwanttospeeduporslowdowntheanimation,simplychangehowoftenthesetInterval()functioncallsdoAnimation()bychangingthesecondparameter.

Whathaveyouseensofar?Well,you’veseentheDOMhierarchyandhowitrepresentstheHTMLdocumentasatree-likestructure.YounavigatedthroughthedifferentpartsofitviaDOMobjects(theNodeobjects)andtheirproperties,andyouchangedthepropertiesofobjects,thusalteringthecontentofthewebpage.ThisleavesjustoneareaoftheDOMtocover:theeventmodel.Youlearnabouteventsinthenextchapter.

SUMMARYThischapterhasfeaturedquiteafewdiversionsanddigressions,butthesewerenecessarytodemonstratethepositionandimportanceofthedocumentobjectmodelinJavaScript.

Thischaptercoveredthefollowingpoints:

Itstartedbyoutliningtwoofthemainstandards—HTMLandECMAScript—andexaminedtherelationshipsbetweenthem.YousawthatacommonaimemergingfromthesestandardswastoprovideguidelinesforcodingHTMLwebpages.Thoseguidelinesinturnbenefitedthedocumentobjectmodel,makingitpossibletoaccessandmanipulateanyitemonthewebpageusingscriptifwebpageswerecodedaccordingtothoseguidelines.

Youexaminedthedocumentobjectmodelandsawthatitofferedabrowser-independentmeansofaccessingtheitemsonawebpage,andthatitresolvedsomeoftheproblemsthatdoggedolderbrowsers.YousawhowtheDOMrepresentstheHTMLdocumentasatreestructureandhowitispossibleforyoutonavigatethroughthetreetodifferentelementsandusethepropertiesandmethodsitexposestoaccessthedifferentpartsofthewebpage.

TheDOMletsyouchangeapageafteritisloadedintothebrowser,andyoucanperformavarietyofuserinterfacetrickstoaddsomeflairtoyourpage.

Youlearnedhowtochangeatag’sstylebyusingthestyleandclassNameproperties.

Youalsolearnedthebasicsofanimationandmadetextbouncebackandforthbetweentwopoints.

EXERCISES1. Here’ssomeHTMLcodethatcreatesatable.Re-createthistableusingonly

JavaScriptandthecoreDOMobjectstogeneratetheHTML.Testyourcodeinallbrowsersavailabletoyoutomakesureitworksinthem.Hint:Commenteachlineasyouwriteittokeeptrackofwhereyouareinthetreestructure,andcreateanewvariableforeveryelementonthepage(forexample,notjustoneforeachoftheTDcellsbutninevariables).

<table>

<tr>

<td>Car</td>

<td>TopSpeed</td>

<td>Price</td>

</tr>

<tr>

<td>Chevrolet</td>

<td>120mph</td>

<td>$10,000</td>

</tr>

<tr>

<td>Pontiac</td>

<td>140mph</td>

<td>$20,000</td>

</tr>

</table>

2. Modifych9_example6.htmlfromthe“AnimatingContent”TryItOutsothattheamountofpixelsmovedineitherdirectioniscontrolledbyaglobalvariable.Callitdirection.RemovetheswitchDirectionvariable,andchangethecodetousethenewdirectionvariabletodeterminewhentheanimationshouldchangedirections.

10EventsWHATYOUWILLLEARNINTHISCHAPTER:

Connectingyourcodetoeventstorespondtouseractions

Writingstandards-compliant,event-drivencode

WritingeventcodeforolderversionsofInternetExplorer

Handlingthedifferencebetweenstandards-compliantandold-IEeventmodels

DragginganddroppingcontentwithHTML5’snativedrag-and-dropcapabilities

Animatingelementsbymanipulatingtheirpositioning

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

There’snodoubtthatJavaScriptisausefultoolinwebprogramming.You’veseenhowtodynamicallycreate,remove,andmanipulateHTMLinthepage,andinthecomingchapters,youlearnhowtoprocessuserinputandsenddatatotheserver.

Althoughthesecapabilitiesareveryimportantintoday’swebprogramming,perhapsthemostimportantconceptyou’lllearnanduseisthatofevents.Intherealworld,aneventis,putsimply,somethingthathappens.Forexample,aringingtelephoneisanevent.Ifyouareexpectingafriendorcolleaguetocall,youusuallywanttodosomething:Answerthecall.

Inprogramming,eventsareverysimilartoatelephonecall.Somethinginthepagewillhappen,andifit’ssomethingyouareexpecting,youcanrespondtoit.Forexample,theuserclickingthepage,pressingakeyonthekeyboard,ormovingthemousepointeroversometextallcauseeventstooccur.Anotherexample,whichisusedquitefrequently,istheloadeventforthepage:Thewindowraises(orfires)anotificationwhenthepageiscompletelyloadedinthebrowser.

Whyshouldyoubeinterestedinevents?

Takeasanexamplethesituationinwhichyouwanttomakeamenupopupwhentheuserclicksanywhereinyourwebpage.Assumingthatyoucanwriteafunctionthatwillmakethepop-upmenuappear,howdoyouknowwhentomakeitappear,orinotherwords,whentocallthefunction?Yousomehowneedtointercepttheeventoftheuserclickinginthedocument,andmakesureyourfunctioniscalledwhenthateventoccurs.

Todothis,youneedtousesomethingcalledaneventhandler,orlistener.Youassociatethiswiththecodethatyouwanttoexecutewhentheeventoccurs.Thisprovidesyouwith

awayofinterceptingeventsandmakingyourcodeexecutewhentheyhaveoccurred.Youwillfindthataddinganeventhandlertoyourcodeisoftenknownas“connectingyourcodetotheevent.”It’sabitlikesettinganalarmclock—yousettheclocktomakearingingnoisewhenacertaineventhappens.Withalarmclocks,theeventiswhenacertaintimeisreached.

TYPESOFEVENTSWebdevelopment,especiallywhenitcomestoJavaScript,isprimarilyevent-driven,meaningthattheflowoftheprogramiscontrolledbyevents.Inotherwords,alargeportionofyourJavaScriptcodeusuallyonlyexecuteswhenaneventoccurs,andyoucanlistenformanyevents.

Takeamomentandthinkabouthowyouinteractwithawebpage.Onacomputerorlaptop,youmoveyourmousearoundthepage,perhapsyouselecttextthatyouwanttocopyandpasteintoyournote-takingprogram,andyoudefinitelyclickthings(likelinks).Ontouch-baseddevices,youtapitemsinthepage.Andonallweb-enableddevices,youfilloutformsbytypingkeysonthekeyboard.Virtuallyeverythingyoudotriggersanevent,andalotofthetime,youwanttowritecodethatreactstosomeofthoseevents.

Followingisalistofthemanytypesofeventsthatyoucanlistenforandreactto:

Mouseevents:Theseoccurwhentheuserdoessomethingwiththemouse,suchasmovingthecursor,clicking,double-clicking,dragging,andsoon.

Keyboardevents:Theseoccurwhenkeysonthekeyboardarepressedordepressed.Thoughcommonlyusedinconjunctionwithforms,keyboardeventsoccureverytimetheuserpressesordepressesakey.

Progressionevents:Thesearemoregenericeventsthatoccuratdifferentstagesofanobject.Forexample,whenthedocumentloads.

Formevents:Theseoccurwhensomethingintheformchanges.

Mutationevents:TheseoccurwhenDOMnodesaremodified.

Touchevents:Theseoccurwhentheusertouchesthesensor.

Errorevents:Theseoccurwhenanerroroccurs.

Themostcommonuser-basedeventsaremouseevents,andrightlyso.Theprimarywayusersinteractwiththeircomputersiswiththemouse,butthat’sstartingtochangeasmoreandmorepeopleowntouch-enableddevices.

Themainfocusofthischapteristoteachyouhowtolistenforevents,anditdoessoprimarilywithmouseevents.Inthenextchapter,youusesomekeyboardeventstointeractwithforms.

CONNECTINGCODETOEVENTSBrowsershavebeenaroundforquitesometime,andasyoucanguess,thewayinwhichwelistenforeventshasevolvedovertheyears.ButevenwiththemanychangestheJavaScriptcommunityhasseenovertheyears,theoldwaysoflisteningforeventsarestillsupportedandusefulincertainsituations.

Chapter5introducedobjectsdefinedbytheirmethodsandproperties.However,objectsalsohaveeventsassociatedwiththem.Thiswasnotmentionedbefore,becausenativeJavaScriptobjectsdonothavetheseevents,buttheobjectsofthebrowserobjectmodel(BOM)anddocumentobjectmodel(DOM)do.

Youcanconnectyourcodetoaneventinthreeways:

AssigningHTMLattributes

Assigninganobject’sspecialproperties

Callinganobject’sspecialmethods

HandlingEventsviaHTMLAttributesInthissectionyoucreateasimpleHTMLpagewithasinglehyperlink,givenbytheelement<a/>.Associatedwiththiselementistheaobject,andoneoftheeventstheaobjecthasistheclickevent.Theclickeventfires,notsurprisingly,whentheuserclicksthehyperlink.Feelfreetofollowalong;openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>ConnectingEventsUsingHTMLAttributes</title>

</head>

<body>

<ahref="somepage.html">ClickMe</a>

</body>

</html>

Asitstands,thispagedoesnothinganormalhyperlinkdoesn’tdo.Youclickit,anditnavigatesthewindowtoanotherpage,calledsomepage.html,whichwouldneedtobecreated.There’sbeennoeventhandleraddedtothelink—yet!

Asmentionedearlier,onewayofconnectingtheeventtoyourcodeistoadditdirectlytotheopeningtagoftheelementobjectwhoseeventyouarecapturing.Inthiscase,it’stheclickeventoftheaobject,asdefinedbythe<a/>element.Onclickingthelink,youwanttocapturetheeventandconnectittoyourcode.Youneedtoaddtheeventhandler,inthiscaseonclick,asanattributetotheopening<a>tag.Yousetthevalueoftheattributetothecodeyouwanttoexecutewhentheeventoccurs.

Rewritetheopening<a>tagtodothisasfollows:

<ahref="somepage.html"onclick="alert('Youclicked?')">ClickMe</a>

Thiscodeaddsonclick="alert('YouClicked?')"tothedefinitionoftheopening<a>tag.Now,whenthelinkisclicked,youseeanalertbox.Afterthis,thehyperlinkdoesitsusualstuffandtakesyoutothepagedefinedinthehrefattribute.

Thisisfineifyouhaveonlyonelineofcodetoconnecttotheeventhandler,butwhatifyouwantanumberoflinestoexecutewhenthelinkisclicked?

Well,allyouneedtodoisdefinethefunctionyouwanttoexecuteandcallitintheonclickcode.Dothatnow:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>ConnectingEventsUsingHTMLAttributes</title>

</head>

<body>

<ahref="somepage.html"onclick="returnlinkClick()">ClickMe</a>

<script>

functionlinkClick(){

alert("YouClicked?");

returntrue;

}

</script>

</body>

</html>

Withinthescriptblock,youhavecreatedastandardfunction.TheonclickattributeisnowconnectedtosomecodethatcallsthefunctionlinkClick().Therefore,whentheuserclicksthehyperlink,thisfunctionwillbeexecuted.

You’llalsoseethatthefunctionreturnsavalue,trueinthiscase.Also,whereyoudefineyouronclickattribute,youreturnthereturnvalueofthefunctionbyusingthereturnstatementbeforethefunctionname.Whydothis?

Thevaluereturnedbyonclick="returnlinkClick()"isusedbyJavaScripttodecidewhetherthenormalactionofthelink—thatis,goingtoanewpage—shouldoccur.Ifyoureturntrue,theactioncontinues,andyougotosomepage.html.Ifyoureturnfalse,thenormalchainofevents(thatis,goingtosomepage.html)doesnothappen.Yousaythattheactionassociatedwiththeeventiscanceled.Trychangingthefunctiontothis:

functionlinkClick(){

alert("Thislinkisgoingnowhere");

returnfalse;

}

Nowyou’llfindthatyoujustgetamessage,andnoattemptismadetogotosomepage.html.

NOTENotallobjectsandtheireventsmakeuseofthereturnvalue,sosometimesit’sredundant.

Someeventsarenotdirectlylinkedwiththeuser’sactionsassuch.Forexample,thewindowobjecthastheloadevent,whichfireswhenapageisloaded,andtheunloadevent,whichfireswhenthepageisunloaded(thatis,whentheusereitherclosesthebrowserormovestoanotherpage).

Eventhandlersforthewindowobjectactuallygoinsidetheopening<body>tag.Forexample,toaddaneventhandlerfortheloadandunloadevents,you’dwritethefollowing:

<bodyonload="myOnLoadfunction()"onunload="myOnUnloadFunction()">

TRYITOUTDisplayingRandomImageswithHTMLAttributeEventHandlersInthisTryItOut,youconnecttoanimage’sclickeventtorandomlychangetheimageloadedinapage.Openyoureditorandtypeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example1</title>

</head>

<body>

<imgsrc="usa.gif"onclick="changeImg(this)"/>

<imgsrc="mexico.gif"onclick="changeImg(this)"/>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(that){

varnewImgNumber=Math.round(Math.random()*3);

while(that.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

that.src=myImages[newImgNumber];

}

</script>

</body>

</html>

Savethepageasch10_example1.html.Youwillneedfourimagefilesfortheexample,whichyoucancreateorretrievefromthecodedownloadavailablewiththisbook.

Loadthepageintoyourbrowser.YoushouldseeapagelikethatshowninFigure10.1.

Figure10.1

Ifyouclickanimage,you’llseeitchangetoadifferentimage,whichisselectedrandomly.

Thefirstlineinthescriptblockatthetopofthepagedefinesavariablewithpage-levelscope.Thisisanarraythatcontainsyourlistofimagesources:

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

NextyouhavethechangeImg()function,whichwillbeconnectedtotheonclickeventhandlerofthe<img/>elementsdefinedinthepage.Youareusingthesamefunctionfortheonclickeventhandlersofbothimages,andindeed,canconnectonefunctiontoasmanyeventhandlersasyoulike.Thisfunctionacceptsoneparametercalledthat.Itiscalledthatbecauseyoupassthethiskeywordtothefunction,whichgivesyouimmediateaccesstotheimgobjectyouclick.Youcanactuallynametheparameterwhateveryouwant,butmostdevelopersusetheword“that”whenitreferencesthis.

Inthefirstlineofthefunction,yousetthenewImgNumbervariabletoarandomintegerbetween0and3:

functionchangeImg(that){

varnewImgNumber=Math.round(Math.random()*3);

TheMath.random()methodprovidesarandomnumberbetween0and1,andyoumultiplythatbythreetogetanumberbetween0and3.Thisnumberisroundedtothenearestwholenumber(0,1,2,or3)bymeansofMath.round().ThisintegerprovidestheindexfortheimagesrcthatyouwillselectfromthemyImagesarray.

Thenextlinesareawhileloop,thepurposeofwhichistoensurethatyoudon’tselectthesameimageasthecurrentone.IfthestringcontainedinmyImages[newImgNumber]isfoundinsidethesrcpropertyofthecurrentimage,youknowit’sthesameandthatyouneedtogetanotherrandomnumber.Youkeeploopinguntilyougetanewimage,atwhichpointmyImages[newImgNumber]willnotbefoundintheexistingsrc,and-1willbereturnedbytheindexOf()method,breakingoutoftheloop:

while(that.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

Next,yousetthesrcpropertyoftheimgobjecttothenewvaluecontainedinyourmyImagesarray:

that.src=myImages[newImgNumber];

}

Youconnecttheonclickeventofthefirst<img/>elementtothechangeImg()function:

<imgsrc="usa.gif"onclick="changeImg(this)"/>

Andnowtothesecond<img/>element:

<imgsrc="mexico.gif"onclick="changeImg(this)"/>

PassingthisinthechangeImg()functiongivesthefunctiondirectaccesstothis<img/>element’scorrespondingobject.WhenyoupassthistoanHTMLelement’sattributeeventhandler,thecorrespondingobjectofthatelementispassedtothefunction.It’sanice,cleanwayofaccessingtheelement’sobjectinyourJavaScriptcode.

Thisexamplehadyoupassthisasanargumenttothefunctionhandlingtheelement’sclickevent.Thisisasimpleandeasywayofaccessingtheelementthatreceivedtheevent,butthere’safarmoreusefulobjectyoucanpass:anEventobjectthatcontainsalltheinformationabouttheevent.

PassingtheEventobjectisverysimpletodo;simplypasseventinsteadofthis.Forexample,inthefollowingcodethe<p/>elementwillraiseadblclickevent:

<pondblclick="handle(event)">Paragraph</p>

<script>

functionhandle(e){

alert(e.type);

}

</script>

Noticethateventispassedtothehandle()functionintheondblclickattribute.Thiseventvariableisspecialinthatitisnotdefinedanywhere;instead,itisanargumentusedonlywitheventhandlersthatareconnectedthroughHTMLattributes.Itpassesareferencetothecurrenteventobjectwhentheeventfires.

Ifyouranthepreviousexample,itwouldjusttellyouwhatkindofeventraisedyourevent-handlingfunction.Thismightseemself-evidentintheprecedingexample,butifyouhadincludedthefollowingextralinesofcode,anyoneofthreeelementscouldhaveraisedthefunction:

<pondblclick="handle(event)">Paragraph</p>

<h1onclick="handle(event)">Heading1</h1>

<spanonmouseover="handle(event)">SpecialText</span>

<script>

functionhandle(e){

alert(e.type);

}

</script>

Thismakesthecodemuchmoreuseful.Ingeneral,youwilluserelativelyfeweventhandlerstodealwithanynumberofevents,andyoucanusetheeventpropertiesasafiltertodeterminewhattypeofeventhappenedandwhatHTMLelementtriggeredit,sothatyoucantreateacheventdifferently.

Inthefollowingexample,youseethatyoucantakedifferentcoursesofactiondependingonwhattypeofeventisreturned:

<pondblclick="handle(event)">Paragraph</p>

<h1onclick="handle(event)">Heading1</h1>

<spanonmouseover="handle(event)">SpecialText</span>

<script>

functionhandle(e){

if(e.type=="mouseover"){

alert("YoumovedovertheSpecialText");

}

}

</script>

Thiscodeusesthetypepropertytodeterminewhattypeofeventoccurred.Ifusersmovetheirmousecursoroverthe<span/>element,analertboxtellsthemso.

YoulearnalotmoreabouttheEventobjectlaterinthechapter,butfornow,justknowthatitexposesapropertycalledtarget.Thisisthetargetoftheevent,theelementobjectthatreceivedtheevent.Withthisinformation,youcanrewritech10_example1.htmltousethemoreversatileEventobject.

TRYITOUTDisplayingRandomImageswithObjectPropertyEventHandlersandtheEventObjectInthisTryItOut,yourewritech10_example1.htmltousetheEventobjectinsteadofthis.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example2</title>

</head>

<body>

<imgsrc="usa.gif"onclick="changeImg(event)"/>

<imgsrc="mexico.gif"onclick="changeImg(event)"/>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=e.target;

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

</script>

</body>

</html>

Savethepageasch10_example2.html.Loadthepageintoyourbrowser,andyouwillseeapagesimilartoch10_example1.html.Clickanimage,andyou’llseeitchangetoarandompicture.

Thecodeforthispageisalmostidenticaltoch10_example1.html.Thisnewversionjusthasafewchanges.

Thefirsttwochangesareintheonclickeventhandlersofthe<img/>elements.InsteadofpassingthistochangeImg(),youpassevent.

ThenextchangeisinthechangeImg()declaration:

functionchangeImg(e){

Theparameternameisnowe,meaningevent.Keepinmindthatitdoesn’tmatterwhatyoucallthisparameter,butthegeneralconventionistousee.

Whenthebrowsercallsthisfunction,itwillpassanEventobjectastheeparameter,andyoucanretrievetheimgelementobjectthatreceivedtheeventbyusinge.target:

varel=e.target;

Youassignthisobjecttoavariablecalledel(shortforelement),andyouuseitinthewhileloop:

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

Youalsouseittoassignitssrcpropertyinthelastlineofthefunction:

el.src=myImages[newImgNumber];

ThechangesmadetochangeImg()areminimal,andthoughitdoesrequirejustalittlebitmorecode,itismuchmoreversatile,asyoulearnlaterinthechapter.

UsingtheHTMLattributeeventhandlersisaneasywaytoconnectyourJavaScriptcodetoanelement’sevents,buttheyhavesomedownsides:

YourHTMLandJavaScriptaremixedtogether.Thismakesitmoredifficulttomaintainandfindandfixbugs.

Youcan’tremoveaneventhandlerwithoutchangingtheHTML.

YoucanonlysetupeventhandlersforelementsthatappearinyourHTMLcode,asopposedtoelementsyoucreatedynamically(like,forexample,whenyoucreateanelementusingdocument.createElement()).

Theseissues,however,aresolvedwithanobject’seventhandlerproperties.

HandlingEventsviaObjectPropertiesWiththismethod,youfirstneedtodefinethefunctionthatwillbeexecutedwhentheeventoccurs.Thenyouneedtosetthatobject’seventhandlerpropertytothefunctionyoudefined.

Thisisillustratedinthefollowingexample.Openyoureditorandtypeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10,Example3</title>

</head>

<body>

<aid="someLink"href="somepage.html">

ClickMe

</a>

<script>

functionlinkClick(){

alert("Thislinkisgoingnowhere");

returnfalse;

}

document.getElementById("someLink").onclick=linkClick;

</script>

</body>

</html>

Savethisasch10_example3.html.

First,youhavethe<a/>element,whoseobject’seventyouareconnectingto.You’llnoticethereisnomentionoftheeventhandlerorthefunctionwithintheattributesofthetag,butdonoticethatitnowhasanidattribute.ThisissothatyoucaneasilyfindtheelementinthedocumentwiththegetElementById()method.

Next,youdefinethefunctionlinkClick(),muchasyoudidpreviously.Asbefore,youcanreturnavalueindicatingwhetheryouwantthenormalactionofthatobjecttohappen.

Theconnectionismadebetweentheobject’seventandthefunctiononthefinallinesofscript,asshowninthefollowingcode:

document.getElementById("someLink").onclick=linkClick;

Asyoulearnedinthepreviouschapter,thegetElementById()methodfindstheelementwiththegivenidandreturnstheaobject.Yousetthisobject’sonclickpropertytoreferenceyourfunction—thismakestheconnectionbetweentheobject’seventhandlerandyourfunction.Notethatnoparenthesesareaddedafterthefunctionname.YouareassigningthelinkClickfunctionobjecttotheelement’sonclickproperty,notexecutinglinkClick()andassigningitsreturnvaluetoonclick.

Takeamomentandlookbackatch10_example2.html.Whenyoulistenedfortheclickeventusingtheonclickattribute,youhadcompletecontroloverhowchangeImg()wascalled;yousimplycalledthefunctionandpassedittheeventobject.

Butthat’snowanissue.Lookagainattheonclickpropertyassignment:

document.getElementById("someLink").onclick=linkClick;

Younolongercontrolhowtheeventhandlerfunctionisexecuted;thebrowserexecutesthefunctionforyou.HowthendoyouattainareferencetotheEvent?Whenaneventtriggersandaneventhandlerexecutes,thebrowserautomaticallypassesanEventobjecttothehandlerfunction.

TRYITOUTDisplayingRandomImageswithObjectPropertyEventHandlersInthisTryItOut,yourewritech10_example2.htmltousetheonclickpropertyof

theimgobjects.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example4</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<imgid="img1"src="mexico.gif"/>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=e.target;

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

document.getElementById("img0").onclick=changeImg;

document.getElementById("img1").onclick=changeImg;

</script>

</body>

</html>

Savethepageasch10_example4.html.Loadthepageintoyourbrowser,andyouwillseeapagesimilartoch10_example2.html.Clickanimage,andyou’llseeitchangetoarandompicture.

Thecodeforthispageisalmostidenticaltoch10_example2.html.Thefirstchangesareinthe<img>tags.Theynolongerhaveonclickattributes,andtheynowhaveidattributes.Thefirstimagehasanidofimg0,andthesecondisimg1.TheseelementshaveanidsothatyoucanreferencetheminyourJavaScriptcode.

TheonlyotherchangesarethefinaltwolinesofJavaScriptcode:

document.getElementById("img0").onclick=changeImg;

document.getElementById("img1").onclick=changeImg;

Youusedocument.getElementById()toretrievethetwoimgobjectsfromtheDOMandassigntheironclickproperties,thussettingupthechangeImg()functionstohandletheclickeventsonbothimgobjects.

Removinganeventhandlerisrathertrivial.Simplyassignnulltotheeventhandlerproperty,likethis:

img1.onclick=null;

Byassigningnull,youhaveoverwrittenthepreviousvaluecontainedbytheproperty,andthatintroducesthemainproblemwiththesetypesofeventhandlers:youcanassignonlyonefunctiontohandleagivenevent.Forexample:

img2.onclick=functionOne;

img2.onclick=functionTwo;

ThefirstlineofthiscodeassignsafunctioncalledfunctionOne()toanelement’sonclickproperty.Thesecondline,however,overwritesthevalueofimg2.onclickbyassigningitanewvalue.So,whentheuserclicksimg2,onlyfunctionTwo()executes.Thatbehaviorisfineifit’swhatyouactuallywant,butmoreoftenthannot,youwantbothfunctionOne()andfunctionTwo()toexecutewhenimg2isclicked.

YoucandothatthankstothestandardDOMeventmodel.

THESTANDARDEVENTMODELUpuntilthispoint,you’vebeenworkingwithnonstandardtechniquesforlisteningforevents.Yes,theyworkineverybrowser,butthatsupportexistsprimarilyforbackwardcompatibility.Theyarenotguaranteedtoworkinfuturebrowserversions.

First,somehistory.Thetwomajorbrowsersinthelate1990swereInternetExplorer4andNetscape4—thefirstbrowserwar.Notsurprisingly,bothbrowservendorsimplementedvastlydifferentDOMsandeventmodels,fragmentingthewebintotwogroups:websitesthatcateredtoNetscapeonly,andwebsitesthatcateredtoIEonly.Veryfewdeveloperschosethefrustratingtaskofcross-browserdevelopment.

Obviously,aneedforastandardgrewfromthisfragmentationandfrustration.SotheW3CintroducedtheDOMstandard,whichgrewintoDOMlevel2,whichincludedastandardeventmodel.

TheDOMstandarddefinesanobjectcalledEventTarget.Itspurposeistodefineastandardwayofaddingandremovinglistenersforaneventonthetarget.EveryelementnodeintheDOMisanEventTarget,andassuch,youcandynamicallyaddandremoveeventlistenersforagivenelement.

ThestandardalsodescribesanEventobjectthatprovidesinformationabouttheelementthathasgeneratedaneventandenablesyoutoretrieveitinscript.Itprovidesasetofguidelinesforastandardwayofdeterminingwhatgeneratedanevent,whattypeofeventitwas,andwhenandwheretheeventoccurred.Ifyouwanttomakeitavailableinscript,itmustbepassedasaparametertothefunctionconnectedtotheeventhandler.

NOTEOlderversionsofInternetExplorer(8andbelow)donotimplementtheDOMeventmodel.Thecodeinthissectiononlyworkswithmodernbrowsers:IE9+,Chrome,Firefox,Opera,andSafari.

ConnectingCodetoEvents—TheStandardWayTheEventTargetobjectdefinestwomethodsforaddingandremovingeventlisteners(rememberthatanEventTargetisanelement).Thefirstmethod,addEventListener(),registersaneventlisteneronthetargetonwhichit’scalled.Youcallitonatarget/elementobject,asyouseeinthefollowingexample.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10,Example5</title>

</head>

<body>

<aid="someLink"href="somepage.html">

ClickMe

</a>

<script>

varlink=document.getElementById("someLink");

link.addEventListener("click",function(e){

alert("Thislinkisgoingnowhere");

e.preventDefault();

});

</script>

</body>

</html>

Savethisasch10_example5.html.Thisisare-creationofch10_example3.html,butitusesthestandardeventmodelapplicationprogramminginterface(API),whichisasetofobjects,properties,andmethods,toregisteraneventlistenerandpreventthedefaultactionofalinkfromoccurring.

ThefirstlineofJavaScriptretrievestheelementthathasanidofsomeLink,andstoresitinthelinkvariable.YouthencalltheaddEventListener()methodandpassittwoarguments.Thefirstisthenameoftheeventwithoutthe"on"prefix.Inthisexample,aneventlistenerisregisteredfortheclickevent.

Thesecondargumentisthefunctionthatexecuteswhentheeventoccurs.Thepreviouscodeusesananonymousfunction,acommonpatternthatyou’llseeveryoften,butit’smoreusefultopassadeclaredfunction,likethis:

functionlinkClick(){

alert("Thislinkisgoingnowhere");

e.preventDefault();

}

link.addEventListener("click",linkClick);

Usingadeclaredfunctionletsyoureuseitformultipleeventlisteners,asyouseeinthenextexercise.Butfirst,noticethatlinkClick()nolongerreturnsfalse;instead,itcallsthepreventDefault()methodontheEventobject.Thisisthestandardwaythatyoupreventthedefaultactionfromoccurring.

TRYITOUTDisplayingRandomImageswithStandardEventHandlersInthisTryItOut,yourewritech10_example4.htmltousethestandardDOMeventmodel.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example6</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<imgid="img1"src="mexico.gif"/>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=e.target;

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

document.getElementById("img0").addEventListener("click",

changeImg);

document.getElementById("img1").addEventListener("click",

changeImg);

</script>

</body>

</html>

Savethepageasch10_example6.html.Loadthepageintoyourbrowser,andyouwillseethefamiliarpagefromthepreviousexamples.Clickanimage,andyou’llseeitchangetoarandompicture.

Theonlychangesfromch10_example4.htmlarethefinaltwolinesofJavaScript:

document.getElementById("img0").addEventListener("click",changeImg);

document.getElementById("img1").addEventListener("click",changeImg);

Insteadofusingeachelementobject’sonclickproperty,youregistertheclickeventhandlerusingaddEventListener().

UsingadeclaredfunctionisalsousefulbecauseitenablesyoutounregisteraneventlistenerwiththeremoveEventListener()method:

elementObj.removeEventListener("click",elementObjClick);

Whenyouremoveaneventlistener,youmustprovidethesameexactinformationthatyoucalledaddEventListener()with;thisincludesnotonlythesamenameoftheevent,butthesamefunctionobjectthatyoupassedtoaddEventListener().

ThebeautyofthestandardDOMeventmodelisthatyoucanregistermultipleeventlistenersforasingleeventonasingleelement.Thisisextremelyusefulwhenyouneedtolistenforthesameeventonanelementwithdifferentandunrelatedfunctions.Todothis,

simplycalladdEventListener()asmanytimesasyouneedto,likethis:

elementObj.addEventListener("click",handlerOne);

elementObj.addEventListener("click",handlerTwo);

elementObj.addEventListener("click",handlerThree);

ThiscoderegistersthreelistenersfortheclickeventontheelementreferencedbyelementObj.Asyoumaysuspect,theselistenersexecuteintheorderinwhichtheywereregistered.So,whenyouclickelementObj,handlerOne()executesfirst,handlerTwo()executessecond,andhandlerThree()executesthird.

TRYITOUTAddingandRemovingMultipleEventListenersInthisTryItOut,youpracticeregisteringmultipleeventlistenersforasingleelement,andyouremovethoselistenerswhenaconditionismet.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example7</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<divid="status"></div>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=e.target;

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

functionupdateStatus(e){

varel=e.target;

varstatus=document.getElementById("status");

status.innerHTML="Theimagechangedto"+el.src;

if(el.src.indexOf("mexico")>-1){

el.removeEventListener("click",changeImg);

el.removeEventListener("click",updateStatus);

}

}

varimgObj=document.getElementById("img0");

imgObj.addEventListener("click",changeImg);

imgObj.addEventListener("click",updateStatus);

</script>

</body>

</html>

Savethepageasch10_example7.html.Loadthepageintoyourbrowser,andyouwillseeapagewithasingleimage.Clicktheimage,anditwillchangetoarandompicture.You’llalsoseethetextofthe<div/>elementchangetocontaintheURLofthenewpicture,asshowninFigure10.2.

Figure10.2

Thiscodeisreminiscentofthepastfewexamples;so,let’sjustfocusonwhat’sdifferent.First,theHTML:

<imgid="img0"src="usa.gif"/>

<divid="status"></div>

Insteadoftwoimageelements,thisHTMLdefinesasingle<img/>elementwithanidofimg0anda<div/>elementwhoseidisstatus.Thecontentsofthe<div/>elementwillchangewhentheuserclickstheimage.

There’sanewfunctioncalledupdateStatus(),anditspurposeistoupdatethetextinside<divid="status"/>.Thefirsttwolinesofthisfunctionacquirereferencesto

theeventtarget(theimage)and<div/>element:

functionupdateStatus(e){

varel=e.target;

varstatus=document.getElementById("status");

Thenextlineofcodechangesthetextofthestatuselement:

status.innerHTML="Theimagechangedto"+el.src;

ElementobjectshaveaninnerHTMLpropertythatletsyousetthecontentsoftheelementtowhatevervalueyouassigntoit.Inthiscode,youchangethe<div/>element’scontentstocontaintheURLofthepicturecurrentlydisplayedinthebrowser.

Toaddsomevariety,thenextfewlinesofcoderemovetheimage’sclickeventlistenersiftheMexicoflagisdisplayedinthebrowser:

if(el.src.indexOf("mexico")>-1){

el.removeEventListener("click",changeImg);

el.removeEventListener("click",updateStatus);

}

}

TheifstatementusestheindexOf()methodontheimage’ssrctodetermineiftheMexicoflagiscurrentlydisplayed.Ifso,youremovetheimage’stwoeventlistenersusingtheremoveEventListener()method.Wehaveyettodiscussthecodeforregisteringtheseclickeventlisteners,butyoupassthesameinformationtoremoveEventListener()thatyoupasstoaddEventListener().Ifyoudon’t,youwon’tremovetheeventlisteners.

Thefinallinesofcodesetuptheeventlisteners:

varimgObj=document.getElementById("img0");

imgObj.addEventListener("click",changeImg);

imgObj.addEventListener("click",updateStatus);

Thefirstlineretrievesthe<imgid="img0"/>element,andyouregistertheclickeventhandlersbycallingaddEventListener()andpassingclickfortheeventandthetwofunctions,changeImg()andupdateStatus(),respectively.

It’simportanttorememberthatwhenyouregistermultipleeventhandlersonasingleelement,thelisteningfunctionsexecuteintheorderinwhichyouregisteredthem.Inthisexample,youregisteredalistenerwithchangeImg()beforealistenerwithupdateStatus().ThisisidealbecauseyouwantthestatustodisplaytheURLoftheimageafteryouchangeit.IfyouhadregisteredupdateStatus()beforechangeImg(),thestatuswouldupdatebeforetheimage,thusdisplayingincorrectinformation.

UsingEventDataThestandardoutlinesseveralpropertiesoftheEventobjectthatofferinformationabout

thatevent:whatelementithappenedat,whattypeofeventtookplace,andwhattimeitoccurred.TheseareallpiecesofdataofferedbytheEventobject.Thefollowingtableliststhepropertiesoutlinedinthespecification.

PROPERTIESOFTHEEVENTOBJECT

DESCRIPTION

bubbles Indicateswhetheraneventcanbubble—passingcontrolfromoneelementtoanotherstartingfromtheeventtargetandbubblingupthehierarchy

cancelable IndicateswhetheraneventcanhaveitsdefaultactioncanceledcurrentTarget Identifiesthecurrenttargetfortheeventastheeventtraversesthe

DOMdefaultPrevented IndicateswhetherornotpreventDefault()hasbeencalledonthe

eventeventPhase Indicateswhichphaseoftheeventflowaneventisintarget Indicateswhichelementcausedtheevent;intheDOMevent

model,textnodesareapossibletargetofaneventtimestamp Indicatesatwhattimetheeventoccurredtype Indicatesthenameoftheevent

Secondly,theDOMeventmodelintroducesaMouseEventobject,whichdealswitheventsgeneratedspecificallybythemouse.Thisisusefulbecauseyoumightneedmorespecificinformationabouttheevent,suchasthepositioninpixelsofthecursor,ortheelementthemousehascomefrom.ThefollowingtablelistssomeoftheMouseEventobject’sproperties:

PROPERTIESOFTHEMOUSEEVENTOBJECT

DESCRIPTION

altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated

button IndicateswhichbuttononthemousewaspressedclientX Indicateswhereinthebrowserwindow,inhorizontalcoordinates,the

mousepointerwaswhentheeventwasgeneratedclientY Indicateswhereinthebrowserwindow,inverticalcoordinates,the

mousepointerwaswhentheeventwasgeneratedctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwas

generatedmetaKey Indicateswhetherthemetakeywaspressedwhentheeventwas

generatedrelatedTarget Usedtoidentifyasecondaryeventtarget.Formouseoverevents,this

propertyreferencestheelementatwhichthemousepointerexited.Formouseoutevents,thispropertyreferencestheelementatwhichthemousepointerentered

screenX IndicatesthehorizontalcoordinatesrelativetotheorigininthescreenscreenY IndicatestheverticalcoordinatesrelativetotheorigininthescreenshiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwas

generated

AlthoughanyeventmightcreateanEventobject,onlyaselectsetofeventscangenerateaMouseEventobject.OntheoccurrenceofaMouseEventevent,you’dbeabletoaccesspropertiesfromtheEventobjectandtheMouseEventobject.Withanon-mouseevent,noneoftheMouseEventobjectpropertiesintheprecedingtablewouldbeavailable.ThefollowingmouseeventscancreateaMouseEventobject:

clickoccurswhenamousebuttonisclicked(pressedandreleased)withthepointeroveranelementortext.

mousedownoccurswhenamousebuttonispressedwiththepointeroveranelementortext.

mouseupoccurswhenamousebuttonisreleasedwiththepointeroveranelementortext.

mouseoveroccurswhenamousebuttonismovedontoanelementortext.

mousemoveoccurswhenamousebuttonismovedanditisalreadyontopofanelementortext.

mouseoutoccurswhenamousebuttonismovedoutandawayfromanelementortext.

UnlikeMouseEvent,thecurrentDOMspecificationdoesnotdefineaKeyboardEventobjectforkeyboard-relatedevents(althoughonewillbedefinedinthenextversion,DOMlevel3).Youcan,however,stillaccessinformationaboutkeyboard-relatedeventswiththepropertieslistedinthefollowingtable.

PROPERTIESOFTHEKEYBOARDEVENTOBJECT

DESCRIPTION

altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated

charCode Usedforthekeypressevent.TheUnicodereferencenumberofthekey

ctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwasgenerated

keyCode Asystem-andbrowser-dependentnumericalcodeidentifyingthepressedkey

metaKey Indicateswhetherthemetakeywaspressedwhentheeventwasgenerated

shiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwasgenerated

TRYITOUTUsingtheDOMEventModelInthisTryItOut,youtakeaquicklookatanexamplethatusessomepropertiesoftheMouseEventobject.

Openatexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example8</title>

<style>

.underline{

color:red;

text-decoration:underline;

}

</style>

</head>

<body>

<p>Thisisparagraph1.</p>

<p>Thisisparagraph2.</p>

<p>Thisisparagraph3.</p>

<script>

functionhandleEvent(e){

vartarget=e.target;

vartype=e.type;

if(target.tagName=="P"){

if(type=="mouseover"){

target.className="underline";

}elseif(type=="mouseout"){

target.className="";

}

}

if(type=="click"){

alert("YouclickedthemousebuttonattheX:"

+e.clientX+"andY:"+e.clientY+"

coordinates");

}

}

document.addEventListener("mouseover",handleEvent);

document.addEventListener("mouseout",handleEvent);

document.addEventListener("click",handleEvent);

</script>

</body>

</html>

Savethisasch10_example8.htmlandrunitinyourbrowser.Whenyoumoveyourmouseoveroneoftheparagraphs,you’llnoticeitstextchangescolortoredanditbecomesunderlined.Clickanywhereinthepage,andyou’llseeanalertboxlikeFigure10.3.

Figure10.3

NowclickOK,movethepointerinthebrowserwindow,andclickagain.Adifferentresultappears.

Thisexampleisconsistentwiththeevent-handlingbehavior:Thebrowserwaitsforanevent,andeverytimethateventoccursitcallsthecorrespondingfunction.Itwillcontinuetowaitfortheeventuntilyouexitthebrowserorthatparticularwebpage.Inthisexample,youassigneventhandlersforthemouseover,mouseout,andclick

eventsonthedocumentobject:

document.addEventListener("mouseover",handleEvent);

document.addEventListener("mouseout",handleEvent);

document.addEventListener("click",handleEvent);

Onefunction,handleEvent(),handlesallthreeoftheseevents.

Wheneveranyoftheseeventsfire,thehandleClick()functionisraisedandanewMouseEventobjectisgenerated.RememberthatMouseEventobjectsgiveyouaccesstoEventobjectpropertiesaswellasMouseEventobjectproperties,andyouusesomeoftheminthisexample.

ThefunctionacceptstheMouseEventobjectandassignsitthereferencee:

functionhandleEvent(e){

vartarget=e.target;

vartype=e.type;

if(target.tagName=="P"){

Insidethefunction,thefirstthingyoudoisinitializethetargetandtypevariableswiththetargetandtypeeventproperties,respectively.Theseareconveniencevariablestomakeaccessingthatinformationeasier.Youthencheckiftheeventtarget(theelementthatcausedtheevent)hasatagNameofP.Ifthetargetisaparagraphelement,thenextbitofinformationyouneedtofindiswhatkindofeventtookplacebyusingthetypevariable:

if(type=="mouseover"){

target.className="underline";

}elseif(type=="mouseout"){

target.className="";

}

}

Iftheeventisamouseover,theparagraph’sCSSclassisassignedtheunderlineclassdefinedinthepage’sstylesheet.Iftheeventtypeismouseout,theelement’sclassNamepropertyiscleared,whichreturnsthetexttoitsoriginalstyle.Thisstyle-changingcoderunsonlyiftheelementthatcausedtheeventisaparagraphelement.

Next,thefunctiondeterminesiftheuserclickedhismousebyagaincheckingthetypevariable:

if(type=="click"){

alert("YouclickedthemousebuttonattheX:"

+e.clientX+"andY:"+e.clientY+"coordinates");

}

Iftheuserdidindeedclicksomewhereinthepage,youusethealert()methodtodisplaythecontentsoftheclientXandclientYpropertiesoftheMouseEventobjectonthescreen.

TheMouseEventobjectsuppliedtothisfunctionisoverwrittenandre-createdeverytimeyougenerateanevent,sothenexttimeyouclickthemouseormovethepointer,

itcreatesanewMouseEventobjectcontainingthecoordinatesforthexandypositionsandtheinformationontheelementthatcausedtheeventtofire.

Let’slookatanotherexample.

TRYITOUTACrudeTabStripInthisTryItOut,youwillwriteafunctional,yetflawed,tabstripusingthemouseover,mouseout,andclickevents.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example9</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<script>

functionhandleEvent(e){

vartarget=e.target;

switch(e.type){

case"mouseover":

if(target.className=="tabStrip-tab"){

target.className="tabStrip-tab-hover";

}

break;

case"mouseout":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab";

}

break;

case"click":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab-click";

varnum=target.getAttribute("data-tab-

number");

showDescription(num);

}

break;

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

descContainer.innerHTML=text;

}

document.addEventListener("mouseover",handleEvent);

document.addEventListener("mouseout",handleEvent);

document.addEventListener("click",handleEvent);

</script>

</body>

</html>

Savethisfileasch10_example9.html.Openitinyourbrowser,andwhenyoumoveyourmousepointeroveratab,itsstylechangestoabluebackgroundwithadarkerblueborder.Whenyouclickatab,itsstylechangesyetagaintomakethetab’sbackgroundcoloralightorangewithadarkerorangebordercolor.Also,whenyouclickatab,textisaddedtothepage.Forexample,clickingtab3resultsinthetext“DescriptionforTab3”beingaddedtothepage.

TakealookattheHTMLinthebody,anditsstyle,first:

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

Thefirst<div/>elementhasaCSSclassoftabStrip.Thethree<div/>elementscontainedwithinitrepresentthreetabs.Eachtab<div/>elementhasanumericvalueassignedtoitsdata-tab-numberattribute,andaCSSclassoftabStrip-tab.

Thetabstrip<div/>elementhasasibling<div/>elementwithanidvalueofdescContainer.Itdoesn’tcontainanychildren,anditdoesn’thaveaCSSclassassociatedwithit.

Inthisexample,thetabstripisvisuallysetapartfromtherestofthepagebygivingitagraybackground:

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

It’sgivenanactualheightof28pixels(height+toppadding+bottompadding).Thisheightandpaddingverticallycentersthetab<div/>elementswithinthetabstrip.

ThetabshaveseveralCSSrulestodefinethewaytheyarerenderedinthebrowserbecausetheyhavethreestates:normal,hover,andclick.Despitethesethreestates,theyarestilltabsandthussharesomevisualcharacteristics.Thefirstruledictatesthesesharedproperties:

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

Theselectortellsthebrowsertoapplythesepropertiestoall<div/>elementsinsidethetabstrip.Theelementsaresettofloatlefttogivethemaninlineappearance(<div/>elementsareblockelements,andappearonanewlinebydefault).

Thenextrule,thetabStrip-tabclass,definesthenormalstate:

.tabStrip-tab{

padding:3px;

}

Allthisruleaddsisapaddingofthreepixelsonallsidesoftheelement.Nextisthehoverstate,asdefinedbythetabStrip-tab-hoverclass:

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

Thisrulereducesthepaddingtotwopixels,addsaone-pixel-wideborder,andchangesthebackgroundcolortoashadeofblue.Borders,likepadding,addtothe

actualdimensionsofanelement;reducingthepaddingwhileaddingaborderkeepstheelementinahoverstate,thesameheightandwidthasitwasinthenormalstate.

ThefinalruledeclaresthetabStrip-tab-clickclass:

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

Thisclassissimilartothehoverclass;theonlydifferenceisthedarkorangebordercolorandlightorangebackgroundcolor.

Nowlet’slookattheJavaScriptcodethatperformsthemagic.ThecodeconsistsofthehandleEvent()function,whichisregisteredasthedocumentobject’smouseover,mouseout,andclickeventlisteners:

document.addEventListener("mouseover",handleEvent);

document.addEventListener("mouseout",handleEvent);

document.addEventListener("click",handleEvent);

Thefunctionbeginsbydeclaringavariablecalledtarget,whichisinitializedwiththeeventobject’stargetproperty:

functionhandleEvent(e){

vartarget=e.target;

NowyouneedtodeterminewhattypeofeventtookplaceandmaketheappropriatechangestotheDOM.Aswitchstatementworkswellhere,andyouusetheeventobject’stypepropertyastheswitchexpression:

switch(e.type){

case"mouseover":

if(target.className=="tabStrip-tab"){

target.className="tabStrip-tab-hover";

}

break;

First,checkforthemouseoverevent.IftheelementthatcausedtheeventhasaclassnameoftabStrip-tab,atabinitsnormalstate,changetheelement’sclassNamepropertytotabStrip-tab-hover.Indoingso,thetabisnowinthehoverstate.

Ifamouseouteventoccurred,youalsoneedtomakechangestotheDOM:

case"mouseout":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab";

}

break;

Thiscodechangesthetab’sclassNamepropertytotabStrip-tab(thenormalstate)onlywhenthetabinwhichthemousepointerexitedisinthehoverstate.

Thelasteventyouneedtolookforistheclickevent,socheckforitnowwiththe

followingcode:

case"click":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab-click";

Thiscodechangesthetabelement’sclassNametotabStrip-tab-click,thusputtingitintotheclickstate.

Next,youneedtoaddthetab’sdescriptiontothepage,andyoustartthisprocessbygettingthetab’snumberfromthe<div/>element’sdata-tab-numberattribute.YouusethegetAttribute()methodtoretrievethisvalue:

varnum=target.getAttribute("data-tab-number");

showDescription(num);

}

break;

}

}

Nowthatyouhavethetab’snumber,youpassittotheshowDescription()function:

functionshowDescription(num){

vardescContainer=document.getElementById("descContainer");

Thetabs’descriptionsareaddedtothe<div/>elementwithanidofdescContainer,soasthiscodeshows,youfirstretrievethatelementusingthegetElementById()method.

Thedescriptionsaredynamicallycreatedbythisfunction,sonowyouneedtobuildthedescriptiontextanddisplaythattextinthedescContainerelement.First,createastringcontainingthedescriptionforthetab.Inthisexample,thedescriptionissimpleandincludesthetab’snumber:

vartext="DescriptionforTab"+num;

ThenaddthetexttothedescriptionelementbyusingitsinnerHTMLproperty:

descContainer.innerHTML=text;

}

Oneproblemthathasplaguedthewebisthelackofcompatibilitybetweenthemajorbrowsers.Today’smodernbrowsersdoaverygoodjobofimplementingthestandardDOM,butolderbrowsers,specificallyIE8andbelow,onlypartiallysupporttheDOMstandard.DespitethelackofsupportfortheDOMstandardintheseoldbrowsers,youcanstillacquirethesameusefulinformationonagiveneventwithold-IE’seventmodel.

EVENTHANDLINGINOLDVERSIONSOFINTERNETEXPLOREROld-IE’seventmodelincorporatestheuseofaglobaleventobject(itisapropertyofthewindowobject),andonesuchobjectexistsforeachopenbrowserwindow.Thebrowserupdatestheeventobjecteverytimetheusercausesaneventtooccur,anditprovidesinformationsimilartothatofthestandardDOMEventobject.

NOTETobeclear,theinformationinthissectionappliestoIE8andbelow.Wewillrefertotheseoldbrowsersas“old-IE.”IE9andlaterimplementthestandardDOMeventmodel.Thankfully,old-IE’susagecontinuestodwindlewitheachpassingyear.

AccessingtheeventObjectBecausetheeventobjectisapropertyofwindow,itisverysimpletoaccess:

<pondblclick="handle()">Paragraph</p>

<script>

functionhandle(){

alert(event.type);

}

</script>

Thiscodeassignsthehandle()functiontohandlethe<p/>element’sdblclickevent.Whenthefunctionexecutes,itgetsthetypeofeventthatcausedthehandle()function’sexecution.Becausetheeventobjectisglobal,thereisnoneedtopasstheobjecttothehandlingfunctionliketheDOMeventmodel.Alsonotethatlikeotherpropertiesofthewindowobject,it’snotrequiredthatyouprecedetheeventobjectwithwindow.

NOTEEventhoughyoudon’thavetopasseventtoaneventhandler,youstillwanttodosoinordertosupportbothold-IEandmodernbrowsers.

ThesameholdstruewhenyouassigneventhandlersthroughJavaScriptusingobjectproperties:

<pid="p">Paragraph</p>

<h1id="h1">Heading1</h1>

<spanid="span">SpecialText</span>

<script>

functionhandle(){

if(event.type=="mouseover"){

alert("YoumovedovertheSpecialText");

}

}

document.getElementById("p").ondblclick=handle;

document.getElementById("h1").onclick=handle;

document.getElementById("span").onmouseover=handle;

</script>

Old-IEdoesnotsupportaddEventListener()andremoveEventListener(),butitdoesimplementtwosimilarmethods:attachEvent()anddetachEvent().RewriteExample5usingold-IE’seventAPI:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10,Example10</title>

</head>

<body>

<aid="someLink"href="somepage.html">

ClickMe

</a>

<script>

varlink=document.getElementById("someLink");

functionlinkClick(e){

alert("Thislinkisgoingnowhere");

e.returnValue=false;

}

link.attachEvent("onclick",linkClick);

</script>

</body>

</html>

Savethisasch10_example10.html.

Let’sfirstlookatthecalltoattachEvent().TheoverallpatternisthesameasaddEventListener()(andthusremoveEventListener());youpasstheeventyouwanttolistenforandthefunctiontoexecutewhentheeventoccurs.Butasyou’llnoticefromthiscode,theeventnamesareprefixedwith“on”.

Thesecondargumentisthefunctionthatexecuteswhentheeventoccurs.Notice,though,thatthelinkClick()functiondefinesaparametercallede.WhenyouregisteraneventhandlerwithattachEvent(),old-IEpassestheeventobjecttothehandlingfunction.

AlsonoticethatlinkClick()doesnotreturnfalseorcallpreventDefault().Instead,old-IE’seventobjecthasapropertycalledreturnValue,andsettingittofalseachievesthesameresult.

UsingEventDataUnsurprisingly,IE’seventobjectprovidessomedifferentpropertiesfromtheDOMstandard’sEventandMouseEventobjects,althoughtheytypicallyprovideyouwithsimilardata.

ThefollowingtablelistssomeofthepropertiesofIE’seventobject.

PROPERTIESOFTHEEVENTOBJECT

DESCRIPTION

altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated

button IndicateswhichbuttononthemousewaspressedcancelBubble Getsorsetswhetherthecurrenteventshouldbubbleupthehierarchy

ofeventhandlersclientX Indicateswhereinthebrowserwindow,inhorizontalcoordinates,the

mousepointerwaswhentheeventwasgeneratedclientY Indicateswhereinthebrowserwindow,inverticalcoordinates,the

mousepointerwaswhentheeventwasgeneratedctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwas

generatedfromElement GetstheelementobjectthemousepointerisexitingkeyCode GetstheUnicodekeycodeassociatedwiththekeythatcausedthe

eventreturnValue GetsorsetsthereturnvaluefromtheeventscreenX Indicateswhereinthebrowserwindow,inhorizontalcoordinates

relativetotheorigininthescreencoordinates,themousepointerwaswhentheeventwasgenerated

screenY Indicateswhereinthebrowserwindow,inverticalcoordinatesrelativetotheorigininthescreencoordinates,themousepointerwaswhentheeventwasgenerated

shiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwasgenerated

srcElement GetstheelementobjectthatcausedtheeventtoElement Getstheelementobjectthatthemousepointerisenteringtype Retrievestheevent’sname

Let’srevisitsomepreviousexamplesandmakethemworkexclusivelyinold-IE.

TRYITOUTAddingandRemovingMultipleEventHandlersinOld-IEInthisTryItOut,yourewritech10_example7.htmltouseold-IE’sattachEvent()anddetachEvent()methods.Typeinthefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example11</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<divid="status"></div>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=e.srcElement;

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

functionupdateStatus(e){

varel=e.srcElement;

varstatus=document.getElementById("status");

status.innerHTML="Theimagechangedto"+el.src;

if(el.src.indexOf("mexico")>-1){

el.detachEvent("onclick",changeImg);

el.detachEvent("onclick",updateStatus);

}

}

varimgObj=document.getElementById("img0");

imgObj.attachEvent("onclick",updateStatus);

imgObj.attachEvent("onclick",changeImg);

</script>

</body>

</html>

Savethepageasch10_example11.html.Loadthepageintoyourbrowser,andyouwillseeitbehavelikech10_example7.html.Clickingtheimageresultsinitchangingtoarandompicture,andthetextofthe<div/>elementchangestocontaintheURLofthenewpicture.

Let’sjumprighttothecode,whichismostlythesameasch10_example7.html.Thefirstbigdifferenceishowyouregistertheeventhandlersfortheimageobject.Instead

ofusingaddEventListener(),youuseold-IE’sattachEvent()method:

imgObj.attachEvent("onclick",updateStatus);

imgObj.attachEvent("onclick",changeImg);

Butthere’sanotherbigdifferencehere.UnlikethestandardaddEventListener(),thehandlersregisteredwithattachEvent()executeinreverseorder.So,youregisterthehandlerwiththeupdateStatus()functionbeforeregisteringwithchangeImg().

ThenextchangeisinthefirststatementofthechangeImg()function.Youwanttoretrievetheelementthatreceivedtheevent,andold-IE’seventobjectgivesyouthatinformationwiththesrcElementproperty:

functionchangeImg(e){

varel=e.srcElement;

Therestofthefunctionisleftunchanged.

YouwanttodothesamethingintheupdateStatus()function,soyouchangethefirststatementtouseold-IE’ssrcElementpropertyaswell:

functionupdateStatus(e){

varel=e.srcElement;

AfteryouretrievethestatuselementandsetitsinnerHTML,youthenwanttoremovetheeventhandlersiftheMexicoflagisdisplayed.YoudothiswiththedetachEvent()method:

if(el.src.indexOf("mexico")>-1){

el.detachEvent("onclick",changeImg);

el.detachEvent("onclick",updateStatus);

}

Here,theorderinwhichyoucalldetachEvent()doesn’tmatter.Itwillsimplyremovetheeventhandlerfromtheelement.

Next,yourewriteExample8touseold-IE’seventmodel.

TRYITOUTUsingtheIEEventModelInthisTryItOut,youusetheold-IE’seventmodel.Openyourtexteditorandtypethefollowing.Feelfreetocopyandpastetheelementswithinthebodyandthestylesheetfromch10_example8.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example12</title>

<style>

.underline{

color:red;

text-decoration:underline;

}

</style>

</head>

<body>

<p>Thisisparagraph1.</p>

<p>Thisisparagraph2.</p>

<p>Thisisparagraph3.</p>

<script>

functionhandleEvent(e){

vartarget=e.srcElement;

vartype=e.type;

if(target.tagName=="P"){

if(type=="mouseover"){

target.className="underline";

}elseif(type=="mouseout"){

target.className="";

}

}

if(type=="click"){

alert("YouclickedthemousebuttonattheX:"

+e.clientX+"andY:"+e.clientY+"

coordinates");

}

}

document.attachEvent("onmouseover",handleEvent);

document.attachEvent("onmouseout",handleEvent);

document.attachEvent("onclick",handleEvent);

</script>

</body>

</html>

Savethisasch10_example12.html,andloaditintoold-IE.It’lllookandbehaveexactlylikeExample8;theparagraphtextwillchangetoredandhaveanunderlineasyoumoveyourmousepointerovertheparagraphs.Whenyourmousepointerleavesaparagraph,thetextreturnstotheoriginalstate.Whenyouclickyourmouse,analertboxtellsyouthecoordinatesofwhereyourmousepointerwaswhenyouclicked.

YouassignthehandleEvent()functiontohandlethemouseover,mouseout,andclickeventsonthedocumentobject:

document.attachEvent("onmouseover",handleEvent);

document.attachEvent("onmouseout",handleEvent);

document.attachEvent("onclick",handleEvent);

Whenyoucauseanyoftheseeventstofire,thebrowserupdatestheeventobjectandcallsthehandleEvent()function:

functionhandleEvent(e){

vartarget=e.srcElement;

vartype=e.type;

First,youwanttogetthetargetoftheevent(orinold-IEspeak,thesourceelement),soinitializethetargetvariablewiththeeventobject’ssrcElementpropertyandthetypevariablewiththeeventobject’stypeproperty.

Next,youcheckiftheeventtargethasatagNameofP.Ifso,youdeterminewhatkindofeventtookplacebyusingthetypevariable:

if(target.tagName=="P"){

if(type=="mouseover"){

target.className="underline";

}elseif(type=="mouseout"){

target.className="";

}

}

Formouseoverevents,youchangetheparagraph’sCSSclasstounderline.Iftheeventtypeismouseout,theelement’sclassNamepropertyissettoanemptystring—returningthetexttoitsoriginalstyle.

Beforemovingon,noticethenameoftheseevents:mouseoverandmouseout.LikethestandardDOM,old-IE’stypepropertyreturnsthenameoftheeventwithoutthe"on"prefix.Soeventhoughyouregistertheeventhandlerswithonmouseover,onmouseout,andonclick,thetypepropertywillreturnmouseover,mouseout,andclick,respectively.

Thenextbitofcodedisplaysthemousepointer’slocationifthemousebuttonwasclicked:

if(type=="click"){

alert("YouclickedthemousebuttonattheX:"

+e.clientX+"andY:"+e.clientY+"coordinates");

}

}

IfyoucompareExample8withExample12,youwillnoticethetwoprimarydifferencesarehowtheeventhandlersareregistered,andhowtoretrievetheelementthatcausedtheeventtooccur.MosteverythingelseissharedbetweenthestandardDOMeventmodelandIE’seventmodel.

Nowlet’slookatExample9throughtheprismofold-IE.

TRYITOUTACrudeTabStripforOld-IEInthisTryItOut,youwillrewritech10_example9.htmltouseold-IE’seventmodel.Openyourtexteditorandtypethefollowing,oryoucancopych10_example9.htmlandchangethehighlightedlinesofcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example13</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<script>

functionhandleEvent(e){

vartarget=e.srcElement;

switch(e.type){

case"mouseover":

if(target.className=="tabStrip-tab"){

target.className="tabStrip-tab-hover";

}

break;

case"mouseout":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab";

}

break;

case"click":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab-click";

varnum=target.getAttribute("data-tab-

number");

showDescription(num);

}

break;

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

descContainer.innerHTML=text;

}

document.attachEvent("onmouseover",handleEvent);

document.attachEvent("onmouseout",handleEvent);

document.attachEvent("onclick",handleEvent);

</script>

</body>

</html>

Savethisfileasch10_example13.html.Openitinyourbrowser,andyou’llseeitworkexactlylikech10_example9.html.Whenyoumoveyourmousepointeroveratab,itsstylechangestoabluebackgroundwithadarkerblueborder.Whenyouclickatab,itsstylechangesyetagainandaddsthetab’sdescriptiontothepage.

Fourthingsaredifferentinthisversionofthetabscript.Thefirstthreearehowyouregistertheeventhandlers:

document.attachEvent("onmouseover",handleEvent);

document.attachEvent("onmouseout",handleEvent);

document.attachEvent("onclick",handleEvent);

InsteadofusingaddEventListener(),youuseold-IE’sattachEvent()methodtoregistertheeventhandlers.

ThenextandlastmodificationisthefirststatementofhandleEvent():

functionhandleEvent(e){

vartarget=e.srcElement;

Asinthepreviousexamples,youusetheeventobject’ssrcElementpropertytoretrievetheeventtarget.Therestofthefunctionremainsunchanged.

Inthenextsection,youlearnhowtohandlethefundamentaldifferencesbetweenbotheventmodelsandtowritecross-browserDHTMLcode.

WRITINGCROSS-BROWSERCODEBynowyou’vewrittentwoversionsofmultipleexamples:oneforstandards-compliantbrowsersandoneforold-IE.Intherealworld,creatingseparateversionsofwebsitesisrarelyconsideredbestpractice,andit’smuch,mucheasiertowriteacross-browserversionofthewebpage.Inthissection,youusetheknowledgeyou’vegainedoftheDOM,thestandardDOMeventmodel,andold-IE’seventmodeltowritecross-browsercode.

Thetricktocross-browserJavaScriptistocreateaunifiedAPIthathidesthecomplexityofworkingwithdifferentbrowserimplementations.Forexample,toregisteraneweventlistener,youneedtodothreethings:

CheckifthebrowsersupportsthestandardDOMeventmodel.

Ifso,useaddEventListener()

Ifnot,useattachEvent()

Usingthetechniqueoffeaturedetection,whichyoulearnedaboutinChapter8,youcaneasilydetermineifthebrowsersupportsaddEventListener().Simplychecktoseeifitexists,likethis:

if(typeofaddEventListener!="undefined"){

//useaddEventListener()

}else{

//useattachEvent()

}

Whenwritingcross-browserJavaScript,youalwayswanttocheckforstandardscompliancefirstbecausesomebrowsersmaysupportbothoptions.Forexample,IE9andIE10supportbothaddEventListener()andattachEvent().IfyoucheckforattachEvent()insteadofaddEventListener(),likethis:

//wrong!Donotdo!

if(typeofattachEvent!="undefined"){

//useattachEvent

}else{

//useaddEventListener

}

IE9andIE10willuseattachEvent()insteadofaddEventListener().WeknowthatattachEvent()exhibitsdifferentbehaviorthanaddEventListener(),andassuch,wewanttoavoidthatbehaviorasmuchaspossible.Plus,wealwayswanttousestandards-compliantcodebecauseitisguaranteedtoworkineverystandards-compliantbrowser.

ThepreviousexampleusesthetypeofoperatortodetermineiftheaddEventListener()methodisnotundefined,butyoucansimplifythecodebyusingaddEventListenerasatruthyorfalsyvalue,likethis:

if(addEventListener){

//useaddEventListener()

}else{

//useattachEvent()

}

Whetheryouusethetypeofoperatorortruthy/falsyvalues,eitherapproachwillgiveyouthesameresults.Justkeepinmindthatyouwanttobeconsistentasyouwriteyourcode.Ifyouusetypeof,useitforallofyourfeature-detectioncode.

Sowiththisinmind,youcanwriteafunctionlikethis:

functionaddListener(obj,type,fn){

if(obj.addEventListener){

obj.addEventListener(type,fn)

}else{

obj.attachEvent("on"+type,fn);

}

}

Let’sbreakdownthiscode.Here,youdefineafunctioncalledaddListener().Ithasthreeparameters—theobjecttoregistertheeventlisteneron,theeventtype,andthefunctiontoexecutewhentheeventfires:

functionaddListener(obj,type,fn){

ThefirstthingyoudoinsidethisfunctionistocheckifthegivenobjecthasanaddEventListener()method:

if(obj.addEventListener){

obj.addEventListener(type,fn)

}

IfaddEventListener()exists,youcallitandpassthetypeandfnparameterstoit.ButifaddEventListener()doesn’texist,youwanttocallattachEvent():

else{

obj.attachEvent("on"+type,fn);

}

}

Here,youappendontothevaluecontainedwithinthetypevariable.Thisway,youcanpassthestandardnameoftheevent,suchasclick,totheaddListener()function,andit’llworkwithbothstandards-compliantbrowsersandold-IE.

Tousethisfunction,you’dcallitlikethis:

addListener(elementObj,"click",eventHandler);

AssumingelementObjisanelementobjectandeventHandler()isafunction,you’dsuccessfullyregisteraneventlistener/handlerforstandards-compliantbrowsersandold-IE.

FollowingthepatternusedintheaddListener()function,youcanwriteaneventutilityobjectthatmakesiteasiertowritecross-browser,event-drivencode.Aneventutilityobjectshouldprovidethecapabilitytoaddandremovelisteners,aswellasgettheevent

target.

TRYITOUTACross-BrowserEventUtilityInthisTryItOut,youwillwriteautilitytomakeiteasiertowritecross-browsercode.Openyourtexteditorandtypethefollowing:

varevt={

addListener:function(obj,type,fn){

if(obj.addEventListener){

obj.addEventListener(type,fn);

}else{

obj.attachEvent("on"+type,fn);

}

},

removeListener:function(obj,type,fn){

if(obj.removeEventListener){

obj.removeEventListener(type,fn);

}else{

obj.detachEvent("on"+type,fn);

}

},

getTarget:function(e){

if(e.target){

returne.target;

}

returne.srcElement;

},

preventDefault:function(e){

if(e.preventDefault){

e.preventDefault();

}else{

e.returnValue=false;

}

}

};

Saveitasevent-utility.js.

Usingobjectliteralnotation,youcreateanobjectcalledevt.Itspurposeistomakeiteasiertowritecross-browsercode:

varevt={

ThefirstmethodyouwriteistheaddListener()method,anditisexactlythesameastheaddListener()functionyoupreviouslywrote:

addListener:function(obj,type,fn){

if(obj.addEventListener){

obj.addEventListener(type,fn);

}else{

obj.attachEvent("on"+type,fn);

}

},

IfthebrowsersupportsaddEventListener(),itusesthemethodtoregisteraneventlistener.Otherwise,thebrowsercallsattachEvent().

ThenextmethodisremoveListener().Asitsnameimplies,itremovesalistenerthatwasaddedpreviouslytoanobject:

removeListener:function(obj,type,fn){

if(obj.removeEventListener){

obj.removeEventListener(type,fn);

}else{

obj.detachEvent("on"+type,fn);

}

},

ThecodeisalmostidenticaltoaddListener()exceptforafewkeychanges.First,itchecksifthegivenobjecthasaremoveEventListener()method,andifso,itcallsremoveEventListener().Ifnot,itassumesthebrowserisold-IEandcallsdetachEvent().

Thethirdmethod,getTarget(),isresponsibleforgettingtheeventtargetfromtheeventobject:

getTarget:function(e){

if(e.target){

returne.target;

}

returne.srcElement;

}

};

ItfollowsthesamepatternusedinaddListener()andremoveListener();itusesthetargetpropertyasatruthy/falsyvaluetodetermineifthebrowsersupportsthestandardAPI.Iftargetissupported,itisreturned.Otherwise,thefunctionreturnstheelementobjectcontainedwithinsrcElement.

ThefourthandfinalmethodispreventDefault().Thepurposeofthismethodistopreventthedefaultactionoftheeventthattookplace(ifsuchanactionexists).ItfirstchecksforstandardscompliancebydeterminingifthesuppliedeventobjecthasapreventDefault()method.Ifso,itcallsthemethod;otherwise,itsetstheeventobject’sreturnValuetofalse.

Beforemovingon,it’simportanttorealizethatthiseventutilityobjectisbasedonanassumption:Ifthebrowserdoesn’tsupportthestandardeventmodel,itmustbeold-IE.Althoughthisisasafeassumptiontomake,itisnotalways100percentcorrect.Someoldmobilebrowsersdonotsupporteitherthestandardeventmodelorold-IE’seventmodel.However,asWindows,Android,andiOSmobiledevicescontinuetogainmarketshare,theseold,non-compliantmobilebrowsersarevanishingfromthemarket.Inmostcases,it’ssafetoignorethem.

Nowthatyouhaveautilityformakingiteasiertowritecross-browser,event-drivencode,let’srevisitthepreviousexamplesandputittouse.

StartbymodifyingExample10.Here’stherevisedcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10,Example14</title>

</head>

<body>

<aid="someLink"href="somepage.html">

ClickMe

</a>

<scriptsrc="event-utility.js"></script>

<script>

varlink=document.getElementById("someLink");

functionlinkClick(e){

alert("Thislinkisgoingnowhere");

evt.preventDefault(e);

}

evt.addListener(link,"click",linkClick);

</script>

</body>

</html>

Savethisasch10_example14.html.

Thehighlightedlinesofcodearetheonlychanges.First,youincludeevent-utility.js.Thecodeinthisexampleassumesthefileisinthesamedirectoryasch10_example14.html:

<scriptsrc="event-utility.js"></script>

Youthenregistertheeventlistenerusingevt.addListener():

evt.addListener(link,"click",linkClick);

Youpassittheelementobjectyouwanttoregisterthelisteneron,thenameoftheeventyouwanttolistenfor,andthefunctiontoexecutewhentheeventoccurs.

ThefinalchangeisinsidethelinkClick()function.Youwanttopreventthebrowserfromnavigatingtosomepage.html,soyoucallyoureventutility’spreventDefault()methodandpassittheeventobject.Now,whenyouclickthelink,thebrowserwillstayonthesamepage.

TRYITOUTAddingandRemovingMultipleEventHandlersInthisTryItOut,yourewritech10_example11.htmlanduseyoureventutilityobjecttoaddandremoveeventlisteners/handlers.Youcanwriteitfromscratch,oryoucancopyandpastefromch10_example11.html.Thehighlightedlinesindicatewhatchangedinthisexample.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example15</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<divid="status"></div>

<scriptsrc="event-utility.js"></script>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=evt.getTarget(e);

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

functionupdateStatus(e){

varel=evt.getTarget(e);

varstatus=document.getElementById("status");

status.innerHTML="Theimagechangedto"+el.src;

if(el.src.indexOf("mexico")>-1){

evt.removeListener(el,"click",changeImg);

evt.removeListener(el,"click",updateStatus);

}

}

varimgObj=document.getElementById("img0");

evt.addListener(imgObj,"click",changeImg);

evt.addListener(imgObj,"click",updateStatus);

</script>

</body>

</html>

Savethepageasch10_example15.html.Loadthepageintoyourbrowser,andyouwillseeitbehavelikech10_example11.html.Clickingtheimageresultsinitchangingtoarandompicture,andthetextofthe<div/>elementchangestocontaintheURLofthenewpicture.

You’veseenthiscodeafewtimesnow,sothepertinentchangesarehighlighted.First,youwanttoincludeyourevent-utility.jsfile.

Thenextchangeishowyouregistertheeventlistenersfortheimageobject.Usingyoureventutility’saddListener()method,youpassittheimageobject,eventname,andthefunction:

evt.addListener(imgObj,"click",changeImg);

evt.addListener(imgObj,"click",updateStatus);

InthechangeImg()andupdateStatus()functions,youchangetheirfirstlinestoretrievetheeventtargettouseyournewgetTarget()method:

varel=evt.getTarget(e);

TheninsideupdateStatus(),youmodifythecodeinsidetheifstatementtouseyournewremoveListener()method:

if(el.src.indexOf("mexico")>-1){

evt.removeListener(el,"click",changeImg);

evt.removeListener(el,"click",updateStatus);

}

Thereis,however,anissuewiththisnewversion:Inold-IE,theeventlistenersexecuteinreverseorder.Thisisaproblem,butoneyou’llfixattheveryendofthischapter.

Next,yourewriteExample12touseyournewevtobject.

TRYITOUTUsingtheEventModelsofDifferingBrowsersInthisTryItOut,youwillrewritech10_example12.htmlusingyoureventutility.Openyourtexteditorandtypethefollowing.Feelfreetocopyandpastetheelementswithinthebodyandthestylesheetfromch10_example12.html.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example16</title>

<style>

.underline{

color:red;

text-decoration:underline;

}

</style>

</head>

<body>

<p>Thisisparagraph1.</p>

<p>Thisisparagraph2.</p>

<p>Thisisparagraph3.</p>

<scriptsrc="event-utility.js"></script>

<script>

functionhandleEvent(e){

vartarget=evt.getTarget(e);

vartype=e.type;

if(target.tagName=="P"){

if(type=="mouseover"){

target.className="underline";

}elseif(type=="mouseout"){

target.className="";

}

}

if(type=="click"){

alert("YouclickedthemousebuttonattheX:"

+e.clientX+"andY:"+e.clientY+"

coordinates");

}

}

evt.addListener(document,"mouseover",handleEvent);

evt.addListener(document,"mouseout",handleEvent);

evt.addListener(document,"click",handleEvent);

</script>

</body>

</html>

Savethisasch10_example16.html,andloaditintodifferentbrowsers(preferablyastandards-compliantbrowserandold-IE,ifyouhaveaccesstoone).It’lllookandbehaveexactlylikech10_example12.html;theparagraphtextwillchangetoredandhaveanunderlineasyoumoveyourmousepointerovertheparagraphs.Whenyourmousepointerleavesaparagraph,thetextreturnstotheoriginalstate.Whenyouclickyourmouse,analertboxtellsyouthecoordinatesofwhereyourmousepointerwaswhenyouclicked.

Onceagain,themajorityofcodeisleftuntouchedwithonlyfivelinesofcodehavingchanges.First,youwanttoincludetheevent-utility.jsfileusinga<script/>element:

<scriptsrc="event-utility.js"></script>

Next,youregisterthemouseover,mouseout,andclickeventlistenersusingyourevt.addListener()method:

evt.addListener(document,"mouseover",handleEvent);

evt.addListener(document,"mouseout",handleEvent);

evt.addListener(document,"click",handleEvent);

Andfinally,youchangethefirstlineofthehandleEvent()function:

functionhandleEvent(e){

vartarget=evt.getTarget(e);

Insteadofusinganybrowser-specificcode,youuseevt.getTarget()toretrievetheelementobjectthatreceivedtheevent.

Nowlet’slookatch10_example13.htmlandusetheevtobject.

TRYITOUTACrudeTabStripforAllBrowsersInthisTryItOut,youwillrewritech10_example13.htmlusingyourcross-browsereventutility.Openyourtexteditorandtypethefollowing,oryoucancopych10_example13.htmlandchangethehighlightedlinesofcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example17</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="event-utility.js"></script>

<script>

functionhandleEvent(e){

vartarget=evt.getTarget(e);

switch(e.type){

case"mouseover":

if(target.className=="tabStrip-tab"){

target.className="tabStrip-tab-hover";

}

break;

case"mouseout":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab";

}

break;

case"click":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab-click";

varnum=target.getAttribute("data-tab-

number");

showDescription(num);

}

break;

}

}

functionshowDescription(num){

vardescContainer=

document.getElementById("descContainer");

vartext="DescriptionforTab"+num;

descContainer.innerHTML=text;

}

evt.addListener(document,"mouseover",handleEvent);

evt.addListener(document,"mouseout",handleEvent);

evt.addListener(document,"click",handleEvent);

</script>

</body>

</html>

Savethisfileasch10_example17.html.Openitinmultiplebrowsers,andyou’llseeitworkexactlylikeExample13.

Thecodeismostlyunchanged;thisnewversionchangesonlyfivelinesofcode.Aswiththepasttwoexamples,youneedtoincludethefilecontainingyourevtobject:

<scriptsrc="event-utility.js"></script>

Next,youregistertheeventlistenersonthedocumentobjectfortheclick,mouseover,andmouseouteventsusingtheevtobject’saddListener()method:

evt.addListener(document,"mouseover",handleEvent);

evt.addListener(document,"mouseout",handleEvent);

evt.addListener(document,"click",handleEvent);

Andfinally,youchangethefirstlineofthehandleEvent()function:

functionhandleEvent(e){

vartarget=evt.getTarget(e);

Insteadofdirectlyusingthestandardorold-IE’stargetandsrcElementproperties,youuseevt.getTarget()toretrievetheelementobjectthatreceivedtheevent.

Thankfullywitheachpassingyear,theimportanceofcross-browserJavaScriptdiminishesasold-IEcontinuestolosemarketshare.IE8iscurrentlythemostpopularversionofold-IE,andthenumberofpeopleusingthatbrowserisdwindling.Whetherornotyouneedtosupportold-IEisdeterminedbyyourtargetaudience,andonlyyoucandecideifyouneedtoputforththeeffortofsupportingit.

Thepastfewsectionshavebeenratherrepetitive,butunderstandingeventsandhowtheyworkisabsolutelyvitalinJavaScriptdevelopment.Muchofthecodeyouwritewillbeinreactiontoaneventoccurringwithinthepage.

Additionally,you’llfindthatmoreeventsareaddedtobrowsersastheyimplementnewfeatures—forexample,thenewHTML5DragandDropAPI.

NATIVEDRAGANDDROPDragginganddroppingobjectswithinawebpagehasbeentheHolyGrailofJavaScriptdevelopment,andrightlyso—thesystemwespendthemajorityofourtimewith,ourcomputer’s/device’soperatingsystem,hasalwaysprovidedthatfunctionality.

Unfortunately,truedrag-and-dropsupporthasbeenelusiveinwebdevelopment,althoughsomeJavaScriptlibrariescameclose.Thoughtheyenabledustodraganddropelementswithinthewebpage,theywerelimitedbythecapabilities,orlackofinthiscase,exposedbythebrowser;interactingwithdroppedobjectsfromtheoperatingsystemwasimpossible.

ButHTML5changesthat.Forbrowsersthatsupportit,youcannowincorporatetruedrag-and-dropcapabilitieswithinyourwebpagesthankstoHTML5’sDragandDropAPI.Notonlycanyoumoveelementsaroundthepagebydragginganddroppingthem,buttheAPIenablesyoutodragobjectsfromtheoperatingsystem,likefiles,anddroptheminyourpage.

NOTENativedraganddropisonlysupportedinIE10+,Chrome,Firefox,Opera,andSafari.

MakingContentDraggableHTML5makesiteasytocreatedraggablecontent.Bysimplyaddingthedraggableattributetoanelementandsettingittotrue,youtellthebrowserthattheelementcanbeusedfordraganddrop:

<divdraggable="true">DraggableContent</div>

Inmostbrowsers,images,links,andselectedtextaredraggablebydefault.Figure10.4showssomeselectedtextbeingdraggedinChrome.

Figure10.4

Threeeventsarerelatedtothesourceofthedrag—thatis,theelementthatisbeingdragged.Thefollowingtableliststhem.

DRAGSOURCEEVENTS

DESCRIPTION

dragstart Firesontheelementwhenadragisstarted.Thisdoesnotfirewhendragginganobjectfromthefilesystem

drag Firescontinuouslywhiletheobjectisdraggeddragend Fireswhenthedragoperationiscomplete,regardlessofwhethertheobject

wasdropped.Thisdoesnotfirewhendragginganobjectfromthefilesystem

Toperformadrag-and-dropoperation,theonlyeventyouneedtolistenforisdragstart,butthatdoesn’tmeanthedraganddragendeventsarenotuseful.Youcanusethemtoaddextrafunctionalityand/orvisualcuestoenhancetheuser’sexperience.

CreatingaDropTargetIfyouaredraggingobjects,chancesareverygoodthatyouneedsomeplacetodropthem—adroptarget.Therearen’tspecialattributesorHTMLtosignifyanelementasadroptarget.Instead,youlistenforoneormultipleeventsontheelementservingasthedroptarget.

Oneofthemisthedragenterevent.Thiseventfireswhenthemousecursorentersthetargetwhiledragginganobject.Forexample:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example18</title>

<style>

.drop-zone{

width:300px;

padding:20px;

border:2pxdashed#000;

}

</style>

</head>

<body>

<divid="dropZone"class="drop-zone">DropZone!</div>

<divid="dropStatus"></div>

<script>

functionhandleDragEnter(e){

dropStatus.innerHTML="You'redraggingsomething!";

}

vardropZone=document.getElementById("dropZone");

vardropStatus=document.getElementById("dropStatus");

dropZone.addEventListener("dragenter",handleDragEnter);

</script>

</body>

</html>

Savethisfileasch10_example18.html.Openitandyou’llseesomethinglikeFigure10.5.

Figure10.5

Draganythingtothetarget.Itcanbeselectedtext,afileonyourcomputer,andsoon.Asyourmousepointerentersthetarget,you’llseethetextYou'redraggingsomething!

appearonthepage.Figure10.6showstextbeingdraggedoverthedropzoneinChrome.

Figure10.6

Inthispage,a<div/>elementisusedasthedropzone:

<divid="dropZone"class="drop-zone">DropZone!</div>

IthasanidofdropZoneandhastheCSSclassofdrop-zone.TheCSSisunimportantfromafunctionalstandpoint,butitdoesaddvisualclaritybecauseitdefinestheareainwhichyoucandropsomething.

TheimportantstuffisintheJavaScript.First,youretrievethedroptargetelementbyusingthedocument.getElementById()methodandlistenforitsdragenterevent.Youalsoretrievethe<div/>elementwithanidofdropStatus.You’lluseittodisplaystatusmessagesduringthedragoperation:

vardropZone=document.getElementById("dropZone");

vardropStatus=document.getElementById("dropStatus");

dropZone.addEventListener("dragenter",handleDragEnter);

Thiseventfiresonlywhenyouaredraggingsomethingandthemousecursorentersthetarget.Whenthishappens,thehandleDragEnter()functionexecutes:

functionhandleDragEnter(e){

dropStatus.innerHTML="You'redraggingsomething!";

}

Thissimplefunctionchangesthestatuselement’scontentstostate,You'redraggingsomething!

Thedragentereventisoneoffoureventsyoucanlistenforonthetargetelement.Thefollowingtableliststhem.

DRAGSOURCEEVENTS

DESCRIPTION

dragenter Fireswhenthemouseisfirstmovedoverthetargetelementwhiledragging

dragover Firesonthetargetasthemousemovesoveranelementwhiledragging

dragleave Firesonthetargetwhenthemouseleavesthetargetwhiledragging

drop Firesonthetargetwhenthedrop(theuserreleasesthemousebutton)occurs

Thedragentereventlooksimportant;afterall,itletsyouknowwhenthemousecursorentersthedropzonewhiledragginganobject.Butinactuality,it’soptional.Youcannotcompleteadrag-and-dropoperationwiththedragenterevent.Instead,youhavetolistenforthedropzone’sdragoverevent.

Thisiswherethingsstarttogetweird.Forthedropeventtofire,youhavetopreventthebehaviorofthedragoverevent.So,youbasicallyhavetocallpreventDefault()ontheEventobjecteverytimeyoulistenforthedragoverevent.

TRYITOUTDroppingObjectsonaTargetInthisTryItOut,youwriteasimpleexamplethatletsyoudraganddropanelementontoatarget.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example19</title>

<style>

.box{

width:100px;

height:100px;

}

.red{

background-color:red;

}

.drop-zone{

width:300px;

padding:20px;

border:2pxdashed#000;

}

</style>

</head>

<body>

<divdraggable="true"class="boxred"></div>

<divid="dropZone"class="drop-zone">DropZone!</div>

<divid="dropStatus"></div>

<script>

functiondragDropHandler(e){

e.preventDefault();

if(e.type=="dragover"){

dropStatus.innerHTML="You'redraggingoverthedrop

zone!";

}else{

dropStatus.innerHTML="Youdroppedsomething!";

}

}

vardropZone=document.getElementById("dropZone");

vardropStatus=document.getElementById("dropStatus");

dropZone.addEventListener("dragover",dragDropHandler);

dropZone.addEventListener("drop",dragDropHandler);

</script>

</body>

</html>

Savethisfileasch10_example19.html,andopenit.YourwebpagewilllooklikeFigure10.7.

Figure10.7

Dragtheredboxoverthetargetelement,andyou’llseethetextofthestatuselementchangetoYou'redraggingoverthedropzone!Droptheelementinthedropzone,andthestatustextwillchangetoYoudroppedsomething!

Thereisoneexception,however:Firefoxwillnotletyoudragtheredbox,butitwillletyoudropobjectsfromothersources(suchastext,filesonthefilesystem,andso

on).We’llexplainwhylater.

TheCSSofthisexampledefinesthreeclasses.You’vealreadyseenthedrop-zoneclass,andtheboxandredclassesareextremelysimple:

.box{

width:100px;

height:100px;

}

.red{

background-color:red;

}

Theboxclasssetstheelement’swidthandheightpropertiesto100pixels,andredgivestheelementabackgroundcolorofred.Thesearearbitraryvaluesmeanttoonlygivethedraggableelementsomevisibility.

Next,theHTML.TheonlynewelementinthisHTMLdocumentisadraggable<div/>element:

<divdraggable="true"class="boxred"></div>

Tomakeitdraggable,yousetthedraggableattributetotrue,andyouapplytheboxandredCSSclassestomakeiteasiertodraganddrop.

ButaswithExample18,thegoodstuffisintheJavaScript.First,youregisterlistenersforthedropZone’sdragoveranddropevents:

dropZone.addEventListener("dragover",dragDropHandler);

dropZone.addEventListener("drop",dragDropHandler);

Let’slookatthedragDropHandler()function.TheveryfirstlinecallstheEventobject’spreventDefault()method:

functiondragDropHandler(e){

e.preventDefault();

Thisiscrucialfortworeasons.First,thedragover’sdefaultbehaviormustbepreventedinorderforthedropeventtofire(andthat’skindofimportant).

Second,thebrowserwilldosomethingwhenyoudropanobject.Inotherwords,thedropeventhasadefaultbehavior,buttheexactbehaviordependsonthebrowserandtheobjectthatyoudrop.Someexamplesare:

Forafileorimage,mostbrowserswillattempttoopenit.

DroppingaURLmaycausethebrowsertonavigatetotheURL.

InFirefox,droppinganelementwillcausethebrowsertonavigatetothevalueintheelement’sidattribute.

Therefore,youwanttopreventthedropevent’sdefaultbehaviorinmostcases.

Afterpreventingthedefaultbehavior,thedragDropHandler()functionchangesthecontentofthedropStatuselementbasedonthetypeofevent:

if(e.type=="dragover"){

dropStatus.innerHTML="You'redraggingoverthedropzone!";

}else{

dropStatus.innerHTML="Youdroppedsomething!";

}

}

Forthedragoverevent,itsimplystatesthatyouaredraggingoverthetargetelement;otherwise,thefunctionknowsthatyoudroppedsomethingandtellsyouso.

Frustratingly,nativedraganddropdoesn’tworkexactlythesameinallmodernbrowsers.Theaforementionedpartiallistofthebrowsers’defaultbehaviorforthedropeventisjustonethingJavaScriptdevelopershavetocontendwith.

ButalsorememberthatExample19doesn’tcompletelyworkinFirefox.AlthoughitisfrustratingthatJavaScriptdevelopershavetocopewithinconsistentimplementations,Firefox’sdrag-and-dropimplementation,whetherit’srightorwrong,doesmakesomesenseinthisregard.Aswetrytodragtheredbox,wehaven’ttoldthebrowserwhatwe’retransferring.

TransferringDataWhenyouthinkaboutit,adrag-and-dropoperationisthetransferenceofdata.Forexample,whenyoudragafileonyourfilesystemfromonefoldertoanother,youaretransferringthedata(thefile)betweenthetwofolderlocations.Whendraggingtextfromoneapplicationtoanother,youaretransferringthetextualdatabetweenthetwoapplications.

Draganddropinthebrowserfollowsasimilarconcept.Whenstartingadrag,youneedtotellthebrowserwhatyouplantotransfer,andwhenyoudroptheobject,youneedtospecifyhowthatdatatransfersfromthesourcetothetarget.

Thedrag-and-dropspecificationdefinesaDataTransferobjectthatisusedtoholdthedatathatisbeingdraggedduringadrag-and-dropoperation.YouaccessthisobjectwiththeEventobject’sdataTransferproperty.YousetdatawiththeDataTransferobject’ssetData()methodinthedragstarteventhandler,andyoureadthatdatainthedropeventhandlerwiththegetData()method.

TomakeExample19workinFirefox,youneedtohandlethedragstarteventandusetheDataTransferobject’ssetData()method.Thefollowingaddsthenecessarycode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example20</title>

<style>

.box{

width:100px;

height:100px;

}

.red{

background-color:red;

}

.drop-zone{

width:300px;

padding:20px;

border:2pxdashed#000;

}

</style>

</head>

<body>

<divdraggable="true"class="boxred"></div>

<divid="dropZone"class="drop-zone">DropZone!</div>

<divid="dropStatus"></div>

<script>

functiondragStartHandler(e){

e.dataTransfer.setData("text","DragandDrop!");

}

functiondragDropHandler(e){

e.preventDefault();

if(e.type=="dragover"){

dropStatus.innerHTML="You'redraggingoverthe"+

"dropzone!";

}else{

dropStatus.innerHTML=e.dataTransfer.getData("text");

}

}

vardragBox=document.querySelector("[draggable]");

vardropZone=document.getElementById("dropZone");

vardropStatus=document.getElementById("dropStatus");

dragBox.addEventListener("dragstart",dragStartHandler);

dropZone.addEventListener("dragover",dragDropHandler);

dropZone.addEventListener("drop",dragDropHandler);

</script>

</body>

</html>

Savethisfileasch10_example20.html,andopenitinFirefox.Nowdragtheredboxtothetarget,andyou’llseethatitbehavessimilarlytoch10_example19.htmlinallbrowsers(Firefoxincluded).

Let’sfocusonlyonthenewlinesofcode.First,youstorethedraggableboxinthedragBoxvariablebyusingdocument.querySelector()andpassingtheattributeselectorof“[draggable]”:

vardragBox=document.querySelector("[draggable]");

Next,youregisteraneventlistenerforthedragstarteventonthedragBoxobject:

dragBox.addEventListener("dragstart",dragStartHandler);

ThedragStartHandler()functionexecuteswhenyoustartadragoperationonthedragBoxobject.ThisfunctionmakesuseoftheDataTransferobject’ssetData()methodtoholddataforthedrag-and-dropoperation:

functiondragStartHandler(e){

e.dataTransfer.setData("text","DragandDrop!");

}

ThesetData()functionacceptstwoarguments:thetypeofdatatostoreandtheactualdata.Theonlydatatypessupportedbyallbrowsersare“text”and“url”;therefore,thisfunctionstoresthetextualdataofDragandDrop!

NOTEMostbrowserssupportotherdatatypes,suchasMIMEtypes(forexample,text/plain,text/html,andsoon).IE10andIE11,however,onlysupporttextandurl.

Thelastnew/changedlineisinthedragDropHandler()function.Insteadofdisplayinganarbitrarystringvalueinthestatuselementwhenthedropeventfires,youretrievethedatafromthedataTransferobjectbyusingthegetData()method:

dropStatus.innerHTML=e.dataTransfer.getData("text");

ThegetData()methodacceptsonlyoneargument:thedatatypeyouusedwhencallingsetData().Therefore,thiscoderetrievesthevalueofDragandDrop!andusesitastheinnerHTMLofthestatuselement.

TRYITOUTFullDragandDropInthisTryItOut,youapplyeverythingyou’velearnedaboutnativedraganddropandwriteapagethatletsyoudraganddropelementsbetweentwodroptargets.

Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Example21</title>

<style>

[data-drop-target]{

height:400px;

width:200px;

margin:2px;

background-color:gainsboro;

float:left;

}

.drag-enter{

border:2pxdashed#000;

}

.box{

width:200px;

height:200px;

}

.navy{

background-color:navy;

}

.red{

background-color:red;

}

</style>

</head>

<body>

<divdata-drop-target="true">

<divid="box1"draggable="true"class="boxnavy"></div>

<divid="box2"draggable="true"class="boxred"></div>

</div>

<divdata-drop-target="true"></div>

<script>

functionhandleDragStart(e){

e.dataTransfer.setData("text",this.id);

}

functionhandleDragEnterLeave(e){

if(e.type=="dragenter"){

this.className="drag-enter";

}else{

this.className="";

}

}

functionhandleOverDrop(e){

e.preventDefault();

if(e.type!="drop"){

return;

}

vardraggedId=e.dataTransfer.getData("text");

vardraggedEl=document.getElementById(draggedId);

if(draggedEl.parentNode==this){

return;

}

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

this.className="";

}

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-target]");

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",

handleDragStart);

}

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

targets[i].addEventListener("dragover",handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",

handleDragEnterLeave);

targets[i].addEventListener("dragleave",

handleDragEnterLeave);

}

</script>

</body>

</html>

Savethisfileasch10_example21.htmlandopenitinyourmodernbrowserofchoice.You’llseeapagethatconsistsoftwocolumns.Ontheleft,ablueboxsitsontopofaredone,andontherightisasolidgrayishrectangle,asshowninFigure10.8.

Figure10.8

Thegrayishareasaredroptargets,andtheblueandredboxesaredraggableobjects.Dragtheblueboxtotheemptydroptarget,andyou’llseeadashedborderappeararoundthetarget(Figure10.9).

Figure10.9

Droptheblueboxonthattarget,andyou’llseeitmovefromthelefttargettotheright.Nowdragtheboxesbetweenthetwodroptargetstoseethefulleffect.

Let’sstartwiththeHTML.Adroptargetinthisexampleisanelementidentifiedwiththedata-drop-targetattributesettotrue.Thisexampleconsistsoftwodroptargets,althoughyoucaneasilyaddmore:

<divdata-drop-target="true">

<divid="box1"draggable="true"class="boxnavy"></div>

<divid="box2"draggable="true"class="boxred"></div>

</div>

<divdata-drop-target="true"></div>

Thefirstdroptargetcontainstwodraggable<div/>elements,andtheyeachhaveanidattribute.Otherthantheiridvalues,theonlydifferenceistheirCSS.BothusetheboxCSSclass,butonealsousesthenavyCSSclass,whereastheotherusestheredclass.

SpeakingofCSS,let’slookatthestylesdefinedinthestylesheet.Thefirstrulematchesallelementsthathaveadata-drop-targetattribute:

[data-drop-target]{

height:400px;

width:200px;

margin:2px;

background-color:gainsboro;

float:left;

}

Theheightandwidtharesettoaccommodatetwodraggableboxesatatime.A

marginoftwopixelsgivesjustenoughspacebetweenthedroptargetelementstovisuallyseparatethem.Abackgroundcolormakesthemeasilydistinguishablebetweenthepage’sbackground,andtheyeachfloatleft.

Thenextrulealsoappliestodroptargets:

.drag-enter{

border:2pxdashed#000;

}

Thedrag-enterclassisusedasavisualcue.Asyoudraganobjectoveradroptargetelement,thisdrag-enterclassisappliedtotheelement.Thisisn’tnecessaryforthedrag-and-dropoperationtocomplete,butitdoesenhancetheuser’sexperience.

ThefinalsetofCSSrulesisusedforthedraggableelements:

.box{

width:200px;

height:200px;

}

.navy{

background-color:navy;

}

.red{

background-color:red;

}

Eachdraggableelementusestheboxclasstosetitsheightandwidth.Thenavyandredclassesareusedinconjunctionwiththeboxclasstogivetheelementabackgroundcolorofnavyorred,respectively.

AsfortheJavaScript,youfirstretrievetwogroupsofelements—thosethataredraggableandthosethataredroptargets:

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-target]");

Sousingthedocument.querySelectorAll()method,youretrievebothgroupsofelementswiththeirrespective[draggable]and[data-drop-target]CSSselectorsandassignthemtothedraggableandtargetsvariables.

Next,youwanttoregisterthedragstarteventlistenersonthedraggableelements:

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",handleDragStart);

}

Usingaforloop,youiterateoverthedraggablecollectionandcalltheaddEventListener()methodoneachdraggableobject,passingdragstartastheeventandthehandleDragStart()functionobjectasthehandler.

Youthenwanttouseasimilarprocessonthetargetelements:

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

targets[i].addEventListener("dragover",handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",handleDragEnterLeave);

targets[i].addEventListener("dragleave",handleDragEnterLeave);

}

Byusinganotherforloop,youloopthroughthetargetscollectionandregistereventhandlersforthedragover,drop,dragenter,anddragleaveevents.Twofunctionsareusedtohandlethesefourevents:thehandleOverDrop()functionhandlesthedragoveranddropevents,andhandleDragEnterLeave()handlesdragenteranddragleave.

Thefirstfunction,handleDragStart(),containsjustasinglelineofcode:

functionhandleDragStart(e){

e.dataTransfer.setData("text",this.id);

}

Itspurposeissimple:tostoretheidofthedraggableelement.Noticetheuseofthisinthis.id.Whenyouregisteraneventlistener,thehandlerfunctionexecuteswithinthecontextoftheelementobjecttheeventfiredon.Inthiscase,thedragstarteventfiredononeofthedraggableelements;so,thisreferstothatelement.Inotherwords,thisisthesamease.target.

ThenextfunctionishandleDragEnterLeave(),andasmentionedearlier,itexecuteswhenthedragenteranddragleaveeventsfireonadroptarget:

functionhandleDragEnterLeave(e){

if(e.type=="dragenter"){

this.className="drag-enter";

}else{

this.className="";

}

}

Thefirstlineofthisfunctionchecksthetypeofeventthatoccurred.Iftheeventisdragenter,theCSSclassofthedroptargetelementissettodrag-enter(onceagain,noticethisisusedinsteadofe.target—it’smucheasiertotype).Iftheeventisn’tdragenter,theelement’sCSSclassissettoanemptystring,thusremovingthedrag-enterclass.

Thefinalfunction,handleOverDrop(),performstherealmagicofthedrag-and-dropoperation.Thisfunctionhandlesboththedragoveranddropeventsandshouldthereforepreventthedefaultactionfromoccurring.Thus,thefirstlineofthefunctioncallse.preventDefault():

functionhandleOverDrop(e){

e.preventDefault();

Thisisallthatisneededforthedragoverevent.So,iftheeventisn’tadropevent,thefunctionsimplyexits:

if(e.type!="drop"){

return;

}

Ifitisadropevent,thefunctioncontinuesonandretrievesthedraggableelement’sidfromtheDataTransferobject:

vardraggedId=e.dataTransfer.getData("text");

vardraggedEl=document.getElementById(draggedId);

Andwiththisid,youretrievethedraggableelement’sobjectwithdocument.getElementById()andstoreitinthedraggedElvariable.

Youhavetwooptionswhenitcomestodroppingoneofthedraggableboxes:youcaneitherdropitinthetargetit’scurrentlyin,oryoucandropitinanothertarget.Ifdroppedinitscurrentlocation,there’snothinglefttodoexceptresetthetarget’sCSSclass.Thisiseasyenoughtocheck;simplyusetheelement’sparentNodeproperty:

if(draggedEl.parentNode==this){

this.className="";

return;

}

Ifthedraggedelement’sparentnodeisthetargetdropzone,yousettheclassNamepropertytoanemptystringandexitthefunctionusingthereturnstatement.Otherwise,youwanttomovethedraggedelementnodefromitsoldparent/droptargettoitsnewparent/droptarget:

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

Thisisasimpleprocess,asyoucansee.Toremovethedraggableelementfromitscurrentparent,youretrieveitsparentNodeandcalltheremoveChild()method.TheremoveChild()methoddoesn’tdeletethenode;itsimplyremovesitsothatyoucanappendittoanothernodeintheDOM.

Withthedraggedelementmovedfromonedroptargettoanother,thedrag-and-dropoperationiscomplete,andyousetthedroptargetelement’sCSSclasstoanemptystring:

this.className="";

Thisvisuallyresetsthedroptarget,givingusersavisualcuethatthedrag-and-dropoperationiscomplete.

Awebpageisaninteractiveenvironment.Usersarebusyclicking,typing,dragging,anddoingotherthings.Assuch,eventsareanextremelyimportantmatterforwebdevelopers.Notonlyareeventshowwerespondandinteractwiththeuser,theyalsoenableustoexecutecodewhenspecificthingshappeninthepage.Inlaterchapters,youseeexamplesofsuchanduseeventstorespondtoanobject’saction,ratherthanauser’saction.

SUMMARYYou’vecoveredalotinthischapter,butnowyouhaveasolidbasisonhowtoworkwithandhandleeventsinthebrowsersthatarecurrentlyinuseontheweb.YouevenknowthedifferencebetweenthestandardDOMeventmodelandold-IE’seventmodel,andyouwroteaneventutilitythatmakeswritingcross-browserJavaScriptrelativelysimple.

Thischaptercoveredthefollowingpoints:

YousawthatHTMLelementshaveeventsaswellasmethodsandproperties.YouhandletheseeventsinJavaScriptbyusingeventhandlers,whichyouconnecttocodethatyouwanttohaveexecutedwhentheeventoccurs.Theeventsavailableforusedependontheobjectyouaredealingwith.

Youcanconnectafunctiontoanelement’seventhandlerusingtheelement’s“on”attributes.ButyoualsolearnedthatdoingsomixesyourHTMLandJavaScript,andthisapproachshouldbeavoidedmostofthetime.

Eventscanbehandledbyusinganobject’s"on"properties,whichisabettersolutionthantheHTMLattributes,butstillhasitsownissues.

ThestandardDOMeventmodelissupportedbyallmodernbrowsers,anditprovidesthebestwaytoconnectyourcodetoevents.

YoulearnedaboutthestandardEventobjectandhowitprovidesalotofinformationabouttheeventthatoccurred,includingthetypeofeventandtheelementthatreceivedtheevent.

Youlearnedaboutold-IE’sproprietaryeventmodel,howtoconnecteventswithattachEvent(),andhowtoaccessold-IE’seventobject.

SomedifferencesexistbetweenthestandardDOMeventmodelandtheold-IEeventmodel.Youlearnedthekeydifferencesandwroteasimplecross-browsereventutility.

Someeventshaveadefaultactionthatoccurswhentheeventfires,andyoucanpreventthatactionwiththestandardEventobject’spreventDefault()methodandold-IE’sreturnValueproperty.

Modernbrowserssupportnativedrag-and-dropcapabilities,andyoucanwritecodethattakesadvantageofthisnewfeature.

Insomeinstances,suchasforthedocumentobject,asecondwayofconnectingeventhandlerstocodeisnecessary.Settingtheobject’spropertywiththenameoftheeventhandlertoyourfunctionproducesthesameeffectasifyoudiditusingtheeventhandlerasanattribute.

Insomeinstances,returningvaluesfromeventfunctionsenablesyoutocanceltheactionassociatedwiththeevent.Forexample,tostopaclickedlinkfromnavigatingtoapage,youreturnfalsefromtheeventhandler’scode.

That’sitforthischapter.Inthenextchapter,youmoveontoformscripting,whereyou

canaddvariouscontrolstoyourpagetohelpyougatherinformationfromtheuser.

EXERCISES1. AddamethodtotheeventutilityobjectcalledisOldIE()thatreturnsaboolean

valueindicatingwhetherornotthebrowserisold-IE.

2. Example15exhibitssomebehaviorinconsistenciesbetweenstandards-compliantbrowsersandold-IE.Rememberthattheeventhandlersexecuteinreverseorderinold-IE.ModifythisexampletousethenewisOldIE()methodsothatyoucanwritespecificcodeforold-IEandstandards-compliantbrowsers(Hint:youwillcalltheaddListener()methodfourtimes).

3. Example17hadyouwriteacross-browsertabscript,butasyouprobablynoticed,itbehavespeculiarly.Thebasicideaisthere,butthetabsremainactiveasyouclickanothertab.Modifythescriptsothatonlyonetabisactiveatatime.

11HTMLForms:InteractingwiththeUserWHATYOUWILLLEARNINTHISCHAPTER:

Scriptingtext,password,textarea,andhiddenformcontrols

Writingcodeforselect,checkbox,andradiobuttonformcontrols

UsingJavaScripttointeractwithnewHTML5formcontrols

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Webpageswouldbeveryboringifyoucouldnotinteractwithorobtaininformationfromtheuser,suchastext,numbers,ordates.Luckily,withJavaScriptthisispossible.Youcanusethisinformationwithinthewebpage,oryoucanpostittothewebserverwhereyoucanmanipulateitandstoreitinadatabaseifyouwish.Thischapterconcentratesonusingtheinformationwithinthewebbrowser,whichiscalledclient-sideprocessing.

You’requiteaccustomedtovarioususerinterfaceelements.Forexample,everyoperatingsystemhasanumberofstandardelements,suchasbuttonsyoucanclick;lists,drop-downlistboxes,andradiobuttonsyoucanselectfrom;andboxesyoucancheck.Theseelementsarethemeansbywhichyounowinterfacewithapplications.Thegoodnewsisthatyoucanincludemanyofthesetypesofelementsinyourwebpage—andevenbetter,it’sveryeasytodoso.Whenyouhavesuchanelement—say,abutton—insideyourpage,youcanthentiecodetoitsevents.Forexample,whenthebuttonisclicked,youcanfireoffaJavaScriptfunctionyoucreated.

AlloftheHTMLelementsusedforinteractionshouldbeplacedinsideanHTMLform.Let’sstartbytakingalookatHTMLformsandhowyouinteractwiththeminJavaScript.

HTMLFORMSFormsprovideyouwithawayofgroupingtogetherHTMLinteractionelementswithacommonpurpose.Forexample,aformmaycontainelementsthatenabletheinputofauser’sdataforregisteringonawebsite.Anotherformmaycontainelementsthatenabletheusertoaskforacarinsurancequote.It’spossibletohaveanumberofseparateformsinasinglepage.Youdon’tneedtoworryaboutpagescontainingmultipleformsuntilyouhavetosubmitinformationtoawebserver—thenyouneedtobeawarethattheinformationfromonlyoneoftheformsonapagecanbesubmittedtotheserveratonetime.

Tocreateaform,usethe<form>and</form>tagstodeclarewhereitstartsandwhereitends.The<form/>elementhasanumberofattributes,suchastheactionattribute,whichdetermineswheretheformissubmitted;themethodattribute,whichdetermineshowtheinformationissubmitted;andthetargetattribute,whichdeterminestheframetowhichtheresponsetotheformisloaded.

Generallyspeaking,forclient-sidescriptingwhereyouhavenointentionofsubmittinginformationtoaserver,theseattributesarenotnecessary.Fornowtheonlyattributeyouneedtosetinthe<form/>elementisthenameattribute,sothatyoucanreferencetheform.

So,tocreateablankform,thetagsrequiredwouldlooksomethinglikethis:

<formname="myForm">

</form>

Youwon’tbesurprisedtohearthatthesetagscreateanHtmlFormElementobject,whichyoucanusetoaccesstheform.Youcanaccessthisobjectintwoways.

First,youcanaccesstheobjectdirectlyusingitsname—inthiscasedocument.myForm.Alternatively,youcanaccesstheobjectthroughthedocumentobject’sformscollectionproperty.RememberthatChapter8includedadiscussionofthedocumentobject’simagescollectionandhowyoucanmanipulateitlikeanyotherarray.Thesameappliestotheformscollection,exceptthatinsteadofeachelementinthecollectionholdinganHtmlImageElementobject,itnowholdsanHtmlFormElement(herebycalledsimplyForm)object.Forexample,ifit’sthefirstforminthepage,youreferenceitusingdocument.forms[0].

NOTEOfcourse,youcanalsoaccessaformusingthedocument.getElementById()anddocument.querySelector()methods.

Manyoftheattributesofthe<form/>elementcanbeaccessedaspropertiesoftheHtmlFormElementobject.Inparticular,thenamepropertymirrorsthenameattributeofthe<form/>element.

TRYITOUTTheformsCollection

InthisTryItOut,you’llusetheformscollectiontoaccesseachofthreeFormobjectsandshowthevalueoftheirnamepropertiesinamessagebox.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example1</title>

</head>

<body>

<formaction=""name="form1">

<p>

Thisisinsideform1.

</p>

</form>

<formaction=""name="form2">

<p>

Thisisinsideform2

</p>

</form>

<formaction=""name="form3">

<p>

Thisisinsideform3

</p>

</form>

<script>

varnumberForms=document.forms.length;

for(varindex=0;index<numberForms;index++){

alert(document.forms[index].name);

}

</script>

</body>

</html>

Savethisasch11_example1.html.Whenyouloaditintoyourbrowser,youshouldseeanalertboxdisplaythenameofthefirstform.ClicktheOKbuttontodisplaythenextform’sname,andthenclickOKathirdtimetodisplaythethirdandfinalform’sname.

Withinthebodyofthepageyoudefinethreeforms.Yougiveeachformanameandaparagraphoftext.

IntheJavaScriptcode,youloopthroughtheformscollection.JustlikeanyotherJavaScriptarray,theformscollectionhasalengthproperty,whichyoucanusetodeterminehowmanytimesyouneedtoloop.Actually,becauseyouknowhowmanyformsyouhave,youcanjustwritethenumberin.However,thisexampleusesthelengthproperty,becausethatmakesiteasiertoaddtothecollectionwithouthavingtochangethecode.Generalizingyourcodelikethisisagoodpracticetogetinto.

ThecodestartsbygettingthenumberofFormobjectswithintheformscollectionandstoringthatnumberinthevariablenumberForms:

varnumberForms=document.forms.length;

Nextyoudefinetheforloop:

for(varformIndex=0;formIndex<numberForms;formIndex++){

alert(document.forms[formIndex].name);

}

Rememberthatbecausetheindexesforarraysstartat0,yourloopneedstogofromanindexof0toanindexofnumberForms–1.Youenablethisbyinitializingtheindexvariableto0,andsettingtheconditionoftheforlooptoindex<numberForms.

Withintheforloop’scode,youpasstheindexoftheformyouwant(thatis,index)todocument.forms[],whichgivesyoutheFormobjectatthatindexintheformscollection.ToaccesstheFormobject’snameproperty,youputadotattheendofthenameoftheproperty,name.

TRADITIONALFORMOBJECTPROPERTIESANDMETHODSTheHTMLformcontrolscommonlyfoundinforms,whichyoulookatinmoredetailshortly,alsohavecorrespondingobjects.OnewaytoaccesstheseisthroughtheelementspropertyoftheFormobject,anothercollection.TheelementscollectioncontainsalltheobjectscorrespondingtotheHTMLinteractionelementswithintheform,withtheexceptionofthelittle-used<inputtype="image"/>element.Asyouseelater,thispropertyisveryusefulforloopingthrougheachoftheelementsinaform.Forexample,youcanloopthrougheachelementtocheckthatitcontainsvaliddatapriortosubmittingaform.

Beingacollection,theelementspropertyoftheFormobjecthasthelengthproperty,whichtellsyouhowmanyelementsareintheform.TheFormobjectalsohasthelengthproperty,whichalsogivesyouthenumberofelementsintheform.Whichoftheseyouuseisuptoyoubecausebothdothesamejob,althoughwritingmyForm.lengthisshorter,andthereforequickertotypeandlesslengthytolookatincode,thanmyForm.elements.length.

Whenyousubmitdatafromaformtoaserver,younormallyusetheSubmitbutton,whichyouwillcometoshortly.However,theFormobjectalsohasthesubmit()method,whichdoesnearlythesamething.

NOTEThesubmit()methodsubmitstheform,butitdoesnotfirethesubmiteventoftheFormobject;thus,submiteventlistenersarenotcalledwhensubmittingtheformwithsubmit().

RecallthatinChapter10youlearnedthatyoucanaffectwhetherthenormalcourseofeventscontinuesoriscanceled.Yousaw,forexample,thatcallingpreventDefault()inahyperlink’sclickeventhandlercausesthelink’snavigationtobecanceled.Well,thesameprincipleappliestotheFormobject’ssubmitevent,whichfireswhentheusersubmitstheform.BycallingpreventDefault(),thesubmissioniscanceled.Thismakesthesubmiteventhandler’scodeagreatplacetodoformvalidation—thatis,tocheckthatwhattheuserhasenteredintotheformisvalid.Forexample,ifyouaskfortheusers’agesandtheyentermindyourownbusiness,youcanspotthatthisistextratherthanavalidnumberandstopthemfromcontinuing.

InadditiontotherebeingaResetbutton,whichisdiscussedlaterinthechapter,theFormobjecthasthereset()method,whichclearstheform,orrestoresdefaultvaluesiftheseexist.

Creatingblankformsisnotexactlyexcitingoruseful,sonowlet’sturnourattentiontotheHTMLelementsthatprovideinteractionfunctionalityinsideforms.

HTMLElementsinForms

Abouttenelementsarecommonlyfoundwithin<form/>elements.ThemostusefulareshowninFigures11.1,11.2,11.3,and11.4,orderedintogeneraltypes.Eachtypenameisgivenand,inparentheses,theHTMLneededtocreateit,thoughnotethisisnotthefullHTMLbutonlyaportion.ThenewHTML5formcontrolsarenotlistedhere;youexaminethemlaterinthechapter.

Figure11.1

Figure11.2

Figure11.3

Figure11.4

Asyoucansee,mostformelementsarecreatedbymeansofthe<input/>element.Oneofthe<input/>element’sattributesisthetypeattribute.It’sthisattributethatdecideswhichoftheformelementsthiselementwillbe.Examplesofvaluesforthisattributeincludebutton(tocreateabutton)andtext(tocreateatextbox).

Eachformelementinsidethewebpageismadeavailabletoyouas—yes,youguessedit—anobject.Aswithalltheotherobjectsyouhaveseen,eachelement’sobjecthasitsownsetofdistinctiveproperties,methods,andevents.You’llbetakingalookateachformelementinturnandhowtouseitsparticularproperties,methods,andevents,butbeforeyoudothat,let’slookatpropertiesandmethodsthattheobjectsoftheformelementshaveincommon.

CommonPropertiesandMethodsBecausemostformelementsarecreatedbythe<input/>element,itwouldbecorrecttoguessthatallformelementsshareseveralpropertiesandmethodsincommon.

Hereareafew.

ThenamePropertyOnepropertythatalltheobjectsoftheformelementshaveincommonisthenameproperty.Youcanusethevalueofthispropertytoreferencethatparticularelementinyourscript.Also,ifyouaresendingtheinformationintheformtoaserver,theelement’snamepropertyissentalongwithanyvalueoftheformelement,sothattheserverknowswhatthevaluerelatesto.

ThevalueProperty

Mostformelementobjectsalsohavethevalueproperty,whichreturnsthevalueoftheelement.Forexample,foratextbox,thevaluepropertyreturnsthetextthattheuserenteredinthetextbox.Also,settingthevalueofthevaluepropertyenablesyoutoputtextinsidethetextbox.However,theuseofthevaluepropertyisspecifictoeachelement,soyou’lllookatwhatitmeansasyoulookateachindividualelement.

TheformPropertyAllformelementobjectsalsohavetheformproperty,whichreturnstheFormobjectinwhichtheelementiscontained.Thiscanbeusefulincaseswhereyouhaveagenericroutinethatchecksthevalidityofdatainaform.Forexample,whentheuserclicksaSubmitbutton,youcanpasstheFormobjectreferencedbytheformpropertyoftheSubmitbuttontoyourdatachecker,whichcanuseittoloopthrougheachelementontheforminturn,checkingthatthedataintheelementisvalid.Thisishandyifyouhavemorethanoneformdefinedonthepageorwhereyouhaveagenericdatacheckerthatyoucutandpastetodifferentpages—thiswayyoudon’tneedtoknowtheform’snameinadvance.

ThetypePropertySometimesit’susefultoknowwhattypeofelementyou’redealingwith,particularlywhereyou’reloopingthroughtheelementsinaformusingtheelementscollectionproperty.Thisinformationcanberetrievedbymeansofthetypeproperty,whicheachelement’sobjecthas.Thispropertyreturnsthetypeoftheelement(forexample,buttonortext).

Thefocus()andblur()MethodsAllformelementobjectsalsohavethefocus()andblur()methods.Focusisaconceptyoumightnothavecomeacrossyet.Ifanelementisthecenterofthefocus,anykeypressesmadebytheuserarepasseddirectlytothatelement.Forexample,ifatextboxhasfocus,pressingkeyswillentervaluesintothetextbox.Also,ifabuttonhasthefocus,pressingtheEnterkeycausesthebutton’sonclickeventhandlercodetofire,justasifauserhadclickedthebuttonwithhismouse.

TheusercansetwhichelementcurrentlyhasthefocusbyclickingitorbyusingtheTabkeytoselectit.However,youastheprogrammercanalsodecidewhichelementhasthefocusbyusingtheformelement’sobject’sfocus()method.Forexample,ifyouhaveatextboxfortheusertoenterhisageandheentersaninvalidvalue,suchasaletterratherthananumber,youcantellhimthathisinputisinvalidandsendhimbacktothattextboxtocorrecthismistake.

Blur,whichperhapscouldbebettercalled“lostfocus,”istheoppositeoffocus.Ifyouwanttoremoveaformelementfrombeingthefocusoftheuser’sattention,youcanusetheblur()method.Whenusedwithaformelement,theblur()methodusuallyresultsinthefocusshiftingtothepagecontainingtheform.

Inadditiontothefocus()andblur()methods,alltheformelement’sobjectshavetheonfocusandonblureventhandlers.Thesearefired,asyou’dexpect,whenanelementgetsorlosesthefocus,respectively,duetouseractionorthefocus()andblur()methods.Theonblureventhandlercanbeagoodplacetocheckthevalidityofdatainthe

elementthathasjustlostthefocus.Ifthedataisinvalid,youcansetthefocusbacktotheelementandlettheuserknowwhythedataheenterediswrong.

NOTERememberthatthesubmit()methodbehavesdifferentlythanfocus()andblur()inthatitdoesnotfirethesubmitevent.

Onethingtobecarefulofisusingthefocus()andblur()methodsinthefocusorblureventlistenercode.Thereisthedangerofaninfiniteloopoccurring.Forexample,considertwoelements,eachofwhosefocuseventspassesthefocustotheotherelement.Then,ifoneelementgetsthefocus,itsfocuseventwillpassthefocustothesecondelement,whosefocuseventwillpassthefocusbacktothefirstelement,andsoonuntiltheonlywayoutistoclosethebrowserdown.Thisisnotlikelytopleaseyourusers!

Alsobeverywaryofusingthefocus()andblur()methodstoputfocusbackinaproblemfieldifthatfieldorothersdependonsomeoftheuser’sinput.Forexample,sayyouhavetwotextboxes:oneinwhichyouwantuserstoentertheircityandtheotherinwhichyouwantthemtoentertheirstate.Alsosaythattheinputintothestatetextboxischeckedtomakesurethatthespecifiedcityisinthatstate.Ifthestatedoesnotcontainthecity,youputthefocusbackonthestatetextboxsothattheusercanchangethenameofthestate.However,iftheuseractuallyinputthewrongcitynameandtherightstatename,shemaynotbeabletogobacktothecitytextboxtorectifytheproblem.

ButtonElementsWe’restartingourlookatformelementswiththestandardbuttonelementbecauseit’sprobablythemostcommonlyusedandisfairlysimple.TheHTMLelementtocreateabuttonis<input/>.Forexample,tocreateabuttoncalledmyButton,whichhasthewords“ClickMe”onitsface,the<input/>elementwouldneedtobeasfollows:

<inputtype="button"name="myButton"value="ClickMe"/>

Thetypeattributeissettobutton,andthevalueattributeissettothetextyouwanttoappearonthefaceofthebutton.Youcanleavethevalueattributeoff,butyou’llendupwithablankbutton,whichwillleaveyourusersguessingastoitspurpose.

ThiselementcreatesanassociatedHTMLInputElementobject(infact,all<input/>elementscreateHTMLInputElementobjects);inthisexampleitiscalledmyButton.Thisobjecthasallthecommonpropertiesandmethodsdescribedearlier,includingthevalueproperty.ThispropertyenablesyoutochangethetextonthebuttonfaceusingJavaScript,thoughthisisprobablynotsomethingyou’llneedtodoveryoften.Whatthebuttonisreallyallaboutistheclickevent.

Youconnecttothebutton’sclickeventjustasyouwouldwithanyotherelement.Allyouneedtodoisdefineafunctionthatyouwanttoexecutewhenthebuttonisclicked(say,buttonClick())andthenregisteraclickeventlistenerwiththeaddEventListener()method.

TRYITOUTCountingButtonClicksInthefollowingexample,youusethemethodsdescribedpreviouslytorecordhowoftenabuttonhasbeenclicked.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example2</title>

</head>

<body>

<formaction=""name="form1">

<inputtype="button"name="myButton"value="Buttonclicked0

times"/>

</form>

<script>

varmyButton=document.form1.myButton;

varnumberOfClicks=0;

functionmyButtonClick(){

numberOfClicks++;

myButton.value="Buttonclicked"+numberOfClicks+"

times";

}

myButton.addEventListener("click",myButtonClick);

</script>

</body>

</html>

Savethispageasch11_example2.html.Ifyouloadthispageintoyourbrowser,youwillseeabuttonwith“Buttonclicked0times”onit.Ifyourepeatedlypressthisbutton,youwillseethenumberofbuttonclicksrecordedonthetextofthebutton.

YoustartthescriptblockbydefiningtwovariablescalledmyButtonandnumberOfClicks.Theformerholdsareferencetothe<input/>elementobject.Yourecordthenumberoftimesthebuttonhasbeenclickedinthelatterandusethisinformationtoupdatethebutton’stext.

TheotherpieceofcodeinthescriptblockisthedefinitionofthefunctionmyButtonClick().Thisfunctionhandlesthe<input/>element’sclickevent:

myButton.addEventListener("click",myButtonClick);

ThiselementisforaButtonelementcalledmyButtonandiscontainedwithinaformcalledform1:

<formaction=""name="form1">

<inputtype="button"name="myButton"value="Buttonclicked0times"

/>

</form>

Let’slookatthemyButtonClick()functionalittlemoreclosely.First,thefunctionincrementsthevalueofthevariablenumberOfClicksbyone:

functionmyButtonClick(){

numberOfClicks++;

Next,youupdatethetextonthebuttonfaceusingtheButtonobject’svalueproperty:

myButton.value="Buttonclicked"+numberOfClicks+"times";

}

Thefunctioninthisexampleisspecifictothisformandbutton,ratherthanagenericfunctionyou’lluseinothersituations.Therefore,thecodeinthisexampledirectlyreferstoabuttonusingthemyButtonvariable.

TRYITOUTmouseupandmousedownEventsTwolesscommonlyusedeventssupportedbytheButtonobjectarethemousedownandmouseupevents.Youcanseethesetwoeventsinactioninthenextexample.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example3</title>

</head>

<body>

<formaction=""name="form1">

<inputtype="button"name="myButton"value="Mousegoesup"/>

</form>

<script>

varmyButton=document.form1.myButton;

functionmyButtonMouseup(){

myButton.value="MouseGoesUp";

}

functionmyButtonMousedown(){

myButton.value="MouseGoesDown";

}

myButton.addEventListener("mousedown",myButtonMousedown);

myButton.addEventListener("mouseup",myButtonMouseup);

</script>

</body>

</html>

Savethispageasch11_example3.htmlandloaditintoyourbrowser.Ifyouclickthebuttonwithyourleftmousebuttonandkeepithelddown,you’llseethetextonthebuttonchangeto“MouseGoesDown.”Assoonasyoureleasethebutton,thetext

changesto“MouseGoesUp.”

Inthebodyofthepage,youdefineabuttoncalledmyButtonwithinaformcalledform1:

<formaction=""name="form1">

<inputtype="button"name="myButton"value="Mousegoesup"/>

</form>

YourJavaScriptcoderetrievesthisButtonobjectfromthedocumentandstoresitinthemyButtonvariable,andyouregistereventlistenersforthemouseupandmousedownevents.

ThemyButtonMouseup()andmyButtonMousedown()functionshandlethoseevents,respectively.Eachfunctionconsistsofjustasinglelineofcode,inwhichyouusethevaluepropertyoftheButtonobjecttochangethetextthatisdisplayedonthebutton’sface.

Animportantpointtonoteisthateventslikemouseupandmousedownaretriggeredonlywhenthemousepointerisactuallyovertheelementinquestion.Forexample,ifyouclickandholddownthemousebuttonoveryourbutton,thenmovethemouseawayfromthebuttonbeforereleasingthemousebutton,you’llfindthatthemouseupeventdoesnotfireandthetextonthebutton’sfacedoesnotchange.Inthisinstanceitwouldbethedocumentobject’smouseupeventthatwouldfire,ifyou’dconnectedanycodetoit.

Don’tforgetthat,likeallformelementobjects,theButtonobjectalsohasthefocusandblurevents,thoughtheyarerarelyusedinthecontextofbuttons.

TwoadditionalbuttontypesaretheSubmitandResetbuttons.Youdefinethesebuttonsjustasyoudoastandardbutton,exceptthatthetypeattributeofthe<input>tagissettosubmitorresetratherthantobutton.Forexample,theSubmitandResetbuttonsinFigure11.4werecreatedusingthefollowingcode:

<inputtype="submit"value="Submit"name="submit1"/>

<inputtype="reset"value="Reset"name="reset1"/>

Thesebuttonshavespecialpurposes,whicharenotrelatedtoscript.

WhentheSubmitbuttonisclicked,theformdatafromtheformthatthebuttonisinsidegetssenttotheserverautomatically,withouttheneedforanyscript.

WhentheResetbuttonisclicked,alltheelementsinaformareclearedandreturnedtotheirdefaultvalues(thevaluestheyhadwhenthepagewasfirstloaded).

TheSubmitandResetbuttonshavecorrespondingobjectscalledSubmitandReset,whichhaveexactlythesameproperties,methods,andeventsasastandardButtonobject.

TextElementsThestandardtextelementsenableuserstoenterasinglelineoftext.ThisinformationcanthenbeusedinJavaScriptcodeorsubmittedtoaserverforserver-sideprocessing.

TheTextBoxAtextboxiscreatedbymeansofthe<input/>element,muchasthebuttonis,butwiththetypeattributesettotext.Again,youcanchoosenottoincludethevalueattribute,butifyoudo,thisvaluewillappearinsidethetextboxwhenthepageisloaded.

Inthefollowingexamplethe<input/>elementhastwoadditionalattributes,sizeandmaxlength.Thesizeattributedetermineshowmanycharacterswidethetextboxis,andmaxlengthdeterminesthemaximumnumberofcharacterstheusercanenterinthebox.Bothattributesareoptionalandusedefaultsdeterminedbythebrowser.

Forexample,tocreateatextbox10characterswide,withamaximumcharacterlengthof15,andinitiallycontainingthewordsHelloWorld,your<input/>elementwouldbeasfollows:

<inputtype="text"name="myTextBox"size="10"maxlength="15"value="Hello

World"/>

Theobjectthatthiselementcreateshasavalueproperty,whichyoucanuseinyourscriptstosetorreadthetextcontainedinsidethetextbox.Inadditiontothecommonpropertiesandmethodsdiscussedearlier,theobjectrepresentingthetextboxalsohastheselect()method,whichselectsorhighlightsallthetextinsidethetextbox.Thismaybeusediftheuserhasenteredaninvalidvalue,andyoucansetthefocustothetextboxandselectthetextinsideit.Thisthenputstheuser’scursorintherightplacetocorrectthedataandmakesitverycleartotheuserwheretheinvaliddatais.Thevaluepropertyalwaysreturnsastringdatatype,evenifnumbercharactersarebeingentered.Ifyouusethevalueasanumber,JavaScriptnormallydoesaconversionfromastringdatatypetoanumberdatatypeforyou,butthisisnotalwaysthecase.Forexample,JavaScriptwon’tdotheconversioniftheoperationyou’reperformingisvalidforastring.Ifyouhaveaformwithtwotextboxesandyouaddthevaluesreturnedfromthese,JavaScriptconcatenatesratherthanaddsthetwovalues,so1plus1willbe11andnot2.Tofixthis,youneedtoconvertallthevaluesinvolvedtoanumericaldatatype,forexamplebyusingparseInt()orparseFloat()orNumber().However,ifyousubtractthetwovalues,anoperationonlyvalidfornumbers,JavaScriptsays“Aha,thiscanonlybedonewithnumbers,soI’llconvertthevaluestoanumberdatatype.”Therefore,1minus1willbereturnedas0withoutyourhavingtouseparseInt()orparseFloat().Thisisatrickybugtospot,soit’sbesttogetintothehabitofconvertingexplicitlytoavoidproblemslater.

Inadditiontothecommonevents,suchasfocusandblur,thetextboxhasthechange,select,keydown,keypress,andkeyupevents.

Theselecteventfireswhentheuserselectssometextinthetextbox.

Moreusefulisthechangeevent,whichfireswhentheelementlosesfocusif(andonlyif)thevalueinsidethetextboxisdifferentfromthevalueithadwhenitgotthefocus.Thisenablesyoutodothingslikevaliditychecksthatoccuronlyifsomethinghaschanged.

Youcanusethereadonlyattributeofthe<input/>element,orthecorrespondingreadOnlyproperty,topreventthecontentsfrombeingchanged:

<inputtype="text"name="txtReadonly"value="Lookbutdon'tchange"

readonly="readonly">

Thekeypress,keydown,andkeyupeventsfire,astheirnamessuggest,whentheuserpressesakey,whentheuserpressesakeydown,andwhenakeythatispresseddownisletbackup,respectively.

TRYITOUTASimpleFormwithValidationLet’sputalltheinformationontextboxesandbuttonstogetherintoanexample.Inthisexample,youhaveasimpleformconsistingoftwotextboxesandabutton.Thetoptextboxisfortheusers’name,andthesecondisfortheirage.Youdovariousvaliditychecks.Youcheckthevalidityoftheagetextboxwhenitlosesfocus.However,thenameandagetextboxesareonlycheckedtoseeiftheyareemptywhenthebuttonisclicked.ThisexampledoesnotworkproperlyonFirefox;we’lldiscussthisshortly.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example4</title>

</head>

<body>

<formaction=""name="form1">

Pleaseenterthefollowingdetails:

<p>

Name:

<inputtype="text"name="txtName"/>

</p>

<p>

Age:

<inputtype="text"name="txtAge"size="3"maxlength="3"/>

</p>

<p>

<inputtype="button"value="Checkdetails"

name="btnCheckForm">

</p>

</form>

<script>

varmyForm=document.form1;

functionbtnCheckFormClick(e){

vartxtName=myForm.txtName;

vartxtAge=myForm.txtAge;

if(txtAge.value==""||txtName.value==""){

alert("Pleasecompletealloftheform");

if(txtName.value==""){

txtName.focus();

}else{

txtAge.focus();

}

}else{

alert("Thanksforcompletingtheform"+

txtName.value);

}

}

functiontxtAgeBlur(e){

vartarget=e.target;

if(isNaN(target.value)){

alert("Pleaseenteravalidage");

target.focus();

target.select();

}

}

functiontxtNameChange(e){

alert("Hi"+e.target.value);

}

myForm.txtName.addEventListener("change",txtNameChange);

myForm.txtAge.addEventListener("blur",txtAgeBlur);

myForm.btnCheckForm.addEventListener("click",

btnCheckFormClick);

</script>

</body>

</html>

Afteryou’veenteredthetext,savethefileasch11_example4.htmlandloaditintoyourwebbrowser.

InthetextboxshowninFigure11.5,typeyourname.Whenyouleavethetextbox,you’llseeHiyournameappearinanalertbox.

Figure11.5

Enteraninvalidvalueintotheagetextbox,suchasaaaa,andwhenyoutrytoleavethebox,it’lltellyouoftheerrorandsendyoubacktocorrectit.

Finally,clicktheCheckDetailsbuttonandbothtextboxeswillbecheckedtoseethatyouhavecompletedthem.Ifeitherisempty,you’llgetamessagetellingyoutocompletethewholeform,andit’llsendyoubacktotheboxthat’sempty.

Ifeverythingisfilledincorrectly,you’llgetamessagethankingyou,asshowninFigure11.5.

Withinthebodyofthepage,youcreatetheHTMLelementsthatdefineyourform.Insideyourform,whichiscalledform1,youcreatethreeformelementswiththenamestxtName,txtAge,andbtnCheckForm:

<formaction=""name="form1">

Pleaseenterthefollowingdetails:

<p>

Name:

<inputtype="text"name="txtName"/>

</p>

<p>

Age:

<inputtype="text"name="txtAge"size="3"maxlength="3"/>

</p>

<p>

<inputtype="button"value="Checkdetails"

name="btnCheckForm">

</p>

</form>

You’llseethatforthesecondtextbox(thetxtAgetextbox),youhaveincludedthe

sizeandmaxlengthattributesinsidethe<input/>element.Settingthesizeattributeto3givestheuseranideaofhowmuchtextyouareexpecting,andsettingthemaxlengthattributeto3helpsensurethatyoudon’tgetoverlylargenumbersenteredfortheagevalue.

Youregisterlistenersforvariouseventsontheseelements:

varmyForm=document.form1;

myForm.txtName.addEventListener("change",txtNameChange);

myForm.txtAge.addEventListener("blur",txtAgeBlur);

myForm.btnCheckForm.addEventListener("click",btnCheckFormClick);

Thefirsttextbox’schangeeventishandledbythetxtNameChange(),thesecondtextbox’sblureventishandledbytxtAgeBlur(),andthebutton’sclickeventwillcausebtnCheckFormClick()toexecute.Let’slookateachofthesefunctionsinturn,startingwithbtnCheckFormClick().

Thefirstthingyoudoisdefinetwovariables,txtNameandtxtAge,andsetthemtoreference<input/>elementswiththesamenames:

functionbtnCheckFormClick(e){

vartxtName=myForm.txtName;

vartxtAge=myForm.txtAge;

Theseareconveniencevariables,thusreducingthesizeofyourcode(youdon’thavetotypemyForm.txtNameeverytimeyoureferencethetxtNameobject).Itmakesyourcodemorereadableandthereforeeasiertodebug,anditsavestyping.

Aftergettingthereferencetothe<input/>elementobjects,youthenuseitinanifstatementtocheckwhetherthevalueinthetextboxnamedtxtAgeorthetextboxnamedtxtNameactuallycontainsanytext:

if(txtAge.value==""||txtName.value==""){

alert("Pleasecompletealloftheform");

if(txtName.value==""){

txtName.focus();

}else{

txtAge.focus();

}

}

Ifyoudofindanincompleteform,youalerttheuser.Theninaninnerifstatement,youcheckwhichtextboxwasnotfilledin.Yousetthefocustotheoffendingtextbox,sothattheusercanstartfillingitinstraightawaywithouthavingtomovethefocustoitherself.Italsoletstheuserknowwhichtextboxyourprogramrequireshertofillin.Toavoidannoyingyourusers,makesurethattextinthepagetellsthemwhichfieldsarerequired.

Iftheoriginalouterifstatementfindsthattheformiscomplete,itletstheuserknowwithathank-youmessage:

else{

alert("Thanksforcompletingtheform"+txtName.value);

}

}

Inthissortofsituation,it’sprobablymorelikelythatyou’llsubmittheformtotheserverthantolettheuserknowwithathank-youmessage.YoucandothisusingtheFormobject’ssubmit()methodorusinganormalSubmitbutton.

ThenextofthethreefunctionsistxtAgeBlur(),whichhandlestheblureventofthetxtAgetextbox.Thisfunction’spurposeistocheckthatthestringvaluetheuserenteredintotheageboxactuallyconsistsofnumericcharacters:

functiontxtAgeBlur(e){

vartarget=e.target;

Atthestartofthefunction,youretrievethetargetoftheevent(thetxtAgetextbox)andstoreitinthetargetvariable.YoucouldusemyForm.txtAgetoreferencethesametxtAgetextbox,butusingtheEventobject’stargetpropertyisabettersolution.ThetxtAgeBlur()functionworksonlywiththeelementthatreceivedtheblurevent.Assuch,usingtheEventobject’stargetpropertygivesyouageneralizedfunctionthatdoesn’tdependonanyexternalvariables,suchasmyForm.Plus,it’slesstyping.

ThefollowingifstatementcheckstoseewhetherwhathasbeenenteredinthetxtAgetextboxcanbeconvertedtoanumber.YouusetheisNaN()functiontodothisforyou.IfthevalueinthetxtAgetextboxisnotanumber,ittellstheuserandsetsthefocusbacktothetextboxbycallingthefocus()method.Additionally,thistimeyouhighlightthetextbyusingtheselect()method.Thismakesitevenclearertotheuserswhattheyneedtofix.Italsoallowsthemtorectifytheproblemwithoutneedingtodeletetextfirst.

if(isNaN(target.value)){

alert("Pleaseenteravalidage");

target.focus();

target.select();

}

}

Youcouldgofurtherandcheckthatthenumberinsidethetextboxisactuallyavalidage—forexample,191isnotavalidage,noris255likelytobe.Youjustneedtoaddanotherifstatementtocheckforthesepossibilities.

ThisfunctionhandlestheblureventofthetxtAgetextbox,butwhydidn’tyouusethechangeevent,withitsadvantagethatitonlyrechecksthevaluewhenthevaluehasactuallybeenchanged?Thechangeeventwouldnotfireiftheboxwasemptybothbeforefocuswaspassedtoitandafterfocuswaspassedawayfromit.However,leavingthecheckingoftheformcompletionuntiljustbeforetheformissubmittedisprobablybestbecausesomeusersprefertofillininformationoutoforderandcomebacktosomeformelementslater.

ThefinalfunctionisforthetxtNametextbox’schangeevent.Itsusehereisalittleflippantandintendedprimarilyasanexampleofthechangeevent:

functiontxtNameChange(e){

alert("Hi"+e.target.value);

}

Whenthechangeeventfires(whenfocusispassedawayfromthenametextboxanditscontentshavechanged),youtakethevalueoftheeventtarget(again,makinguseofthetargetproperty)andputitintoanalertbox.ItsimplysaysHiyourname.

ProblemswithFirefoxandtheblurEventThepreviousexamplewillfailwithFirefoxifyouenteranameinthenametextboxandthenaninvalidageintotheagebox(forexample,ifyouenterabcandthenclicktheCheckFormbutton).Withotherbrowserstheblureventfiresanddisplaysanalertboxiftheageisinvalid,butthebutton’sclickeventdoesn’tfire.However,inFirefox,botheventsfirewiththeresultthattheinvalidagealertishiddenbythe“formcompletedsuccessfully”alertbox.

Inaddition,ifyouenteraninvalidageandthenswitchtoadifferentprogramaltogether,the“invalidage”alertboxappears,whichisannoyingfortheuser.Itcouldbethattheuserwasopeningupanotherprogramtocheckthedetails.

Althoughthisisafineexample,itisnotgreatfortherealworld.Abetteroptionwouldbetochecktheformwhenit’sfinallysubmittedandnotwhiletheuserisenteringdata.Or,alternatively,youcancheckthedataasitisenteredbutnotuseanalertboxtodisplayerrors.Insteadyoucouldwriteoutawarninginrednexttotheerroneousinputcontrol,informingtheuseroftheinvaliddata,andthenalsogetyourcodetochecktheformwhenit’ssubmitted.

ThePasswordTextBoxTheonlyrealpurposeofthepasswordboxistoenableuserstotypeinapasswordonapageandtohavethepasswordcharactershidden,sothatnoonecanlookovertheuser’sshoulderanddiscoverhisorherpassword.However,thisprotectionisvisualonly.Whensenttotheserver,thetextinthepasswordissentasplaintext—thereisnoencryptionoranyattemptathidingthetext(unlessthepageisservedoverasecureconnectionfromtheserver).

Definingapasswordboxisidenticaltodefiningatextbox,exceptthatthetypeattributeispassword:

<inputname="password1"type="password"/>

Thisformelementcreatesan<input/>elementobjectandhasthesameproperties,methods,andeventsasnormaltextboxes.

TheHiddenTextBoxThehiddentextboxcanholdtextandnumbersjustlikeanormaltextbox,withthedifferencebeingthatit’snotvisibletotheuser.Ahiddenelement?Itmaysoundasusefulasaninvisiblepainting,butinfactitprovestobeveryuseful.

Todefineahiddentextbox,youusethefollowingHTML:

<inputtype="hidden"name="myHiddenElement"/>

Thehiddentextboxcreatesyetanother<input/>elementobject,anditcanbemanipulatedinJavaScriptlikeanyotherobject—although,youcanactuallysetitsvalueonlythroughitsHTMLdefinitionorthroughJavaScript.Aswithanormaltextbox,itsvalueissubmittedtotheserverwhentheusersubmitstheform.

Sowhyarehiddentextboxesuseful?Imagineyouhavealotofinformationthatyouneedtoobtainfromtheuser,buttoavoidhavingapagestuffedfullofelementsandlookinglikethecontrolpanelofthespaceshuttle,youdecidetoobtaintheinformationovermorethanonepage.Theproblemis,howdoyoukeeparecordofwhatwasenteredinpreviouspages?Easy—youusehiddentextboxesandputthevaluesinthere.Then,inthefinalpage,alltheinformationissubmittedtotheserver—it’sjustthatsomeofitishidden.

ThetextareaElementThe<textarea/>elementallowsmulti-lineinputoftext.Otherthanthis,itactsverymuchlikethetextboxelement.

However,unlikethetextbox,the<textarea/>elementhasitsowntag,the<textarea>tag,anditcreatesanHTMLTextAreaElementobject.Italsohastwoadditionalattributes:colsandrows.Thecolsattributedefineshowmanycharacterswidethetextareawillbe,andtherowsattributedefineshowmanycharacterrowstherewillbe.Yousetthetextinsidetheelementbyputtingitbetweenthestartandclosingtags,ratherthanbyusingthevalueattribute.Soifyouwanta<textarea/>element40characterswideby20rowsdeepwithinitialtextHelloWorldonthefirstlineandLine2onthesecondline,youdefineitasfollows:

<textareaname="myTextArea"cols="40"rows="20">HelloWorld

Line2

</textarea>

Anotherattributeofthe<textarea/>elementisthewrapattribute,whichdetermineswhathappenswhentheusertypestotheendofaline.Thedefaultvalueforthisissoft,sotheuserdoesnothavetopressReturnattheendofaline,thoughthiscanvaryfrombrowsertobrowser.Toturnwrappingon,youcanuseoneoftwovalues:softandhard.Asfarasclient-sideprocessinggoes,bothdothesamething:Theyswitchwrappingon.However,whenyoucometoserver-sideprocessing,theydomakeadifferenceintermsofwhichinformationissenttotheserverwhentheformisposted.

Ifyousetthewrapattributeonbysettingittosoft,wrappingwilloccurontheclientside,butthecarriagereturnswon’tbepostedtotheserver,justthetext.Ifthewrapattributeissettohard,anycarriagereturnscausedbywrappingwillbeconvertedtohardreturns—itwillbeasiftheuserhadpressedtheEnterkey,andthesereturnswillbesenttotheserver.Also,youneedtobeawarethatthecarriage-returncharacterisdeterminedbytheoperatingsystemthatthebrowserisrunningon—forexample,inWindowsacarriagereturnis\r\n,onUNIX,UNIX-likesystems,andMacOSX,acarriagereturnis\n.Toturnoffwrappingclient-side,setwraptooff.

NOTEThe\ncharacteristheuniversallinefeedcharacter.Ifyouareformattingrawtextoutputandneedanewline,\nworksineverybrowseroneveryoperatingsystem.

Theobjectcreatedbythe<textarea/>elementhasthesameproperties,methods,andeventsasthetextboxobjectyousawpreviously,exceptthatthetextareadoesn’thavethemaxlengthattribute.Notethatthereisavaluepropertyeventhoughthe<textarea/>elementdoesnothaveavalueattribute.Thevaluepropertysimplyreturnsthetextbetweenthe<textarea>and</textarea>tags.Theeventssupportedbythe<textarea/>elementobjectincludethekeydown,keypress,keyup,andchangeeventhandlers.

TRYITOUTEventWatchingTohelpdemonstratehowthekeydown,keypress,keyup,andchangeeventswork(inparticular,theorderinwhichtheyfire),you’llcreateanexamplethattellsyouwhateventsarefiring:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example5</title>

</head>

<body>

<formaction=""name="form1">

<textarearows="15"cols="40"name="textarea1"></textarea>

<textarearows="15"cols="40"name="textarea2"></textarea>

<br/>

<inputtype="button"value="Cleareventtextarea"

name="button1"/>

</form>

<script>

varmyForm=document.form1;

vartextArea1=myForm.textarea1;

vartextArea2=myForm.textarea2;

varbtnClear=myForm.button1;

functiondisplayEvent(e){

varmessage=textArea2.value;

message=message+e.type+"\n";

textArea2.value=message;

}

functionclearEventLog(e){

textArea2.value="";

}

textArea1.addEventListener("change",displayEvent);

textArea1.addEventListener("keydown",displayEvent);

textArea1.addEventListener("keypress",displayEvent);

textArea1.addEventListener("keyup",displayEvent);

btnClear.addEventListener("click",clearEventLog);

</script>

</body>

</html>

Savethispageasch11_example5.html.Loadthepageintoyourbrowser,andseewhathappenswhenyoutypeanyletterintothefirsttextareabox.Youshouldseetheeventsbeingfiredlistedinthesecondtextareabox(keydown,keypress,andkeyup),asshowninFigure11.6.Whenyouclickoutsidethefirsttextareabox,you’llseethechangeeventfire.

Figure11.6

Experimentwiththeexampletoseewhateventsfireandwhen.

Withinaformcalledform1inthebodyofthepage,youdefinetwotextareasandabutton.Thefirsttextareaistheonewhoseeventsyouaregoingtomonitor:

<formaction=""name="form1">

<textarearows="15"cols="40"name="textarea1"></textarea>

Next,youhaveanemptytextareathesamesizeasthefirst:

<textarearows="15"cols="40"name="textarea2"></textarea>

Finally,youhaveyourbutton:

<inputtype="button"value="Cleareventtextarea"name="button1"/>

</form>

You’llregistereventlistenersforthetextarea1andbutton1elementsinyour

JavaScriptcode.Butfirst,youneedtoretrievethoseelementobjectsfromthedocument.Youdothisverysimplybyusingtheformhierarchy:

varmyForm=document.form1;

vartextArea1=myForm.textarea1;

vartextArea2=myForm.textarea2;

varbtnClear=myForm.button1;

YoustartbycreatingthemyFormvariabletocontainthe<form/>elementobject,andthenyouusethatvariabletoretrievetheotherformelements.Nowthatyouhavetheelementobjects,registeringeventlistenersisaseasyascallingtheaddEventListener()method:

textArea1.addEventListener("change",displayEvent);

textArea1.addEventListener("keydown",displayEvent);

textArea1.addEventListener("keypress",displayEvent);

textArea1.addEventListener("keyup",displayEvent);

btnClear.addEventListener("click",clearEventLog);

Onthefirst<textarea/>element(textArea1),youlistenforthechange,keydown,keypress,andkeyupevents,usingthedisplayEvent()functionasthehandlingfunction.Forthebutton,youlistenfortheclickeventwiththeclearEventLog()function.

Thelatterfunctionisthesimplest,solet’slookatthatfirst:

functionclearEventLog(e){

textArea2.value="";

}

ThepurposeofclearEventLog()istoclearthecontentsofthesecond<textarea/>element,anditachievesthisbysettingthe<textarea/>element’svaluepropertytoanemptystring("").

Nowlet’slookatthedisplayEvent()function.Itaddsthenameoftheeventthatoccurredtothetextalreadycontainedinthesecondtextarea:

functiondisplayEvent(e){

varmessage=textArea2.value;

message=message+e.type+"\n";

Youfirstretrievethe<textarea/>element’svalueandstoreitinthemessagevariable.Youthenappendthenameoftheeventaswellasanewlinetothemessage.Puttingeacheventnameonaseparatelinemakesitmucheasiertoreadandfollow.

Thenfinally,youassignthenewmessagetothetextarea’svalueproperty:

textArea2.value=message;

}

CheckBoxesandRadioButtons

Thediscussionsofcheckboxesandradiobuttonsaretogetherbecausetheirobjectshaveidenticalproperties,methods,andevents.Acheckboxenablestheusertocheckanduncheckit.Itissimilartothepapersurveysyoumaygetwhereyouareaskedto“checktheboxesthatapplytoyou.”Radiobuttonsarebasicallyagroupofcheckboxeswhereonlyonecanbecheckedatatime.Ofcourse,theyalsolookdifferent,andtheirgroupnaturemeansthattheyaretreateddifferently.

Creatingcheckboxesandradiobuttonsrequiresouroldfriendthe<input/>element.Itstypeattributeissetto"checkbox"or"radio"todeterminewhichboxorbuttoniscreated.Tosetacheckboxoraradiobuttontobecheckedwhenthepageisloaded,yousimplyinserttheattributecheckedintothe<input>tagandassignitsvalueaschecked.Thisishandyifyouwanttosetadefaultoptionlike,forexample,those“Checkthisboxifyouwantourjunkmail”formsyouoftenseeontheNet,whichareusuallycheckedbydefault,forcingyoutouncheckthem.Sotocreateacheckboxthatisalreadychecked,your<input>tagwillbethefollowing:

<inputtype="checkbox"name="chkDVD"checked="checked"value="DVD"/>

Tocreateacheckedradiobutton,the<input>tagwouldbeasfollows:

<inputtype="radio"name="radCPUSpeed"checked="checked"value="1GHz"/>

Aspreviouslymentioned,radiobuttonsaregroupelements.Infact,thereislittlepointinputtingjustoneonapage,becausetheuserwon’tbeabletochoosebetweenanyalternativeboxes.

Tocreateagroupofradiobuttons,yousimplygiveeachradiobuttonthesamename.Thiscreatesanarrayofradiobuttonsgoingbythatnamethatyoucanaccess,asyouwouldwithanyarray,usingitsindex.

Forexample,tocreateagroupofthreeradiobuttons,yourHTMLwouldbeasfollows:

<inputtype="radio"name="radCPUSpeed"checked="checked"value="800mhz"/>

<inputtype="radio"name="radCPUSpeed"value="1ghz"/>

<inputtype="radio"name="radCPUSpeed"value="1.5ghz"/>

Youcanputasmanygroupsofradiobuttonsinaformasyouwant,byjustgivingeachgroupitsownuniquename.Notethatyouhaveonlyusedonecheckedattribute,becauseonlyoneoftheradiobuttonsinthegroupcanbechecked.Ifyouhadusedthecheckedattributeinmorethanoneoftheradiobuttons,onlythelastofthesewouldhaveactuallybeenchecked.

Usingthevalueattributeofthecheckboxandradiobuttonelementsisnotthesameaswithpreviouselementsyou’velookedat.Ittellsyounothingabouttheuser’sinteractionwithanelementbecauseit’spredefinedinyourHTMLorbyyourJavaScript.Whetheracheckboxorradiobuttonischeckedornot,itstillreturnsthesamevalue.

EachcheckboxhasanassociatedCheckboxobject,andeachradiobuttoninagrouphasaseparateRadioobject.Asmentionedearlier,withradiobuttonsofthesamenameyoucanaccesseachRadioobjectinagroupbytreatingthegroupofradiobuttonsasanarray,withthenameofthearraybeingthenameoftheradiobuttonsinthegroup.Aswithanyarray,youhavethelengthproperty,whichwilltellyouhowmanyradiobuttonsareinthe

group.

NOTEThereactuallyaren’tobjectscalledCheckboxandRadio.All<input/>elementscreateanobjectoftypeHtmlInputElement.Butforthesakeofclarity,thistextusesCheckboxandRadiotomakeexplanationseasiertofollowandunderstand.

Fordeterminingwhetherauserhasactuallycheckedoruncheckedacheckbox,youneedtousethecheckedpropertyoftheCheckboxobject.Thispropertyreturnstrueifthecheckboxiscurrentlycheckedandfalseifnot.

Radiobuttonsareslightlydifferent.Becauseradiobuttonswiththesamenamearegroupedtogether,youneedtotesteachRadioobjectinthegroupinturntoseeifithasbeenchecked.Onlyoneoftheradiobuttonsinagroupcanbechecked,soifyoucheckanotheroneinthegroup,thepreviouslycheckedonewillbecomeunchecked,andthenewonewillbecheckedinitsplace.

BothCheckboxandRadiohavetheclick,focus,andblurevents,andtheseoperateidenticallytotheotherelements,althoughtheycanalsobeusedtocancelthedefaultaction,suchasclickingthecheckboxorradiobutton.

Scriptingcheckboxandradiobuttonsusuallyautomaticallyaddsextrastufftoyourcode—namelyloopsbecauseyouareworkingwithmultiple,near-identicalelements.Thenextexampledemonstratesthis.

TRYITOUTCheckBoxesandRadioButtonsLet’slookatanexamplethatmakesuseofalltheproperties,methods,andeventswehavejustdiscussed.Theexampleisasimpleformthatenablesausertobuildacomputersystem.Perhapsitcouldbeusedinane-commercesituation,tosellcomputerswiththeexactspecificationsdeterminedbythecustomer.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example6</title>

</head>

<body>

<formaction=""name="form1">

<p>

Tickallofthecomponentsyouwantincludedonyour

computer

</p>

<p>

<labelfor="chkDVD">DVD-ROM</label>

<inputtype="checkbox"id="chkDVD"name="chkDVD"

value="DVD-ROM"/>

</p>

<p>

<labelfor="chkBluRay">Blu-ray</label>

<inputtype="checkbox"id="chkBluRay"name="chkBluRay"

value="Blu-ray"/>

</p>

<p>

Selecttheprocessorspeedyourequire

</p>

<p>

<inputtype="radio"name="radCpuSpeed"checked="checked"

value="3.2ghz"/>

<label>3.2GHz</label>

<inputtype="radio"name="radCpuSpeed"value="3.7ghz"/>

<label>3.7GHz</label>

<inputtype="radio"name="radCpuSpeed"value="4.0ghz"/>

<label>4.0GHz</label>

</p>

<inputtype="button"value="Checkform"name="btnCheck"/>

</form>

<script>

varmyForm=document.form1;

functiongetSelectedSpeedValue(){

varradios=myForm.radCpuSpeed;

for(varindex=0;index<radios.length;index++){

if(radios[index].checked){

returnradios[index].value;

}

}

return"";

}

functionfindIndexOfSpeed(radio){

varradios=myForm.radCpuSpeed;

for(varindex=0;index<radios.length;index++){

if(radios[index]==radio){

returnindex;

}

}

return-1;

}

functionradCpuSpeedClick(e){

varradIndex=findIndexOfSpeed(e.target);

if(radIndex==1){

e.preventDefault();

alert("Sorrythatprocessorspeediscurrently

unavailable");

//tofixanissuewithIE

myForm.radCpuSpeed[0].checked=true;

}

}

functionbtnCheckClick(){

varnumberOfControls=myForm.length;

varcompSpec="Yourchosenprocessorspeedis";

compSpec=compSpec+getSelectedSpeedValue();

compSpec=compSpec+"\nWiththefollowingadditional

components:\n";

for(varindex=0;index<numberOfControls;index++){

varelement=myForm[index];

if(element.type=="checkbox"){

if(element.checked){

compSpec=compSpec+element.value+"\n";

}

}

}

alert(compSpec);

}

for(varindex=0;index<myForm.radCpuSpeed.length;index++)

{

myForm.radCpuSpeed[index].addEventListener("click",

radCpuSpeedClick);

}

myForm.btnCheck.addEventListener("click",btnCheckClick);

</script>

</body>

</html>

Savethepageasch11_example6.htmlandloaditintoyourwebbrowser.YoushouldseeaformliketheoneshowninFigure11.7.

Figure11.7

Checksomeofthecheckboxes,changetheprocessorspeed,andclicktheCheckFormbutton.Amessageboxappearsandliststhecomponentsandprocessorspeedyouselected.Forexample,ifyouselectaDVD-ROManda4.0GHzprocessorspeed,youwillseesomethinglikewhatisshowninFigure11.8.

Figure11.8

Notethatthe3.7GHzprocessorisoutofstock,soifyouchoosethat,amessagebox

tellsyouit’soutofstock,andthe3.2GHzprocessorspeedradiobuttonwon’tbeselected.Theprevioussettingwillberestoredwhentheuserdismissesthemessagebox.

Let’sfirstlookatthebodyofthepage,whereyoudefinethecheckboxesandradiobuttonsandastandardbuttoninsideaformcalledform1.Youstartwiththecheckboxes:

<p>

Tickallofthecomponentsyouwantincludedonyourcomputer

</p>

<p>

<labelfor="chkDVD">DVD-ROM</label>

<inputtype="checkbox"id="chkDVD"name="chkDVD"value="DVD-ROM"/>

</p>

<p>

<labelfor="chkBluRay">Blu-ray</label>

<inputtype="checkbox"id="chkBluRay"name="chkBluRay"value="Blu-

ray"/>

</p>

Eachcheckboxhasalabelandiscontainedwithina<p/>elementforformattingpurposes.

NextcometheradiobuttonsforselectingtherequiredCPUspeed.Again,eachhasalabel,butunlikethecheckboxes,theseradiobuttonsarecontainedwithinasingle<p/>element:

<p>

Selecttheprocessorspeedyourequire

</p>

<p>

<inputtype="radio"name="radCpuSpeed"checked="checked"

value="3.2ghz"/>

<label>3.2GHz</label>

<inputtype="radio"name="radCpuSpeed"value="3.7ghz"/>

<label>3.7GHz</label>

<inputtype="radio"name="radCpuSpeed"value="4.0ghz"/>

<label>4.0GHz</label>

</p>

TheradiobuttongroupnameisradCpuSpeed.Here,thefirstoneissettobecheckedbydefaultbytheinclusionofthecheckedattributeinsidethe<input/>element’sdefinition.It’sagoodideatoensurethatyouhaveoneradiobuttoncheckedbydefault,becauseifyoudonotandtheuserdoesn’tselectabutton,theformwillbesubmittedwithnovalueforthatradiogroup.

Next,thestandardbuttonthatcompletesyourform:

<inputtype="button"value="Checkform"name="btnCheck"/>

Beforeproceedingfurther,anote:TomaketheJavaScriptcodeeasier,youcoulduse

theonclickattributesoneachoftheradiobuttonsaswellasthestandardbutton.ButasmentionedinChapter10,youwanttoavoidthoseattributesasmuchaspossiblebecauseitcouplesyourHTMLandJavaScripttogether.

Twofunctionsareusedtohandletheclickeventsforthestandardbuttonandtheradiobuttons:btnCheckClick()andradCpuSpeedClick(),respectively.Andbeforewelookatthesefunctions,youfirstneedtoregistertheclickeventlistenersontheirrespectiveelements.Asinpreviousexamples,firstcreateavariablecalledmyFormtoreferencetheforminthedocument:

varmyForm=document.form1;

Now,registertheclickeventlisteneronyourradiobuttons.Unfortunately,there’snomagicalcommandthatsays“usethisfunctiontohandlealltheradiobuttons’clickevents.”So,you’llhavetocalladdEventListener()oneveryRadioobject.Thisisn’tasdifficultasitsounds;aforloopwillhelpyou:

for(varindex=0;index<myForm.radCpuSpeed.length;index++){

myForm.radCpuSpeed[index].addEventListener("click",

radCpuSpeedClick);

}

Thisforloopisfairlystraightforwardexceptforonething:myForm.radCpuSpeed.WhatyouaredoinghereisusingthecollectionfortheradCpuSpeedradiogroup.Eachelementinthecollectionactuallycontainsanobject,namelyeachofyourthreeRadioobjects.Therefore,you’reloopingovertheRadioobjectsintheradCpuSpeedradiogroup,retrievingtheRadioobjectatthegivenindex,andcallingitsaddEventListener()method.

Next,registertheeventlistenerfortheform’sstandardbutton:

myForm.btnCheck.addEventListener("click",btnCheckClick);

Nowlet’slookattheradCpuSpeedClick()function,thefunctionthatexecuteswhentheradiobuttonsareclicked.ThefirstthingthisfunctionneedstodoistofindtheindexoftheeventtargetintheradCpuSpeedradiogroup:

functionradCpuSpeedClick(e){

varradIndex=findIndexOfSpeed(e.target);

YoudothisbycallingthefindIndexOfSpeed()helperfunction.We’lllookatthisfunctionlater,butfornow,justknowthatitfindstheindexofthesuppliedRadioobjectinthemyForm.radCpuSpeedcollection.

Thedefaultactionofclickingaradiobuttonistochecktheradiobutton.Ifyoupreventthedefaultactionfromoccurring,theradiobuttonwillnotbechecked.Asanexampleofthisinaction,youhaveanifstatementonthenextline.Iftheradiobutton’sindexvalueis1(thatis,iftheusercheckedtheboxfora3.7GHzprocessor),youtelltheuserthatit’soutofstockandcanceltheclickingactionbycallingtheEventobject’spreventDefault()method:

if(radIndex==1){

e.preventDefault();

alert("Sorrythatprocessorspeediscurrentlyunavailable");

Aspreviouslymentioned,cancelingtheclickingactionresultsintheradiobuttonnotbeingchecked.Insuchasituation,allbrowsers(exceptforIE)recheckthepreviouslycheckedradiobutton.IE,however,removesallchecksfromtheradiogroup.Torectifythis,youresettheradiogroup:

//tofixanissuewithIE

myForm.radCpuSpeed[0].checked=true;

}

}

YouonceagainusethemyForm.radCpuSpeedcollection,retrievetheRadioobjectatindex0,andsetitscheckedpropertytotrue.Let’stakeamomentandlookatthefindIndexOfSpeed()helpermethod.ItacceptsaRadioobjectasanargument,anditsearchesthemyForm.radCpuSpeedcollectionforthegivenRadioobject.

Thefirstlineofthefunctioncreatesavariablecalledradios,anditcontainsareferencetothemyForm.radCpuSpeedcollection.Thisistomaketypingandreadingabiteasier:

functionfindIndexOfSpeed(radio){

varradios=myForm.radCpuSpeed;

Next,youwanttoloopthroughtheradioscollectionanddetermineifeachRadioobjectinthecollectionisthesameRadioobjectintheradiovariable:

for(varindex=0;index<radios.length;index++){

if(radios[index]==radio){

returnindex;

}

}

return-1;

}

Ifyoufindamatch,youreturnthevalueoftheindexvariable.Iftheloopexitswithoutfindingamatch,youreturn-1.ThisbehaviorisconsistentwiththeStringobject’sindexOf()method.Consistencyisaverygoodthing!

Thenextfunction,btnCheckClick(),executeswhenthestandardbutton’sclickeventfires.Inareale-commercesituation,thisbuttonwouldbetheplacewhereyou’dcheckyourformandthensubmitittotheserverforprocessing.Hereyouusetheformtoshowamessageboxconfirmingwhichboxesyouhavechecked(asifyoudidn’talreadyknow)!

Atthetopyoudeclaretwolocalvariablestouseinthefunction.ThevariablenumberOfControlsissettotheform’slengthproperty,whichisthenumberofelementsontheform.ThevariablecompSpecisusedtobuildthestringthatyou’lldisplayinamessagebox:

functionbtnCheckClick(){

varnumberOfControls=myForm.length;

varcompSpec="Yourchosenprocessorspeedis";

Inthefollowingline,youaddthevalueoftheradiobuttontheuserhasselectedtoyourmessagestring:

compSpec=compSpec+findSelectedSpeedValue();

compSpec=compSpec+"\nWiththefollowingadditional

components:\n";

YouuseyetanotherhelperfunctioncalledgetSelectedSpeedValue().Asitsnameimplies,itgetsthevalueoftheselectedRadioobject.You’lllookatitscodelater.

Next,youloopthroughtheform’selements:

for(varindex=0;index<numberOfControls;index++){

varelement=myForm[index];

if(element.type=="checkbox"){

if(element.checked){

compSpec=compSpec+element.value+"\n";

}

}

}

alert(compSpec);

}

It’sherethatyouloopthrougheachelementontheformusingmyForm[controlIndex],whichreturnsareferencetotheelementobjectstoredatthecontrolIndexindexposition.

You’llseethatinthisexampletheelementvariableissettoreferencetheobjectstoredinthemyFormcollectionattheindexpositionstoredinvariablecontrolIndex.Again,thisisforconvenientshorthandpurposes;nowtousethatparticularobject’spropertiesormethods,youjusttypeelement,aperiod,andthenthemethodorpropertyname,makingyourcodeeasiertoreadanddebug,whichalsosavesontyping.

Youonlywanttoseewhichcheckboxeshavebeenchecked,soyouusethetypeproperty,whicheveryHTMLformelementobjecthas,toseewhatelementtypeyouaredealingwith.Ifthetypeischeckbox,yougoaheadandseeifit’sacheckedcheckbox.Ifso,youappenditsvaluetothemessagestringincompSpec.Ifitisnotacheckbox,itcanbesafelyignored.

Finally,youusethealert()methodtodisplaythecontentsofyourmessagestring.

ThelastfunctionisgetSelectedSpeedValue().Itdoesn’tacceptanyarguments,althoughyoucouldgeneralizethisfunctiontoacceptacollectionofRadioobjects.Doingsowouldallowyoutoreusethefunctioninmultipleprojects.

Buttogetbacktotheactualcode,thefirststatementofthefunctioncreatesaradiosvariablethatcontainsareferencetothemyForm.radCpuSpeedcollection:

functiongetSelectedSpeedValue(){

varradios=myForm.radCpuSpeed;

Next,youwanttofindtheselectedRadioobjectandretrieveitsvalue.Youcandothiswithyetanotherforloop:

for(varindex=0;index<radios.length;index++){

if(radios[index].checked){

returnradios[index].value;

}

}

return"";

}

Thelogicisstraightforward:LoopthroughtheradioscollectionandcheckeachRadioobject’scheckedproperty.Ifit’strue,returnthevalueofthatRadioobject,butiftheloopexitswithoutfindingacheckedRadioobject,youreturnanemptystring.

SelectionBoxesAlthoughtheylookquitedifferent,thedrop-downlistandthelistboxesareactuallybothelementscreatedwiththe<select>tag,andstrictlyspeakingtheyarebothselectelements.Theselectelementhasoneormoreoptionsinalistthatyoucanselectfrom;eachoftheseoptionsisdefinedbymeansofoneormore<option/>elementsinsidetheopeningandclosing<select>tags.

Thesizeattributeofthe<select/>elementisusedtospecifyhowmanyoftheoptionsarevisibletotheuser.

Forexample,tocreatealistboxfiverowsdeepandpopulateitwithsevenoptions,yourHTMLwouldlooklikethis:

<selectname="theDay"size="5">

<optionvalue="0"selected="selected">Monday</option>

<optionvalue="1">Tuesday</option>

<optionvalue="2">Wednesday</option>

<optionvalue="3">Thursday</option>

<optionvalue="4">Friday</option>

<optionvalue="5">Saturday</option>

<optionvalue="6">Sunday</option>

</select>

Noticethatthe<option/>elementforMondayalsocontainstheattributeselected;thiswillmakethisoptionselectedbydefaultwhenthepageisloaded.Thevaluesoftheoptionshavebeendefinedasnumbers,buttextwouldbeequallyvalid.

Ifyouwantthistobeadrop-downlist,youjustneedtochangethesizeattributeinthe<select/>elementto1,andpresto,it’sadrop-downlist.

Ifyouwanttolettheuserchoosemorethanoneitemfromalistatonce,yousimplyneedtoaddthemultipleattributetothe<select/>definition.

The<select/>elementcreatesanHTMLSelectElementobject(herebyknownasSelect).

Thisobjecthasanoptionscollectionproperty,whichismadeupofHtmlOptionElement(herebyknownasOption)objects,oneforeach<option/>elementinsidethe<select/>elementassociatedwiththeSelectobject.Forinstance,intheprecedingexample,ifthe<select/>elementwascontainedinaformcalledtheFormwiththefollowing:

document.theForm.theDay.options[0]

youwouldaccesstheoptioncreatedforMonday.

Howcanyoutellwhichoptionhasbeenselectedbytheuser?Easy:youusetheSelectobject’sselectedIndexproperty.Youcanusetheindexvaluereturnedbythispropertytoaccesstheselectedoptionusingtheoptionscollection.

TheOptionobjectalsohasindex,text,andvalueproperties.Theindexpropertyreturnstheindexpositionofthatoptionintheoptionscollection.Thetextpropertyiswhat’sdisplayedinthelist,andthevaluepropertyisthevaluedefinedfortheoption,whichwouldbepostedtotheserveriftheformweresubmitted.

Ifyouwanttofindouthowmanyoptionsareinaselectelement,youcanusethelengthpropertyofeithertheSelectobjectitselforofitsoptionscollectionproperty.

Let’sseehowyoucouldloopthroughtheoptionsfortheprecedingselectbox:

vartheDayElement=document.theForm.theDay;

document.write("Thereare"+theDayElement.length+"options<br/>");

for(varindex=0;index<theDayElement.length;index++){

document.write("Optiontextis"+

theDayElement.options[index].text);

document.write("anditsvalueis");

document.write(theDayElement.options[index].value);

document.write("<br/>");

}

First,yousetthevariabletheDayElementtoreferencetheSelectobject.Thenyouwritethenumberofoptionstothepage,inthiscase7.

Nextyouuseaforlooptoloopthroughtheoptionscollection,displayingthetextofeachoption,suchasMonday,Tuesday,andsoon,anditsvalue,suchas0,1,andsoon.Ifyoucreateapagebasedonthiscode,itmustbeplacedafterthe<select/>element’sdefinition.

It’salsopossibletoaddoptionstoaselectelementafterthepagehasfinishedloading.Youlookathowtodothisnext.

AddingandRemovingOptionsToaddanewoptiontoaselectelement,yousimplycreateanewOptionobjectusingthenewoperatorandtheninsertitintotheoptionscollectionoftheSelectobjectatanemptyindexposition.

WhenyoucreateanewOptionobject,youhavetwoparameterstopass.Thefirstisthetextyouwanttoappearinthelist,andthesecondisthevaluetobeassignedtotheoption:

varmyNewOption=newOption("TheText","TheValue");

YouthensimplyassignthisOptionobjecttoanemptyarrayelement.Forexample:

theDayElement.options[0]=myNewOption;

Ifyouwanttoremoveanoption,yousimplysetthatpartoftheoptionscollectiontonull.Forexample,toremovetheelementyoujustinserted,youneedthefollowing:

theDayElement.options[0]=null;

WhenyouremoveanOptionobjectfromtheoptionscollection,thecollectionisreorderedsothatthearrayindexvalueofeachoftheoptionsabovetheremovedonehasitsindexvaluedecrementedbyone.

Whenyouinsertanewoptionatacertainindexposition,beawarethatitwilloverwriteanyOptionobjectthatisalreadythere.

TRYITOUTAddingandRemovingListOptionsInthisTryItOut,youusethelist-of-daysexampleyousawpreviouslytodemonstrateaddingandremovinglistoptions.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example7</title>

</head>

<body>

<formaction=""name="theForm">

<selectname="theDay"size="5">

<optionvalue="0"selected="selected">Monday</option>

<optionvalue="1">Tuesday</option>

<optionvalue="2">Wednesday</option>

<optionvalue="3">Thursday</option>

<optionvalue="4">Friday</option>

<optionvalue="5">Saturday</option>

<optionvalue="6">Sunday</option>

</select>

<br/>

<inputtype="button"value="RemoveWednesday"

name="btnRemoveWed"/>

<inputtype="button"value="AddWednesday"name="btnAddWed"/>

<br/>

</form>

<script>

vartheForm=document.theForm;

functionbtnRemoveWedClick(){

varoptions=theForm.theDay.options;

if(options[2].text=="Wednesday"){

options[2]=null;

}else{

alert("ThereisnoWednesdayhere!");

}

}

functionbtnAddWedClick(){

varoptions=theForm.theDay.options;

if(options[2].text!="Wednesday"){

varlastOption=newOption();

options[options.length]=lastOption;

for(varindex=options.length-1;index>2;

index––){

varcurrentOption=options[index];

varpreviousOption=options[index-1];

currentOption.text=previousOption.text;

currentOption.value=previousOption.value;

}

varoption=newOption("Wednesday",2);

options[2]=option;

}else{

alert("DoyouwanttohaveTWOWednesdays?");

}

}

theForm.btnRemoveWed.addEventListener("click",

btnRemoveWedClick);

theForm.btnAddWed.addEventListener("click",btnAddWedClick);

</script>

</body>

</html>

Savethisasch11_example7.html.Ifyoutypethepageinandloaditintoyourbrowser,youshouldseetheformshowninFigure11.9.ClicktheRemoveWednesdaybutton,andyou’llseeWednesdaydisappearfromthelist.AdditbackbyclickingtheAddWednesdaybutton.IfyoutrytoaddasecondWednesdayorremoveanonexistentWednesday,you’llgetapolitewarningtellingyouthatyoucan’tdothat.

Figure11.9

Withinthebodyofthepage,youdefineaformwiththenametheForm.Thiscontainsthe<select/>element,whichincludesday-of-the-weekoptionsthatyouhaveseenpreviously.Theformalsocontainstwobuttons,asshownhere:

<inputtype="button"value="RemoveWednesday"name="btnRemoveWed"/>

<inputtype="button"value="AddWednesday"name="btnAddWed"/>

YouwanttoexecuteJavaScriptcodewhenthesebuttonsareclicked;therefore,youwanttoregisterclickeventlistenersforeachofthebuttons.Tomakethisabiteasier,youfirstcreateavariablecalledtheForm,whichcontainsthe<form/>elementobject:

vartheForm=document.theForm;

Youusethisvariabletoaccesstheindividualbuttonsandregistertheirclickeventlisteners:

theForm.btnRemoveWed.addEventListener("click",btnRemoveWedClick);

theForm.btnAddWed.addEventListener("click",btnAddWedClick);

The“remove”buttonexecutesthebtnRemoveWedClick()function,andthe“add”buttonexecutesbtnAddWedClick().Youtakealookateachofthesefunctionsinturn.

Thefirstfunction,btnRemoveWedClick(),removestheWednesdayoption:

functionbtnRemoveWedClick(){

varoptions=theForm.theDay.options;

if(options[2].text=="Wednesday"){

options[2]=null;

}else{

alert("ThereisnoWednesdayhere!");

}

}

ThefirstthingyoudointhefunctioniscreateavariablethatcontainsthecollectionofOptionelements.Thisletsyourepeatedlyreferencetheoptioncollectionwithouttypingdocument.theForm.theDay.options,oranyvariationthereof.

Next,asanitycheck:YoumusttrytoremovetheWednesdayoptiononlyifit’sthereinthefirstplace!Youmakesureofthisbyseeingifthethirdoptioninthecollection(withindex2becausearraysstartatindex0)hasthetext"Wednesday".Ifitdoes,youcanremovetheWednesdayoptionbysettingthatparticularoptiontonull.IfthethirdoptioninthearrayisnotWednesday,youalerttheusertothefactthatthereisnoWednesdaytoremove.Althoughthiscodeusesthetextpropertyintheifstatement’scondition,youcouldjustaseasilyhaveusedthevalueproperty;itmakesnodifference.

NextyoucometothebtnAddWedClick()function,which,asthenamesuggests,addstheWednesdayoption.Thisisslightlymorecomplexthanthecoderequiredtoremoveanoption.First,youcreateanothervariable,calledoptions,tocontainthecollectionofOptionobjects.Then,youuseanifstatementtocheckthatthereisnotalreadyaWednesdayoption:

functionbtnAddWedClick(){

varoptions=theForm.theDay.options;

if(options[2].text!="Wednesday"){

varlastOption=newOption();

options[options.length]=lastOption;

for(varindex=options.length-1;index>2;index––){

varcurrentOption=options[index];

varpreviousOption=options[index-1];

currentOption.text=previousOption.text;

currentOption.value=previousOption.value;

}

IfthereisnoWednesdayoption,youthenneedtomakespaceforthenewWednesdayoptiontobeinserted.

Atthispoint,youhavesixoptions(thelastelementisasindex5),sonextyoucreateanewoptionwiththevariablenamelastOptionandassignittotheelementattheendofthecollection.Thisnewelementisassignedatindexposition6byusingthelengthpropertyoftheoptionscollection,whichpreviouslyhadnocontents.YounextassignthetextandvaluepropertiesofeachoftheOptionobjectsfromThursdaytoSundaytotheOptionatanindexvaluehigherbyoneintheoptionsarray,leavingaspaceintheoptionsarrayatposition2toputWednesdayin.Thisisthetaskfortheforloopwithintheifstatement.

Next,youcreateanewOptionobjectbypassingthetext"Wednesday"andthevalue

2totheOptionconstructor.TheOptionobjectistheninsertedintotheoptionscollectionatposition2,andpresto,itappearsinyourselectbox.

varoption=newOption("Wednesday",2);

options[2]=option;

}

YouendthefunctionbyalertingtheusertothefactthatthereisalreadyaWednesdayoptioninthelist,iftheconditionintheifstatementisfalse:

else{

alert("DoyouwanttohaveTWOWednesdays?");

}

}

Thisexampleworksineverybrowser;however,allmodernbrowsersprovideadditionalmethodstomakeaddingandremovingoptionseasier.

AddingNewOptionswithStandardMethodsInparticular,theSelectobjectyouareinterestedinhasadditionaladd()andremove()methods,whichaddandremoveoptions.Thesemakelifealittlesimpler.

Beforeyouaddanoption,youneedtocreateit.Youdothisjustasbefore,usingthenewoperator.

TheSelectobject’sadd()methodenablesyoutoinsertanOptionobjectthatyouhavecreatedandacceptstwoparameters.ThefirstparameteristheOptionobjectyouwanttoadd.ThesecondparameteristheOptionobjectyouwanttoplacethenewOptionobjectbefore.However,inIE7(orIE8non-standardsmode),thesecondparameteristheindexpositionatwhichyouwanttoaddtheoption.Inallbrowsers,youcanpassnullasthesecondparameter,andtheaddedOptionobjectwillbeaddedattheendoftheoptionscollection.

Theadd()methodwon’toverwriteanyOptionobjectalreadyatthatposition,butinsteadwillsimplymovetheOptionobjectsupinthecollectiontomakespace.ThisisbasicallythesameaswhatyouhadtocodeintothebtnAddWedClick()functionusingyourforloop.

Usingtheadd()method,youcanrewritethebtnAddWedClick()functioninch11_example7.htmltolooklikethis:

functionbtnAddWedClick(){

vardays=theForm.theDay;

varoptions=days.options;

if(options[2].text!="Wednesday"){

varoption=newOption("Wednesday",2);

varthursdayOption=options[2];

try{

days.add(option,thursdayOption);

}

catch(error){

days.add(option,2);

}

}else{

alert("DoyouwanttohaveTWOWednesdays?");

}

}

InIE7(orIE8innon-standardsmode),thebrowserwillthrowanerrorifyoupassanOptionobjectasthesecondparameter.Souseatry…catchstatementtocatchtheerrorandpassanumbertothesecondargument,asthiscodeshows.

TheSelectobject’sremove()methodacceptsjustoneparameter,namelytheindexoftheoptionyouwantremoved.Whenanoptionisremoved,theoptionsathigherindexpositionsaremoveddowninthecollectiontofillthegap.

Usingtheremove()method,youcanrewritethebtnRemoveWedClick()functioninch11_example7.htmltolooklikethis:

functionbtnRemoveWedClick(){

vardays=theForm.theDay;

if(days.options[2].text=="Wednesday"){

days.remove(2);

}else{

alert("ThereisnoWednesdayhere!");

}

}

Modifythepreviousexampleandsaveitasch11_example8.htmlbeforeloadingitintoyourbrowser.You’llseethatitworksjustasthepreviousversiondid.

SelectElementEventsSelectelementshavethreeevents:blur,focus,andchange.You’veseenalltheseeventsbefore.Yousawthechangeeventwiththetextboxelement,whereitfiredwhenfocuswasmovedawayfromthetextboxandthevalueinthetextboxhadchanged.Hereitfireswhentheuserchangeswhichoptioninthelistisselected.

TRYITOUTWorldTimeConverterLet’stakealookatanexamplethatusesthechangeevent.TheWorldTimeConverterletsyoucalculatethetimeindifferentcountries:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example9</title>

</head>

<body>

<div>LocalTimeis<spanid="spanLocalTime"></span></div>

<divid="divCityTime"></div>

<formname="form1">

<selectsize="5"name="lstCity">

<optionvalue="60"selected>Berlin

<optionvalue="330">Bombay

<optionvalue="0">London

<optionvalue="180">Moscow

<optionvalue="-300">NewYork

<optionvalue="60">Paris

<optionvalue="-480">SanFrancisco

<optionvalue="600">Sydney

</select>

<p>

<inputtype="checkbox"id="chkDst"name="chkDst"/>

<labelfor="chkDst">AdjustcitytimeforDaylight

Savings</label>

</p>

</form>

<script>

varmyForm=document.form1;

functionupdateTimeZone(){

varlstCity=myForm.lstCity;

varselectedOption=

lstCity.options[lstCity.selectedIndex];

varoffset=selectedOption.value;

varselectedCity=selectedOption.text;

vardstAdjust=0;

if(myForm.chkDst.checked){

dstAdjust=60;

}

updateOutput(selectedCity,offset,dstAdjust);

}

functionupdateOutput(selectedCity,offset,dstAdjust){

varnow=newDate();

document.getElementById("spanLocalTime")

.innerHTML=now.toLocaleString();

now.setMinutes(now.getMinutes()+now.getTimezoneOffset()+

parseInt(offset,10)+dstAdjust);

varresultsText=selectedCity+"timeis"+

now.toLocaleString();

document.getElementById("divCityTime").innerHTML=

resultsText;

}

myForm.lstCity.addEventListener("change",updateTimeZone);

myForm.chkDst.addEventListener("click",updateTimeZone);

updateTimeZone();

</script>

</body>

</html>

Savethisasch11_example9.html.Openthepageinyourbrowser.

TheformlayoutlookssomethingliketheoneshowninFigure11.10.Whenevertheuserclicksacityinthelist,herlocaltimeandtheequivalenttimeintheselectedcityareshown.IntheexampleshowninFigure11.10,thelocalregionissettoCentralStandardTimeintheU.S.,andtheselectedcityisBerlin,withthedaylightsavingsboxchecked.

Figure11.10

It’sworthpointingoutthatthisisjustanexampleandnotatotallyfoolproofone,becauseoftheproblemspresentedbydaylightsavings.Somelocationsdon’thaveit,othersdoatfixedtimesofyear,andyetothersdobutatvaryingtimesoftheyear.Thismakesitdifficulttopredictaccuratelywhenacountrywillhaveitsdaylightsavingsperiod.Youhavetriedtosolvethisproblembyaddingacheckboxfortheusertoclickifthecityshechoosesfromthelistisusingdaylightsavingshours(whichyouassumewillputthetimeinthecityforwardbyonehour).

Inaddition,don’tforgetthatsomeusersmaynotevenhavetheirregionalsettingssetcorrectly—there’snoeasywayaroundthisproblem.

Inthebodyofthispageisapairof<div/>elementsusedforoutput:

<div>LocalTimeis<spanid="spanLocalTime"></span></div>

<divid="divCityTime"></div>

There’salsoaforminwhichyou’vedefinedalistboxusinga<select>element:

<selectsize="5"name="lstCity">

<optionvalue="60"selected>Berlin

<optionvalue="330">Bombay

<optionvalue="0">London

<optionvalue="180">Moscow

<optionvalue="-300">NewYork

<optionvalue="60">Paris

<optionvalue="-480">SanFrancisco

<optionvalue="600">Sydney

</select>

Eachoftheoptionsdisplaysthecity’snameinthelistboxandhasitsvaluesettothedifferenceinminutesbetweenthatcity’stimezone(inwinter)andUTC.SoLondon,whichusesUTC,hasavalueof0.Paris,whichisanhouraheadofUTC,hasavalueof60(thatis,60minutes).NewYork,whichisfivehoursbehindUTC,hasavalueof-300.

There’salsoacheckboxwithanassociatedlabel:

<p>

<inputtype="checkbox"id="chkDst"name="chkDst"/>

<labelfor="chkDst">AdjustcitytimeforDaylightSavings</label>

</p>

Checkingthischeckboxwilladdanhourtoacity’scalculatedtime.

You’llregisterthechangeeventlistenerofthe<select/>elementandtheclickeventlistenerofthecheckboxtocalltheupdateTimeZone()function.Aswithpreviousversions,youcreateaglobalvariabletoprovideeasieraccesstothe<form/>elementobject:

varmyForm=document.form1;

Thenyouregistertheeventlisteners:

myForm.lstCity.addEventListener("change",updateTimeZone);

myForm.chkDst.addEventListener("click",updateTimeZone);

ThefunctionupdateTimeZone()doesn’treallyupdateanything,butitdoesgatherinformationandkickofftheupdateprocess:

functionupdateTimeZone(){

varlstCity=myForm.lstCity;

Thefirstfourstatementsofthisfunctioncreatefourvariables.Thefirst,lstCity,containsareferencetothe<select/>elementobject.Youcreatethisvariableforconveniencepurposes—namelyforthecreationofthesecondvariable:selectedOption:

varselectedOption=lstCity.options[lstCity.selectedIndex];

ThisselectedOptionvariableisretrievedbyusingthelstCityobject’soptionspropertyinconjunctionwithitsselectedIndexproperty,andnowthatyouhavetheselectedOption,youcaneasilygettheinformationattachedtotheoption:

varoffset=selectedOption.value;

varselectedCity=selectedOption.text;

Next,youwanttodetermineiftheusercheckedthedaylightsavingscheckbox:

vardstAdjust=0;

if(myForm.chkDst.checked){

dstAdjust=60;

}

YouinitializethedstAdjustvariablewith0.Ifthecheckboxischecked,youmodifydstAdjusttocontainthevalueof60.Thevalueof60isfor60minutes.Asyouhaveprobablyguessed,yourtimeconversioncalculationwillbewithminutevalues.

InthefinalpartofupdateTimeZone(),youcalltheupdateTime()function,passingthevaluescontainedwithintheselectedCity,offset,anddstAdjustvariables:

updateTime(selectedCity,offset,dstAdjust);

}

InthefunctionupdateTime(),youwritethecurrentlocaltimeandtheequivalenttimeintheselectedcitytotheoutputelements.

YoustartatthetopofthefunctionbycreatinganewDateobject,whichisstoredinthevariablenow.TheDateobjectwillbeinitializedtothecurrentlocaltime:

functionupdateOutput(selectedCity,offset,dstAdjust){

varnow=newDate();

Next,yououtputthelocaltimetothe<span/>elementwithanidofspanLocalTime:

document.getElementById("spanLocalTime").innerHTML=

now.toLocaleString();

YouusetheDateobject’stoLocaleString()methodtoformatthedateandtimeinyourregion’sformat.

YousawinChapter7thatifyousetthevalueofaDateobject’sindividualparts(suchashours,minutes,andseconds)toavaluebeyondtheirnormalrange,JavaScriptassumesyouwanttoadjustthedate,hours,orminutestotakethisintoaccount.Forexample,ifyousetthehoursto36,JavaScriptsimplychangesthehoursto12andaddsonedaytothedatestoredinsidetheDateobject.Youusethistoyourbenefitinthefollowingline:

now.setMinutes(now.getMinutes()+now.getTimezoneOffset()+

parseInt(offset,10)+dstAdjust);

Let’sbreakdownthislinetoseehowitworks.Supposethatyou’reinNewYork,withthelocalsummertimeof5:11,andyouwanttoknowwhattimeitisinBerlin.

Howdoesyourlineofcodecalculatethis?

First,yougettheminutesofthecurrentlocaltime;it’s5:11,sonow.getMinutes()returns11.

Thenyougetthedifference,inminutes,betweentheuser’slocaltimeandUTCusingnow.getTimezoneOffset().IfyouareinNewYork,whichisdifferentfromUTCby4hoursduringthesummer,thisis240minutes.

ThenyougettheintegervalueofthetimedifferencebetweenthestandardwintertimeintheselectedcityandUTCtime,whichisstoredinoffset.You’veusedparseInt()herebecauseit’soneofthefewsituationswhereJavaScriptgetsconfusedandassumesyouwanttojointwostringstogetherratherthantreatthevaluesasnumbersandaddthemtogether.RememberthatyougotoffsetfromanHTMLelement’svalue,andthatanHTMLelement’svaluesarestrings,evenwhentheyholdcharactersthataredigits.BecauseyouwantthetimeinBerlin,whichis60minutesdifferentfromUTCtime,thisvaluewillbe60.

Finally,youaddthevalueofdstAdjust.Becauseit’ssummerwhereyouareandBerlinusesdaylightsavingshours,thisvalueis60.

Soyouhavethefollowing:

11+240+60+60=371

Therefore,now.setMinutes()issettingtheminutesto371.Clearly,there’snosuchthingas371minutespastthehour,soinsteadJavaScriptassumesyoumean6hoursand11minutesafter5:00,thatbeing11:11—thetimeinBerlinthatyouwanted.

Finally,theupdateTime()functioncreatestheresultsTextvariableandthenwritestheresultstothedivCityTime:

varresultsText=selectedCity+"timeis"+

now.toLocaleString();

document.getElementById("divCityTime").innerHTML=resultsText;

}

HTML5FORMOBJECTPROPERTIESANDMETHODSHTML4wasfinalizedin1997,anditwasn’tuntil2012thatthewebcommunitysawapushforHTML5.Needlesstosay,HTMLhadn’tseenasignificantupdateuntiltheintroductionofHTML5.Soforfifteenyears,webdevelopershaveworkedwithformcontrolsthatgrosslydon’tmeetdevelopers’andusers’needs.Thankfully,thatchangeswithHTML5.

Onethingyou’vedonethroughoutthischapterisrespondtovariousformcontrols’change,click,focus,blur,andkeypressevents(amongothers).Alloftheseeventscanbeusedinconjunctionwithoneanothersothatyoucanrespondtoanyuserinput,butthatrequiresalotofextracode.

AbettersolutionwouldbetousetheinputeventintroducedinHTML5.Thisneweventfireswhenthevalueofanelementchanges.Thatmeansyoucanlistenfortheinputeventona<form/>objectandprocessitsdataasanyfieldisupdated.

Thetargetoftheinputeventistheelementthatchanged.Youusetheinputeventlaterinthischapter.

NewInputTypesHTML5introducesaslewofnewtypesfor<input/>elements,andthefollowingtableliststhem,theirdescriptions,andadescriptionoftheiroutput(thecontrol’svalueifknown).Inallcases,thevalueisastringobject.

TYPE DESCRIPTION VALUEcolor Acontrolforspecifyingacolor.Thevalue

isthecolorinhexadecimalformat.Ahexadecimalvalueofthenumber(#ff00ff).

date Usedforenteringthedate(year,month,andday).

Thedateinyyyy-mm-ddformat(2014-07-14).

datetime AllowsforenteringthedateandtimebasedonUTC.

Notyetsupported.

email Afieldforeditingane-mailaddress.Thevalueisautomaticallyvalidated.

Thetextinputintothefield(evenifinvalide-mail).

month Acontrolforenteringmonthandyear;notimezone.

Thedateinyyyy-mmformat(2014-07).

number Createsacontrolfornumericinput,butdoesnotprohibitalpha-characterinput.

Thenumericdatainputintothefield,oranemptystringifnotanumber.

range Createsanativesliderforimprecisenumericinput.

Thevalueoftheslider.

search Asingle-linetextentrycontrol. Thetextinputintothefield.Linebreaksareremoved.

tel Createsacontrolfortelephoneentry. Thetextinputintothefield.Linebreaksareremoved.

time Allowstimeinputwithnotimezone. Thetimein24-hourformat(15:37for03:37PM).

url AcontrolforeditingabsoluteURLs. Thetextinputintothefield.Linebreaksandleading/trailingwhitespaceareremoved.

week Createsacontrolforenteringadateconsistingofaweek-yearnumberandaweeknumberwithnotimezone.

Theyearandweeknumber(2014-W29).

Unfortunately,someofthenewinputtypesarenotsupportedbyanybrowser,andsomeareonlysupportedbyafew.Manyofthesupportedinputtypesexhibitinconsistentbehaviorbetweenbrowsers.Inshort,ifyouplanonusinganyofthesenewinputtypes,besuretotestyourpageinallmodernbrowsers.

HTML5alsobringsseveralnewattributesto<input/>elements,allofwhichareaccessibleaspropertiesoftheelementobject.Thefollowingtablelistsjustsomeoftheseattributes.

TYPE DESCRIPTIONautocomplete Specifiesthatthevalueofthecontrolcanbeautomaticallycompletedby

thebrowser.autofocus Determinesifthecontrolshouldhavefocuswhenthepageloads.form TheIDoftheassociatedform.Ifspecified,thecontrolcanbeplaced

anywhereinthedocument.Ifnotspecified,thecontrolcanonlyresidewithintheform.

maxLength Specifiesthemaximumnumberofcharacterstheusercanenterfortext,email,search,password,tel,andurltypes.

pattern Aregularexpressionthatthecontrol’svalueischeckedagainst.placeholder Displaysahinttotheuserofwhatcanbeenteredinthefield.required Specifiesthattheusermustfillinavalueforthefieldbeforesubmitting

theform.

Inadditiontotheseproperties,HTML5specifiesthreeuniqueproperties/attributesfortherangetype:

min:Theminimumvalueoftheslider

max:Themaximumvalueoftheslider

step:Theincrementbetweenvalues

TRYITOUTNewInputTypesLet’slookatanexampleofthenumberandrangeinputtypes,aswellastheinputevent.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example10</title>

</head>

<body>

<formname="form1">

<p>

<labelfor="minValue">Min:</label>

<inputtype="number"id="minValue"name="minValue"/>

</p>

<p>

<labelfor="maxValue">Max:</label>

<inputtype="number"id="maxValue"name="maxValue"/>

</p>

<p>

<labelfor="stepValue">Step:</label>

<inputtype="number"id="stepValue"name="stepValue"/>

</p>

<p>

<inputtype="range"id="slider"name="slider"/>

</p>

</form>

<divid="output"></div>

<script>

varmyForm=document.form1;

varoutput=document.getElementById("output");

functionformInputChange(){

varslider=myForm.slider;

slider.min=parseFloat(myForm.minValue.value);

slider.max=parseFloat(myForm.maxValue.value);

slider.step=parseFloat(myForm.stepValue.value);

output.innerHTML=slider.value;

}

myForm.addEventListener("input",formInputChange);

</script>

</body>

</html>

Savethisasch11_example10.html.

Whenyouopenthispageinamodernbrowser,youwillseethreetextboxesandoneslider.Thethreetextboxesenableyoutoedittheminimum,maximum,andstepoftheslider.Providinganyinputtoanyoftheformfieldsupdatesthemin,max,andsteppropertiesoftheslider,aswellasdisplaysthevalueofthesliderina<div/>element.

Thereisoneexception:InIE,changingthevalueofthesliderdoesnotcausetheinputeventtofire.

Let’sfirstlookattheform’sHTML:

<formname="form1">

<p>

<labelfor="minValue">Min:</label>

<inputtype="number"id="minValue"name="minValue"/>

</p>

<p>

<labelfor="maxValue">Max:</label>

<inputtype="number"id="maxValue"name="maxValue"/>

</p>

<p>

<labelfor="stepValue">Step:</label>

<inputtype="number"id="stepValue"name="stepValue"/>

</p>

Youstartwiththree<input/>elementsoftypenumber.Theirpurposeistoallowyoutospecifytheminimum,maximum,andstepvaluesofthefourth<input/>element:

<p>

<inputtype="range"id="slider"name="slider"/>

</p>

</form>

Thisisarange<input/>element,andtherearenoattributesotherthantype,id,andname.

Outsideoftheformisa<div/>elementwithanidofoutput:

<divid="output"></div>

Asyouinputdataintheform,thecontentsofthis<div/>elementchangewiththevalueoftherange<input/>element.

NowfortheJavaScript.ThefirsttwolinesofJavaScriptcodereachintotheDOMandgrabreferencestotwoelements:

varmyForm=document.form1;

varoutput=document.getElementById("output");

Thefirstisareferencetothe<form/>element,andthesecondisthe<divid="output"/>element.

Tomakethisexamplework,youlistenforthemyFormobject’sinputevent.So,nextyoucallmyForm.addEventListener()toregisterthelistener:

myForm.addEventListener("input",formInputChange);

TheformInputChange()functionexecuteswhentheinputeventfires,andinitsfirstlineofcode,youcreateavariablecalledslidertocontaintherange<input/>element:

functionformInputChange(){

varslider=myForm.slider;

Thisisforconveniencepurposesbecauseeverystatementinthisfunctionwillreferencethesliderelementinsomeway.

Next,youwanttomodifytheslider’smin,max,andsteppropertieswiththedataenteredintotheform:

slider.min=parseFloat(myForm.minValue.value);

slider.max=parseFloat(myForm.maxValue.value);

slider.step=parseFloat(myForm.stepValue.value);

Rememberthatan<input/>element’svalueisstringdata—evenifthatstringcontainsanumber.Therefore,youneedtoconvertthestringintoanumericvalue.TheparseFloat()functionshouldbeusedherebecausefloating-pointnumbersarevalidvaluesforarange’smin,max,andstepproperties.

Finally,youdisplayslider’svalue.

output.innerHTML=slider.value;

}

NewElementsHTML5alsointroducesthreenewformcontrols:

<output/>isusedtodisplaytheresultofacalculation.

<meter/>isagraphicaldisplayofavalue.

<progress/>representsthecompletionprogressofatask.

The<output/>elementismoreofatraditionalformcontrolinthatithastobeassociatedwithaform;itcanresidewithinaformoryoucanprovideaform’sidasthevalueofitsformattribute.

The<meter/>and<progress/>elements,however,havenosuchrequirement.Theycanappearanywherewithinthedocumentwithoutanyformassociation.

The<output/>ElementThe<output/>elementrepresentstheresultofaparticularcalculationoruseraction.Nographicsorstylingareassociatedwiththeelement;itsimplydisplaystext(althoughyoucanapplystylingwithCSS).

Attheheartofthe<output/>elementisitsvalueproperty.Likeatypicalformcontrol,thevaluepropertyletsyougetandsetthevalueofthecontrol,andsettingthevaluevisuallyupdatesthecontroltodisplaywhatevervalueyouassignedtotheproperty.Butunliketypicalformcontrols,the<output/>elementdoesnothaveavalueattribute.Thevalueoftheelementisinsteadrepresentedbyatextnodebetweentheopeningandclosing<ouput>tags.Forexample:

<outputname="result"id="result"for="field1field2">10</output>

IE11andbelowdonotofficiallysupportthe<output/>element,andsettingthevaluepropertywillresultinanerror.Youmightworkaroundthisissuebystillusingthe<output/>elementandsettingsits“value”withinnerHTML.However,thisworkaroundisnotstandardandisnotrecommended.

Finally,the<output/>elementshouldbeassociatedwithfieldsinvolvedintheresultofcalculationsthatthe<output/>displays.Youdothiswiththefamiliarforattribute.InthepreviousHTML,the<output/>elementisassociatedwithfield1andfield2.

TRYITOUTsingthe<output/>ElementInthisexercise,youmodifyExample10andusethe<output/>elementtodisplaytherange’svalue.FeelfreetocopyandpasteExample10andmodifythehighlightedlinesofcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example11</title>

</head>

<body>

<formid="form1"name="form1">

<p>

<labelfor="minValue">Min:</label>

<inputtype="number"id="minValue"name="minValue"/>

</p>

<p>

<labelfor="maxValue">Max:</label>

<inputtype="number"id="maxValue"name="maxValue"/>

</p>

<p>

<labelfor="stepValue">Step:</label>

<inputtype="number"id="stepValue"name="stepValue"/>

</p>

<p>

<inputtype="range"id="slider"name="slider"/>

</p>

</form>

<outputid="result"name="result"form="form1"for="slider">

</output>

<script>

varmyForm=document.form1;

varoutput=myForm.result;

functionformInputChange(){

varslider=myForm.slider;

slider.min=parseFloat(myForm.minValue.value);

slider.max=parseFloat(myForm.maxValue.value);

slider.step=parseFloat(myForm.stepValue.value);

result.value=slider.value;

}

myForm.addEventListener("input",formInputChange);

</script>

</body>

</html>

Savethisasch11_example11.html.

Becauseyou’reusingstandard<output/>code,youwillneedtoopenthispageinChrome,Firefox,orOpera.

Let’sfocusonlyonthelinesthatchanged.First,youaddanidattributetothe<form/>element:

<formid="form1"name="form1">

Thisadditionisonlynecessarybecauseyoudefinethe<output/>elementoutsideoftheform:

<outputid="result"name="result"form="form1"for="slider"></output>

Youdefinethe<output/>elementbysettingitsidandnameattributestoresult,the

formattributetoform1,andtheforattributetoslider.Thelatterisn’tabsolutelynecessaryforthisexampletowork,buttheforattributeexistssothatyoucanwritesemanticmarkup.Bysettingfortoslider,you(andreadersofyourcode)knowthatthe<output/>elementdisplaysthevaluerelatedtotherangefield.

ThenextchangeisthesecondlineofJavaScriptcode.Insteadofretrievinga<div/>element,yougrabareferencetoyournew<output/>element:

varoutput=myForm.result;

Noticethecode:myForm.result.Eventhoughthe<output/>elementisnotinsidetheform,itisstillassociatedwiththeformbecauseoftheforattribute.Therefore,youcanwalktheFormobjecthierarchytoreferencethe<output/>element.

ThefinalchangeisthelaststatementoftheformInputChange()function:

result.value=slider.value;

Yousetthe<output/>element’svaluepropertytothevalueofslider;thus,updatingtheinformationdisplayedinthepage.

The<meter/>and<progress/>ElementsAsmentionedearlier,the<meter/>and<progress/>formcontrolsareratheruniqueinthattheycanbeusedanywherewithinapage.Itmightseemstrangetocallthem“formcontrols”whentheydon’thavetobeusedwithinaform—theydon’tevenacceptuserinput!Nevertheless,they’recategorizedassuch.

Atfirstglance,theseelementslooksimilar,butthey,infact,servetwodifferentpurposesandhaveadifferentsetofattributesandproperties.

The<meter/>elementisusedtographicallydisplayanindividualvaluewithinaparticularrange.Forexample,theRPMsofavehicle’sengine,theheatofaCPU,ordiskusageindicatorsareperfectexamplesofwhatthe<meter/>elementisusedfor.

The<meter/>elementconsistsofanopeningandclosingtag,andyoucanspecifythelow,optimum,andhighsectionsofthemeter.Theseareranges,mostlyforsemanticpurposes,thataffectthemeter’scolor.Youcanalsosettheminandmaxofpossiblevalues,aswellasthevalueofthemeter:

<metermin="0"max="150"low="40"optimum="75"

high="100"value="80">80UnitsofSomething</meter>

Thesesixattributesmaptopropertiesofthesamenames.Ifabrowserdoesn’tsupportthe<meter/>element,thetextbetweentheopeningandclosingtagisdisplayedinthebrowser.

NOTEIE9,IE10,andIE11donotsupportthe<meter/>element.

The<progress/>elementrepresentsthecompletionprogressofatask,andaswiththeprecedingnewelements,itconsistsofanopeningandclosingtag:

<progressmax="100"value="40">40%donewithwhatyou'redoing</progress>

Italsohasamaxattributethatmapstotheelementobject’smaxproperty,andthecontrol’svalueiscontainedwithinthevalueattribute/property.Like<meter/>,thetextbetweentheopeningandclosingtagsisdisplayedifthebrowserdoesn’tsupportthe<progress/>element.

TRYITOUTThe<meter/>and<progress/>ElementsLet’susethe<meter/>and<progress/>elementsinanexample.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Example12</title>

</head>

<body>

<h2>HighwaySpeedTracker</h2>

<formid="form1"name="form1">

<p>

<labelfor="driverName">DriverName:</label>

<inputtype="text"id="driverName"name="driverName"/>

</p>

<p>

<labelfor="speed">Speed(Miles/Hour):</label>

<inputtype="number"id="speed"name="speed"/>

<meterid="speedMeter"value="0"low="55"optimum="75"

high="90"max="120"></meter>

</p>

<p>

<labelfor="vehicle">VehicleType:</label>

<inputtype="text"id="vehicle"name="vehicle"/>

</p>

</form>

<p>

FormCompletionProgress:

<progressid="completionProgress"max="3"value="0"></progress>

</p>

<script>

varmyForm=document.form1;

varcompletionProgress=

document.getElementById("completionProgress");

varspeedMeter=document.getElementById("speedMeter");

functioncountFieldData(){

varcount=0;

for(varindex=0;index<myForm.length;index++){

varelement=myForm[index];

if(element.value){

count++;

}

}

returncount;

}

functionformInputChange(){

completionProgress.value=countFieldData();

speedMeter.value=myForm.speed.value;

}

myForm.addEventListener("input",formInputChange);

</script>

</body>

</html>

Savethisasch11_example12.html.Openthepageinyourbrowser(includingIE—thisexamplemostlyworksinIE9,IE10,andIE11),andyou’llseeaformwiththreefields:adriver’sname,thedriver’sspeed,andthetypeofvehiclethedriverdrove.Asyoufillouttheform,you’llnoticeafewthingsgoingon.

First,theprogressbarbelowtheformchangesinvalue.Thisindicatesyourprogressinfillingouttheform.Whenallfieldshaveavalue,you’redone!Second,you’llnoticethemeternexttotheSpeedfieldupdatestovisuallyrepresentthedatafromthatfield.

Nowlet’slookattheHTML.Inthebodyofthepage,youdefineaformwiththree<input/>elements.Thefirstisanormaltextboxforthedriver’sname:

<formid="form1"name="form1">

<p>

<labelfor="driverName">DriverName:</label>

<inputtype="text"id="driverName"name="driverName"/>

</p>

Thenextfieldisanumberfieldforinputtingthedriver’sspeed:

<p>

<labelfor="speed">Speed(Miles/Hour):</label>

<inputtype="number"id="speed"name="speed"/>

<meterid="speedMeter"value="0"low="55"optimum="75"

high="90"max="120"></meter>

</p>

Here,youalsodefinea<meter/>elementwithanidofspeedMeter.Thismeterissupposedtovisuallyrepresenthighwayspeedinmilesperhour.Insuchcases,55MPHisslow,75MPHisoptimum/standard,and90MPHishigh.Themaximumvaluethismetercandisplayis120.

Thelastfieldisanothertextboxforthedriver’svehicle:

<p>

<labelfor="vehicle">VehicleType:</label>

<inputtype="text"id="vehicle"name="vehicle"/>

</p>

Thenaftertheform,youdefinea<progress/>element:

<p>

FormCompletionProgress:

<progressid="completionProgress"max="3"value="0"></progress>

</p>

Thisistotracktheuser’sprogressinfillingouttheform.IthasanidofcompletionProgressandhasamaximumvalueof3becauseitcontainsthreefields.

Ofcourse,theHTMLbyitselfisn’tveryinteresting;so,let’slookattheJavaScript.Youfirstretrievethreeelementsfromthedocument:the<form/>,<progress/>,and<meter/>elements.

varmyForm=document.form1;

varcompletionProgress=document.getElementById("completionProgress");

varspeedMeter=document.getElementById("speedMeter");

Toretrievethe<progress/>and<meter/>elements,youusedocument.getElementById()becausealthoughthesetwoelementsareconsideredformcontrols,youcannotaccessthemthroughtheformhierarchy(whichadmittedlycanbealittleconfusing).

Onceagain,theform’sinputeventprovidesthemagicforthisexample;so,youregisteritslistener:

myForm.addEventListener("input",formInputChange);

TheformInputChange()functionisrathersimple;itupdatesthevaluesofboththe<progress/>and<meter/>elements:

functionformInputChange(){

completionProgress.value=countFieldData();

speedMeter.value=myForm.speed.value;

}

ThevalueforspeedMetercomesfromthespeedfieldintheform,butalittlemoreworkisneededtosetthevalueforcompletionProgress.

YoucreateahelperfunctioncalledcountFieldData().Itsjobisstraightforward:Examinetheelementswithintheformanddetermineiftheyhaveavalue.It’snotafoolproofsolutionfordeterminingiftheuserhascompletedtheform,butitworksforthisexample.

First,youdefineacountervariabletocounthowmanyfieldshaveavalue.Youcallthisvariablecount:

functioncountFieldData(){

varcount=0;

Nowyouneedtocheckthevaluepropertyofeveryelementintheform.Youcouldwritecodeexplicitlyforthisform,oryoucantakeamoregenericapproachandloopthroughtheform’selements.Let’sdothelatter:

for(varindex=0;index<myForm.length;index++){

varelement=myForm[index];

if(element.value){

count++;

}

}

Usingaforloop,youiterateoverthemyFormobject/collectiontoretrieveeachformcontrolandcheckifithasavalue.Iftheelementhasavalue,youincrementthecountvariable.

Aftertheloopexits,youreturnthevalueofthecountvariable:

returncount;

}

SUMMARYInthischapter,youlookedathowtoaddauserinterfaceontoyourJavaScriptsothatyoucaninteractwithyourusersandacquireinformationfromthem.Thischaptercoveredthefollowing:

TheHTMLformiswhereyouplaceelementsmakinguptheinterfaceinapage.

EachHTMLformgroupstogetherasetofHTMLelements.Whenaformissubmittedtoaserverforprocessing,allthedatainthatformissenttotheserver.Youcanhavemultipleformsonapage,butonlytheinformationinoneformcanbesenttotheserver.

Aformiscreatedwiththeopeningtag<form>andendswiththeclosetag</form>.Alltheelementsyouwantincludedinthatformareplacedinbetweentheopenandclose<form>tags.The<form/>elementhasvariousattributes—forclient-sidescripting,thenameattributeistheimportantone.YoucanaccessformswitheithertheirnameattributeortheirIDattribute.

Each<form>elementcreatesaFormobject,whichiscontainedwithinthedocumentobject.ToaccessaformnamedmyForm,youwritedocument.myForm.Thedocumentobjectalsohasaformsproperty,whichisacollectioncontainingeveryforminsidethedocument.Thefirstforminthepageisdocument.forms[0],thesecondisdocument.forms[1],andsoon.Thelengthpropertyoftheformsproperty(document.forms.length)tellsyouhowmanyformsareonthepage.

Havingdiscussedforms,wethenwentontolookatthedifferenttypesofHTMLelementsthatcanbeplacedinsideforms,howtocreatethem,andhowtheyareusedinJavaScript.

Theobjectsassociatedwiththeformelementshaveanumberofproperties,methods,andeventsthatarecommontothemall.Theyallhavethenameproperty,whichyoucanusetoreferencetheminyourJavaScript.Theyalsoallhavetheformproperty,whichprovidesareferencetotheFormobjectinwhichthatelementiscontained.Thetypepropertyreturnsatextstringtellingyouwhattypeofelementthisis;typesincludetext,button,andradio.

Youalsosawthatthemethodsfocus()andblur(),andtheeventsfocusandblur,areavailabletoeveryformelementobject.Suchanelementissaidtoreceivethefocuswhenitbecomestheactiveelementintheform,eitherbecausetheuserhasselectedthatelementorbecauseyouusedthefocus()method.Howeveranelementgotthefocus,itsfocuseventwillfire.Whenanotherelementissetasthecurrentlyactiveelement,thepreviouselementissaidtoloseitsfocus,ortoblur.Again,lossoffocuscanbetheresultoftheuserselectinganotherelementortheuseoftheblur()method;eitherway,whenithappenstheblureventfires.Yousawthatthefiringoffocusandblurcan,ifusedcarefully,beagoodplacetocheckthingslikethevalidityofdataenteredbyauserintoanelement.

Allelementsreturnavalue,whichisthestringdataassignedtothatelement.The

meaningofthevaluedependsontheelement;foratextbox,itisthevalueinsidethetextbox,andforabutton,it’sthetextdisplayedonitsface.

Havingdiscussedthecommonfeaturesofelements,wethenlookedateachofthemorecommonlyusedelementsinturn,startingwiththebuttonelement.

Thebuttonelement’spurposeinlifeistobeclickedbytheuser,wherethatclickingfiressomescriptyouhavewritten.Youcancapturetheclickingbyconnectingtothebutton’sclickevent.Abuttoniscreatedbymeansofthe<input/>elementwiththetypeattributesettobutton.Thevalueattributedetermineswhattextappearsonthebutton’sface.Twovariationsonabuttonarethesubmitandresetbuttons.Inadditiontoactingasbuttons,theyalsoprovideaspecialservicenotlinkedtocode.Thesubmitbuttonautomaticallysubmitstheformtotheserver;theresetbuttonclearstheformbacktoitsdefaultstatewhenloadedinthepage.

Thetextelementallowstheusertoenterasinglelineofplaintext.Atextboxiscreatedbymeansofthe<input/>elementwiththetypeattributesettotext.Youcansethowmanycharacterstheusercanenterandhowwidethetextboxiswiththemaxlengthandsizeattributes,respectively,ofthe<input/>element.ThetextboxhasanassociatedobjectcalledText,whichhastheadditionaleventsselectandchange.Theselecteventfireswhentheuserselectstextinthebox,andthemoreusefulchangeeventfireswhentheelementlosesfocusanditscontentshavechangedsincetheelementgainedthefocus.Thefiringofthechangeeventisagoodplacetodovalidationofwhattheuserhasjustentered.Ifsheenteredillegalvalues,suchasletterswhenyouwantednumbers,youcanletherknowandsendherbacktocorrecthermistake.Avariationonthetextboxisthepasswordbox,whichisalmostidenticaltothetextboxexceptthatthevaluestypedintoitarehiddenandshownasasterisks.Additionally,thetextboxalsohasthekeydown,keypress,andkeyupevents.

Thenextelementyoulookedatwasthetextarea,whichissimilartothetextboxexceptthatitallowsmultiplelinesoftexttobeentered.Thiselementiscreatedwiththeopentag<textarea>andclosedwiththe</textarea>tag,thewidthandheightincharactersofthetextboxbeingdeterminedbythecolsandrowsattributes,respectively.Thewrapattributedetermineswhetherthetextareawrapstextthatreachestheendofalineandwhetherthatwrappingissentwhenthecontentsarepostedtotheserver.Ifthisattributeisleftout,orsettooff,nowrappingoccurs;ifsettosoft,itcauseswrappingclient-side,butisnotsenttotheserverwhentheformissent;ifsettohard,itcauseswrappingclient-sideandissenttotheserver.TheassociatedTextareaobjecthasvirtuallythesameproperties,methods,andeventsasaTextobject.

Youthenlookedatthecheckboxandradiobuttonelementstogether.Essentiallytheyarethesametypeofelement,exceptthattheradiobuttonisagroupedelement,meaningthatonlyoneinagroupcanbecheckedatonce.Checkinganotheronecausesthepreviouslycheckedbuttontobeunchecked.Bothelementsarecreatedwiththe<input/>element,thetypeattributebeingcheckboxorradio.Ifcheckedisputinsidethe<input>tag,thatelementwillbecheckedwhenthepageisloaded.Creatingradiobuttonswiththesamenamecreatesaradiobuttongroup.Thenameof

aradiobuttonactuallyreferstoanarray,andeachelementwithinthatarrayisaradiobuttondefinedontheformtobewithinthatgroup.TheseelementshaveassociatedobjectscalledCheckboxandRadio.Usingthecheckedpropertyoftheseobjects,youcanfindoutwhetheracheckboxorradiobuttoniscurrentlychecked.Bothobjectsalsohavetheclickeventinadditiontothecommoneventsfocusandblur.

Nextinyourlookatelementswerethedrop-downlistandlistboxes.Both,infact,arethesameselectelement,withthesizeattributedeterminingwhetherit’sadrop-downorlistbox.The<select>tagcreatestheseelements,thesizeattributedetermininghowmanylistitemsarevisibleatonce.Ifasizeof1isgiven,adrop-downboxratherthanalistboxiscreated.Eachiteminaselectelementisdefinedbythe<option/>element,oraddedtolaterbymeansoftheSelectobject’soptionscollectionproperty,whichisanarray-likestructurecontainingeachOptionobjectforthatelement.However,addingoptionsafterthepageisloadeddiffersslightlybetweenstandards-compliantbrowsersandold-IE.TheSelectobject’sselectedIndexpropertytellsyouwhichoptionisselected;youcanthenusethatvaluetoaccesstheappropriateoptionintheoptionscollectionandusetheOptionobject’svalueproperty.TheOptionobjectalsohasthetextandindexproperties,textbeingthedisplayedtextinthelistandindexbeingitspositionintheSelectobject’soptionscollectionproperty.Youcanloopthroughtheoptionscollection,findingoutitslengthfromtheSelectobject’slengthproperty.TheSelectobjecthasthechangeevent,whichfireswhentheuserselectsanotheritemfromthelist.

YouthenlookedatHTML5’snewelementsandinputtypes,aswellastheinputevent.YoulearnedhowtowriteJavaScriptcodetomanipulatethe<output/>,<meter/>,and<progress/>elementsandmodifytheiroutputwhenusersinputdatainaform.

Inthenextchapter,youlookatJavaScriptObjectNotation(JSON),adataformatthatletsyoustoreJavaScriptobjectsandarraysasstringdata.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. UsingthecodefromthetemperatureconverterexampleyousawinChapter2,createauserinterfaceforitandconnectittotheexistingcodesothattheusercanenteravalueindegreesFahrenheitandconvertittocentigrade.

2. Createauserinterfacethatallowsuserstopickthecomputersystemoftheirdreams,similarinprincipletothee-commercesitessellingcomputersovertheInternet.Forexample,theycouldbegivenachoiceofprocessortype,speed,memory,andharddrivesize,andtheoptiontoaddadditionalcomponentslikeaDVD-ROMdrive,asoundcard,andsoon.Astheuserschangetheirselections,thepriceofthesystemshouldupdateautomaticallyandnotifythemofthecostofthesystemastheyspecifiedit,eitherbyusinganalertboxorbyupdatingthecontentsofatextbox.

12JSONWHATYOUWILLLEARNINTHISCHAPTER:

DiscoveringthelimitationsofusingXMLwithJavaScript

RecognizingthedifferencesbetweenJavaScriptandJSON

Serializingobjectsusingthebuilt-inJSONobject

ParsingJSONbackintoactualobjectsandvaluesyoucanuseinyourpages

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Ifyouaren’talready,startthinkingofawebpageasaprogram.Itdoes,afterall,haveallthetrappingsofatraditionalprogram.Ithasauserinterface,anditcanprocessdatawithJavaScript.Butasyouwellknow,traditionalprogramscandomore;theycanstoredataaswellastransmitdatatoothercomputersandsystems.Inthecomingchapters,youlearnthatyoucandothesamethingsinawebpage—allthankstoJavaScript.

Butasyousoonlearn,youcan’tjuststoreobjectsandarraysastheyare;instead,youneedtoserializethem.Serializationistheprocessoftranslatinganobjectintoastringrepresentationofthatobject.Onceanobjectisserialized,thestringrepresentationofthatobjectcanthenbestoredinamorepermanentstoragefacilityortransmittedtoanothercomputer.

Serializationtranslatesonlythestructureandpertinentinformationofanobject—thatis,onlythepropertiesarepresentinaserializedobject.ButonceyouneedtoworkwiththeobjectwithinJavaScript,youcandeserializeit,convertingitbackintoanativeJavaScriptobject.

TheserializationformatthatwebdevelopersoverwhelminglyembraceiscalledJavaScriptObjectNotation,orJSON(pronouncedlikethename:Jason).ItisasubsetoftheJavaScriptlanguage;assuch,it’seasytoread,it’sconcise,andmostimportantly,it’seasytoserializetoanddeserializefrom.

Butthewebhasn’talwaysusedJSONforserializingJavaScriptobjects.SobeforewelookattheJSONformat,let’slookatwhatwebdevelopersusedtouse.

XMLTherewasatimewhenthewebdevelopmentcommunityembracedXMLforjustabouteverything.Webservicesusedittocommunicatewithoneanotherandothercomputers,andJavaScriptdevelopersusedittocommunicatewiththewebapplication’sserver.

XMLisahuman-readablelanguagethankstoitsdeclarativesyntax.It’snotnecessaryforhumanstoreadXMLdata,butbeingabletoreadanddeciphertheXMLcanbeuseful.ConsiderthefollowingXMLdocumentasanexample:

<person>

<firstName>John</firstName>

<lastName>Doe</lastName>

<age>30</age>

</person>

Despitebeingasimpledocument,youknowthatthisXMLrepresentsanindividualpersonnamedJohnDoewhois30yearsold.YoucouldcatchandfixerrorsthatmayoccurinyourapplicationasitgeneratestheprecedingXML-formatteddata.

XMLisalsomachine-readable,anditwasaknowncommoditywhendevelopersstartedusingit.Everymodernprogramminglanguagehadthetoolsandcapabilitiesforreading,parsing,andcreatingXML-formatteddata,andsousingXMLtocommunicatebetweencomputersystemsandapplicationsseemedlikeagoodidea.

ButXMLhasitsdrawbacks.Forone,XML’sdeclarativesyntaxaddsalotofextracrufttothedata.LookagainattheXMLdescribingapersonnamedJohnDoe:

<person>

<firstName>John</firstName>

<lastName>Doe</lastName>

<age>30</age>

</person>

ThissimpleXMLis101bytes.That’snotlargebytoday’sstandards,butrememberthatthisisjustanexample.ThisisinformationthatacomputerwouldsendovertheInternettoanothercomputer.

First,theopeningandclosing<person>tagssurroundtheactualdata.Ofcourse,theouter<person/>elementexistsfororganizationalpurposes,butitis17bytes—16percentoftheentirepayload.Otherformatswillstillhavesomewaytoorganizethedocument’srealinformation(thefirstandlastname),buttheywouldbesmallerinsize.

Next,openingandclosingtagssurroundboththefirstandlastname.Naturally,thereneedstobesomewaytoorganizethatdata,butyet,thisXMLuses55bytestodenotethefirstname,lastname,andtheage.

AnotherofXML’sissuesisthecodenecessaryforreading,parsing,andgeneratingXMLdata.Yes,mostmodernprogramminglanguagescanhandleXML,butitrequiresalotofcode—codethatusuallyhastoberewrittenforspecificXMLformats.Forexample,thefollowingcodeisonewayyoucouldreadthepreviousXMLandparseitintoanobject

calledperson:

varpersonElement=document.querySelector("person");

varfirstName=personElement.querySelector("firstName").innerHTML;

varlastName=personElement.querySelector("lastName").innerHTML;

varage=personElement.querySelector("age").innerHTML;

varperson={

firstName:firstName,

lastName:lastName,

age:age

};

ThiscodedemonstratesastraightforwardapproachtoparsingtheJohnDoeXML.Itfirstretrievesthe<person/>elementusingdocument.querySelector().Itthenretrievesthe<firstName/>,<lastName/>,and<age/>elementsandstorestheirrespectivecontentsinthefirstName,lastName,andagevariables.Finally,itcreatesthepersonobjectandassignstheappropriatedatatoitsproperties.Thiscodeisn’tcomplex,butasyoumightsuspect,itwouldn’tworkforXML-formatteddatawithdifferentelementnamesandstructures.Naturally,documentswithmorecomplexstructuresrequiremuchmorecode.

ButparsingXMLintoaJavaScriptobjectisonlyhalfofthestory.BeforeyoucansenddatafromJavaScripttotheserver,youhavetoserializetheJavaScriptobject.SerializingaJavaScriptobjecttoXML-formatteddataisnotatrivialtask.Likeparsing,thesamecodeusuallydoesn’tworkfordifferentdatastructures.Plus,developersmustensuretheirgeneratedXMLdataiswell-formed.

Around2007and2008,thewebcommunitythankfullyadoptedadifferentdataformatforstoringandtransmittingJavaScriptdata.

JSONIn2006,DouglasCrockfordwrotetheJavaScriptObjectNotationspecification.JSONisasubsetoftheJavaScriptlanguage,anditusesseveralofJavaScript’ssyntacticalpatternsfororganizingandstructuringdata.Assuch,itisdoesaverygoodjobofrepresentingobjectsandtheirdata(it’ssogoodthatotherlanguagesuseJSON,too).It’sextremelyeasytoparseJSONintoJavaScriptobjectsandtoserializeobjectsintoJSON.Intoday’smodernbrowsers,itonlytakesonelineofcode!

Asyousoonsee,JSONlooksalotlikeJavaScript’sobjectandarrayliterals.It’seasytoconfuseJSONandJavaScriptasbeingthesamething,butit’simportanttounderstandthedifferencebetweenthetwo.JavaScriptisaprogramminglanguage;JSONisadataformat.

JSONletsyourepresentthreetypesofdata:simplevalues,objects,andarrays.

SimpleValuesYoucanrepresentsimplevalueslikestrings,numbers,booleans,andnull.Forexample,thefollowinglineisvalidJSON:

"JavaScript"

ThisJSONrepresentsthestringvalueof"JavaScript",anditlooksexactlylikeanormalJavaScriptstring.Butthere’sabigdifferencebetweenstringsinJavaScriptandJSON;JSONstringsmustusedoublequotes.Thus,thefollowingisinvalidJSON:

'JavaScript'

Numericdataisrepresentedbywhatappearstobenumberliterals,likethis:

10

ThisisvalidJSONrepresentingthenumber10.Similarly,booleanvaluesandnulllooklikeJavaScriptliterals,too:

true

null

ObjectsObjectsinJSONarerepresentedwithwhatlookslikeJavaScript’sobjectliteralnotation.Forexample,thefollowingisaJavaScriptobjectthatrepresentsthesamepersonfromearlier:

varperson={

firstName:"John",

lastName:"Doe",

age:30

};

TheJSONrepresentationofthisobjectlookssimilar.HereisthesameobjectrepresentedinJSON:

{

"firstName":"John",

"lastName":"Doe",

"age":30

}

AfewnoticeabledifferencesexistbetweentheJavaScriptandJSONrepresentationsofthisobject.First,JSONdoesn’thavethepersonvariablename.RememberthatJSONisadataformat,notalanguage.Ithasnovariables,functions,ormethods.Itsimplydefinesthestructureanddataofanobject.

Theseconddifferenceistheobject’spropertynames.Noticethattheyaresurroundedbydoublequotes.InJSON,anobject’spropertynamesarestrings,andthevaluesofthosepropertiesfollowtherulesspecifiedintheprevioussection.Doublequotessurroundthestringvaluesof"John"and"Doe",andthenumber30appearsasaliteralvalue.

Thefinaldifferenceisthelackofatrailingsemicolonaftertheclosingcurlybrace.Thisisn’taJavaScriptstatement,andthus,thesemicolonisnotneeded.

ThesizeofthisJSONdatastructureis69bytes.That’s68percentofthe101bytesoftheequivalentXML.

LikeJavaScriptobjects,JSONobjectscanbesimpleorcomplex.ThedatastructurerepresentingJohnDoeisrathersimple,butyoucaneasilyaddcomplexitybyincorporatinghisaddress:

{

"firstName":"John",

"lastName":"Doe",

"age":30,

"address":{

"numberAndStreet":"123Someplace",

"city":"Somewhere",

"state":"Elsewhere"

}

}

Thisaddsanaddresspropertytothemainobject,anditsvalueisanotherobjectthatcontainsJohn’smailingaddress.

ArraysLikeobjects,arraysinJSONaresimilartoJavaScript’sarrayliteralnotation.ThefollowinglineofcodeisanarrayliteralinJavaScript:

varvalues=["John",30,false,null];

ThesamearraylookslikethisinJSON:

["John",30,false,null]

Again,noticetheJSONarraydoesnothavethevaluesvariable,nordoesithavethetrailingsemicolon.Andlikeobjects,arraysarenotlimitedtojustsimplevalues;theycancontaincomplexobjects,too:

[

{

"firstName":"John",

"lastName":"Doe",

"age":30,

"address":{

"numberAndStreet":"123Someplace",

"city":"Somewhere",

"state":"Elsewhere"

}

},

{

"firstName":"Jane",

"lastName":"Doe",

"age":28,

"address":{

"numberAndStreet":"246Someplace",

"city":"Somewhere",

"state":"Elsewhere"

}

}

]

ThisJSONarraycontainsmultipleobjectsthatrepresentpeopleandtheiraddresses.ThefirstisourfamiliarJohnDoe,andthesecondishislittlesister,Jane,wholivesdownthestreet.JSONdatastructurescanbeassimpleorcomplexasyouneedthemtobe.

SerializingIntoJSONIt’sextremelyeasytoserializeJavaScriptobjectsintoJSON.JavaScripthasanaptlynamedJSONobjectthatyouusetoparseJSONdataandserializeJavaScriptobjects.AllmajorbrowserssupportthisJSONobject.Olderbrowsers,suchasIE7andbelow,canuseCrockford’sJSONimplementation(https://github.com/douglascrockford/JSON-js)toachievethesameresults.

ToserializeaJavaScriptobjectintoJSON,youusetheJSONobject’sstringify()method.Itacceptsanyvalue,object,orarrayandserializesitintoJSON.Forexample:

varperson={

firstName:"John",

lastName:"Doe",

age:30

};

varjson=JSON.stringify(person);

ThiscodeserializesthepersonobjectwithJSON.stringify()andstoresitinthejsonvariable.TheresultingJSON-formatteddatalookslikethis:

{"firstName":"John","lastName":"Doe","age":30}

Allunnecessarywhitespaceisremoved,givingyouanoptimizedpayloadthatyoucanthensendtothewebserverorstoreelsewhere.

ParsingJSONParsingJSONintoJavaScriptobjectsisequallysimple.TheJSONobjecthasaparse()methodthatparsestheJSONandreturnstheresultingobject.Usingthejsonvariablefromthepreviouscode:

varjohnDoe=JSON.parse(json);

ThiscodeparsestheJSONtextcontainedinjsonandstorestheresultingobjectinthejohnDoevariable.Andhere’sthewonderfulthing—youcanimmediatelyusejohnDoeandaccessitsproperties,suchas:

varfullName=johnDoe.firstName+""+johnDoe.lastName;

It’sreallynowonderwhydevelopersembracedJSON.It’seasytoworkwith!

JSONisusefulwhenyouneedtostoreanobject,buttheAPIyou’reworkingwithonlyletsyoustoretext.InChapter10,youlearnedthatthenativedraganddropAPIhasadataTransferobjectthatyoucanusetoworkwithdataduringthedrag-and-dropoperation.Butasyoulearned,itdoesn’tletyoustoreobjects,butyoucanstoretext.JSONistext,soyoucanserializeaJavaScriptobjectatthebeginningofthedragoperationandparsetheJSONwhenthedropeventfires.

TRYITOUTUsingJSONinDragandDropThisexampleusesch10_example21.htmlasabasis.Feelfreetocopyandpastethecodefromthatexampleandmakethehighlightedmodifications.Otherwise,openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter12:Example1</title>

<style>

[data-drop-target]{

height:400px;

width:200px;

margin:2px;

background-color:gainsboro;

float:left;

}

.drag-enter{

border:2pxdashed#000;

}

.box{

width:200px;

height:200px;

}

.navy{

background-color:navy;

}

.red{

background-color:red;

}

</style>

</head>

<body>

<divdata-drop-target="true">

<divid="box1"draggable="true"class="boxnavy"></div>

<divid="box2"draggable="true"class="boxred"></div>

</div>

<divdata-drop-target="true"></div>

<script>

functionhandleDragStart(e){

vardata={

elementId:this.id,

message:"Youmovedanelement!"

};

e.dataTransfer.setData("text",JSON.stringify(data));

}

functionhandleDragEnterLeave(e){

if(e.type=="dragenter"){

this.className="drag-enter";

}else{

this.className="";

}

}

functionhandleOverDrop(e){

e.preventDefault();

if(e.type!="drop"){

return;

}

varjson=e.dataTransfer.getData("text");

vardata=JSON.parse(json);

vardraggedEl=document.getElementById(data.elementId);

if(draggedEl.parentNode==this){

this.className="";

return;

}

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

this.className="";

alert(data.message);

}

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-target]");

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",

handleDragStart);

}

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

targets[i].addEventListener("dragover",handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",

handleDragEnterLeave);

targets[i].addEventListener("dragleave",

handleDragEnterLeave);

}

</script>

</body>

</html>

Savethisfileasch12_example1.html.

Youneedjustafewchangestomakethisexampledifferentfromch10_example21.html.ThefirstisinthehandleDragStart()function:

functionhandleDragStart(e){

vardata={

elementId:this.id,

message:"Youmovedanelement!"

};

Thenewcodecreatesanobjectcalleddata.IthasanelementIdpropertytocontaintheelement’sidvalue,andamessagepropertythatcontainsarbitrarytext.Youwanttousethisobjectasthedraganddrop’stransferdata;so,youhavetoserializeit:

e.dataTransfer.setData("text",JSON.stringify(data));

}

YoucalltheJSON.stringify()methodtodojustthat,andtheresultingJSONtextissetasthetransfer’sdata.

TheremainingchangesappearinthehandleOverDrop()function.Itsfirstfewlinesarethesame:

functionhandleOverDrop(e){

e.preventDefault();

if(e.type!="drop"){

return;

}

Butthenexttwolinesarenew:

varjson=e.dataTransfer.getData("text");

vardata=JSON.parse(json);

YouretrievethetransferreddatawiththegetData()methodandstoreitinthejsonvariable.YouthenparsetheJSONintoaJavaScriptobjectthatyoustoreinthedatavariable.Youneedtoretrievethedraggedelementobjectfromthedocument.So,youusedata.elementIdandpassittodocument.getElementById():

vardraggedEl=document.getElementById(data.elementId);

if(draggedEl.parentNode==this){

this.className="";

return;

}

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

this.className="";

Afteryouremovethedraggedelementfromitsparentandappendittothedroptarget,youreachintoyourdataobjectandalertitsmessagetotheuser:

alert(data.message);

}

ThistechniqueofusingJSONtostoreobjectdataisusefulinavarietyofscenarios.Inthenextchapter,youusethesametechniquetostoreobjectdatadirectlyinthebrowser.

SUMMARYInthischapter,youlookedatJSON,atextformatforstoringandtransmittingobjects,arrays,andsimplevalues.Let’slookatsomeofthethingsdiscussedinthischapter:

Serializationistheprocessoftranslatingobjectsandvaluesintoastringrepresentationofthoseobjectsandvalues.

ThewebusedtouseXMLforstoringandtransmittingJavaScriptdata,butJSONisnowtheformatofchoice.

JSONisnotJavaScript,butasubsetofJavaScript.Itssyntaxlookssimilar,butkeydifferencesexistbetweenthetwo.Forone,JSONdoesnothavevariablesorfunctions.Itissimplyadataformat.

JSONstringsmustbesurroundedbydoublequotes.Singlequotesresultinanerror.

Numbers,booleans,andnullappearasliteralvaluesinJSON.

JSONobjectslookverymuchlikeJavaScriptobjectliteralsexcepttheirpropertiesarestringsandtherearenotrailingsemicolons.

JSONarraysarealmostidenticaltoJavaScriptarrayliterals,buttheydonothaveatrailingsemicolon.

YouserializeJavaScriptobjects,arrays,andvaluesusingtheJSONobject’sstringify()method.

YouparseJSONtextintoaJavaScriptobjectorvalueusingJSON.parse().

Inthenextchapter,youlookathowtostoredatainandforthebrowserusinglocalstorageandcookies.

EXERCISESYoucanfindasuggestedsolutiontothisquestioninAppendixA.

1. ThecodeforalertingasinglemessageinExample1isn’tveryexciting.Modifythecodetodisplayarandommessagefromasetofthreepossiblemessages.

13DataStorageWHATYOUWILLLEARNINTHISCHAPTER:

Storingdataontheuser’scomputerispossiblewithcookiesandwebstorage

Creatingcookiesisrelativelystraightforward,butreadingthemiscomplex

Usingwebstorageiseasy

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Ourgoalaswebsiteprogrammersshouldbetomakethewebsiteexperienceaseasyandpleasantfortheuseraspossible.Clearly,well-designedpageswitheasilynavigablelayoutsarecentraltothis,butthey’renotthewholestory.Youcangoonestepfurtherbylearningaboutyourusersandusinginformationgainedaboutthemtopersonalizethewebsite.

Forexample,imagineauser,whosenameyouaskedonthefirstvisit,returnstoyourwebsite.Youcouldwelcomeherbacktothewebsitebygreetingherbyname.Anothergoodexampleisgivenbyawebsite,suchasAmazon’s,thatincorporatestheone-clickpurchasingsystem.Byalreadyknowingtheuser’spurchasingdetails,suchascredit-cardnumberanddeliveryaddress,youcanallowtheusertogofromviewingabooktobuyingitinjustoneclick,makingthelikelihoodoftheuserpurchasingitthatmuchgreater.Also,basedoninformation,suchasthepreviouspurchasesandbrowsingpatternsoftheuser,it’spossibletomakebooksuggestions.

Suchpersonalizationrequiresthatinformationaboutusersbestoredsomewhereinbetweentheirvisitstothewebsite.Accessingtheuser’slocalfilesystemfromawebapplicationisprettymuchofflimitsbecauseofsecurityrestrictionsincludedinbrowsers.However,you,asawebsitedeveloper,canstoresmallamountsofinformationinaspecialplaceontheuser’slocaldisk,usingwhatiscalledacookie,andinthebrowserusingHTML5’sWebStorage.

BAKINGYOURFIRSTCOOKIEThekeytocookiesisthedocumentobject’scookieproperty.Usingthisproperty,youcancreateandretrievecookiedatafromwithinyourJavaScriptcode.

Youcansetacookiebysettingdocument.cookietoacookiestring.You’llbelookingindetailathowthiscookiestringismadeuplaterinthechapter,butlet’sfirstcreateasimpleexampleofacookieandseewheretheinformationisstoredontheuser’scomputer.

AFresh-BakedCookieThefollowingcodesetsacookiewiththeUserNamesetasPaulandanexpirationdateof28December,2020:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Fresh-BakedCookie</title>

<script>

document.cookie=

"UserName=Paul;expires=Tue,28Dec202000:00:00;";

</script>

</head>

<body>

<p>Thispagejustcreatedacookie</p>

</body>

</html>

Savethepageasfreshbakedcookie.html.You’llseehowthecodeworksasyoulearnthepartsofacookiestring,butfirstlet’sseewhathappenswhenacookieiscreated.

Howyouviewcookieswithoutusingcodevarieswiththebrowseryouareusing.

ViewingCookiesinInternetExplorerInthissection,youseehowtolookatthecookiesthatarealreadystoredbyInternetExplorer(IE)onyourcomputer.Youthenloadthecookie-creatingpageyoujustcreatedwiththeprecedingcodetoseewhateffectthishas.Followthesesteps:

1. First,youneedtoopenIE.TheexamplesinthischapteruseIE11,soifyou’reusinganearlierversionofIEyoumayfindthescreenshotsandmenusinslightlydifferentplaces.

2. Beforeyouviewthecookies,firstclearthetemporaryInternetfilefolderforthebrowser,becausethiswillmakeiteasiertoviewthecookiesthatyourbrowserhasstored.ClicktheGeariconandchoosetheInternetOptionsmenuitem,whichisshowninFigure13.1.

Figure13.1

3. YouarepresentedwiththeInternetOptionsdialogboxshowninFigure13.2.

Figure13.2

4. ClicktheDeletebuttonunderBrowsingHistory.Anotherdialogboxappears,asshowninFigure13.3.

Figure13.3

5. Makesuretoselectthetickboxesnextto“TemporaryInternetfilesandwebsitefiles”and“Cookiesandwebsitedata”andthenclicktheDeletebutton.Younowhaveanicecleancache,whichmakesiteasytoseewhenyoucreateacookie.

6. YoucannowclosethedialogboxandreturntothemainInternetOptionsdialogbox.

Let’shavealookatthecookiesyouhavecurrentlyresidingonyourmachine.

7. FromtheInternetOptionsdialogbox,clicktheSettingsbuttonnexttotheDeletebuttongroupedunderBrowsingHistory.YoushouldseethedialogboxshowninFigure13.4.

Figure13.4

8. NowclicktheViewFilesbutton,andalistofallthetemporarypagesandcookiefilesonyourcomputerisdisplayed.IfyoufollowedthepreviousinstructionsanddeletedalltemporaryInternetfiles,thereshouldbenothinglisted,asshowninFigure13.5.

Figure13.5

Theactualcookies,theirnames,andtheirvaluesmaylookslightlydifferentdependingonyourcomputer’soperatingsystem.

Youcanexaminethecontentsofthecookiesbydouble-clickingthem.Notethatyoumaygetawarningaboutthepotentialsecurityriskofopeningatextfile,althoughyouarefairlysafewithcookiesbecausetheyaresimplytextfiles.InFigure13.6youcanseethecontentsofthecookiefilenamedgooglesetbythesearchengineGoogle.

Figure13.6

Asyoucansee,acookieisjustaplainoldtextfile.Eachwebsite,ordomainname,hasitsowntextfilewhereallthecookiesforthatwebsitearestored.Inthiscase,there’sjustonecookiecurrentlystoredforgoogle.com.Domainslikeamazon.comwillalmostcertainlyhavemanycookiesset.

InFigure13.6,youcanseethecookie’sdetails.Here,thenameofthecookieisPREF;itsvalueisaseriesofcharacters,whichalthoughindecipherabletoyoumakesensetotheGooglewebsite.Itwassetbythedomaingoogle.com,anditrelatestotherootdirectory/.Thecontentsprobablylooklikeamessofcharacters,butdon’tworry.Whenyoulearnhowtoprogramcookies,you’llseethatyoudon’tneedtoworryaboutsettingthedetailsinthisformat.

Afteryouhavefinished,closethecookieandclickOKonthedialogboxestoreturntothebrowser.

Nowlet’sloadthefreshbakedcookie.htmlpageintoyourIEbrowser.Thiswillsetacookie.Let’sseehowithaschangedthings:

1. ReturntotheInternetOptionsdialogbox(bychoosingTools ➪ InternetOptions).2. ClicktheSettingsbutton.

3. ClickViewFiles.YourcomputernowshowssomethingliketheinformationinFigure13.7.

Figure13.7

IfyouloadedtheHTMLfilefromyourcomputer,youcreatedacookiefromawebpagestoredonthelocalharddriveratherthanaserver.Thus,itsdomainnamehasbeensettothenameofthedirectoryinwhichthewebpageisstored.Obviously,thisisalittleartificial.Inreality,peoplewillbeloadingyourwebpagesfromyourwebsiteontheInternetandnotoffyourlocalharddrive.TheInternetaddressisbasedonthedirectorythefreshbakedcookie.htmlfilewasin.YoucanalsoseethatitexpiresonDecember31,2020,asyouspecifiedwhenyoucreatedthecookie.Double-clickthecookietoviewitscontents,whichlooklikethoseinFigure13.8.

Figure13.8

Youcanseethenameyougavetothecookieattheleft,UserName,itsvalue,Paul,andalsothedirectoryit’sapplicableto.Theexpirationdateisthereaswell;it’sjustnotinaneasilyrecognizableform.Notethatyoumaysometimesneedtoclosethebrowserandreopenitbeforeyouseethecookiefile.

ViewingCookiesinFirefoxThereisnosharingofcookiesbetweenbrowsers,sothecookiesstoredwhenyouvisitedwebsitesusingIEwon’tbeavailabletoFirefoxandviceversa.TheexamplesinthissectionuseFirefox31.

FirefoxkeepsitscookiesinatotallydifferentplacefromIE,andthecontentsareviewedbyadifferentmeans.ToviewcookiesinFirefox:

1. Clickthe“Hamburger”iconandchooseOptionsasshowninFigure13.9.

Figure13.9

2. SelectthePrivacyoption.

3. Clickthe“removeindividualcookies”linkandyoushouldseethedialogboxshowninFigure13.10.

Figure13.10

4. ClickClosetogetbacktothebrowser,andloadfreshbakedcookie.html.

5. RepeattheprocessyoufollowedpreviouslytogettotheCookieManager,andyoushouldfindthattheUserNamecookiehasbeenaddedtothebox.IfloadedfromyourPCandnottheInternet,thecookiewillhaveablankwebaddress.TheexpandedcookiedetailsareshowninFigure13.11.

Figure13.11

NotethatbuttonsareprovidedatthebottomoftheCookieManagertoremovetheselectedcookieorallofthecookiesthatarestored.

ViewingCookiesinChromeWhenitcomestocookies,ChromeissomewhatsimilartoFirefoxinthatyouviewandmanagethemthroughthebrowser:

1. Clickthe“Hamburger”iconandchooseSettingsasshowninFigure13.12.

Figure13.12

2. Inthe“Searchsettings”box,typecookies.You’llseeChromechangetheSettingspagetolooksomethinglikeFigure13.13.Clickthe“Contentsettings”button.

Figure13.13

3. Inthe“Contentsettings”window,clickthe“Allcookiesandsitedata…”button.Anewwindowpopsupthatletsyoumanageyourcookies(Figure13.14).

Figure13.14

4. Loadfreshbakedcookie.htmlinanewtaborwindow.

5. GobacktotheSettingspageandclicktheRefreshicon.You’llnowseeanentryforthenewcookieasshowninFigure13.15.

Figure13.15

Nowthatyou’veseenhowtoviewcookiesmanually,let’slookathowyoucreatethemandreadthemusingcode.Youstartbylookingateachofthepartsthatmakeupacookiestring.

TheCookieStringWhenyouarecreatingacookie,youcansetsixparts:name,value,expires,path,domain,andsecure,althoughthelatterfouroftheseareoptional.You’llnowlookateachoftheseinturn.

nameandvalueThefirstpartofthecookiestringconsistsofthenameandvalueofthecookie.Thenameisusedsothatyoucanreferencethecookielater,andthevalueistheinformationpartofthecookie.

Thisname/valuepartofthecookiestringiscompulsory;itsortofdefeatsthepointofthecookieifyoudon’tstoreanameorvalue,becausestoringinformationiswhatcookiesareallabout.Youshouldmakesurethatthispartcomesfirstinthecookiestring.

Thevalueforthecookieisaprimitivestring,althoughthestringcanholdnumber

charactersifitisnumericaldatathatyouwanttostore.Ifyouarestoringtext,certaincharacters,suchassemicolons,cannotbeusedinsidethevalue,unlessyouuseaspecialencoding,whichyou’llseelater.Inthecaseofsemicolons,thisisbecausetheyareusedtoseparatethedifferentpartsofthecookiewithinthecookiestring.

Inthefollowinglineofcode,yousetacookiewiththenameUserNameandthevaluePaul:

document.cookie="UserName=Paul;";

Thiscookiehasaverylimitedlifespan,whichisthelengthoftimetheinformationwillcontinuetoexist.Ifyoudon’tsetanexpirationdate,acookiewillexpirewhentheuserclosesthebrowser.Thenexttimetheuseropensthebrowserthecookiewillbegone.Thisisfineifyoujustwanttostoreinformationforthelifeofausersession,whichisasinglevisitbytheusertoyourwebsite.However,ifyouwanttoensurethatyourcookieisavailableforlonger,youmustsetitsexpirationdate,whichyoulookatnext.

expiresIfyouwantacookietoexistforlongerthanjustasingleusersession,youneedtosetanexpirationdateusingthesecondpartofthecookiestring,expires,asfollows:

document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00GMT;";

ThecookiesetbythepreviouslineofcodewillremainavailableforfutureuserightupuntilDecember28,2020.

NOTETheformatoftheexpirationdateisveryimportant.ItshouldbethesameformatthecookieisgivenbythetoUTCString()method.

Inpractice,you’llprobablyusetheDateobjecttogetthecurrentdate,andthensetacookietoexpirethreeorsixmonthsafterthisdate.Otherwise,you’regoingtoneedtorewriteyourpagesonDecember28,2020.

Forexample,youcouldwritethefollowing:

varexpire=newDate();

expire.setMonth(expire.getMonth()+6);

document.cookie="UserName=Paul;expires="+expire.toUTCString()+";";

ThiswillcreateanewcookiecalledUserNamewiththevalueofPaul,whichwillexpiresixmonthsfromthecurrentdate.Notethatotherfactorscancauseacookietoexpirebeforeitsexpirationdate,suchastheuserdeletingthecookieortheuppercookielimitbeingreached.

pathYou’llfindthat99percentofthetimeyouwillonlyneedtosetthename,value,andexpirespartsofacookie.However,attimestheotherthreeparts,suchasthepathpartthatyouarelookingatinthissection,needtobeset.Thefinaltwoparts,domainandsecure,areforadvancedusebeyondthescopeofabeginners’book,butyou’lllookat

thembrieflyjustforcompleteness.

You’reprobablyusedtotheideaoftherebeingdirectoriesonyourharddrive.Ratherthanstoringeverythingonyourcomputerinoneplaceontheharddrive,youdivideitintothesedirectories.Forexample,youmightkeepyourword-processingfilesinMyDocuments,yourimagefilesinMyImages,andsoon.Youprobablyalsosubdivideyourdirectories,sounderMyImagesyoumighthavesubdirectoriescalledMyFamilyandMyHoliday.

Well,webserversusethesameprinciple.Ratherthanputtingthewholewebsiteintoonewebdirectory,it’scommonandindeedsensibletodivideitintovariousdifferentdirectories.Forexample,ifyouvisittheWroxwebsiteatwww.wrox.comandthenclickoneofthebookcategories,you’llfindthatthepathtothepagenavigatedtoisnowwww.wrox.com/Books/.

Thisisallveryinteresting,butwhyisitrelevanttocookies?

Theproblemisthatcookiesarespecificnotonlytoaparticularwebdomain,suchaswww.wrox.com,butalsotoaparticularpathonthatdomain.Forexample,ifapageinwww.wrox.com/Books/setsacookie,onlypagesinthatdirectoryoritssubdirectorieswillbeabletoreadandchangethecookie.Ifapageinwww.wrox.com/academic/triedtoreadthecookie,itwouldfail.Whyarecookiesrestrictedlikethis?

Takethecommonexampleoffreewebspace.Alotofcompaniesonthewebenableyoutosignupforfreewebspace.Usuallyeveryonewhosignsupforthiswebspacehasasiteatthesamedomain.Forexample,Bob’swebsitemightbeatwww.freespace.com/members/bob/.Belindamighthavehersatwww.freespace.com/members/belinda.Ifcookiescouldberetrievedandchangedregardlessofthepath,thenanycookiessetonBob’swebsitecouldbeviewedbyBelindaandviceversa.Thisisclearlysomethingneitherofthemwouldbehappyabout.Notonlyisthereasecurityproblem,butif,unknowntoeachother,theybothhaveacookienamedMyHotCookie,therewouldbeproblemswitheachofthemsettingandretrievingthesamecookie.Whenyouthinkhowmanyusersafreewebspaceprovideroftenhas,youcanseethatthereispotentialforchaos.

Okay,sonowyouknowthatcookiesarespecifictoacertainpath,butwhatifyouwanttoviewyourcookiesfromtwodifferentpathsonyourserver?Say,forexample,youhaveanonlinestoreatwww.mywebsite.com/mystore/butyousubdividethestoreintosubdirectories,suchas/Booksand/Games.Nowlet’simaginethatyourcheckoutisinthedirectorywww.mywebsite.com/mystore/Checkout.Anycookiessetinthe/Booksand/Gamesdirectorieswon’tbevisibletoeachotherorpagesinthe/Checkoutdirectory.Togetaroundthisyoucaneithersetcookiesonlyinthe/mystoredirectory(becausethesecanbereadbythatdirectoryandanyofitssubdirectories),oryoucanusethepathpartofthecookiestringtospecifythatthepathofthecookieis/mystoreevenifit’sbeingsetinthe/Gamesor/Booksor/Checkoutsubdirectories.

Forexample,youcoulddothislikeso:

document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00"+

";path=/mystore;";

Now,evenifthecookieissetbyapageinthedirectory/Books,itwillstillbeaccessibletofilesinthe/mystoredirectoryanditssubdirectories,suchas/Checkoutand/Games.

Ifyouwanttospecifythatthecookieisavailabletoallsubdirectoriesofthedomainitissetin,youcanspecifyapathoftherootdirectoryusingthe/character:

document.cookie="UserName=Paul;expires=Tue,28Dec2020

00:00:00;path=/;";

Now,thecookiewillbeavailabletoalldirectoriesonthedomainitissetfrom.Ifthewebsiteisjustoneofmanyatthatdomain,it’sbestnottodothisbecauseeveryoneelsewillalsohaveaccesstoyourcookieinformation.

It’simportanttonotethatalthoughWindowscomputersdon’thavecase-sensitivedirectorynames,manyotheroperatingsystemsdo.Forexample,ifyourwebsiteisonaUnix-orLinux-basedserver,thepathpropertywillbecase-sensitive.

domainThefourthpartofthecookiestringisthedomain.Anexampleofadomainiswrox.comorbeginningjs.com.Likethepathpartofthecookiestring,thedomainpartisoptionalandit’sunlikelythatyou’llfindyourselfusingitveryoften.

Bydefault,cookiesareavailableonlytopagesinthedomaininwhichtheywereset.Forexample,ifyouhaveyourfirstwebsiterunningonaserverwiththedomainmypersonalwebsite.mydomain.comandyouhaveasecondwebsiterunningundermybusinesswebsite.mydomain.com,acookiesetinonewebsitewillnotbeavailabletopagesaccessedundertheotherdomainname,andviceversa.Mostofthetime,thisisexactlywhatyouwant,butifitisnot,youcanusethedomainpartofthecookiestringtospecifythatacookieisavailabletoallsubdomainsofthespecifieddomain.Forexample,thefollowingsetsacookiethatcanbesharedacrossbothsubdomains:

document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00;path=/"

+

";domain=mydomain.com;";

Notethatthedomainmustbethesame.Youcan’tsharewww.someoneelsesdomain.comwithwww.mydomain.com.

secureThefinalpartofthecookiestringisthesecurepart.Thisissimplyabooleanvalue;ifit’ssettotruethecookiewillbesentonlytoawebserverthattriestoretrieveitusingasecurechannel.Thedefaultvalue,whichisfalse,meansthecookiewillalwaysbesent,regardlessofthesecurity.ThisisonlyapplicablewhereyouhavesetupaserverwithSSL(SecureSocketsLayer).

CREATINGACOOKIETomakelifeeasierforyourself,you’llwriteafunctionthatenablesyoutocreateanewcookieandsetcertainofitsattributeswithmoreease.Thisisthefirstofanumberofusefulfunctionsyou’llcreateandaddtoaseparate.jsfilesoyoucaneasilyreusethecodeinyourfutureprojects.You’lllookatthecodefirstandcreateanexampleusingitshortly.Firstcreateafilecalledcookiefunctions.jsandaddthefollowingtoit:

functionsetCookie(name,value,path,expires){

value=escape(value);

if(!expires){

varnow=newDate();

now.setMonth(now.getMonth()+6);

expires=now.toUTCString();

}

if(path){

path=";Path="+path;

}

document.cookie=name+"="+value+";expires="+expires+path;

}

Thesecureanddomainpartsofthecookiestringareunlikelytobeneeded,soyouallowjustthename,value,expires,andpathpartsofacookietobesetbythefunction.Ifyoudon’twanttosetapathorexpirationdate,youcanomitthemorpassemptystringsforthoseparameters.Ifnopathisspecified,thecurrentdirectoryanditssubdirectorieswillbethepath.Ifnoexpirationdateisset,youjustassumeadatesixmonthsfromnow.

Thefirstlineofthefunctionintroducestheescape()function,whichyou’venotseenbefore:

value=escape(value);

Whenwetalkedaboutsettingthevalueofacookie,wementionedthatcertaincharacterscannotbeuseddirectly,suchasasemicolon.(Thisalsoappliestothenameofthecookie.)Togetaroundthisproblem,youcanusethebuilt-inescape()andunescape()functions.Theescape()functionconvertscharactersthatarenottextornumbersintothehexadecimalequivalentoftheircharacterintheLatin-1characterset,precededbya%character.

Forexample,aspacehasthehexadecimalvalue20,andthesemicolonthevalue3B.SothefollowingcodeproducestheoutputshowninFigure13.16:

Figure13.16

alert(escape("2001aspaceodyssey;"));

Youcanseethateachspacehasbeenconvertedto%20,the%indicatingthatitrepresentsanescapeorspecialcharacterratherthananactualcharacter,andthat20istheASCIIvalueoftheactualcharacter.Thesemicolonhasbeenconvertedto%3B,asyou’dexpect.

Asyouseelater,whenretrievingcookievaluesyoucanusetheunescape()functiontoconvertfromtheencodedversiontoplaintext.

Backtoyourfunction;nextyouhaveanifstatement:

if(!expires){

varnow=newDate();

now.setMonth(now.getMonth()+6);

expires=now.toUTCString();

}

Thisdealswiththesituationinwhichtheexpiresparameterdoesnotcontainausablevalue(eitherbyomittingitorpassinganemptystring"").Becausemostofthetimeyouwantacookietolastlongerthanthesessionit’screatedin,yousetadefaultvalueforexpiresthatissixmonthsafterthecurrentdate.

Next,ifavaluehasbeenpassedtothefunctionforthepathparameter,youneedtoaddthatvaluewhenyoucreatethecookie.Yousimplyput"path="infrontofanyvaluethathasbeenpassedinthepathparameter:

if(path){

path=";Path="+path;

}

Finally,onthelastlineyouactuallycreatethecookie,puttingtogetherthename,cvalue,expires,andpathpartsofthestring:

document.cookie=name+"="+value+";expires="+expires+path;

You’llbeusingthesetCookie()functionwheneveryouwanttocreateanewcookiebecauseitmakessettingacookieeasierthanhavingtorememberallthepartsyouwanttoset.Moreimportant,itcanbeusedtosettheexpirationdatetoadatesixmonthsaheadofthecurrentdate.

Forexample,tousethefunctionandsetacookiewithdefaultvaluesforexpiresandpath,youjusttypethefollowing:

setCookie("cookieName","cookieValue");

TRYITOUTUsingsetCookie()YounowputallthistogetherinasimpleexampleinwhichyouuseyoursetCookie()functiontosetthreecookiesnamedName,Age,andFirstVisit.Youthendisplaywhatisinthedocument.cookiepropertytoseehowithasbeenaffected.

Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Example1</title>

</head>

<body>

<scriptsrc="cookiefunctions.js"></script>

<script>

setCookie("Name","Bob");

setCookie("Age","101");

setCookie("FirstVisit","10May2007");

alert(document.cookie);

</script>

</body>

</html>

Savetheexampleasch13_example1.htmlandloaditintoawebbrowser.

You’llseethealertboxshowninFigure13.17.Notethatallthreecookiesaredisplayedasname/valuepairsseparatedfromtheothersbysemicolons,andalsothattheexpirationdateisnotdisplayed.Ifyouhadsetthepathparameter,thisalsowouldnothavebeendisplayed.TheUserNamecookiefromapreviousexampleisalsodisplayed.

Figure13.17

YoualreadyknowhowthesetCookie()functionworks,solet’slookatthethreelinesthatusethefunctiontocreatethreenewcookies:

setCookie("Name","Bob");

setCookie("Age","101");

setCookie("FirstVisit","10May2007");

Itisallfairlysimple.Thefirstparameteristhenamethatyou’llgivethecookie.(Youseeshortlyhowyoucanretrieveavalueofacookiebasedonthenameyougaveit.)It’simportantthatthenamesyouusebeonlyalphanumericcharacters,withnospaces,punctuation,orspecialcharacters.Althoughyoucanusecookienameswiththesecharacters,doingsoismorecomplexandbestavoided.Nextyouhavethevalueyouwanttogivethecookie.Thethirdparameteristhepath,andthefourthparameteristhedateonwhichyouwantthecookietoexpire.

Forexample,takethefirstlinewhereyouusethesetCookie()function.HereyouaresettingacookiethatwillbenamedNameandhavethevalueBob.Youdon’twanttosetthepathorexpiresparts,soyouomitthoseparameters.

TheremainingtwolinesinthepreviouscodesnippetsetthecookiesnamedAgeandFirstVisitandsettheirvaluesto101and10May2007,respectively.

Ifyoudidwanttosetthepathandtheexpirationdate,howmightyouchangeyourcode?

Well,imaginethatyouwantthepathtobe/MyStoreandtheexpirationdatetobeoneyearinthefuture.ThenyoucanusethesetCookie()functioninthefollowingway:

varexpires=newDate();

expires.setMonth(expires.getMonth()+12);

setCookie("Name","Bob","/MyStore",expires.toUTCString());

First,youcreateanewDateobject,andbypassingnoparametertoitsconstructor,youletitinitializeitselftothecurrentdate.Inthenextline,youadd12monthstothatdate.WhensettingthecookieusingsetCookie()youpass"/MyStore"asthepathandexpires.toUTCString()astheexpiresparameter.

Whataboutthesituationinwhichyou’vecreatedyourcookie,say,onenamedNamewithavalueofBob,andyouwanttochangeitsvalue?Todothis,youcansimplysetthesamecookieagain,butwiththenewvalue.TochangethecookienamedNamefromavalueofBobtoavalueofBobby,you’dneedthefollowingcode:

setCookie("Name","Bobby");

Whatifyouwanttodeleteanexistingcookie?Well,that’seasy.Justmakeitexpirebychangingitsvalueandsettingitsexpirationdatetoadateinthepast,asinthefollowingexample:

setCookie("Name","","","Mon,1Jan199000:00:00");

GETTINGACOOKIE’SVALUEIntheprecedingexample,youuseddocument.cookietoretrieveastringcontaininginformationaboutthecookiesthathavebeenset.However,thisstringhastwolimitations:

Thecookiesareretrievedinname/valuepairs,witheachindividualcookieseparatedbyasemicolon.Theexpires,path,domain,andsecurepartsofthecookiearenotavailabletoyouandcannotberetrieved.

Thecookiepropertyenablesyoutoretrieveonlyallthecookiessetforaparticularpathand,whentheyarehostedonawebserver,thatwebserver.So,forexample,there’snosimplewayofjustgettingthevalueofacookiewiththenameAge.Todothisyou’llhavetousethestringmanipulationtechniquesyoulearnedinpreviouschapterstocuttheinformationyouwantoutofthereturnedstring.

Alotofdifferentwaysexisttogetthevalueofanindividualcookie,butthewayyou’llusehastheadvantageofworkingwithallcookie-enabledbrowsers.Youusethefollowingfunction,whichyouneedtoaddtoyourcookiefunctions.jsfile:

functiongetCookieValue(name){

varvalue=document.cookie;

varcookieStartsAt=value.indexOf(""+name+"=");

if(cookieStartsAt==-1){

cookieStartsAt=value.indexOf(name+"=");

}

if(cookieStartsAt==-1){

value=null;

}else{

cookieStartsAt=value.indexOf("=",cookieStartsAt)+1;

varcookieEndsAt=value.indexOf(";",cookieStartsAt);

if(cookieEndsAt==-1){

cookieEndsAt=value.length;

}

value=unescape(value.substring(cookieStartsAt,

cookieEndsAt));

}

returnvalue;

}

Thefirsttaskofthefunctionistogetthedocument.cookiestringandstoreitinthevaluevariable:

varvalue=document.cookie;

Next,youneedtofindoutwherethecookiewiththenamepassedasaparametertothefunctioniswithinthevaluestring.YouusetheindexOf()methodoftheStringobjectto

findthisinformation,asshowninthefollowingline:

varcookieStartsAt=value.indexOf(""+name+"=");

Themethodwillreturneitherthecharacterpositionwheretheindividualcookieisfoundor-1ifnosuchname,andthereforenosuchcookie,exists.Yousearchon"”+name+"="sothatyoudon’tinadvertentlyfindcookienamesorvaluescontainingthenamethatyourequire.Forexample,ifyouhavexFoo,Foo,andyFooascookienames,asearchforFoowithoutaspaceinfrontwouldmatchxFoofirst,whichisnotwhatyouwant!

IfcookieStartsAtis-1,thecookieeitherdoesnotexistorit’sattheverybeginningofthecookiestringsothereisnospaceinfrontofitsname.Toseewhichoftheseistrue,youdoanothersearch,thistimewithnospace:

if(cookieStartsAt==-1){

cookieStartsAt=value.indexOf(name+"=");

}

Inthenextifstatement,youchecktoseewhetherthecookiehasbeenfound.Ifithasn’t,yousetthevaluevariabletonull:

if(cookieStartsAt==-1){

value=null;

}

Ifthecookiehasbeenfound,yougetthevalueofthecookieyouwantfromthedocument.cookiestringinanelsestatement.Youdothisbyfindingthestartandtheendofthevaluepartofthatcookie.Thestartwillbeimmediatelyaftertheequalssignfollowingthename.Sointhefollowingline,youfindtheequalssignfollowingthenameofthecookieinthestringbystartingtheindexOf()searchforanequalssignfromthecharacteratwhichthecookiename/valuepairstarts:

else{

cookieStartsAt=value.indexOf("=",cookieStartsAt)+1;

Youthenaddonetothisvaluetomovepasttheequalssign.

Theendofthecookievaluewilleitherbeatthenextsemicolonorattheendofthestring,whichevercomesfirst.Youdoasearchforasemicolon,startingfromthecookieStartsAtindex,inthenextline:

varcookieEndsAt=value.indexOf(";",cookieStartsAt);

Ifthecookieyouareafteristhelastoneinthestring,therewillbenosemicolonandthecookieEndsAtvariablewillbe-1fornomatch.Inthiscaseyouknowtheendofthecookievaluemustbetheendofthestring,soyousetthevariablecookieEndsAttothelengthofthestring:

if(cookieEndsAt==-1){

cookieEndsAt=value.length;

}

Youthengetthecookie’svalueusingthesubstring()methodtocutthevaluethatyou

wantoutofthemainstring.Becauseyouhaveencodedthestringwiththeescape()function,youneedtounescapeittogettherealvalue,hencetheuseoftheunescape()function:

value=unescape(value.substring(cookieStartsAt,

cookieEndsAt));

Finally,youreturnthevalueofthecookietothecallingfunction:

returnvalue;

TRYITOUTWhat’sNew?Nowyouknowhowtocreateandretrievecookies.Let’susethisknowledgeinanexampleinwhichyouchecktoseeifanychangeshavebeenmadetoawebsitesincetheuserlastvisitedit.

You’llbecreatingtwopagesforthisexample.Thefirstisthemainpageforawebsite;thesecondisthepagewithdetailsofnewadditionsandchangestothewebsite.Alinktothesecondpagewillappearonthefirstpageonlyiftheuserhasvisitedthepagebefore(thatis,ifacookieexists)buthasnotvisitedsincethepagewaslastupdated.

Let’screatethefirstpage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Example2a</title>

</head>

<body>

<h1>WelcometoExample2a</h1>

<divid="whatsNew"></div>

<scriptsrc="cookiefunctions.js"></script>

<script>

varlastUpdated=newDate("Tue,28Dec2020");

varlastVisit=getCookieValue("LastVisit");

if(lastVisit){

lastVisit=newDate(lastVisit);

if(lastVisit<lastUpdated){

document.getElementById("whatsNew").innerHTML=

"<ahref='ch13_example2b.html'>What'sNew?</a>";

}

}

varnow=newDate();

setCookie("LastVisit",now.toUTCString());

</script>

</body>

</html>

Savethispageasch13_example2a.html.Notethatitusesthetwofunctions,setCookie()andgetCookieValue(),thatyoucreatedearlier.

Next,youjustcreateasimplepagetolinktofortheWhat’sNew?details:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Example2b</title>

</head>

<body>

<h1>WelcometoExample2b</h1>

<h3>Here'swhat'snew!</h3>

</body>

</html>

Savethispageasch13_example2b.html.

Loadch13_example2a.htmlintoabrowser.Thefirsttimeyougotothemainpage,therewillbenothingbutaheadingsaying“WelcometoExample2a.”Obviously,ifthiswerearealwebsite,itwouldhaveabitmorethanthat,butitsufficesforthisexample.However,refreshthepageandsuddenlyyou’llseethepageshowninFigure13.18.

Figure13.18

Ifyouclickthelink,you’retakentothech13_example2b.htmlpagedetailingallthethingsaddedtothewebsitesinceyoulastvisited.Obviously,nothinghasactuallychangedinyourexamplewebsitebetweenyouloadingthepageandthenrefreshingit.Yougotaroundthisfortestingpurposesbysettingthedatewhenthewebsitelastchanged,storedinvariablelastUpdated,toadateinthefuture(here,December28,2020).

Thech13_example2b.htmlpageisjustasimpleHTMLpagewithnoscript,soyouwillconfineyourattentiontoch13_example2a.html.Inthescriptblock,youdeclarethevariablelastUpdated:

varlastUpdated=newDate("Tue,28Dec2020");

Wheneveryoumakeachangetothewebsite,thisvariableneedstobechanged.It’scurrentlysettoTue,28Dec2020,justtomakesureyouseetheWhat’sNew?linkwhenyourefreshthepage.Abetteralternativeforlivepageswouldbethedocument.lastModifiedproperty,whichreturnsthedateonwhichthepagewaslastchanged.

Next,yougetthedateoftheuser’slastvisitfromtheLastVisitcookieusingthegetCookieValue()function:

varlastVisit=getCookieValue("LastVisit");

Ifit’sfalsy,theuserhaseitherneverbeenherebefore,orithasbeensixormoremonthssincethelastvisitandthecookiehasexpired.Eitherway,youwon’tputtheWhat’sNew?linkupbecauseeverythingisnewiftheuserisafirst-timevisitor,andalothasprobablychangedinthelastsixmonths—morethanwhatyourWhat’sNew?pagewilldetail.

IflastVisithasavalue,youneedtocheckwhethertheuservisitedthesitebeforeitwaslastupdated,andifsotodirecttheusertoapagethatshowswhatisnew.Youdothiswithintheifstatement:

if(lastVisit){

lastVisit=newDate(lastVisit);

if(lastVisit<lastUpdated){

document.getElementById("whatsNew").innerHTML=

"<ahref='ch13_example2b.html'>What'sNew?</a>";

}

}

YoufirstcreateanewDateobjectbasedonthevalueoflastVisitandstorethatbackintothelastVisitvariable.Then,intheconditionoftheinnerifstatement,youcomparethedateoftheuser’slastvisitwiththedateonwhichyoulastupdatedthewebsite.Ifthingshavechangedsincetheuser’slastvisit,youwritetheWhat’sNew?linktothepage,sotheusercanclickitandfindoutwhat’snew.Finally,attheendofthescriptyouresettheLastVisitcookietotoday’sdateandtimeusingthesetCookie()function:

varnow=newDate();

setCookie("LastVisit",nowDate.toUTCString());

COOKIELIMITATIONSYoushouldbeawareofanumberoflimitationswhenusingcookies.

AUserMayDisableCookiesThefirstlimitationisthatalthoughallmodernbrowserssupportcookies,theusermayhavedisabledthem.InFirefoxyoucandothisbyselectingtheOptionsmenu,followedbythePrivacytabandtheCookiestab.InIEyouselectInternetOptionsonthegearmenu.SelectthePrivacytabandyoucanchangethelevelwiththescrollcontrol.AndinChrome,choosetheSettingsoptionfromthegearmenu,searchforcookies,andclick“Contentsettings.”Mostusershavesessioncookiesenabledbydefault.Sessioncookiesarecookiesthatlastforaslongastheuserisbrowsingyourwebsite.Afterhe’sclosedthebrowserthecookiewillbecleared.Morepermanentcookiesarealsonormallyenabledbydefault.However,third-partycookies,thosefromathird-partysite,areusuallydisabled.Thesearethecookiesusedfortrackingpeoplefromsitetositeandhencetheonesthatraisethemostprivacyconcerns.

Boththefunctionsthatyou’vemadeforcreatingandgettingcookieswillcausenoerrorswhencookiesaredisabled,butofcoursethevalueofanycookiesetwillbenullandyouneedtomakesureyourcodecancopewiththis.

Youcouldsetadefaultactionforwhencookiesaredisabled.Inthepreviousexample,ifcookiesaredisabled,theWhat’sNew?linkwillneverappear.

Alternatively,youcanlettheuserknowthatyourwebsiteneedscookiestofunctionbyputtingamessagetothateffectinthewebpage.

Anothertacticistoactivelychecktoseewhethercookiesareenabledand,ifnot,totakesomeactiontocopewiththis,suchasbydirectingtheusertoapagewithlessfunctionalitythatdoesnotneedcookies.Howdoyouchecktoseeifcookiesareenabled?

Inthefollowingscript,yousetatestcookieandthenreadbackitsvalue.Ifthevalueisnull,youknowcookiesaredisabled:

setCookie("TestCookie","Yes");

if(!getCookieValue("TestCookie")){

alert("Thiswebsiterequirescookiestofunction");

}

NumberandInformationLimitationAsecondlimitationisonthenumberofcookiesyoucansetontheuser’scomputerforyourwebsiteandhowmuchinformationcanbestoredineach.Inolderbrowsers,foreachdomain,itwascommonthatyoucouldstoreonlyupto20cookies,andeachcookiepair—thatis,thenameandvalueofthecookiecombined—mustnotbemorethan4,096characters(4KB)insize.It’salsoimportanttobeawarethatallbrowsersdosetsomeupperlimitforthenumberofcookiesstored.Whenthatlimitisreached,oldercookies,regardlessofexpirationdate,areoftendeleted.Somemodernbrowsershavea50-cookie

limit,thoughthismayvary.

Togetaroundthecookielimits,youcanstoremorethanonepieceofinformationpercookie.Thisexampleusesmultiplecookies:

setCookie("Name","Karen")

setCookie("Age","44");

setCookie("LastVisit","10Jan2001");

Youcouldcombinethisinformationintoonecookie,witheachdetailseparatedbyasemicolon:

setCookie("UserDetails","Karen;44;10Jan2001");

BecausethesetCookie()functionescapesthevalueofthecookie,thereisnoconfusionbetweenthesemicolonsseparatingpiecesofdatainthevalueofthecookie,andthesemicolonsseparatingthepartsofthecookie.WhenyougetthecookievaluebackusinggetCookieValue(),youjustsplititintoitsconstituentparts;however,youmustremembertheorderyoustoreditin:

varcookieValues=getCookieValue("UserDetails");

cookieValues=cookieValues.split(";");

alert("Name="+cookieValues[0]);

alert("Age="+cookieValues[1]);

alert("LastVisit="+cookieValues[2]);

Nowyouhaveacquiredthreepiecesofinformationandstillhave19cookiesleftinthejar.Thisapproach,however,islessthanideal,andyoulearnhowtostoredatausingnewertechnologieslaterinthischapter.

COOKIESECURITYANDIEIE6introducedanewsecuritypolicyforcookiesbasedontheP3PaninitiativesetupbytheWorldWideWebConsortium(W3C).ThegeneralaimofP3Pistoreassureuserswhoareworriedthatcookiesarebeingusedtoobtainpersonalinformationabouttheirbrowsinghabits.InIEyoucanselecttheGearmenu ➪ InternetOptionsandclickthePrivacytabtoseewhereyoucansetthelevelofprivacywithregardstocookies(seeFigure13.19).Youhavetostrikeabalancebetweensettingitsohighthatnowebsitewillworkandsolowthatyourbrowsinghabitsandpotentiallypersonaldatamayberecorded.

Figure13.19

Generally,bydefaultsessioncookies—cookiesthatlastforonlyaslongastheuserisbrowsingyourwebsite—areallowed.Assoonastheuserclosesthebrowser,thesessionends.However,ifyouwantcookiestooutlasttheuser’svisittoyourwebsite,youneedtocreateaprivacypolicyinlinewiththeP3Precommendations.Thissoundsalittlecomplex,andcertainlythefinedetailsofthepolicycanbe.Becauseofthiscomplexity,veryfewimplementationsofP3Pexist.Butmanygroupsareworkingtomakeiteasierforpeopletouse.

WEBSTORAGECookiesareausefultoolthatwebdeveloperscantakeadvantageoftostoredataontheuser’scomputer.Butcookiesareatooldesignedforadifferenttime,andthus,adifferentWeb.Althoughtheyservedaspecificpurpose(anddidsoreasonablywell),theirlimitationsarenotidealformodernJavaScriptdevelopment:

Thefirstissueistheapplicationprogramminginterface(API).Towriteandreadcookies,youusethedocument.cookieproperty.Writingacookieisrelativelystraightforward,butreadingaspecificcookierequiresalotofcode.Youwrotetwohelperfunctionstomakewritingandreadingcookieseasier,butideally,youshouldn’thaveto.

Cookiesarenotabrowserfeature,butafeatureofHTTP.Assuch,thebrowsersendsthemtotheserveroneveryrequest.Thisisusefulforapplicationsthatliveontheserver,butit’sunnecessaryforJavaScriptthatrunsinthebrowser.

Thebrowserlimitstheamountofcookiesitstoresandthesizetheycanbe.Asmentionedearlier,thiscanbeanywherefrom20to50cookiesforeachdomain,andeachcookiecannotexceed4KB.

Cookiesaresharedbetweenboththebrowserandtheserver.Ifyourserverapplicationneeds30cookies(120KB)tofunction,thatatbestleavesyouwith20cookies(80KB).You’reoutofluckifyouneedmore.

Theycanexpire.Althoughyoucancontrolthisbysettingandmaintaininganexpirationdate,it’ssimplertonothaveone.

HTML5introducedanewfeaturecalledwebstorage,anditsolveseachofcookies’aforementionedproblems.Sinceitsintroduction,webstoragehasbeenmovedoutoftheHTML5specificationandintoitsown(whichisnamedWebStorage).Itconsistsoftwocomponents:sessionstorageandlocalstorage.Asyoumayhaveguessed,sessionstorageistemporarystoragethatisclearedwhentheuserclosesthebrowser(likeacookiewithoutanexpirationdate).Butinmostcases,youwanttostoredatathatpersistsbetweenvisits,andthatislocalstorage’spurpose.Othernoteworthyfeaturesofwebstorageare:

Itstayswithinthebrowserandisnottransmittedtotheserver.ItisstorageforJavaScriptdevelopers.

Itprovidessignificantlymorestoragespace.ChromeandFirefoxsupport5MBperdomain.IEsupports10MB.

Thedatastoredinlocalstorageneverexpires;itremainsuntilyouortheuserdeletesit.

NOTEThissectionfocusesonlocalstorage,butyoucanapplythesameconceptstosessionstorage.

Thedatastoredinwebstorageisassociatedwithauniquename.Intechnicalterms,we

refertothisnameasakey,andthedataassociatedwithakeyisreferredtoasthevalue.Together,werefertothekeyanditsvalueasakey/valuepair.

YouaccesslocalstorageusingthelocalStorageobject(sessionstorageisaccessedthroughsessionStorage),anditmakesiteasytoset,get,andremovedata.

SettingDataThelocalStorageobjectexposesamethodcalledsetItem(),anditspurposeistosetavalueassociatedwithagivenkey.It’sverysimpletouse,asshownhere:

localStorage.setItem("userName","Paul");

ThefirstargumentpassedtosetItem()isthekey;thesecondisthevalueassociatedwiththatkey.Inthecaseofthiscode,thevalueofPaulisstoredinlocalstorageandisassociatedwiththekeyofuserName.

Youcanalsosetdatausingthemoretraditionalobject.propertyNamesyntax,likeso:

localStorage.userName="Paul";

TheresultofthiscodeisidenticaltotheprevioussetItem()example;thevalueofPaulissetforthekeyofuserName.

Iftheresultsareidentical,whyusesetItem()?Theansweristhatyoudon’thavetounlessyourkeyisaninvalidJavaScriptidentifier.Forexample,let’ssayyouwanttousethekeyusername.That’simpossibletouseasapropertyname:

localStorage.username="Paul";//invalid!

Butyoucanuse“username”asakeywiththesetItem()method:

localStorage.setItem("username","Paul");

Inmostcases,youwon’tusesetItem(),butitistheretouseifandwhenyouneedto.

GettingDataRetrievingdatafromlocalstorageisjustasstraightforwardassettingit.WiththegetItem()method,yousupplythekeyforwhichyouwantthevalueof:

varname=localStorage.getItem("userName");

ThiscodeusesthegetItem()methodtoretrievethevalueassociatedwiththe“userName”keyandassignsthatvaluetothenamevariable.Inthecaseoftheexamplefromtheprevioussection,namewouldcontain“Paul“.

YoucanalsousethekeyaslocalStorage’spropertyifitisavalididentifier:

varname=localStorage.userName;

ThiscodealsogetsthevalueofPaulandassignsittothenamevariable.

Awordofnote:Keysarecase-sensitive.Thatmayseemobviousifyouareusing

object.propertyNamesyntax,buttheruleappliestosetItem()andgetItem().Forexample:

localStorage.setItem("userName","Paul");

varname=localStorage.getItem("UserName");//null

ThiscodesetakeyofuserNamewithavalueofPaul.ItthentriestoretrieveavaluewiththekeyofUserName.BecauseoftheuppercaseU,UserNameanduserNamearetwodifferentkeys.Wehaven’tsetavaluewithUserName,sogetItem()returnsnull.

RemovingDataEventually,youwillwanttoremovesomedatathatyoustoredinlocalstorage,andyoucandothatwiththeremoveItem()method.Simplyprovidethekeyyouwanttoremove,andthekey/valuepairwillbedeletedfromlocalstorage.Forexample:

localStorage.removeItem("userName");

ThiscodedeletestheuserName/Paulkey/valuepairfromlocalstorage.IfthekeyisavalidJavaScriptidentifier,youcanalsouseobject.propertyNamesyntaxtodothesamething,likeso:

localStorage.userName=null;

Here,youassignthevalueofnulltotheuserNamekey/property,thusremovingthekey/valuepairfromlocalstorage.

Ifyourgoalistoremoveallkeysandvaluesfromlocalstorage,youcanusetheclear()method,likethis:

localStorage.clear();//nomorekey/valuepairs

StoringDataasStringsIt’simportanttonotethatwebstorageisastring-onlydatastore.Thismeansthatkeysandtheirvaluescanonlybestrings.Ifyoutrytostoresomeothertypeofvalue(likeanumber)orobject,itisconvertedtoastringandstoredasastring.Forexample,let’ssayyouwanttostoretheuser’sageinlocalstorage.Youcaneasilydosolikethis:

localStorage.age=35;

Asyourightlysuspect,thiscreatesakey/valuepairofage/35.But35wasconvertedtoastringbeforeitwasstoredinlocalstorage.Therefore,whenyouretrievethevalueassociatedwiththeagekey,youhavethestringof35:

varage=localStorage.age;

alert(typeofage);//string

Thismeansthattouseageinanymathematiccalculations,youneedtoconvertittoanumber.That’seasyenoughtofix:

varage=parseInt(localStorage.age,10);

Butwhataboutmorecomplexobjects?Considerthefollowingobjectasanexample:

varjohnDoe={

firstName:"John",

lastName:"Doe",

age:35

};

ThisjohnDoeobjectrepresentsanindividualpersonnamedJohnDoe,andheis35yearsold.Wewanttosavethisobjectinlocalstorage,soweassignitasthevaluetothepersonkey,likethis:

localStorage.person=johnDoe;

Butthere’saproblemhere:Thepersonobjectcannotbereasonablyconvertedintoastring.

Whenyouassignavalueorobjecttoakey,itstoString()methodisautomaticallycalledtoconvertittoastring.ForprimitivetypeslikeNumberandBoolean,wegetthestringrepresentationofthatvalue.Butbydefault,anobject’stoString()methodreturns“[objectObject]“.Thereforeintheprecedingexample,thestring“[objectObject]”isstoredinlocalStorage.person:

varsavedPerson=localStorage.person;

alert(typeofsavedPerson);//string

alert(savedPerson);"[objectObject]"

Thissoundslikeahugelimitation(anditis!),butwecanserializeobjectsintoJSONandparsethembackintoactualobjects.Therefore,wecanwritethis:

localStorage.person=JSON.stringify(johnDoe);

varsavedPerson=JSON.parse(localStorage.person);

ThiscodeserializesthejohnDoeobjectandstorestheresultingJSONwiththepersonkey.Then,whenyouneedtoretrieveandusethatinformation,youdeserializetheJSONusingJSON.parse()andassigntheresultingobjecttothesavedPersonvariable.Nowwecanstorejustaboutanythingweneedtoinlocalstorage,andwehaveatonofspacetostoreitin!

TRYITOUTWhat’sNew?NowwithLocalStorageLet’srewriteExample2usinglocalstorage.Feelfreetocopyandpastethecontentsofch13_example2a.htmlandch13_example2b.htmlasthebasisforthenewfiles.

Let’screatethefirstpage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Example3a</title>

</head>

<body>

<h1>WelcometoExample3a</h1>

<divid="whatsNew"></div>

<script>

varlastUpdated=newDate("Tue,28Dec2020");

varlastVisit=localStorage.lastVisit;

if(lastVisit){

lastVisit=newDate(lastVisit);

if(lastVisit<lastUpdated){

document.getElementById("whatsNew").innerHTML=

"<ahref='ch13_example3b.html'>What'sNew?</a>";

}

}

localStorage.lastVisit=newDate();

</script>

</body>

</html>

Savethispageasch13_example3a.html.Next,createasimplepagetolinktofortheWhat’sNew?details:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Example3b</title>

</head>

<body>

<h1>WelcometoExample3b</h1>

<h3>Here'swhat'snew!</h3>

</body>

</html>

Savethispageasch13_example3b.html.

Loadch13_example3a.htmlintoabrowser.ThispagebehavesexactlylikeExample2a.Thefirsttimeyougotothemainpage,therewillbenothingbutaheadingsaying“WelcometoExample3a.”Refreshingthepagedisplaysthe“What’sNew?”linkinthepage.Clickingthislinktakesyoutoch13_example3b.html.

Asbefore,we’llfocusontheJavaScriptcontainedwithinch13_example3b.html.

First,youdeclarethelastUpdatedvariable:

varlastUpdated=newDate("Tue,28Dec2020");

Next,yougetthedateoftheuser’slastvisitfromlocalstoragewiththelastVisitkey:

varlastVisit=localStorage.lastVisit;

ThisassignsoneoftwovaluestothelastVisitvariable.Ifthisistheuser’sfirstvisittothepage,thelocalStorage.lastVisitkeywon’texistandreturnsnulltolastVisit.Inwhichcase,youwon’tdisplaytheWhat’sNew?linkinthedocument.

ThesecondpossiblevalueoflastVisitisastringrepresentationofthedatetheuserlastvisitedthepage.Inthissituation,youneedtocheckwhethertheuservisitedthesitebeforeitwaslastupdatedanddirecttheusertotheWhat’sNew?pageifso:

if(lastVisit){

lastVisit=newDate(lastVisit);

if(lastVisit<lastUpdated){

document.getElementById("whatsNew").innerHTML=

"<ahref='ch13_example3b.html'>What'sNew?</a>";

}

}

Rememberthatthedatastoredinlocalstorageisstrings;so,youcreateanewDateobjectbasedonthevalueoflastVisitandstoreitinthelastVisitvariable.Then,iflastVisitislessthanlastUpdated,youdisplaytheWhat’sNew?linkinthedocument.

Inthefinallineofcode,youresetthevalueofthelocalState.lastVisitkey:

localStorage.lastVisit=newDate();

ViewingWebStorageContentLikecookies,youcanalsoviewthedatastoredinwebstorage,butdoingsorequiresyoutousethefeaturesfoundineachbrowser’sdevelopmenttools.YoulearnaboutthedevelopmenttoolsfoundinInternetExplorer,Chrome,andFirefoxinChapter18,butviewingthewebstoragecontentinChromeisstraightforward.SimplypressF12tobringupthedevelopmenttoolsandclicktheResourcestab.Figure13.20showsyouthelocalstorageforthebeginningjs.comdomain.

Figure13.20

Youcanonlyviewthewebstorageofthedomainofthepagecurrentlyloadedinagiventab;youcannotviewonedomain’swebstoragefromanotherdomain.

SUMMARYInthischapter,youlookedathowyoucanstoreinformationontheuser’scomputerandusethisinformationtopersonalizethewebsite.Inparticular,youfoundthefollowing:

Thekeytocookiesisthedocumentobject’scookieproperty.

Creatingacookiesimplyinvolvessettingthedocument.cookieproperty.Cookieshavesixdifferentpartsyoucanset.Thesearethename,thevalue,whenitexpires,thepathitisavailableon,thedomainit’savailableon,andfinallywhetheritshouldbesentonlyoversecureconnections.

Althoughsettinganewcookieisfairlyeasy,youfoundthatretrievingitsvalueactuallygetsallthecookiesforthatdomainandpath,andthatyouneedtosplitupthecookiename/valuepairstogetaspecificcookieusingStringobjectmethods.

Cookieshaveanumberoflimitations.First,theusercansetthebrowsertodisablecookies;andsecond,youarelimitedto50cookiesperdomaininIE7+andFirefoxandamaximumof4,096characterspercookiename/valuepair.

Webstorageisanewkey/valuepairdatastorethatreplacestheneedforcookiesforJavaScriptdevelopers.ThoughitwasoriginallyintroducedwithHTML5,itisnowitsownspecification.

Setting,getting,andremovingdatafromwebstorageissimple.YoucaneitheruselocalStorage’sgetItem(),setItem(),andremoveItem()methods,oryoucanassignandusepropertiesonlocalStorageitself.

Thedatastoredinwebstorageisconvertedtostrings.So,youhavetoconvertthedatabackintoitsappropriatedatatypeinordertoeffectivelyuseit.ThisiseasilydonethankstovariousfunctionslikeparseInt(),Date’sconstructor,andJSON.parse().

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. Usinglocalstorage,createapagethatkeepstrackofhowmanytimesthepagehasbeenvisitedbytheuserinthelastmonth.

2. Uselocalstoragetoloadadifferentadvertisementeverytimeauservisitsawebpage.

14AjaxWHATYOUWILLLEARNINTHISCHAPTER:

MakingHTTPrequestswiththeXMLHttpRequestobject

WritingacustomAjaxmodule

WorkingwitholderAjaxtechniquestopreserveusability

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Sinceitsinception,theInternethasusedatransaction-likecommunicationmodel;abrowsersendsarequesttoaserver,whichsendsaresponsebacktothebrowser,which(re)loadsthepage.ThisistypicalHTTPcommunication,anditwasdesignedtobethisway.Butthismodelisrathercumbersomefordevelopers,becauseitrequireswebapplicationstoconsistofseveralpages.Theresultinguserexperiencebecomesdisjointedandinterruptedduetotheseseparatepageloads.

Intheearly2000s,amovementbegantolookforanddevelopnewtechniquestoenhancetheuser’sexperience;tomakewebapplicationsbehavemorelikeconventionalapplications.Thesenewtechniquesofferedtheperformanceandusabilityusuallyassociatedwithconventionaldesktopapplications.Itwasn’tlongbeforedevelopersbegantorefinetheseprocessestoofferricherfunctionalitytotheuser.

Attheheartofthismovementwasonelanguage:JavaScript,anditsabilitytomakeHTTPrequeststransparenttotheuser.

WHATISAJAX?Essentially,Ajaxallowsclient-sideJavaScripttorequestandreceivedatafromaserverwithoutrefreshingthewebpage.Thistechniqueenablesthedevelopertocreateanapplicationthatisuninterrupted,makingonlyportionsofthepagereloadwithnewdata.

ThetermAjaxwasoriginallycoinedbyJesseJamesGarrettin2005.Hewroteanarticleentitled“Ajax:ANewApproachtoWebApplications”(www.adaptivepath.com/publications/essays/archives/000385.php).Init,Garrettstatesthattheinteractivitygapbetweenwebanddesktopapplicationsisbecomingsmaller,andhecitesapplicationssuchasGoogleMapsandGoogleSuggestasproofofthis.ThetermoriginallystoodforAsynchronousJavaScript+XML(XMLwastheformatinwhichthebrowserandservercommunicatedwitheachother).Today,AjaxsimplyreferstothepatternofusingJavaScripttosendandreceivedatafromthewebserverwithoutreloadingtheentirepage.

AlthoughthetermAjaxwasderivedin2005,theunderlyingmethodologywasusedyearsbefore.EarlyAjaxtechniquesconsistedofusinghiddenframes/iframes,dynamicallyadding<script/>elementstothedocument,and/orusingJavaScripttosendHTTPrequeststotheserver;thelatterhasbecomequitepopularinthepastfewyears.Thesenewtechniquesrefreshonlyportionsofapage,bothcuttingthesizeofdatasenttothebrowserandmakingthewebpagefeelmorelikeaconventionalapplication.

WhatCanItDo?Ajaxopenedthedoorsforadvancedwebapplications—onesthatmimicdesktopapplicationsinformandinfunction.AvarietyofcommercialwebsitesemploytheuseofAjax.Thesesiteslookandbehavemorelikedesktopapplicationsthanwebsites.ThemostnotableAjax-enabledwebapplicationscomefromthesearchgiantGoogle:GoogleMapsandGoogleSuggest.

GoogleMapsDesignedtocompetewithexistingcommercialmappingsites(andusingimagesfromitsGoogleEarth),GoogleMaps(http://maps.google.com)usesAjaxtodynamicallyaddmapimagestothewebpage.Whenyouenteralocation,themainpagedoesnotreloadatall;theimagesaredynamicallyloadedinthemaparea.GoogleMapsalsoenablesyoutodragthemaptoanewlocation,andonceagain,themapimagesaredynamicallyaddedtothemaparea(seeFigure14.1).

Figure14.1

GoogleSuggestThenowcommonplaceGoogleSuggestisanotherGoogleinnovationthatemploystheuseofAjax.Uponfirstglance,itappearstobeanormalGooglesearchpage.Whenyoustarttyping,however,adrop-downboxdisplayssuggestionsforsearchtermsthatmightinterestyou.Underthesuggestedwordorphraseisthenumberofresultsthesearchtermreturns(seeFigure14.2).

Figure14.2

BrowserSupportIntheearlyyearsofAjax,browsersupportwasmixed.Everybrowsersupportedthebasicsinsomeway,butsupportdifferedfrombrowsertobrowser.Today,AjaxisajustanothernormalpartofJavaScriptdevelopment,andtoday’smodernbrowsersunquestionablysupportAjax.

USINGTHEXMLHTTPREQUESTOBJECTAsstatedbefore,youcancreateAjax-enabledapplicationsinavarietyofways.However,probablythemostpopularAjaxtechniqueincorporatestheJavaScriptXMLHttpRequestobject,whichispresentinallmajorbrowsers.

NOTEDespiteitsname,youcanretrieveothertypesofdata,likeplaintext,withXMLHttpRequest.

TheXMLHttpRequestobjectoriginatedasaMicrosoftcomponent,calledXmlHttp,intheMSXMLlibraryfirstreleasedwithIE5.ItoffereddevelopersaneasywaytoopenHTTPconnectionsandretrieveXMLdata.MicrosoftimprovedthecomponentwitheachnewversionofMSXML,makingitfasterandmoreefficient.

AsthepopularityoftheMicrosoftXMLHttpRequestobjectgrew,MozilladecidedtoincludeitsownversionoftheobjectwithFirefox.TheMozillaversionmaintainedthesamepropertiesandmethodsusedinMicrosoft’sActiveXcomponent,makingcross-browserusagepossible.Soonafter,OperaSoftwareandApplecopiedtheMozillaimplementation,andGooglenaturallyimplementeditwithChrome’sinitialrelease.AsforInternetExplorer,XMLHttpRequestisnolongeranActiveXcomponentbutanativeobjectinthebrowser.

CreatinganXMLHttpRequestObjectTheXMLHttpRequestobjectislocatedinthewindowobject.CreatinganXMLHttpRequestobjectisassimpleascallingitsconstructor:

varrequest=newXMLHttpRequest();

ThislinecreatesanXMLHttpRequestobject,whichyoucanusetoconnectto,andrequestandreceivedatafrom,aserver.

UsingtheXMLHttpRequestObjectOnceyoucreatetheXMLHttpRequestobject,youarereadytostartrequestingdatawithit.Thefirststepinthisprocessistocalltheopen()methodtoinitializetheobject:

request.open(requestType,url,async);

Thismethodacceptsthreearguments.Thefirst,requestType,isastringvalueconsistingofthetypeofrequesttomake.ThevaluecanbeeitherGETorPOST.ThesecondargumentistheURLtosendtherequestto,andthethirdisanoptionaltrueorfalsevalueindicatingwhethertherequestshouldbemadeinasynchronousorsynchronousmode.

RequestsmadeinsynchronousmodehaltallJavaScriptcodefromexecutinguntilaresponseisreceivedfromtheserver.Thiscanslowdownyourapplication’sexecutiontime.Inmostcases,youwanttouseasynchronousmode,whichletsthebrowsercontinue

toexecuteyourapplication’scodewhiletheXMLHttpRequestobjectawaitsaresponsefromtheserver.AsynchronousmodeisthedefaultbehaviorofXMLHttpRequest,soyoucanusuallyomitthethirdargumenttoopen().

NOTEInthepast,itwasconsideredbestpracticetopasstrueasthethirdargument.

Thenextstepistosendtherequest;dothiswiththesend()method.Thismethodacceptsoneargument,whichisastringthatcontainstherequestbodytosendalongwiththerequest.GETrequestsdonotcontainanyinformation,sopassnullastheargument:

varrequest=newXMLHttpRequest();

request.open("GET","http://localhost/myTextFile.txt",false);

request.send(null);

ThiscodemakesaGETrequesttoretrieveafilecalledmyTextFile.txtinsynchronousmode.Callingthesend()methodsendstherequesttotheserver.

WARNINGThesend()methodrequiresanargumenttobepassed,evenifitisnull.

EachXMLHttpRequestobjecthasastatusproperty.ThispropertycontainstheHTTPstatuscodesentwiththeserver’sresponse.Theserverreturnsastatusof200forasuccessfulrequest,andoneof404ifitcannotfindtherequestedfile.Withthisinmind,considerthefollowingexample:

varrequest=newXMLHttpRequest();

request.open("GET","http://localhost/myTextFile.txt",false);

request.send(null);

varstatus=request.status;

if(status==200){

alert("Thetextfilewasfound!");

}elseif(status==404){

alert("Thetextfilecouldnotbefound!");

}else{

alert("Theserverreturnedastatuscodeof"+status);

}

Thiscodechecksthestatuspropertytodeterminewhatmessagetodisplaytotheuser.Ifsuccessful(astatusof200),analertboxtellstheusertherequestfileexists.Ifthefiledoesn’texist(status404),theuserseesamessagestatingthattheservercannotfindthefile.Finally,analertboxtellstheuserthestatuscodeifitequalssomethingotherthan200or404.

ManydifferentHTTPstatuscodesexist,andcheckingforeverycodeisnotfeasible.Mostofthetime,youshouldonlybeconcernedwithwhetheryourrequestissuccessful.Therefore,youcancutthepreviouscodedowntothis:

varrequest=newXMLHttpRequest();

request.open("GET","http://localhost/myTextFile.txt",false);

request.send(null);

varstatus=request.status;

if(status==200){

alert("Thetextfilewasfound!");

}else{

alert("Theserverreturnedastatuscodeof"+status);

}

Thiscodeperformsthesamebasicfunction,butitonlychecksforastatuscodeof200andsendsagenericmessagetoalerttheuserforotherstatuscodes.

AsynchronousRequestsThepreviouscodesamplesdemonstratethesimplicityofsynchronousrequests.Asynchronousrequests,ontheotherhand,addsomecomplexitytoyourcodebecauseyouhavetohandlethereadystatechangeevent.Inasynchronousrequests,theXMLHttpRequestobjectexposesareadyStateproperty,whichholdsanumericvalue;eachvaluereferstoaspecificstateinarequest’slifespan,asfollows:

0:Theobjecthasbeencreated,buttheopen()methodhasn’tbeencalled.

1:Theopen()methodhasbeencalled,buttherequesthasn’tbeensent.

2:Therequesthasbeensent;headersandstatusarereceivedandavailable.

3:Aresponsehasbeenreceivedfromtheserver.

4:Therequesteddatahasbeenfullyreceived.

ThereadystatechangeeventfireseverytimethereadyStatepropertychanges,callingtheonreadystatechangeeventhandler.Thefourthandfinalstateisthemostimportant;itletsyouknowthattherequestcompleted.

NOTEItisimportanttonotethateveniftherequestwassuccessful,youmaynothavetheinformationyouwanted.Anerrormayhaveoccurredontheserver’sendoftherequest(a404,500,orsomeothererror).Therefore,youstillneedtocheckthestatuscodeoftherequest.

Codetohandlethereadystatechangeeventcouldlooklikethis:

varrequest=newXMLHttpRequest();

functionreqReadyStateChange(){

if(request.readyState==4){

varstatus=request.status;

if(status==200){

alert(request.responseText);

}else{

alert("Theserverreturnedastatuscodeof"+status);

}

}

}

request.open("GET","http://localhost/myTextFile.txt");

request.onreadystatechange=reqReadyStateChange;

request.send(null);

ThiscodefirstdefinesthereqReadyStateChange()function,whichhandlesthereadystatechangeevent.ItfirstchecksiftherequestcompletedbycomparingreadyStateto4.Thefunctionthencheckstherequest’sstatustoensuretheserverreturnedtherequesteddata.Oncethesetwocriteriaaremet,thecodealertsthevalueoftheresponseTextproperty(theactualrequesteddatainplaintextformat).Notetheopen()method’scall;thethirdargumentisomitted.ThismakestheXMLHttpRequestobjectrequestdataasynchronously.

Thebenefitsofusingasynchronouscommunicationarewellworththeaddedcomplexityofthereadystatechangeevent,becausethebrowsercancontinuetoloadthepageandexecuteyourotherJavaScriptcodewhiletherequestobjectsendsandreceivesdata.Perhapsauser-definedmodulethatwrapsanXMLHttpRequestobjectcouldmakeasynchronousrequestseasiertouseandmanage.

NOTEAnXMLHttpRequestobjectalsohasapropertycalledresponseXML,whichattemptstoloadthereceiveddataintoanHTMLDOM(whereasresponseTextreturnsplaintext).

CREATINGASIMPLEAJAXMODULETheconceptofcodereuseisimportantinprogramming;itisthereasonwhyfunctionsaredefinedtoperformspecific,common,andrepetitivetasks.Chapter5introducedyoutotheobject-orientedconstructofcodereuse:referencetypes.Theseconstructscontainpropertiesthatcontaindataand/ormethodsthatperformactionswiththatdata.

Inthissection,youwriteyourownAjaxmodulecalledHttpRequest,therebymakingasynchronousrequestseasiertomakeandmanage.Beforegettingintowritingthismodule,let’sgooverthepropertiesandmethodstheHttpRequestreferencetypeexposes.

PlanningtheHttpRequestModuleThere’sonlyonepieceofinformationthatyouneedtokeeptrackof:theunderlyingXMLHttpRequestobject.Therefore,thismodulewillhaveonlyoneproperty,request,whichcontainstheunderlyingXMLHttpRequestobject.

TheHttpRequestexposesasinglemethodcalledsend().Itspurposeistosendtherequesttotheserver.

Nowlet’sbegintowritethemodule.

TheHttpRequestConstructorAreferencetype’sconstructordefinesitspropertiesandperformsanylogicneededtofunctionproperly:

functionHttpRequest(url,callback){

this.request=newXMLHttpRequest();

//morecodehere

}

Theconstructoracceptstwoarguments.Thefirst,url,istheURLtheXMLHttpRequestobjectwillrequest.Thesecond,callback,isacallbackfunction;itwillbecalledwhentheserver’sresponseisreceived(whentherequest’sreadyStateis4anditsstatusis200).Thefirstlineoftheconstructorinitializestherequestproperty,assigninganXMLHttpRequestobjecttoit.

Withtherequestpropertycreatedandreadytouse,youpreparetosendtherequest:

functionHttpRequest(url,callback){

this.request=newXMLHttpRequest();

this.request.open("GET",url);

functionreqReadyStateChange(){

//morecodehere

}

this.request.onreadystatechange=reqReadyStateChange;

}

ThefirstlineofthenewcodeusestheXMLHttpRequestobject’sopen()methodtoinitializetherequestobject.SettherequesttypetoGET,andusetheurlparametertospecifytheURLyouwanttorequest.Becauseyouomitopen()’sthirdargument,yousettherequestobjecttouseasynchronousmode.

ThenextfewlinesdefinethereqReadyStateChange()function.Definingafunctionwithinafunctionmayseemweird,butitisperfectlylegaltodoso.Thisinnerfunctioncannotbeaccessedoutsidethecontainingfunction(theconstructorinthiscase),butithasaccesstothevariablesandparametersofthecontainingconstructorfunction.Asitsnameimplies,thereqReadyStateChange()functionhandlestherequestobject’sreadystatechangeevent,andyoubindittodosobyassigningittotheonreadystatechangeeventhandler:

functionHttpRequest(url,callback){

this.request=newXMLHttpRequest();

this.request.open("GET",url);

vartempRequest=this.request;

functionreqReadyStateChange(){

if(tempRequest.readyState==4){

if(tempRequest.status==200){

callback(tempRequest.responseText);

}else{

alert("Anerroroccurredtryingtocontacttheserver.");

}

}

}

this.request.onreadystatechange=reqReadyStateChange;

}

Thenewlinesofcodemayonceagainlookalittlestrange,butit’sactuallyapatternyou’lloftenseewhenlookingatotherpeople’scode.ThefirstnewlinecreatesthetempRequestvariable.Thisvariableisapointertothecurrentobject’srequestproperty,andit’susedwithinthereqReadyStateChange()function.Thisisatechniquetogetaroundscopingissues.Ideally,youwouldusethis.requestinsidethereqReadyStateChange()function.However,thethiskeywordpointstothereqReadyStateChange()functioninsteadoftotheXMLHttpRequestobject,whichwouldcausethecodetonotfunctionproperly.SowhenyouseetempRequest,thinkthis.request.

InsidethereqReadyStateChange()function,youseethefollowingline:

callback(tempRequest.responseText);

Thislinecallsthecallbackfunctionspecifiedbytheconstructor’scallbackparameter,andyoupasstheresponseTextpropertytothisfunction.Thisallowsthecallbackfunctiontousetheinformationreceivedfromtheserver.

Creatingthesend()MethodThereisonemethodinthisreferencetype,anditenablesyoutosendtherequesttotheserver.SendingarequesttotheserverinvolvestheXMLHttpRequestobject’ssend()

method.Thissend()issimilar,withthedifferencebeingthatitdoesn’tacceptarguments:

HttpRequest.prototype.send=function(){

this.request.send(null);

};

Thisversionofsend()issimpleinthatallyoudoiscalltheXMLHttpRequestobject’ssend()methodandpassitnull.

TheFullCodeNowthatthecode’sbeencovered,openyourtexteditorandtypethefollowing:

functionHttpRequest(url,callback){

this.request=newXMLHttpRequest();

this.request.open("GET",url);

vartempRequest=this.request;

functionreqReadyStateChange(){

if(tempRequest.readyState==4){

if(tempRequest.status==200){

callback(tempRequest.responseText);

}else{

alert("Anerroroccurredtryingtocontacttheserver.");

}

}

}

this.request.onreadystatechange=reqReadyStateChange;

}

HttpRequest.prototype.send=function(){

this.request.send(null);

};

Savethisfileashttprequest.js.You’lluseitlaterinthechapter.

Thegoalofthismodulewastomakeasynchronousrequestseasiertouse,solet’slookatabriefcode-onlyexampleandseeifthatgoalwasaccomplished.

Thefirstthingyouneedisafunctiontohandlethedatareceivedfromtherequest;thisfunctiongetspassedtotheHttpRequestconstructor:

functionhandleData(text){

alert(text);

}

ThiscodedefinesafunctioncalledhandleData()thatacceptsoneargumentcalledtext.Whenexecuted,thefunctionmerelyalertsthedatapassedtoit.NowcreateanHttpRequestobjectandsendtherequest:

varrequest=newHttpRequest(

"http://localhost/myTextFile.txt",handleData);

request.send();

Passthetextfile’slocationandapointerofthehandleData()functiontotheconstructor,andsendtherequestwiththesend()method.ThehandleData()functioniscalledintheeventofasuccessfulrequest.

ThismoduleencapsulatesthecoderelatedtoasynchronousXMLHttpRequestrequestsnicely.Youdon’thavetoworryaboutcreatingtherequestobject,handlingthereadystatechangeevent,orcheckingtherequest’sstatus;theHttpRequestmoduledoesitallforyou.

VALIDATINGFORMFIELDSWITHAJAXYou’veprobablyseenitmanytimes:registeringasanewuseronawebsite’sforumorsigningupforweb-basede-mail,onlytofindthatyourdesiredusernameistaken.Ofcourse,youdon’tfindthisoutuntilafteryou’vefilledouttheentireform,submittedit,andwatchedthepagereloadwithnewdata(nottomentionthatyou’velostsomeofthedatayouentered).Asyoucanattest,formvalidationcanbeafrustratingexperience.Thankfully,Ajaxcansoftenthisexperiencebysendingdatatotheserverbeforesubmittingtheform—allowingtheservertovalidatethedata,andlettingtheuserknowtheoutcomeofthevalidationwithoutreloadingthepage!

Inthissection,youcreateaformthatusesAjaxtechniquestovalidateformfields.It’spossibletoapproachbuildingsuchaforminavarietyofways;theeasiestofwhichtoimplementprovidesalinkthatinitiatesanHTTPrequesttotheserverapplicationtocheckwhethertheuser’sdesiredinformationisavailabletouse.

Theformyoubuildresemblestypicalformsusedtoday;itwillcontainthefollowingfields:

Username(validated):Thefieldwheretheusertypeshisorherdesiredusername

Email(validated):Thefieldwheretheusertypeshisorhere-mail

Password(notvalidated):Thefieldwheretheusertypeshisorherpassword

VerifyPassword(notvalidated):Thefieldwheretheuserverifieshisorherpassword

NotethatthePasswordandVerifyPasswordfieldsarejustforshowinthisexample.Verifyingapasswordiscertainlysomethingtheserverapplicationcando;however,itisfarmoreefficienttoletJavaScriptperformthatverification.Doingsoaddsmorecomplexitytothisexample,andwewanttokeepthisassimpleaspossibletohelpyougetagraspofusingAjax.

NexttotheUsernameandEmailfieldswillbeahyperlinkthatcallsaJavaScriptfunctiontoquerytheserverwithyourHttpRequestmodulefromtheprevioussection.

Asmentionedearlier,Ajaxiscommunicationbetweenthebrowserandserver.Sothisexampleneedsasimpleserverapplicationtovalidatetheformfields.PHPprogrammingisbeyondthescopeofthisbook.However,weshoulddiscusshowtorequestdatafromthePHPapplication,aswellaslookattheresponsetheapplicationsendsbacktoJavaScript.

RequestingInformationThePHPapplicationlooksforoneoftwoargumentsinthequerystring:usernameandemail.

Tochecktheavailabilityofausername,usetheusernameargument.TheURLtodothislookslikethefollowing:

http://localhost/formvalidator.php?username=[usernameToSearchFor]

Whensearchingforausername,replace[usernameToSearchFor]withtheactualname.

Searchingforane-mailfollowsthesamepattern.Thee-mailURLlookslikethis,whereyoureplace[emailToSearchFor]withtheactualname:

http://localhost/formvalidator.php?email=[emailToSearchFor]

TheReceivedDataAsuccessfulrequestresultsinasimpleJSONstructurethatdefinestwomemberscalledsearchTermandavailable,likethis:

{

"searchTerm":"jmcpeak",

"available":true

}

Asitsnameimplies,thesearchTermitemcontainsthestringusedintheusernameore-mailsearch.Theavailableitemisabooleanvalue.Iftrue,therequestedusernameand/ore-mailisavailableforuse.Iffalse,theusernameand/ore-mailisinuseandthereforenotavailable.

BeforeYouBeginThisisalive-codeAjaxexample;therefore,yoursystemmustmeetafewrequirementsifyouwanttorunthisexamplefromyourcomputer.

AWebServerFirst,youneedawebserver.IfyouareusingWindows,youhaveMicrosoft’swebserversoftware,InternetInformationServices(IIS),freelyavailabletoyou.ToinstallitonWindows,openProgramsandFeaturesintheControlPanelandclickTurnWindowsfeaturesonoroff.Figure14.3showstheWindowsFeaturesdialogboxinWindows8.

Figure14.3

ExpandInternetInformationServicesandcheckthefeaturesyouwanttoinstall.YoumustcheckWorldWideWebServices(Figure14.4).Youmayneedyouroperatingsystem’sinstallationCDtocompletetheinstallation.

Figure14.4

Ifyouuseanotheroperatingsystem,oryouwanttouseanotherwebserverapplication,youcaninstallApacheHTTPServer(www.apache.org).Thisisanopensourcewebserverandcanrunonavarietyofoperatingsystems,suchasLinux,Unix,andWindows,tolistonlyafew.MostwebsitesrunonApache,sodon’tfeelnervousaboutinstallingitonyourcomputer.Itisextremelystable.

IfyoudochoosetouseApache,don’tdownloadandinstallitjustyet;therearedifferentversionsofApache.Instead,downloadPHPfirstbecausePHP’swebsitegivesyouaccurateinformationonwhichApacheversionyoushoulddownloadandinstall.

PHPPHPisapopularopensourceserver-sidescriptinglanguageandmustbeinstalledonyourcomputerifyouwanttorunPHPscripts.YoucandownloadPHPinavarietyofforms(binaries,Windowsinstallationwizards,andsourcecode)atwww.php.net.ThePHPcodeusedinthisexamplewaswritteninPHP5.

TRYITOUTXMLHttpRequestSmartForm

InthisTryItOut,youwilluseAjaxtovalidateformfields.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter14:Example1</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="httprequest.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=document.getElementById("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varurl="ch14_formvalidator.php?username="+userValue;

varrequest=newHttpRequest(url,handleResponse);

request.send();

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_formvalidator.php?email="+emailValue;

varrequest=newHttpRequest(url,handleResponse);

request.send();

}

functionhandleResponse(responseText){

varresponse=JSON.parse(responseText);

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

document.getElementById("usernameAvailability")

.addEventListener("click",checkUsername);

document.getElementById("emailAvailability")

.addEventListener("click",checkEmail);

</script>

</body>

</html>

Savethisfileinyourwebserver’srootdirectory.Ifyou’reusingIISforyourwebserver,saveitasc:\inetpub\wwwroot\ch14_example1.html.Ifyou’reusingApache,you’llwanttosaveitinsidethehtdocsfolder:path_to_htdocs\htdocs\ch14_example1.html.

Youalsoneedtoplacehttprequest.js(theHttpRequestmodule)andthech14_formvalidator.phpfile(fromthecodedownload)intothesamedirectoryasch14_example1.html.

Nowopenyourbrowserandnavigatetohttp://localhost/ch14_formvalidator.php.Ifeverythingisworkingproperly,youshouldseethetext“PHPisworkingcorrectly.Congratulations!”asinFigure14.5.

Figure14.5

Nowpointyourbrowsertohttp://localhost/ch14_example1.html,andyoushouldseesomethinglikeFigure14.6.

Figure14.6

TypejmcpeakintotheUsernamefieldandclicktheCheckAvailabilitylinknexttoit.You’llseeanalertboxliketheoneshowninFigure14.7.

Figure14.7

Nowtypesomeone@xyz.cominthee-mailfieldandclicktheCheckAvailabilitylinknexttoit.Again,you’llbegreetedwithanalertboxstatingthatthee-mail’salreadyinuse.Nowinputyourownusernameande-mailintothesefieldsandclicktheappropriatelinks.Chancesareanalertboxwilltellyouthatyourusernameand/ore-mailisavailable(theusernamesjmcpeakandpwiltonandthee-mailssomeone@[email protected]).

ThebodyofthisHTMLpagecontainsasimpleformwhosefieldsarecontainedwithinatable.Eachformfieldexistsinitsownrow.Thefirsttworowscontainthefieldsyou’remostinterestedin:theUsernameandEmailfields:

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<!––HTMLtobecontinuedlater––>

Thefirstcolumncontainstextidentifiersforthefields.Thesecondcolumncontainsthe<input/>elementsthemselves.Eachofthesetagshasanidattribute:usernamefortheUsernamefieldandemailfortheEmailfield.Thisenablesyoutoeasilyfindthe<input/>elementsandgetthetextenteredintothem.

Thethirdcolumncontainsan<a/>element.ThesehyperlinksexistforthesolepurposeofkickingoffAjaxrequests.Assuch,theyhaveahash(#)intheirhrefattributes,thuspreventingthebrowserfromnavigatingtoadifferentpage(tobeconsideredavalid,clickablehyperlink,an<a/>elementmusthaveanhrefvalue).Eachoftheselinkshasanidattributethatyou’lluselaterinyourJavaScriptcode.

TheremainingthreerowsinthetablecontaintwopasswordfieldsandtheSubmitbutton(thesmartformcurrentlydoesnotusethesefields):

<!––HTMLcontinuedfromearlier––>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

TheCSSinthisHTMLpageconsistsofonlyacoupleofCSSrules:

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

Theserulesalignthefieldstogivetheformacleanandunifiedlook.

Asstatedearlier,thehyperlinksarekeytotheAjaxfunctionality,becausetheycallJavaScriptfunctionswhenclicked.Thefirstfunction,checkUsername(),retrievesthetexttheuserenteredintotheUsernamefieldandissuesanHTTPrequesttotheserver.

Thisfunctionexecutesbecausetheuserclickedalink.Therefore,youwanttopreventthebrowserfromnavigatingtotheURLspecifiedinitshrefattribute.EventhoughtheURListhehash(#),youstillwanttocallpreventDefault():

functioncheckUsername(e){

e.preventDefault();

varuserValue=document.getElementById("username").value;

Usethedocument.getElementById()methodtofindthe<inputid="FileName_username"/>elementanduseitsvaluepropertytoretrievethetexttypedintothetextbox.Youthenchecktoseeiftheusertypedanytext:

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

Ifthetextboxisempty,thefunctionalertstheusertoinputausernameandstopsthefunctionfromfurtherprocessing.Theapplicationwouldmakeunnecessaryrequeststotheserverifthecodedidn’tdothis.

NextconstructtheURLtomaketherequesttothePHPapplicationandassignittotheurlvariable.ThencreateanHttpRequestobjectbypassingtheURLandthehandleResponse()callbackfunctiontotheconstructor,andsendtherequestbycallingsend():

varurl="ch14_formvalidator.php?username="+userValue;

varrequest=newHttpRequest(url,handleResponse);

request.send();

}

YoulookatthehandleResponse()functionlater.Fornow,let’sexaminethecheckEmail()function.

Checkingthee-mailaddressavailabilityisalmostidenticaltotheusernameprocess.ThecheckEmail()functionretrievesthetexttypedintheEmailfieldandsendsthatinformationtotheserverapplication:

functioncheckEmail(e){

e.preventDefault();

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_formvalidator.php?email="+emailValue;

varrequest=newHttpRequest(url,handleResponse);

request.send();

}

ThisfunctionalsouseshandleResponse()tohandletheserver’sresponse.ThehandleResponse()functionexecuteswhentheHttpRequestobjectreceivesacompleteresponsefromtheserver.Thisfunctionusestherequestedinformationtotelltheuserwhethertheusernameore-mailaddressisavailable.Remember,theresponsefromtheserverisJSON-formatteddata.So,youneedtofirstparsethedataintoaJavaScriptobject:

functionhandleResponse(responseText){

varresponse=JSON.parse(responseText);

Theserver’sresponseisparsedintoanobjectthatisstoredintheresponsevariable.Youthenusethisobject’savailablepropertytodisplaytheappropriatemessagetotheuser:

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+"isnot

available.");

}

}

Ifavailableistrue,thefunctiontellstheuserthathisdesiredusernameore-mailaddressisokaytouse.Ifnot,thealertboxsaysthattheuser’sdesiredusernameore-mailaddressistaken.

Finally,youneedtosetuptheeventlistenersforyourtwolinks:

document.getElementById("usernameAvailability")

.addEventListener("click",checkUsername);

document.getElementById("emailAvailability")

.addEventListener("click",checkEmail);

Youdothisbysimplyretrievingthe<a/>elementsbytheirrespectiveidvaluesandlisteningfortheclickevent.

THINGSTOWATCHOUTFORUsingJavaScripttocommunicatebetweenserverandclientaddstremendouspowertothelanguage’sabilities.However,thispowerdoesnotcomewithoutitsshareofcaveats.Thetwomostimportantissuesaresecurityandusability.

SecurityIssuesSecurityisahottopicintoday’sInternet,andasawebdeveloperyoumustconsiderthesecurityrestrictionsplacedonAjax.KnowingthesecurityissuessurroundingAjaxcansaveyoudevelopmentanddebuggingtime.

TheSame-OriginPolicySincetheearlydaysofNetscapeNavigator2.0,JavaScriptcannotaccessscriptsordocumentsfromadifferentorigin.Thisisasecuritymeasurethatbrowsermakersadhereto;otherwise,maliciouscoderscouldexecutecodewherevertheywanted.Thesame-originpolicydictatesthattwopagesareofthesameoriginonlyiftheprotocol(HTTP),port(thedefaultis80),andhostarethesame.

Considerthefollowingtwopages:

Page1islocatedathttp://www.site.com/folder/mypage1.htm.

Page2islocatedathttp://www.site.com/folder10/mypage2.htm.

Accordingtothesame-originpolicy,thesetwopagesareofthesameorigin.Theysharethesamehost(www.site.com),usethesameprotocol(HTTP),andareaccessedonthesameport(noneisspecified;therefore,theybothuse80).Becausetheyareofthesameorigin,JavaScriptononepagecanaccesstheotherpage.

Nowconsiderthenexttwopages:

Page1islocatedathttp://www.site.com/folder/mypage1.htm.

Page2islocatedathttps://www.site.com/folder/mypage2.htm.

Thesetwopagesarenotofthesameorigin.Thehostisthesame,buttheirprotocolsandportsaredifferent.Page1usesHTTP(port80),whereasPage2usesHTTPS(port443).Thisdifference,thoughslight,isenoughtogivethetwopagestwoseparateorigins.Therefore,JavaScriptononeofthesepagescannotaccesstheotherpage.

SowhatdoesthishavetodowithAjax?Everything,becausealargepartofAjaxisJavaScript.Forexample,becauseofthispolicy,anXMLHttpRequestobjectcannotretrieveanyfileordocumentfromadifferentoriginbydefault.Thereis,however,alegitimateneedforcross-originrequests,andtheW3CrespondedwiththeCross-OriginResourceSharing(CORS)specification.

CORSTheCORSspecificationdefineshowbrowsersandserverscommunicatewithoneanother

whensendingrequestsacrossorigins.ForCORStowork,thebrowsermustsendacustomHTTPheadercalledOriginthatcontainstheprotocol,domainname,andportofthepagemakingtherequest.Forexample,iftheJavaScriptonthepagehttp://www.abc.com/xyz.htmlusedXMLHttpRequesttoissuearequesttohttp://beginningjs.com,theOriginheaderwouldlooklikethis:

Origin:http://www.abc.com

WhentheserverrespondstoaCORSrequest,itmustalsosendacustomheadercalledAccess-Control-Allow-Origin,anditmustcontainthesameoriginspecifiedintherequest’sOriginheader.Continuingfromthepreviousexample,theserver’sresponsemustcontainthefollowingAccess-Control-Allow-OriginheaderforCORStowork:

Access-Control-Allow-Origin:http://www.abc.com

Ifthisheaderismissing,oriftheoriginsdon’tmatch,thebrowserdoesn’tprocesstherequest.

Alternatively,theservercanincludetheAccess-Control-Allow-Originheaderwithavalueof*,signifyingthatalloriginsareaccepted.Thisisprimarilyusedbypubliclyavailablewebservices.

NOTEThesecustomheadersareautomaticallyhandledbythebrowser.YoudonotneedtosetyourownOriginheader,andyoudonothavetomanuallychecktheAccess-Control-Allow-Origin.

UsabilityConcernsAjaxbreaksthemoldoftraditionalwebapplicationsandpages.Itenablesdeveloperstobuildapplicationsthatbehaveinamoreconventional,non-“webbish”way.This,however,isalsoadrawback,becausetheInternethasbeenaroundformany,manyyears,andusersareaccustomedtotraditionalwebpages.

Therefore,itisuptodeveloperstoensurethatuserscanusetheirwebpages,andusethemastheyexpectto,withoutcausingfrustration.

TheBrowser’sBackButtonOneoftheadvantagesofXMLHttpRequestisitseaseofuse.Yousimplycreatetheobject,sendtherequest,andawaittheserver’sresponse.Unfortunately,thisobjectdoeshaveadownside:Mostbrowsersdonotlogahistoryofrequestsmadewiththeobject.Therefore,XMLHttpRequestessentiallybreaksthebrowser’sBackbutton.Thismightbeadesiredside-effectforsomeAjax-enabledapplicationsorcomponents,butitcancauseserioususabilityproblemsfortheuser.

CreatingaBack/Forward-CapableFormwithanIFrameIt’spossibletoavoidbreakingthebrowser’snavigationalbuttonsbyusinganolderbutreliableAjaxtechnique:usinghiddenframes/iframestofacilitateclient-server

communication.Youmustusetwoframesforthismethodtoworkproperly.Onemustbehidden,andonemustbevisible.

NOTENotethatwhenyouareusinganiframe,thedocumentthatcontainstheiframeisthevisibleframe.

Thehidden-frametechniqueconsistsofafour-stepprocess:

1. TheuserinitiatesaJavaScriptcalltothehiddenframebyclickingalinkinthevisibleframeorperformingsomeothertypeofuserinteraction.Thiscallisusuallynothingmorecomplicatedthatredirectingthehiddenframetoadifferentwebpage.Thisredirectionautomaticallytriggersthesecondstep.

2. Therequestissenttotheserver,whichprocessesthedata.

3. Theserversendsitsresponse(awebpage)backtothehiddenframe.

4. ThebrowserloadsthewebpageinthehiddenframeandexecutesanyJavaScriptcodetocontactthevisibleframe.

Theexampleinthissectionisbasedontheformvalidatorbuiltearlierinthechapter,butyou’lluseahiddeniframetofacilitatethecommunicationbetweenthebrowserandtheserverinsteadofanXMLHttpRequestobject.Beforegettingintothecode,youshouldfirstknowaboutthedatareceivedfromtheserver.

TheServerResponseYouexpectedaJSONdatastructureastheserver’sresponsewhenusingXMLHttpRequesttogetdatafromtheserver.Theresponseinthisexampleisdifferentandmustconsistoftwothings:

Thedata,whichmustbeinHTMLformat

AmechanismtocontacttheparentdocumentwhentheiframereceivestheHTMLresponse

ThefollowingcodeisanexampleoftheresponseHTMLpage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>ReturnedData</title>

</head>

<body>

<script>

//morecodehere

</script>

</body>

</html>

ThissimpleHTMLpagecontainsasingle<script/>elementinthebodyofthedocument.TheJavaScriptcodecontainedinthisscriptblockisgeneratedbythePHP

application,callinghandleResponse()inthevisibleframeandpassingittheexpectedJSON.

TheJSONdatastructurehasanewmember:thevaluefield.Itcontainstheusernameore-mailthatwassentintherequest.Therefore,thefollowingHTMLdocumentisavalidresponsefromthePHPapplication:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>ReturnedData</title>

</head>

<body>

<script>

top.handleResponse('{"available":false,"value":"jmcpeak"}');

</script>

</body>

</html>

TheHTMLpagecallsthehandleResponse()functionintheparentwindowandpassestheJSONstructuresignifyingthattheusernameore-mailaddressisavailable.Withtheresponseinthisformat,youcankeepagoodportionoftheJavaScriptcodeidenticaltoExample1.

TRYITOUTIframeSmartFormThecodeforthisrevisedsmartformisverysimilartothecodeusedpreviouslywiththeXMLHttpRequestexample.Thereare,however,afewchanges.Openupyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter14:Example2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

#hiddenFrame{

display:none;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td></td>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td></td>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td></td>

</tr>

</table>

</form>

<iframesrc="about:blank"id="hiddenFrame"name="hiddenFrame">

</iframe>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=document.getElementById("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varurl="ch14_iframevalidator.php?username="+userValue;

frames["hiddenFrame"].location=url;

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_iframevalidator.php?email="+emailValue;

frames["hiddenFrame"].location=url;

}

functionhandleResponse(responseText){

varresponse=JSON.parse(responseText);

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

document.getElementById("usernameAvailability")

.addEventListener("click",checkUsername);

document.getElementById("emailAvailability")

.addEventListener("click",checkEmail);

</script>

</body>

</html>

Savethisfileasch14_example2.html,andsaveitinyourwebserver’srootdirectory.Alsolocatethech14_iframevalidator.phpfilefromthecodedownloadandplaceitinthesamedirectory.

Openyourwebbrowserandnavigatetohttp://localhost/ch14_example2.html.YoushouldseeapagesimilartoExample1.

Checkforthreeusernamesande-mailaddresses.Afteryouclearthefinalalertbox,clickthebrowser’sBackbuttonafewtimes.You’llnoticethatitiscyclingthrough

theinformationyoupreviouslyentered.Thetextinthetextboxwillnotchange;however,thealertboxwilldisplaythenamesande-mailsyouentered.YoucandothesamethingwiththeForwardbutton.

TheHTMLinthebodyofthepageremainsunchangedexceptfortheadditionofthe<iframe/>tagaftertheclosing<form/>tag:

<iframesrc="about:blank"id="hiddenFrame"name="hiddenFrame"/>

ThisframeisinitializedtohaveablankHTMLpageloaded.ItsnameandidattributescontainthevalueofhiddenFrame.YouusethevalueofthenameattributelatertoretrievethisframefromtheframescollectionintheBOM.Next,yousettheCSSfortheframe:

#hiddenFrame{

display:none;

}

Thisrulecontainsonestyledeclarationtohidetheiframefromview.

NOTEHidinganiframethroughCSSenablesyoutoeasilyshowitifyouneedtodebugtheserver-sideapplication.

Nextup,theJavaScript:

functioncheckUsername(e){

e.preventDefault();

varuserValue=document.getElementById("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varurl="ch14_iframevalidator.php?username="+userValue;

frames["hiddenFrame"].location=url;

}

ThischeckUsername()functionisalmostidenticaltoExample1.Thevalueoftheurlvariableischangedtothenewch14_iframvalidator.phpfile.Theactualrequestismadebyaccessingthe<iframe/>elementusingtheframescollectionandsettingitslocationpropertytothenewURL.

ThecheckEmail()functionhasthesamemodifications:

functioncheckEmail(e){

e.preventDefault();

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_iframevalidator.php?email="+emailValue;

frames["hiddenFrame"].location=url;

}

Asbefore,thecheckEmail()functionretrievesthetextbox’svalueandcheckstoseeiftheuserentereddata.ItthenconstructstheURLusingch14_iframevalidator.phpandloadstheURLintothe<iframe/>.

DealingwithDelaysThewebbrowserisjustlikeanyotherconventionalapplicationinthatuserinterface(UI)cuestelltheuserthatsomethingisgoingon.Forexample,whenauserclicksalink,thethrobberanimationmayrunorthecursormightchangetodisplaya“busy”animation.

ThisisanotherareainwhichAjaxsolutions,andXMLHttpRequestspecifically,missthemark.However,thisproblemissimpletoovercome:SimplyaddUIelementstotelltheusersomethingisgoingonandremovethemwhentheactioniscompleted.Considerthefollowingcode:

functionrequestComplete(responseText){

//dosomethingwiththedatahere

document.getElementById("divLoading").style.display="none";

}

varmyRequest=newHttpRequest("http://localhost/myfile.txt",

requestComplete);

//showthatwe'reloading

document.getElementById("divLoading").style.display="block";

myRequest.send();

ThiscodeusestheHttpRequestmoduletorequestatextfile.Beforesendingtherequest,itretrievesanHTMLelementinthedocumentwithanidofdivLoading.This<div/>elementtellstheuserthatdataisloading.Thecodethenhidestheelementwhentherequestcompletes,thuslettingtheuserknowthattheprocesscompleted.

Offeringthisinformationtoyourusersletsthemknowtheapplicationisdoingsomething.Withoutsuchvisualcues,usersarelefttowonderiftheapplicationisworkingonwhatevertheyrequested.

DegradeGracefullyWhenAjaxFailsInaperfectworld,thecodeyouwritewouldworkeverytimeitruns.Unfortunately,youhavetofacethefactthatmanytimesAjax-enabledwebpageswillnotusetheAjax-

enabledgoodnessbecauseauserturnedoffJavaScriptinhisbrowser.

Theonlyrealanswertothisproblemistobuildanold-fashionedwebpagewithold-fashionedforms,links,andotherHTMLelements.Then,usingJavaScript,youcandisablethedefaultbehaviorofthoseHTMLelementsandaddAjaxfunctionality.Considerthishyperlinkasanexample:

<ahref="http://www.wrox.com"title="WroxPublishing">WroxPublishing</a>

Thisisanormal,run-of-the-millhyperlink.Whentheuserclicksit,thebrowserwilltakehimtohttp://www.wrox.com.ByusingJavaScript,youofcoursecanpreventthisbehaviorbyusingtheEventobject’spreventDefault()method.Simplyregisteraclickeventhandlerforthe<a/>elementandcallpreventDefault().BothExamples1and2demonstratedthistechnique.

Asaruleofthumb,buildyourwebpagefirstandaddAjaxlater.

SUMMARYThischapterintroducedyoutoAjax,anditbarelyscratchedthesurfaceofAjaxanditsmanyuses:

YoulookedattheXMLHttpRequestobject,andlearnedhowtomakebothsynchronousandasynchronousrequeststotheserverandhowtousetheonreadystatechangeeventhandler.

YoubuiltyourownAjaxmoduletomakeasynchronousHTTPrequestseasierforyoutocode.

YouusedyournewAjaxmoduleinasmarterform,onethatchecksusernamesande-mailstoseeiftheyarealreadyinuse.

YousawhowXMLHttpRequestbreaksthebrowser’sBackandForwardbuttons,andaddressedthisproblembyrebuildingthesameformusingahiddeniframetomakerequests.

YoulookedatsomeofthedownsidestoAjax,includingthesecurityissuesandthegotchas.

EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.

1. ExtendtheHttpRequestmoduletoincludesynchronousrequestsinadditiontotheasynchronousrequeststhemodulealreadymakes.You’llhavetomakesomeadjustmentstoyourcodetoincorporatethisfunctionality.(Hint:Createanasyncpropertyforthemodule.)

2. Itwasmentionedearlierinthechapterthatyoucouldmodifythesmartformtonotusehyperlinks.ChangetheformthatusestheHttpRequestmodulesothattheUsernameandEmailfieldsarecheckedwhentheusersubmitstheform.Listenfortheform’ssubmiteventandcancelthesubmissionifausernameore-mailistaken.

15HTML5MediaWHATYOUWILLLEARNINTHISCHAPTER:

Playingaudioandvideonativelyinmodernwebbrowsers

WritingacustomcontrolUIformediaplayback

SynchronizingyourUIwiththebrowser’snativecontrols

ParsingJSONbackintoactualobjectsandvaluesyoucanuseinyourpages

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

Atitsinception,theInternetwasatextdeliverysystem.WhereasthefirstHTMLspecificationdescribedthe<img>tagforembeddingimageswithinadocument,HTTPandHTMLweredesignedprimarilyfortransmittinganddisplayingtext(hence,Hyper-Text).

Inthelate1990s,personalcomputerswerefindingtheirwayintomorehouseholds,andordinarypeoplewereabletoaccesstheweb.Naturally,peoplewantedmorefromtheweb,andbrowsermakersaccommodatedthisbydesigningtheirbrowserstouseplug-ins,third-partyapplicationsthatweredesignedtodothingsbrowsersnormallydidn’t,suchasplayingvideoandaudio.Plug-inssolvedaparticularproblem,buttheyweren’twithouttheirfaults—thelargestbeingtheneedforsomanyofthem.Awidevarietyofmusicandvideoformatswereavailable,andcertainplug-inswouldonlyplaycertainformats.Stabilitywasalsoanissuebecauseamalfunctioningplug-incouldcrashthebrowser.

Thenin2005,someenterprisingfolkscreatedYouTube,avideo-sharingwebsite.InsteadofrelyingonQuickTimeorWindowsMediaPlayer,YouTube’svideoswereservedtousersasMacromedia/AdobeFlashfiles.ThiswasadvantageousbecauseofFlash’subiquity;Macromedia/AdobehadFlashplug-insforeverymajorbrowserandoperatingsystem.Soonthereafter,websitesstartedusingFlashfordeliveringtheirvideoandaudiocontenttousers,andeverythingwasrightintheworld.Orwasit?

Manypeoplebelievethebrowsershouldhavethebuilt-incapabilityforplayingvideoandaudio.SothepeopledevelopingtheHTML5specificationincludedtwonewtags,<video>and<audio>,forthatexpresspurpose.Andalthoughit’swonderfulthat,aftersomanyyears,browsersfinallyhavethebuilt-incapabilityofplayingmedia,issuesstillexistthatwedevelopershavetodealwith.Butfirst,let’stakeabrieflookatthesenewtagsandhowtheyworkwithinthebrowser.

APRIMERBeforewebegin,thevideousedinthischapteriscalledBigBuckBunny,anditisCreativeCommons-licensedasanopenmovie.Becauseofitssize,youwillnotfindthevideointhecodedownload.Youcan,however,downloadBigBuckBunnyinavarietyofformatsathttp://www.bigbuckbunny.org.

It’salsoworthnotingthatvideoandaudioareverysimilar;infact,theprimarydifferencebetweenthetwoelementsisthat<audio/>elementshavenoplaybackareaforvisualcontent.Althoughthisdiscussionfocusesprimarilyonvideo,thesameconceptscanbeappliedtoaudio.

BeforeHTML5,embeddingvideowithinawebpagewascumbersomebecauseitrequiredyoutousenolessthanthreeelementsforthevideotoworkinallbrowsers.WithHTML5,however,allyouneedisthe<video/>element:

<videosrc="bbb.mp4"></video>

The<video/>element’ssrcattributecontainsthelocationofthevideofile.Inthiscase,thebrowserwillattempttoloadthebbb.mp4filethatisinthesamedirectoryasthepage.

Ofcourse,olderbrowsersdonotsupportthe<video/>element,andassuch,theywillsimplyignorethe<video/>element.Youcan,however,addsomecontentinsidethe<video/>elementlikethis:

<videosrc="bbb.mp4">

<ahref="bbb.mp4">Downloadthisvideo.</a>

</video>

Browsersthatsupportnativevideowillnotdisplaythelink,butbrowsersthatdonotsupportnativevideowill,asshowninFigure15.1.

Figure15.1

Inmostcases,youwon’tusethesrcattributeinyourHTML.Instead,you’lldefinea<source/>elementinside<video/>,likethis:

<video>

<sourcesrc="bbb.mp4"/>

<ahref="bbb.mp4">Downloadthisvideo.</a>

</video>

Thereasonisfairlysimple:Differentbrowserssupportdifferentformats.Thisistheprimaryissuewefacewithnativevideosupport.Forexample,Figure15.2showsIE11withapagethatcontainsthepreviouscode.

Figure15.2

ThevideoisinH.264format,whichissupportedbyIE11andChrome.Firefox,atthetimeofthiswriting,haspartialsupport,andviewingthesamepagegivesyouFigure15.3.

Figure15.3

Bupkis.Butyoucanskirtaroundthisissuebyprovidingthesamevideoindifferentformats.FirefoxhascompletesupportforWebM,andyoucanaccommodateotherWebM-supportingbrowsersbyaddinganother<source/>element,likethis:

<video>

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

<ahref="bbb.mp4">Downloadthisvideo.</a>

</video>

BrowserswillreadeachsourceintheorderinwhichitappearsintheHTML.Theydownloadthevideo’smetadatatodeterminewhichvideotoload,andtheyloadthefirstvideothatitsupports.ChromesupportsbothH.264andWebM;so,ifChromeweretoloadapagewiththiscode,itwouldloadthe.mp4file.

Youcanpreventthebrowserfromdownloadingavideo’smetadatabyprovidingtheMIMEtypeforeach<source/>element.Youdothiswiththetypeattribute,asshownhere:

<video>

<sourcesrc="bbb.mp4"type="video/mp4"/>

<sourcesrc="bbb.webm"type="video/webm"/>

<ahref="bbb.mp4">Downloadthisvideo.</a>

</video>

Youcanalsoprovidethecodecinformationinthetypeattributetoallowthebrowsertomakemoreintelligentdecisionslikethis:

<video>

<sourcesrc="bbb.mp4"

type='video/mp4;codecs="avc1.4D401E,mp4a.40.2"'/>

<sourcesrc="bbb.webm"type'video/webm;codecs="vp8.0,vorbis"'/>

<ahref="bbb.mp4">Downloadthisvideo.</a>

</video>

NOTEIt’sbeyondthescopeofthisbooktoprovideanin-depthdiscussiononthevariouscodecsusedandthebrowsersthatsupportthem.Soforthesakeofsimplicity,thischapteromitsthetypeattributealtogether—alongwiththetext-basedfallback.

Bydefault,videosdonotdisplaycontrols,butyoucaneasilyaddthedefaultcontrolsbyaddingthecontrolsattributetothe<video/>element:

<videocontrols>

Youdon’thavetosetcontrolstoanyvalue;itspresenceisenoughtoturnonthebrowser’sdefaultcontrolsforthevideo.

Youcanalsotellthebrowsertopreloadthevideowiththepreloadattribute:

<videocontrolspreload>

Thistellsthebrowsertoimmediatelystartloadingthevideo.Likethecontrolsattribute,youdon’thavetosetavalueforpreload.

Bydefault,thebrowserusesthefirstframeofthevideoastheposterofthevideo,theinitialvisualrepresentationofthevideo.Youcanusetheposterattributetodisplaya

customimageforthevideo’sposter:

<videocontrolspreloadposter="bbb.jpg">

Theposterattribute,asyoumightimagine,isspecificallyfor<video/>elements,butyoucanaddafewotherattributestothe<video/>and<audio/>elements.Probablythemostimportant,fromaJavaScriptperspective,istheidattribute.Itis,afterall,howyoufindspecificmediainthepagesothatyoucanscriptthem.

SCRIPTINGMEDIAIntheDOM,<video/>and<audio/>elementsareHTMLMediaElementobjects,andtheHTML5specificationdefinesanAPIforworkingwiththeseobjects.Butnaturally,beforeyoucanuseanyofthemethods,properties,oreventsofamediaobject,youneedtofirstobtainone.Youcanretrieveanexisting<video/>or<audio/>elementinthepageusinganyofthevariousmethodsforfindingelements.Forthesakeofsimplicity,assumethere’sa<videoid="bbbVideo">taginthepage.Youcouldgetitwiththefollowingcode:

varvideo=document.getElementById("bbbVideo");

Oryoucancreateonedynamicallyusingdocument.createElement(),likethis:

varvideo=document.createElement("video");

AndonceyouhaveanHTMLMediaElementobject,youcanbegintoprogramitwithitsrobustAPI.

MethodsMediaobjectshavejustahandfulofmethods,andthey’reprimarilyusedforcontrollingmediaplayback,asshowninthefollowingtable.

METHODNAME DESCRIPTIONcanPlayType(mimeType) Determinesthelikelihoodthatthebrowsercanplaymediaof

theprovidedMIMEtypeand/orcodecload() Beginstoloadthemediafromtheserverpause() Pausesthemediaplaybackplay() Beginsorcontinuestheplaybackofthemedia

ThesearethemethodsdefinedbytheHTML5specification,butbeawarethatthevariousbrowserscanalsoimplementtheirownmethodsinadditiontothesefour.Forexample,FirefoxaddsmanymoremethodstoHTMLMediaElementobjects.Thisbook,however,doesnotcoverthem.

Thepause()andplay()methodsarestraightforward;youusethemtopauseandplaythemedia,respectively:

video.play();

video.pause();

Theothertwomethodsareusedwhenyouwanttoloadmediadynamically.Theload()method,obviously,tellsthebrowsertoloadthespecifiedmedia.ThecanPlayType()method,however,isabitmoreinvolvedbecauseitdoesn’treturntrueorfalse.Instead,itreturnsavarietyofvaluesindicatingthelikelihoodthatthebrowsersupportsthegiventype.ThepossiblevaluesreturnedbycanPlayType()are:

"probably":Indicatesthatthetypeappearstobeplayable

"maybe":It’simpossibletotellifthetypeisplayablewithoutactuallyplayingit.

"":Themediadefinitelycannotbeplayed.

ThecanPlayType()andload()methodsareonlyneededifyouplantoloadavideodynamically.Here’sanexampleofhowthatcodecouldlook:

if(video.canPlayType("video/webm")=="probably"){

video.src="bbb.webm";

}else{

video.src="bbb.mp4";

}

video.load();

video.play();

ThiscodeusesthecanPlayType()methodtodetermineifthebrowsersupportstheWebMformat.Ifitdoes,thevideo’ssrcproperty(whichyoulearnmoreaboutinthenextsection)issettotheWebMversionofthevideo.IfWebMisn’tsupported,thebrowser’ssrcissettotheMP4version.Then,afterthevideoisloadedwiththeload()method,theplay()methodplaysthevideo.

TRYITOUTControllingMediaPlaybackLet’sapplysomeofthisnewfoundknowledgewithasimpleexample.Youwriteawebpagethatplaysandpausesavideo.Notethatthisexampleassumesyouhavetwovideos:bbb.mp4andbbb.webm.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter15:Example1</title>

</head>

<body>

<div>

<buttonid="playbackController">Play</button>

</div>

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

<script>

functionplaybackClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

if(target.innerHTML=="Play"){

video.play();

target.innerHTML="Pause";

}else{

video.pause();

target.innerHTML="Play";

}

}

document.getElementById("playbackController")

.addEventListener("click",playbackClick);

</script>

</body>

</html>

Savethisfileasch15_example1.htmlandopenitinyourbrowser.YoushouldseeabuttonwiththetextPlayandavideodirectlybeneathitasshowninFigure15.4.

Figure15.4

ClickingthebuttonchangesitstexttoPauseandstartsplayingthevideo.ClickingthebuttonagainchangesthetextbacktoPlayandpausesthevideo.

Inthebodyofthepage,youhavea<button/>elementwiththeidofplaybackController.AsitsIDimplies,itisusedforcontrollingtheplaybackofthemedia,avideoembeddedwiththe<video/>element:

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

ThemainportionoftheJavaScriptcodeisafunctioncalledplaybackClick(),aneventhandlerforthe<button/>’sclickevent.Thefirsttwostatementsofthisfunctioncreatetwovariablescalledtargetandvideo:

functionplaybackClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

Thetargetvariableistheeventtarget(thebutton),andvideocontainsareferencetothe<video/>elementobject.

Nextyoudeterminewhetheryouneedtoplayorpausethevideo,andyoudothatbycheckingthetextofthe<button/>element:

if(target.innerHTML=="Play"){

video.play();

target.innerHTML="Pause";

}

Ifit’sPlay,youwanttoplaythevideo.YoudosobyusingtheHTMLMediaElementobject’splay()method,andyouchangethebutton’stexttoreadPause.

Iftheresultofthisifstatementisfalse,youcanassumethatyouwanttopausethevideo:

else{

video.pause();

target.innerHTML="Play";

}

}

So,intheelsestatement,youusethemediaobject’spause()methodandchangethebutton’stextbacktoPlay.

Ofcourse,thisfunctionwon’texecuteitself,soyouregisteraclickeventlisteneronthe<button/>object:

document.getElementById("playbackController")

.addEventListener("click",playbackClick);

Thisexampleworks,butit’snotanidealsolutionforcontrollingmedia.Specifically,youshouldn’trelyuponthetextofanelementtodetermineifyoushouldplayorpause.YoucanbettercontrolmediabyincorporatingsomeofthemanypropertiesdefinedbytheHTML5specification.

PropertiesAlthoughtheHTML5specificationdefinesjustafewmethodsformediaobjects,itdefinesalotofproperties.Youwon’tfindacompletelistofpropertiesinthissection,butAppendixClistsallofthem.

MostoftheHTMLMediaElement’spropertiesareforqueryingand/ormodifyingthestateofthemedia;others,likecontrolsandposter(thelatterforvideo)arecosmetic.

Thefollowingtablelistsafewofthepropertiesandtheirdescriptions.

PROPERTYNAME

DESCRIPTION

autoplay GetsorsetstheautoplayHTMLattribute,indicatingwhetherplaybackshouldautomaticallybeginassoonasenoughmediaisavailable

controls ReflectsthecontrolsHTMLattributecurrentTime Getsthecurrentplaybacktime.Settingthispropertyseeksthemediato

thenewtime.duration Getsthelengthofthemediainseconds;zeroifnomediaisavailable.

ReturnsNaNifthedurationcannotbedeterminedended Indicateswhetherthemediaelementhasendedplaybackloop ReflectstheloopHTMLattribute.Indicateswhetherthemediaelement

shouldstartoverwhenplaybackreachestheendmuted Getsorsetswhethertheaudioismutedpaused IndicateswhetherthemediaispausedplaybackRate Getsorsetstheplaybackrate.1.0isnormalspeed.poster GetsorsetstheposterHTMLattributepreload ReflectsthepreloadHTMLelementattributesrc GetsorsetsthesrcHTMLattributevolume Theaudiovolume.Validvaluesrangefrom0.0(silent)to1.0(loudest).

Likethemethodsfromtheprevioussection,thesepropertiesaredefinedbytheHTML5specification,butsomebrowsermakersalsoimplementtheirownproprietaryproperties.Alsoliketheaforementionedmethods,themajorityofthesepropertiesarestraightforward;theirnamesdoaprettygoodjobofdescribingwhatthey’reusedfor.

Forexample,theaptlynamedpausedpropertycantellyouifthemediaispaused,likethis:

if(video.paused){

video.play();

}else{

video.pause();

}

It’simportanttoknowthatthedefaultstateofanymediaispaused.Thebrowseronlyplaysmediawhenit’stoldtodoso—eitherexplicitlywiththeplay()methodorviathebuilt-incontrols,orimplicitlywiththeautoplayproperty/HTMLattribute.

Youcanusethemutedpropertytonotonlytellyouiftheaudioismuted,buttoalsomutetheaudio.Forexample:

if(video.muted){

video.muted=false;

}else{

video.muted=true;

}

Ortowriteitinamoresimplifiedmanner:

video.muted=!video.muted;

Thiscodeachievesthesameresultsasthepreviousexample;itsetsvideo.mutedtotheoppositeofitscurrentvalue.

Thesrcproperty,however,isabitdifferent.It’sclearthatitsetsthemediaofa<video/>or<audio/>element,butwhenyousetthesrcofamediaobject,youhavetoloaditexplicitlywiththeload()method.Otherwise,whatevermediaiscurrentlyloadedbythebrowserwillplaywhenyoucalltheplay()method.Therefore,thefollowingcodedoesnotcorrectlychangeandplaythemediaofamediaobject:

//incorrect

video.src="new_media.mp4";

video.play();

Thiscodesetsthesrcproperty,butitdoesn’tloadthenewmediawiththeload()method.Therefore,whenthevideoplaysagain,itstillplaysthemediacurrentlyloadedbythebrowser.Tofixthis,youhavetocallload()beforeyoucallplay(),likethis:

video.src="new_media.mp4";

video.load();

video.play();

TRYITOUTControllingMediaPlaybackIILet’srevisitExample1andimproveitbytakingadvantageofsomeoftheHTMLMediaElementobject’sproperties.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter15:Example2</title>

</head>

<body>

<div>

<buttonid="playbackController">Play</button>

<buttonid="muteController">Mute</button>

</div>

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

<script>

functionplaybackClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

if(video.paused){

video.play();

target.innerHTML="Pause";

}else{

video.pause();

target.innerHTML="Resume";

}

}

functionmuteClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

if(video.muted){

video.muted=false;

target.innerHTML="Mute";

}else{

video.muted=true;

target.innerHTML="Unmute";

}

}

document.getElementById("playbackController")

.addEventListener("click",playbackClick);

document.getElementById("muteController")

.addEventListener("click",muteClick);

</script>

</body>

</html>

Savethisasch15_example2.htmlandopenitinyourbrowser.Youshouldnowseetwobuttons:PlayandMute.Directlybeneaththesebuttonsisthevideo,asshowninFigure15.5.

Figure15.5

StartplayingthevideoandclicktheMutebutton.You’llnoticethattheaudioisnowmutedandthebutton’stextreadsUnmute.Clickthebuttonagaintounmutetheaudio.

NowclickthePausebutton.You’llnoticethatthevideopausesandthebutton’stextchangestoResume.Clickingthebuttonagainresumesthevideo.

ThisexampleisquitedifferentfromExample1.StartingwiththeHTML,youaddedanew<button/>element:

<div>

<buttonid="playbackController">Play</button>

<buttonid="muteController">Mute</button>

</div>

IthasanidofmuteControllerandthetextofMute.Asyoualreadyknow,it’susedformutingandunmutingtheaudio.Youregistertheclickeventlisteneratthebottomofthecode:

document.getElementById("muteController")

.addEventListener("click",muteClick);

ThefunctionusedtohandlethiseventiscalledmuteClick().Itsfirsttwolinescreatethetargetandvideovariables—theformercontainingareferencetothe<button/>elementobject,andthelatterreferencingtheHTMLMediaElementobject:

functionmuteClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

Thisfunctiontogglesthemutedpropertyofthemediaobject,soyoufirstneedtocheckitscurrentvaluewithanifstatement:

if(video.muted){

video.muted=false;

target.innerHTML="Mute";

}

Ifit’strue,theaudioiscurrentlymuted.So,yousetvideo.mutedtofalseandchangethetextofthebuttontoMute,thusunmutingthevideo.

Butifmutedisfalse,theelsestatementexecutes,mutingthevideo:

else{

video.muted=true;

target.innerHTML="Unmute";

}

}

Yousetthevideo’smutedpropertytotruetomuteit,andthenyouchangethebutton’stexttoUnmute.

TheplaybackClick()functionislogicallyidenticaltomuteClick().Afteryousetthetargetandvideo,youthendeterminewhetheryouneedtoplayorpausethevideo.Youcanaccomplishthiseasilywiththemediaobject’spausedproperty:

functionplaybackClick(e){

vartarget=e.target;

varvideo=document.getElementById("bbbVideo");

if(video.paused){

video.play();

target.innerHTML="Pause";

}

Ifit’strue,youcalltheplay()methodtoeitherstartorresumeplayback.Ifpausedisfalse,youwanttopauseplayback:

else{

video.pause();

target.innerHTML="Resume";

}

}

Youdosowiththepause()method,andyouchangethebutton’stexttoResume.Theword“resume”waschosentoenhancetheuser’sexperience;peopleexpecttoresumefromapausedstate.YoucouldhaveimplementedsomethingsimilarinExample1,butbecausethevideo’sstatewasdeterminedbythetextofabutton,itwould’verequiredextracodetomakeitwork.

Now,thisexampleisamarkedimprovementoverExample1,butitstillhasanissue:Userscancontrolthevideothroughthecontextmenu(Figure15.6).

Figure15.6

Thisinandofitselfisn’texactlyaproblem;afterall,thebestuserinterfaceshaveredundancies.ItbecomesproblemwhenyourcustomUIdoesn’taccuratelyportraytheactualstateofthemedia.ReferbacktoFigure15.6.ThecontextmenusaysPlaywhereasthecustomPlay/PausebuttonsaysPause.Ideally,boththecontextmenuandthecustomUIshouldbeinsync,andyoucandothatbylisteningforcertainevents.

EventsEventsarethelifebloodofgraphicalapplications,andmedia-basedeventsarenoexception.ThefolksbehindtheHTML5specificationdidaverythoroughjobofdefiningtheeventswebdevelopersneedtowriterobustmedia-drivenpagesandapplications.

Asyoumightsuspect,therearealotofevents,andyoucanviewthecompletelistinAppendixC.Thefollowingtable,however,listsjustafew.

EVENTNAME DESCRIPTIONabort Fireswhenplaybackisabortedcanplay Sentwhenenoughdataisavailabletoplaythemediacanplaythrough Indicatesthattheentiremediacanbeplayedthroughwithout

interruptiondurationchange Themedia’smetadatahaschanged,indicatingachangeinthemedia’s

duration.ended Fireswhenplaybackcompleteserror Sentwhenanerroroccursloadstart Downloadinghasbegun.pause Fireswhenplaybackispausedplaying Sentwhenthemediastartsorresumesplayingprogress Downloadingisinprogress.ratechange Fireswhentheplaybackspeedchangesseeked Seekinghasended.seeking Fireswhenplaybackismovedtoanewpositiontimeupdate ThecurrentTimepropertyhaschanged.volumechange Eitherthevolumepropertyormutedpropertyhaschanged.

Youregisterlistenersfortheseeventsexactlylikeyouwouldanyotherstandardevent:withaddEventListener().Forexample,youcanexecutecodewhenthemediaispausedbylisteningforthepauseevent,likethis:

functionmediaPaused(e){

alert("Youpausedthevideo!");

}

video.addEventListener("pause",mediaPaused);

Andjustlikeanyothertypeofevent,youcanregisterdifferenteventlistenersusingthesamehandlerfunction:

functionmediaPausedPlaying(e){

if(e.type=="pause"){

alert("Youpausedthevideo!");

}else{

alert("You'replayingthevideo!");

}

}

video.addEventListener("pause",mediaPausedPlaying);

video.addEventListener("playing",mediaPausedPlaying);

Thisisadvantageousifyouneedtoexecutethesameorsimilarcodeforbothevents.Inmany(andperhapsmost)cases,however,you’llmorethanlikelywanttodefineanduse

differentfunctionsfordifferentevents.

Listeningforthese“statechange”eventsisidealwhencodingyourowncustomcontrollerUI.YouwantyourUItoaccuratelyreflectthestateofthemedia,andthe“statechange”eventsfireonlywhenthemedia’sstatechanges.This,ofcourse,makesthemidealforkeepingacustomUIinsyncwiththebuilt-inUIofthebrowser,asyouseeinthenextexample.

TRYITOUTControllingMediaPlaybackIIILet’susesomeoftheeventsintheprevioustabletorewriteExample2.Thefollowingcodecontainssubstantialchanges,soyoucanuseExample2asastartingpointortypeitallfromscratch:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter15:Example3</title>

</head>

<body>

<div>

<buttonid="playbackController">Play</button>

<buttonid="muteController">Mute</button>

</div>

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

<script>

functionpauseHandler(e){

playButton.innerHTML="Resume";

}

functionplayingHandler(e){

playButton.innerHTML="Pause";

}

functionvolumechangeHandler(e){

muteButton.innerHTML=video.muted?"Unmute":"Mute";

}

functionplaybackClick(e){

video.paused?video.play():video.pause();

}

functionmuteClick(e){

video.muted=!video.muted;

}

varvideo=document.getElementById("bbbVideo");

varplayButton=document.getElementById("playbackController");

varmuteButton=document.getElementById("muteController");

video.addEventListener("pause",pauseHandler);

video.addEventListener("playing",playingHandler);

video.addEventListener("volumechange",volumechangeHandler);

playButton.addEventListener("click",playbackClick);

muteButton.addEventListener("click",muteClick);

</script>

</body>

</html>

Savethisasch15_example3.htmlandopenitinyourbrowser.ItwilllookexactlylikeExample2.Eachtimeyouplay,pause,mute,orunmutethevideo,besuretoopenthemedia’scontextmenu.BoththecustomUIandthecontroloptionsinthecontextmenuwillbeinsync,asshowninFigure15.7.

Figure15.7

TheHTMLinthisexampleisuntouchedfromExample2,solet’sjumprighttothecode.Outsideofanyfunction,youdefinethreevariablesforreferencingthe<video/>andtwo<button/>elements:

varvideo=document.getElementById("bbbVideo");

varplayButton=document.getElementById("playbackController");

varmuteButton=document.getElementById("muteController");

You’llusethesevariablesthroughoutthevariousfunctions,butfirst,youregistertheeventlisteners.

Forthe<video/>element,youregisterpause,playing,andvolumechangeevent

listeners:

video.addEventListener("pause",pauseHandler);

video.addEventListener("playing",playingHandler);

video.addEventListener("volumechange",volumechangeHandler);

Eacheventlistenerusesauniquefunction—thepauseHandler()functionhandlesthepauseevent,playingHandler()handlestheplayingevent,andvolumechangeHandler()handlesthevolumechangeevent.Youcouldmaketheargumentthattheplayingandpauseeventcodeissimilarenoughtouseasinglefunction,butkeepitsimple!Simplefunctionsarehappyfunctions.

Andonceagain,thetwo<button/>elementsregisterclickeventsusingtheplaybackClick()andmuteClick()functions:

playButton.addEventListener("click",playbackClick);

muteButton.addEventListener("click",muteClick);

Eachofthefivefunctionsinthisexampleisreducedtoasingleresponsibility.Thisisagoodthingbecauseitmakesyourcodeeasiertomanageandmaintain(aswellasfindandfixerrorsiftheyoccur).ThefirstfunctionisthepauseHandler()function,whichasyouknow,handlesthemedia’spauseevent:

functionpauseHandler(e){

playButton.innerHTML="Resume";

}

Itsjobissimple;changethetextofthePlay/PausebuttontoResumewhenthepauseeventfires.Thisway,thebutton’stextchangesasthestateofthevideochanges.

ThenextfunctionisplayingHandler(),thecounterparttothepauseHandler()function:

functionplayingHandler(e){

playButton.innerHTML="Pause";

}

Whenthemediaplays,thisfunctionchangesthePlay/Pausebutton’stexttoPause.

ThevolumechangeHandler()functionisslightlymorecomplicatedbecauseitfiresfortwotypesofevents—whenthevolumechangesandwhenthemediaismuted:

functionvolumechangeHandler(e){

muteButton.innerHTML=video.muted?"Unmute":"Mute";

}

Liketheothermediaeventhandlers,volumechangeHandler()isresponsibleforchangingthetextofbuttonsintheUI.Buttoknowwhichtextvaluetouse,youhavetocheckthevalueofvideo.muted.Youusetheternaryoperatorheretoreducethecodetoasingleline.Youcoulduseif…elseifyouwantedto:

if(video.muted){

muteButton.innerHTML="Unmute";

}else{

muteButton.innerHTML="Mute";

}

Thisapproachwouldbeidealifyouneededtoexecutemorecodewithintheif…elsestatement,butinthiscase,theternaryapproachmightbebetter.

NextistheplaybackClick()function,andithaschangedsignificantly.BecausethepauseandplayingeventhandlersareresponsibleforupdatingtheUI,theplaybackClick()functionisonlyresponsibleforplayingandpausingthemedia:

functionplaybackClick(e){

video.paused?video.play():video.pause();

}

Onceagain,youusetheternaryoperatortodeterminewhichmethodtoexecute.Ifvideo.pausedistrue,youcalltheplay()method.Otherwise,youcallpause().

ThemuteClick()functionhasalsobeensimplifiedbecauseitisnolongerresponsibleforupdatingtheUI.Itissolelyresponsibleformutingandunmutingthemedia:

functionmuteClick(e){

video.muted=!video.muted;

}

Yousetthemutedpropertytotheoppositevalue.Therefore,ifmutedistrue,it’ssettofalse,andviceversa.

Nativemediaisafeaturethatwebdevelopershaveclamoredfor,formanyyears,andthefirstimplementation(asspecifiedbyHTML5)isveryrobustandfeature-filled.Weunfortunately,however,stillhavetobattlewiththedifferentbrowsersandthecodecstheysupport.Hopefully,thewebdevelopmentcommunitywillseeaunifiedsetofcodecsthataresupportedbyallbrowsers.

Naturally,we’veonlyscratchedthesurfaceofthenativemediaAPIandwhatyoucandowithit.Aswitheverything,experiment!Thesky’sthelimitwithsucharobustandcapableAPI.

SUMMARYThischapterintroducedyoutotheHTML5videoandaudioAPI.

YoulearnedthatHTML5bringstwonewmediaelements:<video/>and<audio/>.Italsodefinesa<source/>elementtodescribeamediasource.

Unsurprisingly,differentbrowserssupportdifferentvideoandaudioformatsandcodecs,butyoucanaddressthisissuebyprovidingmultiplesources.Thebrowserissmartenoughtoknowwhichonetoload.

Videoandaudioareprogrammaticallyidentical—exceptvideohasaposterproperty.BothtypesofmediaarerepresentedasHTMLMediaElementobjectsintheDOM.

Youlearnedhowtoplayandpausemedia.

Youlearnedhowtomutemediaandquerythestateofplaybackusingthepausedproperty.

Youlearnedhowtoregistereventlistenersforthemanymedia-basedevents,whichallowedyoutosimplifyyourcustomUI’scode.

EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.

1. Beingabletocontrolplaybackiscool,butyourcustomUIneedstoalsocontrolvolume.Addan<inputtype="range"/>elementtoExample3tocontrolthevolume.Rememberthattherangeofvolumesupportedbymediaelementsis0.0to1.0.LookbackatChapter11ifyouneedarefresheroftherangeinputtype.ThisunfortunatelywillnotworkinIE.

2. AddanotherrangeformcontroltoQuestion1’sanswer,andprogramittoseekthemedia.Itshouldalsoupdateasthemediaplays.Usethedurationchangeeventtosettheslider’smaxvalue,andthetimeupdateeventtoupdatetheslider’svalue.

16jQueryWHATYOUWILLLEARNINTHISCHAPTER:

UsingjQuerycansimplifycommontasks

Creating,modifying,andremovingelementswithjQueryiseasierthanwithtraditionalDOMmethods

jQuerymakesstylemodifications,bothwithindividualCSSpropertiesandCSSclasses,abreeze

HandlingHTTPrequestsandresponsesismucheasierthanwritingpureXMLHttpRequestcode

Deferredobjectsareuseful,especiallywhenusedwithAjaxrequests

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

JavaScriptisessentialtowebdevelopment.AndeventhoughJavaScriptdevelopmentisrelativelystraightforwardtoday,itwasextremelychallenginguntilearly2011whenMicrosoftreleasedtheninthversionofInternetExplorer.

Let’srewindtheclocktotheyear2001.Thefirstbrowserwarswerecomingtoaclose,andMicrosoftsealeditsoverwhelmingvictorywithIE6’srelease.AfewmonthslaterthesoftwaregiantreleasedWindowsXP,thelongest-supportedoperatingsysteminMicrosoft’shistory,withIE6asitsdefaultbrowser.

Atfirst,Microsoftenjoyedits85percentmarketshare,butastheyearspassed,growingpressurefromMozilla’sFirefoxspurredMicrosofttoresumedevelopmentonIE.In2006,MicrosoftreleasedIE7.Thisnewversionincludedmanybugfixes,aswellastheimplementationofnew(andoftennonstandard)features.

ThiswasthebeginningofaverychallengingtimeforJavaScriptdevelopers.Theproblemwithclient-sidedevelopmentwasthemanydifferentwebbrowsersdevelopersneededtosupport.NotonlydiddevelopershavetosupportIEandFirefox,butdevelopershadtosupportthreemajorversionsofIE(6,7,and8).Beitwritingevent-drivencodeoranAjaxapplication,somewheredownthelinedevelopersranintothemanyincompatibilitiesbetweendifferentbrowsersandversions.

Manyprofessionaldevelopersfoundcross-browserdevelopmenttobetootime-consumingandcumbersometodealwithonadailybasis,sotheysetouttodevelopframeworksorlibrariestoaidintheircross-browserdevelopment.Somedevelopersreleasedtheirframeworkstothepublic,andafewofthemgainedquiteafollowing.And

muchlikethebrowserwarsofold,eventuallyavictoremerged.FrameworkssuchasMooToolsandPrototypewerequitepopular,butjQuerybecamethedefactostandard.

jQuery,likemostotherframeworks,originatedasanAjaxlibrarytosimplifyclient/servercommunication.Today,however,jQuerysimplifiesjustabouteverycommonaspectofJavaScriptdevelopment;DOMmanipulation,Ajax,animation,andcomponentdevelopmentaremucheasierwithjQuery.Inthischapter,youlookatjQueryandlearnhowtouseittosimplifyyourJavaScriptdevelopment.

Beforebeginning,awordofnote:ThereisnodoubtthatjQueryaddsbenefittoyourdevelopmenttimeandprocess.ButitisnotasubstituteforasolidunderstandingoftheJavaScriptlanguageandtheintricaciesofthedifferentbrowsersforwhichyouhavetodevelop.Frameworksandlibrariescomeandgo,butknowledge(andpureJavaScript)isforever.

GETTINGJQUERYInstallingjQuery(oranyframeworkforthatmatter)isverydifferentfrominstallinganapplicationonyourcomputer;thereisnosetupprogram,andtheinstallationdoesn’tchangeanyportionofyoursystem.Basically,allyoudoisreferencethejQueryJavaScriptfileinyourwebpage.

Openyourbrowserandgotohttp://jquery.com/download/.Onthispage,you’llfindseverallinkstodifferentjQuery-relatedfiles.First,you’llseetwoversionsofjQuery:1.xand2.x.Thetwoversionsarealmostidenticalexceptthatv1.xsupportsIE6,7,and8andv2.xdoesnot.

Second,you’llneedtochoosethecompressedoruncompressedversion:

Compressedversion:Thisisminified(allcommentsandunnecessarywhitespaceareremovedfromthecodefiles)tomaketheirsizeassmallaspossible;doingsomakesthemfastertodownloadwhensomeonevisitsyourwebpage.Unfortunately,theminificationprocessmakestheJavaScriptcodedifficulttoreadifyouopenitinatexteditor,butthat’sareasonabletrade-offinaproductionenvironment.

Uncompressedversion:Thisisnotminified;itissimplynormalJavaScriptcodefileswiththeirwhitespaceandcommentsintact.It’sperfectlyOKtouseuncompressedJavaScriptfiles.Becausetheyareeasiertoreadthancompressedfiles,youcanlearnmuchfromtheguruswhodesignanddeveloptheseframeworks.However,ifyouplantorolloutawebpageusingaframework,besuretodownloadandusethecompressedversion,becauseitsfilesizesaresmalleranddownloadfaster.

NOTETheproductionversionofjQuery2.1.1isprovidedinthecodedownloadfromWrox.

YoucanobtainjQueryinoneoftwoways.First,simplydownloadwhicheverversionyoupreferbyright-clicking(orcontrol-clickingonaMac)thelink,andsaveitinalocationyoucaneasilygetto.

Alternatively,youcanusejQuery’sContentDeliveryNetwork(CDN)toaddjQuerytoyourwebpages.ThispreventsyoufromhavingtodownloadyourowncopyofjQuery,anditcanalsoslightlyincreasetheperformanceofyourwebpages.

RegardlessofhowyouobtainjQuery,youaddittoyourpagesjustlikeanyotherexternalJavaScriptfilewiththe<script/>element:

<scriptsrc="jquery-2.1.1.min.js"></script>

<scriptsrc="//code.jquery.com/jquery-2.1.1.min.js"></script>

Theonlydifferenceisthevalueofthesrcattribute.Thefirst<script/>elementinthisexampleusesalocalcopyofjQuery2.1.1,whereasthesecondusesjQuery’sCDN.TheexamplesinthischapterusealocalcopyofjQuery.

jQUERY’SAPIjQueryisJavaScript,butitchangesthewaythatyouinteractwiththebrowseranddocument.Whetheryou’recreatingHTMLelementsandappendingthemtothepageormakingAjaxcallstotheserver,jQueryletsyoudoitinaneasyfashion.

AttheheartofjQueryisthejQuery()function,butinmostcases,youwon’twriteyourcodewithjQuery().Instead,you’lluseanalias:thedollarfunction,$().Thiscanseemveryweirdatfirst,butitwillbecomecompletelynaturalthemoreyouuseit.

You’llusethe$()functionforjustabouteverything,including:

Findingandselectingelements

Creating,appending,andremovingelements

WrappingnormalDOMobjectswithjQueryobjects

SelectingElementsjQueryrevolutionizedthewaydevelopersfindelementsintheDOM:withCSSselectors.Infact,thequerySelector()andquerySelectorAll()methodsdiscussedinChapter9existbecauseofjQuery.ToretrieveelementswithjQuery,youuse$()andpassityourCSSselector,likethis:

varelements=$("a");

Thiscodeassignsaspecialobject,calledajQueryobject,thatrepresentsanarrayofall<a/>elementsinthepagetotheelementsvariable.

jQuerywasdesignedtomakeDOMmanipulationeasy,andbecauseofthisdesignphilosophy,youcanmakechangestoseveralelementsatthesametime.Forexample,imagineyoubuiltawebpagewithmorethan100linksinthedocument,andonedayyoudecideyouwantthemtoopeninanewwindowbysettingthetargetattributeto_blank.That’satalltasktotakeon,butitissomethingyoucaneasilyachievewithjQuery.Becauseyoucanretrieveall<a/>elementsinthedocumentbycalling$("a"),youcancalltheattr()method,whichgetsorsetsthevalueofanattribute,tosetthetargetattribute.Thefollowingcodedoesthis:

elements.attr("target","_blank");

Calling$("a")resultsinajQueryobject,butthisobjectalsodoublesasanarray.AnymethodyoucallonthisparticularjQueryobjectwillperformthesameoperationonallelementsinthearray.Byexecutingthislineofcode,yousetthetargetattributeto_blankonevery<a/>elementinthepage,andyoudidn’tevenhavetousealoop!

BecausejQueryobjectsareanarray,youcanusethelengthpropertytofindouthowmanyelementswereselectedwithaCSSquery:

varlength=elements.length;

Thisinformationcanbeuseful,butyouusuallywon’tneedtoknowthelengthofajQueryobject.Themostcommonuseofanarray’slengthpropertyisforlooping,andjQueryisdesignedtoworkwithmultipleelementsatthesametime.ThemethodsyouexecuteonajQueryobjecthavebuilt-inloops;so,thelengthpropertyisrarelyused.

jQueryhasabuilt-inCSSselectorengine,andyoucanusejustaboutanyvalidCSSselectortoretrieveyourdesiredelements—evenifthebrowserdoesn’tsupportit.Forexample,IE6doesnotsupporttheparent>childCSSselector.Ifyouhavetheunfortunateneedtosupportthatbrowser,jQuerycanstillselecttheappropriateelementswiththatselector.ConsiderthefollowingHTMLasanexample:

<p>

<div>Div1</div>

<div>Div2</div>

<span>Span1</div>

</p>

<span>Span2</span>

ThisHTMLcodedefinesa<p/>elementthatcontainstwo<div/>elementsanda<span/>element.Outsidethe<p/>elementisanother<span/>element.Let’ssaythatyouneedthe<span/>elementinsidetheparagraph.Youcaneasilyselectthatelementwiththefollowing:

varinnerSpan=$("p>span");

Thislineofcodeusestheparent>childCSSselectorsyntax,andbecausejQueryhasitsownCSSselectorengine,thiscodewillworkineverybrowser.

jQueryalsoletsyouusemultipleselectorsinonefunctioncall.Simplydelimiteachselectorwithacommaasshowninthefollowingcode:

$("a,#myDiv,.myCssClass,p>span")

Thiscoderetrievesall<a/>elements,anelementwithanidofmyDiv,elementswiththeCSSclassmyCssClass,andall<span/>childrenof<p/>elements.Ifyouwantedtochangethetext’scoloroftheseelementstored,youcouldsimplyusethefollowingcode:

$("a,#myDiv,.myCssClass,p>span").attr("style","color:red;");

Thisisn’tthebestwaytochangeanelement’sstyle.Infact,jQueryprovidesyouwithmanymethodstoalteranelement’sstyle.

NOTEForacompletelistofsupportedselectors,seehttp://docs.jquery.com/Selectors.

ChangingStyleChanginganelement’sstylerequiresyoutoeithermodifyindividualCSSpropertiesormanipulateitsCSSclasses.jQuerymakesiteasytodoboth.TochangeindividualCSS

properties,thejQueryobjecthasamethodcalledcss(),andyoucanusethismethodintwoways.

First,youcanpasstwoargumentstothecss()method:theCSSproperty’snameanditsvalue.Forexample:

$("#myDiv").css("color","red");

Thiscodesetsthecolorpropertytored,thuschangingtheelement’stextcolortored.Thepropertynamesyoupasstothecss()methodcanbeineitherstylesheetformatorinscriptformat.Thatmeansifyouwanttochangeanelement’sbackgroundcolor,youcanpassbackground-colororbackgroundColortothemethod,likethis:

varallParagraphs=$("p");

allParagraphs.css("background-color","yellow");//correct!

allParagraphs.css("backgroundColor","blue");//correct,too!

Thiscodechangesthebackgroundcolorofevery<p/>elementinthepagetoyellowandthentoblue.

NOTEIt’simportanttorememberthatjQuery’smethodsworkwithoneormultipleelements.Itdoesn’tmatterhowmanyelementsarereferencedbyajQueryobject,amethodlikecss()willchangethestyleofeveryelementintheobject.

Manytimes,however,youneedtochangemorethanoneCSSproperty.Althoughyoucaneasilyaccomplishthisbycallingcss()multipletimeslikethis:

//don'tdothis

allParagraphs.css("color","blue");

allParagraphs.css("background-color","yellow");

abettersolutionwouldbetopassanobjectthatcontainstheCSSpropertiesandtheirvaluestothecss()method.Thefollowingcodecallscss()onceandachievesthesameresults:

allParagraphs.css({

color:"blue",

backgroundColor:"yellow"

});

Here,youpassanobjectthathascolorandbackgroundColorpropertiestothecss()method,andjQuerychangestheelement’sorelements’textcolortoblueandbackgroundcolortoyellow.

Typically,though,ifyouwanttochangeanelement’sstyle,it’sbettertochangetheelement’sCSSclassinsteadofindividualstyleproperties.

AddingandRemovingCSSClassesThejQueryobjectexposesseveralmethodstomanipulateanelement’sclassNameproperty;youcanadd,remove,andeventoggletheclassesthatareappliedtoanelement.

NOTEDidyouknowyoucanassignmultipleCSSclassestoanelement?Simplyseparateeachclassnamewithaspace!

Let’sassumethatthefollowingHTMLisinoneofyourwebpages:

<divid="content"class="class-oneclass-two">

MydivwithtwoCSSclasses!

</div>

ThisHTMLdefinesa<div/>elementwithtwoCSSclasses,class-oneandclass-two.Youneedtoapplytwomoreclasses(class-threeandclass-four)tothiselement,andjQuerymakesthatveryeasytodowiththeaddClass()method.Forexample:

varcontent=$("#content");

content.addClass("class-three");

content.addClass("class-four");

Thiscodefirstretrievesthe<div/>elementandthencallstheaddClass()methodtoaddthedesiredclasses.Butyoucansimplifythiscodebyusingatechniquecalledmethodchaining.MostjQuerymethodsreturnajQueryobject,soit’spossibletocallamethodimmediatelyaftercallinganothermethod—essentiallychainingthemethodcallsasdemonstratedwiththiscode:

content.addClass("class-three").addClass("class-four");

Thiscodeachievesthesameresultsasbeforebutwithfewerkeystrokes.

NOTEMostjQuerymethodsreturnajQueryobject,allowingyoutoimmediatelycallmethodsoneafteranother.

ButyoucansimplifythiscodeevenmorebecauseyoucanpassbothCSSclassnamestoaddClass(),likethis:

content.addClass("class-threeclass-four");

Youjusthavetoseparatetheclassnameswithaspace.

TheremoveClass()methodremovesoneormultipleclasses:

content.removeClass("class-one");

ThiscodeusestheremoveClass()methodtoremovetheclass-oneclassfromtheelement.Ifyouneedtoremovemultipleclasses,simplyseparatethemwithaspace,likethis:

content.removeClass("class-twoclass-four");

Asyoucansee,thesameconceptsthatletyouaddclassestoanelementapplytoremovingclasses.Butthere’soneveryimportantdifference:Theargumentsyoupassto

removeClass()areoptional.IfyoudonotpassanyargumentstoremoveClass(),itwillremoveallclassesfromtheelement:

content.removeClass();

Thiscode,therefore,removesallCSSclassesfromtheelement(s)representedbythecontentobject.

TogglingClassesAlthoughtheaddClass()andremoveClass()methodsarecertainlyuseful,sometimesyouneedtojusttoggleaclass.Inotherwords,youremoveaclassifit’spresentoradditifit’snot.jQuerymakesthiseasywiththeaptlynamedtoggleClass()method:

content.toggleClass("class-one");

Thiscodefirsttogglestheclass-oneclass.Ifitisalreadyappliedtotheelement,jQueryremovesclass-one.Otherwise,itaddsclass-onetotheelement’sclasslist.

Thisbehaviorisusefulwhenyouneedtoaddorremoveaspecificclassfromtheelement.Forexample,thefollowingcodeisvanillaJavaScriptandDOMcodingtoaddandremoveaspecificCSSclassdependingonthetypeofevent:

vartarget=e.target;

if(e.type=="mouseover"){

target.className="class-one";

}elseif(e.type=="mouseout"){

eSrc.className="";

}

YoucangreatlysimplifythiscodebyusingthetoggleClass()method,likethis:

vartarget=$(e.target);

if(e.type=="mouseover"||e.type=="mouseout"){

target.toggleClass("class-one");

}

Noticehowthe$()functionisusedinthiscode:Itpassese.target,aDOMobject,to$().Thiscanatfirstseemlikeastrangethingtodo,butrememberwhatwesaidearlier:$()isusedformanythings.OneofthosethingsistowrapanormalDOMobjectwithajQueryobject.

Intechnicalterms,wecalltheresultingjQueryobjectawrapperobject.Wrapperobjectsaretypicallyusedtoenhancethefunctionalityofanotherobject.WithjQuery,you’rewrappingajQueryobjectaroundanelementobject,enablingyoutousejQuery’sAPItomanipulatetheelement.Inthecaseofthiscode,you’rewrappingajQueryobjectaroundanelementobjectsothatyoucanusetoggleClass()totoggletheclass-oneclass.

CheckingifaClassExistsThelastCSSclassmethodisthehasClass()method,anditreturnstrueorfalse

dependingonifanelementhasthespecifiedCSSclass.Forexample:

varhasClassOne=content.hasClass("class-one");

ThiscodeuseshasClass()todetermineiftheclass-oneisappliedtocontent.Ifitis,hasClassOneistrue.Otherwise,it’sfalse.

Creating,Appending,andRemovingElementsThinkbacktoChapter9andhowyoucreateandappendelementstothepage.Thefollowingcodewillrefreshyourmemory:

vara=document.createElement("a");

a.id="myLink";

a.setAttribute("href","http://jquery.com");

a.setAttribute("title","jQuery'sWebsite");

vartext=document.createTextNode("ClicktogotojQuery'swebsite");

a.appendChild(text);

document.body.appendChild(a);

Thiscodecreatesan<a/>element,assignsitanid,andsetsthehrefandtitleattributes.Itthencreatesatextnodeandassignstheobjecttothetextvariable.Finally,itappendsthetextnodetothe<a/>elementandappendsthe<a/>elementtothedocument’s<body/>element.ItgoeswithoutsayingthatcreatingelementswiththeDOMmethodsrequiresalotofcode.

CreatingElementsjQuerysimplifieshowyoucreateelementswithJavaScript.Thefollowingcodeshowsyouoneway:

vara=$("<a/>").attr({

id:"myLink",

href:"http://jquery.com",

title:"jQuery'sWebsite"

}).text("ClickheretogotojQuery'swebsite");

$(document.body).append(a);

Let’sbreakdownthiscodetogetabetterunderstandingofwhat’stakingplace.First,thiscodecalls$()andpassesittheHTMLtocreate.Inthiscase,it’san<a/>element:

vara=$("<a/>")

Next,itchainstheattr()methodtosetthe<a/>element’sattributes:

.attr({

id:"myLink",

href:"http://jquery.com",

title:"jQuery'sWebsite"

})

Theattr()methodisalotlikethecss()methodinthatyoucansetanindividualattributebypassingittheattribute’snameandvalue,oryoucansetmultipleattributesbypassinganobjectthatcontainstheattributesandtheirvalues.

Thecodethenchainsthetext()method,settingtheelement’stext:

.text("ClickheretogotojQuery'swebsite");

YoucanalsocreatethesameelementbypassingtheentireHTMLto$(),likethis:

vara=$('<ahref="http://jquery.com"title="jQuery\'sWebsite">'+

"ClickheretogotojQuery'swebsite</a>");

Thisapproach,however,canbecomelessofabenefitandmoreofahassle.Notonlydoyouhavetokeeptrackofwhichtypeofquoteyouusewhere,butyoumightalsohavetoescapequotes.

AppendingElementsTheappend()methodissimilartotheDOMappendChild()methodinthatitappendschildnodestotheparentobject.ThesimilaritiesendtherebecausejQuery’sappend()methodismuchmoreflexiblethanitsDOMcounterpart.Theappend()methodcanacceptaDOMobject,ajQueryobject,orastringcontainingHTMLortextcontent.Regardlessofwhatyoupassastheparametertoappend(),itwillappendthecontenttotheDOMobject.

ThepreviouscodeappendsthejQuery-created<a/>elementtothedocument’sbody,likethis:

$(document.body).append(a);

Onceagain,the$()functionwrapsajQueryobjectaroundthenativedocument.bodyobjecttotakeadvantageofjQuery’ssimpleAPI.

RemovingElementsRemovingelementsfromtheDOMisalsomucheasierwithjQuerythanwithtraditionalDOMmethods.WithDOMmethods,youneedatleasttwoelementobjects:theelementyouwanttoremoveanditsparentelement.

Aswitheverythingthusfar,jQuerysimplifiesthisprocess.Theonlythingyouneedistheelementthatyouwanttoremove.SimplycalljQuery’sremove()method,anditremovestheelement.Forexample:

$(".class-one").remove();

Thiscodefindsallelementsthathavetheclass-oneCSSclassandremovesthemfromthedocument.

Youcanalsocompletelyempty,orremoveallchildrenof,anelementwiththeaptlynamedempty()method.Ifyouwantedtoremoveeveryelementwithinthe<body/>,youcouldusethefollowingcode:

$(document.body).empty();

MostDOMchangesyou’llmakeareinresponsetosomethingtheuserdid,whethermovingthemouseoveraparticularelementorclickingsomewhereonthepage.Sonaturally,you’llhavetohandleeventsatsomepoint.

HandlingEventsWhenjQuerywascreated,JavaScriptdevelopershadtocontendwithboththeW3CstandardandlegacyIEeventmodels.Althoughmanydeveloperswroteandusedtheirowneventutilities,thevastmajoritylookedtothird-partytoolstomakecross-browsercodeeasiertowriteandmaintain.jQuerywasonesuchtool,andwhilestandardsupporthasgottensubstantiallybetterinallbrowsers,jQuery’seventAPI,specificallythemethodsusedtoregistereventlisteners,isstilleasiertouse.

AlljQueryobjectsexposeamethodcalledon()thatyouusetoregistereventlistenersforoneormoreeventsontheselectedelements.Itsmostbasicusageisverysimple,asdemonstratedhere:

functionelementClick(e){

alert("Youclickedme!");

}

$(".class-one").on("click",elementClick);

Thiscoderegistersaclickeventlisteneronallelementsthathaveaclass-oneCSSclass.Therefore,theelementClick()functionexecuteswhentheuserclicksanyoftheseelements.

Youcanalsoregistermultipleeventlistenerswiththesameeventhandlerfunctionbypassingmultipleeventnamesinthefirstargument.Simplyseparateeacheventnamewithaspace,likethis:

functioneventHandler(e){

if(e.type=="click"){

alert("Youclickedme!");

}else{

alert("Youdouble-clickedme!");

}

}

$(".class-two").on("clickdblclick",eventHandler);

Thiscoderegisterseventlistenersfortheclickanddblclickeventsonallelementswithaclass-twoCSSclass.ThecodeinsideeventHandler()determineswhateventcausedthefunctiontoexecuteandrespondsappropriately.

Althoughitcanbeusefultouseasinglefunctionforhandlingmultipleevents,jQueryalsoletsyoudefinemultipleeventlistenerswithdifferentfunctions.Insteadofpassingtwoargumentstoon()asshowninthepreviousexamples,youpassanordinaryJavaScriptobjectinwhichthepropertiesaretheeventnames,andtheirvaluesarethefunctionsthathandletheevents.Forexample:

functionclickHandler(e){

alert("Youclickedme!");

}

functiondblclickHandler(e){

alert("Youdouble-clickedme!");

}

$(".class-three").on({

click:clickHandler,

dblclick:dblclickHandler

});

Thiscoderegistersclickanddblclickeventlistenersforeveryelementwiththeclass-threeCSSclass;differentfunctionshandletheclickanddblclickevents.

Removingeventlistenersisequallysimplewiththeoff()method.Simplysupplythesameinformationyoupassedtoon().Thefollowingcoderemovestheeventlistenersregisteredinthepreviousexamples:

$(".class-one").off("click",elementClick);

$(".class-two").off("clickdblclick",eventHandler);

$(".class-three").off({

click:clickHandler,

dblclick:dblclickHandler

});

Youcanalsousetheoff()methodtoremovealleventlistenersfortheselectedelementsbynotpassinganyargumentstothemethod:

$(".class-four").off();

ThejQueryEventObjectAsyoulearnedinChapter10,somebigdifferencesexistbetweenthestandardandlegacyIEeventmodels.RememberthatjQuerywascreatedtomakecross-browserJavaScripteasiertowriteandmaintain.Sowhenitcametoevents,JohnResig,thecreatorofjQuery,decidedtocreatehisownEventobjectandbaseitonthestandardDOMEventobject.Thismeansthatyoudonothavetoworryaboutsupportingmultipleeventmodels;it’salreadydoneforyou.Allyouhavetodoiswritestandardcodeinsideyoureventhandlers.

Todemonstrate,youcanwritesomethinglikethefollowingcode,andit’llworkineverybrowser:

functionclickHandler(e){

e.preventDefault();

alert(e.target.tagName+"clickedwasclicked.");

}

$(".class-two").on("click",clickHandler);

NOTEForacompletelistofsupportedevents,seejQuery’swebsiteathttp://docs.jquery.com/Events.

RewritingtheTabStripwithjQueryYouhavelearnedhowtoretrieveelementsintheDOM,changeanelement’sstylebyaddingandremovingclasses,addandremoveelementsfromthepage,anduseeventswithjQuery.

Nowyou’llputthisnewfoundknowledgetoworkbyrefactoringthetoolbarfromChapter10.

TRYITOUTRevisitingtheTabStripwithjQueryOpenyourtexteditorandtypethefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter16:Example1</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="jquery-2.1.1.min.js"></script>

<script>

functionhandleEvent(e){

vartarget=$(e.target);

vartype=e.type;

if(type=="mouseover"||type=="mouseout"){

target.toggleClass("tabStrip-tab-hover");

}elseif(type=="click"){

target.addClass("tabStrip-tab-click");

varnum=target.attr("data-tab-number");

showDescription(num);

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("#descContainer").text(text);

}

$(".tabStrip>div").on("mouseovermouseoutclick",

handleEvent);

</script>

</body>

</html>

Savethisasch16_example1.htmlandopenitinyourbrowserandnoticethatitsbehaviorisidenticaltothatofch10_example17.html.

Ifyoucomparethisexamplewithch10_example17.html,you’llnoticequiteafewdifferencesinthecode’sstructure.Let’sstartwiththeverylastlineofcodewhereyouregistertheeventlisteners.Yourtabstripneedstorespondtothemouseover,mouseout,andclickeventsonthe<div/>elementsinsideofthetabstrip.jQuerymakesitextremelyeasytoregistereventlistenersonthese<div/>elementsforthedesiredevents:

$(".tabStrip>div").on("mouseovermouseoutclick",handleEvent);

Thiscodeselectsall“tabelements”inthedocumentwithjQuery’s$()functionandusestheon()methodtoregisterthemouseover,mouseout,andclickeventlistenersonthoseelements.

jQuerycodeaside,thisapproachisdifferentfromtheoriginal.Here,theevent

listenersareonthe<div/>elementsthemselvesasopposedtodocument.ThiswillsimplifythehandleEvent()function.Let’slookatthatnow.

ThefirsttwolinesofhandleEvent()dotwothings.ThefirstlinewrapsajQueryobjectaroundtheeventtarget,andthesecondgetsthetypeofeventthatoccurred:

functionhandleEvent(e){

vartarget=$(e.target);

vartype=e.type;

Intheoriginalversionofthiscode,youusedboththeeventtypeandthetarget’sCSSclasstodeterminewhichnewCSSclassyouassignedtotheelement’sclassNameproperty.Inthisnewversion,youonlyneedtoknowtheeventtype.Formouseoverandmouseoutevents,yousimplytogglethetabStrip-tab-hoverclass:

if(type=="mouseover"||type=="mouseout"){

target.toggleClass("tabStrip-tab-hover");

}

Butforclickevents,yournewcodecloselyresemblestheoriginal’s.First,youaddthetabStrip-tab-clickclasstotheelementusingjQuery’saddClass()method:

elseif(type=="click"){

target.addClass("tabStrip-tab-click");

varnum=target.attr("data-tab-number");

showDescription(num);

}

Thenyougetthevalueofthedata-tab-numberattribute.YoucouldoptionallyusejQuery’sdata()methodtodothesamethingbypassingittheattributenamewithoutdata-,likethis:data("tab-number").

Onceyouhavethetab’snumber,youpassitontoshowDescription().Thisfunctiondidnotchangemuch;itsimplyusesjQuery’sAPItoaccomplishitstask:

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("#descContainer").text(text);

}

Afteryoubuildthedescriptiontext,youselecttheelementservingasthedescriptioncontainerandsetitstextusingjQuery’stext()method.

Asyoucanseefromthisexample,jQuerysimplifiesDOMmanipulationandeventhandling.Inthisparticularexample,youwrotelessJavaScripttoattainthesameresults.That’swellworththetimeoflearningjQuery,isn’tit?

Butthat’snotall;jQuerycandothesamethingforyourAjaxcode.

UsingjQueryforAjax

InChapter14,youlearnedaboutAjaxandhowasynchronousrequestsrequireyoutowritealotofextracode.YouwroteasimpleutilitytohelpalleviatethecomplexityofAjaxcode,butjQuerycansimplifyAjaxevenmore.

UnderstandingthejQueryFunctionThejQueryfunction($())isthedoorwayintoallthingsjQuery,andyou’veuseditquiteabitthroughoutthischapter.However,thisfunctionhasotheruses.

Functionsareobjectsandtheyhaveapropertycalledprototype.Likeallotherobjects,youaccessaFunctionobject’spropertiesandmethodsusingtheobject.propertyorobject.method()syntax.Well,jQuery’s$functionhasmanymethods,andsomeofthemareformakingAjaxrequests.Oneofthemistheget()method,whichisformakingGETrequests.Thefollowingcodeshowsanexample:

$.get("textFile.txt");

ThiscodemakesaGETrequesttotheserverforthetextFile.txtfile.Butthiscodeisn’tveryusefulbecauseitdoesn’tdoanythingwiththeserver’sresponse.SoliketheHttpRequestmoduleyoubuiltinChapter14,the$.get()methodletsyoudefineacallbackfunctionthathandlestheresponsefromtheserver:

functionhandleResponse(data){

alert(data);

}

$.get("textFile.txt",handleResponse);

ThiscodedefinesafunctioncalledhandleResponse()andpassesitto$.get().jQuerycallsthisfunctiononasuccessfulrequestandpassesittherequesteddata(representedbythedataparameter).

RemembertheexamplesfromChapter14?Youcreatedaformthatcheckedifusernamesande-mailaddresseswereavailableusingAjax,andyousentthosevaluestotheserverasparametersintheURL.Forexample,whenyouwantedtotestausername,youusedtheusernameparameter,likethis:

phpformvalidator.php?username=jmcpeak

Withthe$.get()method,youcandothesamethingbypassinganobjectcontainingthekey/valuepairstothemethod.Forexample:

varparms={

username="jmcpeak"

};

functionhandleResponse(json){

varobj=JSON.parse(json);

//dosomethingwithobj

}

$.get("phpformvalidator.php",parms,handleResponse);

Thiscodecreatesanewobjectcalledparms,andithasausernamepropertywiththevalueofjmcpeak.Thisobjectispassedtothe$.get()methodasthesecondargument,withthehandleResponse()callbackfunctionpassedasthethird.

Youcansendasmanyparametersasyouneed;simplyaddthemaspropertiestotheparameterobject.

AutomaticallyParsingJSONDataInChapter14,theformvalidatorPHPfilereturnstherequesteddatainJSONformat,andnoticethattheprevioussamplecodeexpectsJSONdataandparsesitwiththeJSON.parse()method.jQuerycaneliminatethisstepandparsetheresponseforyou.Simplyusethe$.getJSON()methodinsteadof$.get().Forexample:

varparms={

username="jmcpeak"

};

functionhandleResponse(obj){

//objisalreadyanobject

}

$.getJSON("phpformvalidator.php",parms,handleResponse);

Thiscodeisalmostidenticaltothepreviousexampleexceptfortwothings.First,thiscodeuses$.getJSON()toissuearequesttothePHPfile.Bydoingso,youareexpectingJSON-formatteddataintheresponse,andjQuerywillautomaticallyparseitintoaJavaScriptobject.

TheseconddifferenceisinsidethehandleResponse()function.Becausetheresponseisautomaticallyparsed,youdon’thavetocallJSON.parse()inhandleResponse().

ThejqXHRObjectAsyou’veseenintheprevioussections,jQuery’sget()andgetJSON()methodsdonotactuallyreturnthedatayourequested;theyrelyuponacallbackfunctionthatyouprovideandpasstherequesteddatatoit.Butthesemethodsdo,infact,returnsomethinguseful:aspecialjqXHRobject.

ThejqXHRobjectiscalledadeferredobject;itrepresentsataskthathasn’tyetcompleted.Whenyouthinkaboutit,anasynchronousAjaxrequestisadeferredtaskbecauseitdoesn’timmediatelycomplete.Afteryoumaketheinitialrequest,you’releftwaitingforaresponsefromtheserver.

jQuery’sjqXHRobjecthasmanymethodsthatrepresentdifferentstagesofadeferredtask,butforthesakeofthisdiscussion,you’lllookatonlythree.Theyare:

METHODNAME DESCRIPTIONdone() Executeswhenthedeferredtasksuccessfullycompletesfail() Executeswhenthetaskfailsalways() Alwaysexecutes,regardlessifthetaskcompletedorfailed

Thesemethodsletyouaddfunctionstowhatarecalledcallbackqueues—collectionsoffunctionsthatserveascallbacksforaspecifiedpurpose.Forexample,thedone()methodletsyouaddfunctionstothe“done”callbackqueue,andwhenthedeferredactionsuccessfullycompletes,allofthefunctionsinthe“done”queueexecute.

Withthisinmind,youcanrewritethepreviouscodelikethis:

varparms={

username="jmcpeak"

};

functionhandleResponse(obj){

//objisalreadyanobject

}

varxhr=$.getJSON("phpformvalidator.php",parms);

xhr.done(handleResponse);

Noticethatinthiscode,thehandleResponse()functionisn’tpassedtothegetJSON()method;instead,it’saddedtothe“done”queuebypassingittothejqXHRobject’sdone()method.Inmostcases,you’dseethiscodewrittenasfollows:

$.getJSON("phpformvalidator.php",parms).done(handleResponse);

Youcanalsochainthesemethodcallstoeasilyaddmultiplefunctionstothecallbackqueues:

$.getJSON("phpformvalidator.php",parms)

.done(handleResponse)

.done(displaySuccessMessage)

.fail(displayErrorMessage);

Inthisexample,twofunctions,handleResponse()anddisplaySuccessMessage(),areaddedtothe“done”queue;whentheAjaxcallsuccessfullycompletes,bothofthesefunctionswillexecute.Additionally,thiscodeaddsthedisplayErrorMessage()functiontothe“fail”queue,anditexecutesiftheAjaxrequestfails.

Usingthesecallbackqueuemethodsdoesrequireyoutowriteslightlymorecode,buttheymakeyourcode’sintentionsabsolutelyclear.Plus,usingthemisgenerallyacceptedasabestpractice,andyou’llfindthemusedinmostmodernjQuery-basedcodethatyouread.

TRYITOUTRevisitingtheFormValidatorApplywhatyou’velearnedandmodifytheformvalidatorfromch14_example1.html.Openyourtexteditorandtypethefollowingcode:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter16:Example2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="jquery-2.1.1.min.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("#username").val();

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varparms={

username:userValue

};

$.getJSON("ch14_formvalidator.php",

parms).done(handleResponse);

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("#email").val();

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varparms={

email:emailValue

};

$.getJSON("ch14_formvalidator.php",

parms).done(handleResponse);

}

functionhandleResponse(response){

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

$("#usernameAvailability").on("click",checkUsername);

$("#emailAvailability").on("click",checkEmail);

</script>

</body>

</html>

Savethisasch16_example2.htmlinyourwebserver’srootdirectory.LiketheexamplesinChapter14,thisfilemustbehostedonawebserverinordertoworkcorrectly.Openyourwebbrowsertohttp://yourserver/ch16_example2.html.TypejmcpeakintotheUsernamefieldandclicktheCheckAvailabilitylinknexttoit.You’llseeanalertboxtellingyoutheusernameistaken.

Nowtypesomeone@xyz.comintheEmailfieldandclicktheCheckAvailabilitylinknexttoit.Again,you’llbegreetedwithanalertboxstatingthatthee-mailisalreadyinuse.Nowinputyourownusernameande-mailintothesefieldsandclicktheappropriatelinks.Chancesareanalertboxwilltellyouthatyourusernameand/ore-mailisavailable(theusernamesjmcpeakandpwiltonandthee-mailssomeone@[email protected]).

TheHTMLandCSSinthisexampleareidenticaltoch14_example1.html.So,let’sdigintotheJavaScriptstartingwiththefinaltwolinesofcodethatsetuptheclickeventlistenersontheCheckAvailabilitylinks.Youcouldeasilyreusethecodefromtheoriginal,butjQuerymakesitalittleeasiertosetupevents:

$("#usernameAvailability").on("click",checkUsername);

$("#emailAvailability").on("click",checkEmail);

YouselecttheelementsbytheirIDandusejQuery’son()methodtoregistertheclickeventonthoseelements.Onceagain,checkingtheusernamevalueisthejobofcheckUsername(),andcheckEmail()isresponsibleforcheckingthee-mailvalue.

ThenewcheckUsername()functionissomewhatsimilartotheoriginal.Youstartbypreventingthedefaultbehavioroftheeventbycallinge.preventDefault():

functioncheckUsername(e){

e.preventDefault();

Next,youneedtogetthevalueoftheappropriate<input/>element.Youhaven’tlearnedhowtoretrievethevalueofaformcontrolwithjQuery,butdon’tworry—it’sverysimple:

varuserValue=$("#username").val();

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

Youuse$()toselecttheappropriate<input/>elementandcalltheval()method.ThisretrievesthevalueoftheformcontrolandassignsittotheuserValuevariable.

Afteryouvalidatetheuser’sinput,you’rereadytostartissuingaGETrequesttotheserver.First,youcreateanobjecttocontaintheinformationyouwanttosendtotheserver:

varparms={

username:userValue

};

Youcallthisobjectparmsandpopulateitwiththeusernameproperty.Asyoulearnedearlierinthischapter,jQuerywilladdthispropertyanditsvaluetothequerystring.

Now,youcansendtherequestusingjQuery’sgetJSON()method:

$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);

}

YouaddthehandleResponse()functiontothe“done”queue,sothatwhentherequestsuccessfullycompletes,analertboxwilldisplaythesearchresults.

ThenewcheckEmail()functionisverysimilartocheckUsername().Thetwomaindifferences,ofcourse,arethedatayouretrievefromtheformandthedatayousendtotheserver:

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("#email").val();

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varparms={

email:emailValue

};

$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);

}

Thefinalfunction,handleResponse(),ismostlyunchangedfromtheoriginalversion.BecausejQuery’sgetJSON()methodautomaticallyparsestheresponseintoaJavaScriptobject,thenewhandleResponse()functionsimplyusesthepasseddataas-is:

functionhandleResponse(response){

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+"isnot

available.");

}

}

jQueryisanextensiveframework,andadequatelycoveringthetopicindepthrequiresmuchmorethanthischaptercanprovide.EntirebooksaredevotedtojQuery!However,thejQuerydocumentationisquitegood,andyoucanviewitathttp://docs.jquery.com.jQuery’swebsitealsolistsavarietyoftutorials,sodon’tforgettocheckthemoutat

http://docs.jquery.com/Tutorials.

SUMMARYThischapterintroducedyoutojQuery,themostpopularJavaScriptlibrary.

YoulearnedwhereandhowtoobtainjQueryandreferenceitinyourpages.

YoualsolearnedaboutjQuery’s$()function,andhowitiscentraltojQuery’sfunctionality.

jQuerypopularizedusingCSSselectorstofindelementswithintheDOM,andyoulearnedhowfindelementswiththe$()function.

Youcanchangeelementstyleswitheitherthecss()method,orbymodifyingtheCSSclasseswiththeaddClass(),removeClass(),andtoggleClass()methods.

Cross-browsereventscanbeadragwhendealingwitholderbrowserversions,butjQuerymakeregisteringeventlistenersandworkingwitheventdataeasy(andmostlystandardscompliant).

jQueryalsosimplifiesAjaxwithitsget()andgetJSON()methods,andyoulearnedthatgetJSON()automaticallyparsestheresponseintoaJavaScriptobject.

Youlearnedaboutdeferredobjects.Youalsolearnedaboutthe“done,”“fail,”and“always”queues,andhowyoucanchainthemtogethertoassignmultiplehandlerstothedifferentqueues.

EXERCISES1. Example1isbasedonChapter10’sExample17,andasyouprobablyremember,you

modifiedthatexampleinresponsetooneofChapter10’sexercisequestions.Modifythischapter’sExample1sothatonlyonetabisactiveatatime.

2. ThereissomerepetitivecodeinExample2.Refactorthecodetoreducetheduplication.Additionally,addafunctiontohandleanyerrorsthatmayoccurwiththerequest.

17OtherJavaScriptLibrariesWHATYOUWILLLEARNINTHISCHAPTER:

UsingModernizrtowritefeature-specificcode

Loadingexternalresourcesforbrowsersthatdonotsupportcertainfeatures

UsingPrototypeandMooToolstoperformcommontasks,suchasDOMmanipulationandAjaxrequests

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

jQueryisthemostpopularJavaScriptlibrarytoday.It’susedonhundredsofthousandsofwebsites,andyetit’snottheonlylibraryJavaScriptdevelopersuse.Infact,thousandsofJavaScriptlibrariesandutilitiesareavailable,andeachonecantypicallybecategorizedintotwogroups:generalandspecialty.

Theaimofgeneralframeworksistobalancethedifferencesbetweenbrowsersbycreatinganew,unifiedAPItoperformgeneraltaskslikeDOMmanipulationandAjaxfunctionality(jQueryisageneralframework).Specialtyframeworks,ontheotherhand,focusonaspecificability,suchasfeaturedetection.Soidentifywhatitisyouwanttoachieveandchooseaframeworkbasedonthat.Forexample,ifyouwantedtoperformanimationsandonlyanimations,thescript.aculo.usframework(http://script.aculo.us/)couldbeagoodchoiceforyou.

Thischapterlooksatbothgeneralandspecificframeworks.Whendecidingwhichframeworktouse,lookattheframework’sbrowsersupport,documentation,andcommunityinvolvement.Theframeworkscoveredinthischapterareestablished,stable,popular,andcompatiblewitheverymajormodernbrowser(andevenlegacyversionsofIE).You’lllearnabout:

Modernizr:AlibrarydesignedtodetectHTML5andCSSfeaturessupportedbythebrowser.(http://modernizr.com/)

Prototype:AframeworkthatprovidesasimpleAPItoperformwebtasks.AlthoughitofferswaysofmanipulatingtheDOM,Prototype’sprimaryaimistoenhancetheJavaScriptlanguagebyprovidingclassdefinitionandinheritance.(http://www.prototypejs.org)

MooTools:AframeworkthataimstobecompactwhileofferingasimpleAPItomakecommontaskseasier.LikePrototype,MooToolsalsoaimstoenhancetheJavaScriptlanguage—notjustmakeDOMmanipulationandAjaxeasier.Italsoincludesalightweighteffectscomponentoriginallycalledmoo.fx.

(http://www.mootools.net)

Thesearejustatinysamplingofwhatisavailableforyoutouseinyourwebpages.Someothersolutionsnotcoveredinthischapterare:

Yahoo!UserInterfaceFramework(YUI):AframeworkthatrangesfrombasicJavaScriptutilitiestocompleteDHTMLwidgets.Yahoo!hasateamdevotedtodevelopingYUI.(http://developer.yahoo.com/yui/)

ExtJS:ThisframeworkstartedasanextensiontotheYUI.ItofferscustomizableUIwidgetsforbuildingrichInternetapplications.(http://www.extjs.com)

Dojo:Atoolkitdesignedaroundapackagesystem.Thecorefunctionalityresemblesthatofanyotherframework(DOMmanipulation,eventnormalization,DHTMLwidgets,andsoon),butitprovidesandallowsawaytoaddmorefunctionalitybyaddingmorepackages.(http://www.dojotoolkit.org)

MochiKit:Aframeworkthatpridesitselfonitswell-testedness(hundredsoftestsaccordingtotheMochiKitsite)anditscompatibilitywithotherJavaScriptframeworksandlibraries.(http://www.mochikit.com)

DIGGINGINTOMODERNIZRAsyouundoubtedlyknowfromvariouspreviouschapters,JavaScriptdevelopmentisnotutopia.Itneverhasbeen,andrealistically,itneverwillbesimplyduetothefactthatmultiplebrowsersexist(whichisagoodthing—don’tgetuswrong),andthereisacertaindisparitybetweenthefeaturesthosebrowsersimplement.Thisisespeciallytrueasnewfeaturesaredevelopedandintroducedtothebrowser.Forexample,HTML5andCSS3introducemanynewfeaturesthatsomebrowsershaven’tyetimplemented.Ifyouwanttouseanyofthesenewfeaturesinyourpageorapplication,youhavetoensurethatthebrowseryourvisitorisusingproperlysupportsthem.Otherwise,yourpagewillbreak.

InChapter8,youlearnedhowtowritecodethattargetsspecificfeaturesthroughaprocesscalledfeaturedetection,andalthoughfeaturedetectionisatime-testedstrategy,twoproblemsexist:

Somefeaturescanbedifficulttodetect.

Differentbrowsersmaysupportwhatisessentiallythesamefeature,butitmaybeimplementeddifferently.

ModernizrfixestheseproblemsbyprovidingaunifiedAPIfordetectingHTML5andCSSfeaturesinthebrowser.

NOTEEventhoughModernizroffersmanyCSS-basedfeatures,thischapterfocusesonModernizr’sJavaScriptcapabilities.IfyouareinterestedinitsCSScapabilities,seehttp://modernizr.com/docs/formoreinformation.

GettingModernizrJustlikeeveryotherJavaScriptlibraryandframework,ModernizrisnothingmorethanaJavaScriptfilethatyouincludewithinyourpage.Itcomesintwodifferentflavors:development(uncompressed)andproduction(minified).Inmostcases,theproductionversioniswhatyouwanttouseinyourpageorapplicationbecauseitissmallerinsize,butthedevelopmentversioncouldproveusefulincertainsituationswhereyouneedtodebugyourcodealongwithModernizr’s(youlearnaboutdebugginginChapter18).

Modernizralsoletsyoupickandchoosethetestsyouneedtoperforminyourpageorapplication(Figure17.1).Forexample,ifyouonlyuselocalStorageornativedraganddropinyourpage,youcanbuildacustomizedversionofModernizrthatcontainsonlythenecessarycodefortestingthebrowser’ssupportforthosefeatures.

Figure17.1

AfeaturethatModernizrincludesbydefaultisautilitycalledHTML5Shiv.ThisutilityisonlyforlegacyversionsofIE,anditenablesyoutostyleHTML5elementsthatarenotsupportedinversionspriortoIE9.IfyoudonotplantotargetlegacyIE,youcanomitHTML5Shivinyourcustomizedbuild.

Modernizr’sdownloadexperiencevariesdependingontheversionyouwanttodownload.Thedevelopmentversionincludesmosttestsbydefault(youcanstillcustomizethebuildifthat’syourthing),butthedownloadpagealsohasaneasy-to-useDownloadbutton(asshowninFigure17.1).SimplyclickingthebuttondownloadsModernizrtoyourcomputer,andyoucansaveitwhereveryouneedto.

Theproductionversionisjustassimpletodownload.Mostfeaturesareexcludedbydefault,forcingyoutopickthefeaturesthatyouneedforyourpageorapplication.ThisisactuallyagoodmovebytheModernizrfolksbecauseyouwantacustomized(andthusoptimized)buildforyourspecificneeds.AfteryouselectyourdesiredfeaturesandclicktheGeneratebutton,theDownloadbuttonappears.

NOTEForthesakeofsimplicity,youcanfindthefullproductionversion(v2.8.3)inthecodedownloadforthischapter.Youcanalsodownloaditathttp://beginningjs.com/modernizr.js.

Modernizr’sdeveloperssuggestthat,forbestperformance,youreferenceModernizr’s<script/>elementinsidethe<head/>andafteryourstylesheetreferences.

Modernizr’sAPIModernizerhasastraightforwardAPIthatrevolvesaroundasingleobjectcalledModernizr.Ithasasetofpropertiesandmethodsthatyouusetodetermineifabrowser

supportsaparticularfeature.Forexample,youcandetermineifabrowsersupportsthegeolocationAPIfromChapter8likethis:

if(Modernizr.geolocation){

//usegeolocation

}

Atfirstglance,itlookslikeyouhaven’tgainedmuchbyusingModernizrbecauseinChapter8,youlearnedthatyoucandothesamethingwiththenavigatorobject,likethis:

if(navigator.geolocation){

//usegeolocation

}

ButrememberthatModernizrisalibraryfordetectingmanyfeatures,eventhosethatrequireabitmoreinvolvementtodetect.Forexample,thecodefordeterminingsupportfornativedraganddropismorecomplex.Theelementsinbrowsersthatsupportnativedraganddrophaveadraggableattribute,ortheysupporteventslikedragstartanddrop.Thatmeansthecodeneededtocheckfordraganddropsupportcouldlooklikethis:

varel=document.createElement("span");

if(typeofel.draggable!="undefined"||

(typeofel.ondragstart!="undefined"&&

typeofel.ondrop!="undefined")){

//usenativedraganddrop

}

Thiscodecreatesanarbitrary<span/>elementandchecksifithasadraggablepropertyorondragstartandondropproperties.Ifanyoftheseconditionsaretrue,thebrowsersupportsdraganddrop.

NOTETheaforementionedtestiswrittentoaccommodateIE8becauseitsupportsnativedraganddrop,butitdoesn’tsupportthedraggableattribute/property.

Thiscode,however,iscumbersometowriteandread.Modernizrsimplifiesitto:

if(Modernizr.draganddrop){

//usedraganddrop

}

Here,youcheckthebrowser’ssupportfordraganddropwithModernizr’sdraganddropproperty,andyougetthesameresultsastheprevioustest.

ModernizrchecksforawidevarietyofHTML5(andCSS3)features.Thefollowingtablelistsjustafew:

HTML5FEATURE MODERNIZRPROPERTYHTML5Audio audio

M4AAudio audio.m4a

MP3Audio audio.mp3

OGGAudio audio.ogg

WAVAudio audio.wav

HTML5Video video

H.264Video video.h264

OGGVideo video.ogg

WebMVideo video.webm

DragandDrop draganddrop

LocalStorage localstorage

Geolocation geolocation

Inadditiontothebuilt-intests,youcanalsoextendModernizrwithyourowntests.

CustomTestsYoucanaddyourownteststoModernizrwithitsaddTest()method.Theprocessissimple:simplycallModernizr.addTest(),passitthenameofyourtest,andpassthefunctionthatperformsthetest.

Forexample,itwasmentionedearlierthatalthoughIE8supportsnativedraganddrop,itdoesnotsupportthedraggableattribute/property.YoucanextendModernizrtotestforthisspecificfunctionalitylikethis:

Modernizr.addTest("draggable",function(){

varspan=document.createElement("span");

returntypeofspan.draggable!="undefined"

});

Thiscodeaddsanewtestcalled"draggable".Itsfunctioncreatesanarbitrary<span/>elementandchecksifithasadraggableproperty.Inmodernbrowsers,thedraggablepropertydefaultstofalse,butitisundefinedinIE8.Therefore,whenyouusethetestlikethis:

if(!Modernizr.draggable){

//codeforIE8

}

youcanruncodeforbrowsersthatdonotsupportthedraggableattribute/property.

Sometimes,however,youdon’twanttouseanifstatementtoruncodeforaspecificbrowser(orasetofbrowsers).Instead,wouldn’titbeniceifyoucouldloadanexternalJavaScriptfileforbrowsersthatpassedorfailedacertaintest?Modernizrcandothat!

LoadingResourcesModernizrhasanoptionalmethodcalledload()(youcanomititfromyourcustombuild),andit’susedtoloadexternalJavaScriptandCSSfilesbasedontheresultofatest.

Theload()method’sbasicusageissimple;youpassitanobjectthatdescribesthetestandresourcesyouwanttoload.Forexample:

Modernizr.load({

test:Modernizr.geolocation,

nope:"geo-polyfill.js",

yep:"geo.js"

});

ThiscodecallsModernizr.load()andpassesanobjectthathastest,nope,andyepasproperties(we’llcallthisayepnopeobject).Thetestpropertycontainstheresultofthetest.Ifitpasses,Modernizrloadsthefileassignedtotheyepproperty(geo.jsinthisexample).Butifitfails,thefileassignedtothenopeproperty(geo-polyfill.js)isloadedinstead.

NOTEApolyfillisathird-partyJavaScriptcomponentthatreplicatesthestandardAPIforolderbrowsers.

Theyepandnopepropertiesareoptional,soyoucanloadonlyoneresourceifyouneedto.Forexample,thefollowingcodeloadsaJavaScriptfileonlyforbrowsersthatdonotsupportthedraggableattribute/property:

Modernizr.load({

test:Modernizr.draggable,

nope:"draggable-polyfill.js"

});

Thistypeofbehaviorisidealinthesesituations.Youdon’twantorneedtoloadapolyfillforthedraggableattribute/propertyformodernbrowsers,butyoudoforolderbrowsers,likeIE8,thatdonotsupportit.

Modernizr’sload()methodalsoletsyourunmultipletests.Insteadofpassingasingleyepnopeobject,youcanpassanarrayofthem,likethis:

Modernizr.load([{

test:Modernizr.draggable,

nope:"draggable-polyfill.js"

},

{

test:document.addEventListener,

nope:"event-polyfill.js"

}]);

Thiscodepassesanarrayoftwoyepnopeobjectstotheload()method.Thefirstobjectisthesamecustomdraggabletestfromthepreviousexample.Thesecondobjectchecksifthebrowsersupportsthedocument.addEventListener()method;ifitdoesn’t,Modernizr

loadsaneventpolyfill.

Modernizrloadsexternalresourcesasynchronously.ThismeansthatthebrowserwillcontinuetoloadtherestofthepagewhileModernizrdownloadsandexecutestheexternalresources.Thiscancauseissuesifyourpagereliesonthoseresources;youhavetoensuretheyarecompletelyloadedbeforeyouattempttousethem.

Youcanavoidthistypeofissuebyaddingacompletepropertytoyouryepnopeobject.Thispropertyshouldcontainafunction,anditexecutesregardlessofwhathappenswhenall(orevennone)oftheresourcesarefinishedloading.Forexample:

functioninit(){

alert("Pageinitializationgoeshere!");

}

Modernizr.load([{

test:Modernizr.draggable,

nope:"draggable-polyfill.js"

},

{

test:document.addEventListener,

nope:"event-polyfill.js",

complete:init

}]);

Thisnewcodeaddstwochangestothepreviousexample.First,itdefinesafunctioncalledinit().ThisfunctionwouldnormallycontaincodetoinitializetheJavaScriptusedonthepage(suchassettingupeventlisteners).

Thesecondchangeistheadditionofthecompletepropertytooneoftheyepnopeobjects.It’ssettotheaforementionedinit()function,anditalwaysexecutes—eitherwhentheresourcesarecompletelyloaded,orimmediatelyforbrowsersthatdonotneedtheresources.

TRYITOUTRevisitingNativeDragandDropAsmentionedearlierinthissection,IE8supportsnativedraganddrop,butitdoesn’tsupportthedraggableattribute/property.Inthisexample,yourevisitch10_example21.htmlanduseModernizrtoloadtwopolyfills:onetosupportdraggable,andanothertosupportthestandardDOMeventmodel.

ThesepolyfillsarewrittenbyJeremyandareprovidedinthecodedownload.Theyareevent-polyfill.jsanddraggable-polyfill.js.Bothareopensource.Loadingthesepolyfillswillmakethisexampleworkwithminimalmodificationstotheexistingcode.

Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example1</title>

<style>

[data-drop-target]{

height:400px;

width:200px;

margin:2px;

background-color:gainsboro;

float:left;

}

.drag-enter{

border:2pxdashed#000;

}

.box{

width:200px;

height:200px;

}

.navy{

background-color:navy;

}

.red{

background-color:red;

}

</style>

<scriptsrc="modernizr.min.js"></script>

</head>

<body>

<divdata-drop-target="true">

<divid="box1"draggable="true"class="boxnavy"></div>

<divid="box2"draggable="true"class="boxred"></div>

</div>

<divdata-drop-target="true"></div>

<script>

functionhandleDragStart(e){

e.dataTransfer.setData("text",this.id);

}

functionhandleDragEnterLeave(e){

if(e.type=="dragenter"){

this.className="drag-enter";

}else{

this.className="";

}

}

functionhandleOverDrop(e){

e.preventDefault();

if(e.type!="drop"){

return;

}

vardraggedId=e.dataTransfer.getData("text");

vardraggedEl=document.getElementById(draggedId);

if(draggedEl.parentNode==this){

this.className="";

return;

}

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

this.className="";

}

functioninit(){

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-

target]");

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",

handleDragStart);

}

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

targets[i].addEventListener("dragover",

handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",

handleDragEnterLeave);

targets[i].addEventListener("dragleave",

handleDragEnterLeave);

}

}

Modernizr.addTest('draggable',function(){

varspan=document.createElement("span");

returntypeofspan.draggable!="undefined";

});

Modernizr.load([{

test:Modernizr.draggable,

nope:"draggable-polyfill.js"

},

{

test:document.addEventListener,

nope:"event-polyfill.js",

complete:init

}]);

</script>

</body>

</html>

Savethisasch17_example1.htmlandloaditintoanybrowser(youcanalsoviewit

athttp://beginningjs.com/examples/ch17_example1.html).You’llseethatitbehavesexactlylikech10_example21.html,andifyoucanviewitinIE8,you’llseethatitworksthere,too.

Thiscodeisalmostidenticaltoch10_example21.html,solet’sjustgooverthenew/changedcode.First,youaddareferencetoModernizr:

<scriptsrc="modernizr.min.js"></script>

AsrecommendedbythefolksatModernizr,the<script/>elementresideswithinthedocument’s<head/>.

Thenextchangeistheadditionoftheinit()function.Thefunctionitselfisnew,butthecodeitexecutesisthesameinitializationcodefromch10_example21.html:

functioninit(){

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-target]");

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",handleDragStart);

}

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

targets[i].addEventListener("dragover",handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",handleDragEnterLeave);

targets[i].addEventListener("dragleave",handleDragEnterLeave);

}

}

Thiscodewaswrappedwithintheinit()functionsothatModernizrcanuseitasthecompletecallbackfunction,thereforesettinguptheeventlistenersaftertheevent-polyfill.jsfilehasbeencompletelyloaded.Thisiscrucialbecauseiftheeventpolyfillisn’tready,thepagewillnotworkinIE8.

Thefinaltwoadditionsarefamiliartoyou;thefirstcreatesacustomModernizrtestcalleddraggable:

Modernizr.addTest('draggable',function(){

varspan=document.createElement("span");

returntypeofspan.draggable!="undefined";

});

ThesecondcallsModernizr’sload()methodtoloadthenecessarypolyfillsifthey’reneeded:

Modernizr.load([{

test:Modernizr.draggable,

nope:"draggable-polyfill.js"

},

{

test:document.addEventListener,

nope:"event-polyfill.js",

complete:init

}]);

Weshouldadmitthat,inthecaseofthisexample,creatingthecustomdraggabletestisabitoverboard.Youonlyusethetestonce,soitwouldbeslightlymoreefficienttoomitthecustomtestandwritethefirstyepnopeobjectlikethis:

{

test:typeofdocument.createElement("span").draggable!=

"undefined",

nope:"draggable-polyfill.js"

}

Atthesametime,thisslightlymoreefficientversionisabituglier.Ultimately,thechoiceisyours.Incaseslikethis,however,manypeoplecreatethecustomtestinautilityfilebecauseitcouldbereusedinotherprojects.

DIVINGINTOPROTOTYPEjQueryisthemostpopularframeworktoday,butthatcrownusedtosituponPrototype’shead.UnlikejQuery,Prototype’sfocusisaugmentingthewayyouprogramwithJavaScriptbyprovidingclassesandinheritance.Itdoes,however,alsoprovidearobustsetoftoolsforworkingwiththeDOMandAjaxsupport.

GettingPrototypePointyourbrowsertoPrototype’sdownloadpageathttp://prototypejs.org/download.Here,you’llbegiventhechoicetodownloadthelateststableversion,oranolderversion.Theexamplesinthisbookusethelateststableversionatthetimeofthiswriting:v1.7.2.

NOTEThestableversionofPrototype1.7.2isprovidedinthecodedownload.

NocompressedversionsofPrototypeexist.

TestingYourPrototypeInstallationThelargestportionofthePrototypelibraryisitsDOMextensions.LikejQuery,itprovidesavarietyofhelpfulutilityfunctionstomakeDOMprogrammingabiteasier;itevenhasitsown$()function(unlikejQuery,Prototypedoesn’thaveaspecialnameforthisfunction;it’ssimplycalledthedollarfunction):

varbuttonObj=$("theButton");

Prototype’s$()functiononlyacceptselementidattributevaluesorDOMelementobjectstoselectandaddextrafunctionalitytoDOMobjects.PrototypedoeshaveafunctionthatallowsyoutouseCSSselectorstoselectelements;youlearnaboutthatlater.

LikejQuery,PrototypeprovidesitsownAPIforregisteringeventlisteners.ItextendstheEventobjectwithamethodcalledobserve(),whichisnotunliketheevt.addListener()methodyouwroteinChapter10.Forexample:

functionbuttonClick(){

alert("Hello,PrototypeWorld!");

}

Event.observe(buttonObj,"click",buttonClick);

TheEvent.observe()methodacceptsthreearguments:ThefirstistheDOMorBOMobjectyouwanttoregisteraneventlistenerfor,thesecondistheeventname,andthethirdisthefunctiontocallwhentheeventfires.YoucanuseEvent.observe()toregisteraneventlistenertoanyDOMorBOMobject.Youlookatthismethod,andotherwaystolistenforevents,laterinthischapter.

LikejQuery,youcanchainmethodcallstogetheronwrapperobjectscreatedwiththe$()function.Prototype’smethodnames,however,areabitmoreverbose:

functionbuttonClick(){

$(document.body).writeAttribute("bgColor","yellow")

.insert("<h1>Hello,Prototype!</h1>");

}

Event.observe(buttonObj,"click",buttonClick);

ThebuttonClick()functionnowmodifiesthe<body/>elementbychangingthebackgroundcolortoyellowandaddingcontenttothepage.Let’sbreakdownthisstatement.

First,youpassdocument.bodytothe$()function:

$(document.body)

Thisextendsthestandard<body/>elementwithPrototype’sextensionmethods—oneofwhichisthewriteAttribute()method.Asitsnameimplies,it“writes”orsetsanattributeontheelement:

writeAttribute("bgColor","yellow")

Thissetsthebody’sbgColorattributetoyellow.ThewriteAttribute()methodreturnstheDOMobjectitwascalledon,theextendeddocument.bodyobjectinthiscase.Soyoucancallanotherextensionmethod,calledinsert(),tosetitscontent:

insert("<h1>Hello,Prototype!</h1>")

Let’susethisasthebasisforafiletotestyourPrototypeinstallation.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example2</title>

</head>

<body>

<buttonid="theButton">ClickMe!</button>

<scriptsrc="prototype.1.7.2.js"></script>

<script>

varbuttonObj=$("theButton");

functionbuttonClick(){

$(document.body).writeAttribute("bgColor","yellow")

.insert("<h1>Hello,Prototype!</h1>");

}

Event.observe(buttonObj,"click",buttonClick);

</script>

</body>

</html>

Savethisasch17_example2.htmlandopenitinyourbrowser(http://beginningjs.com/examples/ch17_example2.html).YoushouldseesomethinglikeFigure17.2.Ifyoudon’t,makesurethatthePrototypeJavaScriptfileisinthesame

directoryastheHTMLfile.

Figure17.2

RetrievingElementsPrototype’s$()functionisverydifferentfromjQuery’s.Ifyourememberfromthepreviouschapter,jQuery’s$()functioncreatesajQueryobjectthatwrapsitselfaroundoneormultipleDOMelementobjects.Incontrast,Prototype’s$()functionreturnstheactualDOMobject(muchlikedocument.getElementById()),butitalsoextendstheelementobjectwithmanynewpropertiesandmethods:

varel=$("myDiv");

ThiscoderetrievestheelementwithanidofmyDiv,andyoucanusethisobjectjustlikeyouuseanyotherelementobject.Forexample,thefollowingcodealertstheelement’stagnamewiththetagNameproperty:

alert(el.tagName);

Youcanalsoextendanelementbypassingtheelement’sobjecttothedollarfunction.Thefollowingcodepassesthedocument.bodyobjecttothedollarfunctioninordertoextendit:

varbody=$(document.body);

Bydoingthis,youcanusebothnativeDOMmethodsandpropertiesaswellasPrototype’smethods.

NOTEPrototype’sdollarfunctionreturnsnullifthespecifiedelementcannotbefound.ThisisunlikejQuery’s$()functionbecausePrototypereturnsanextendedDOMelementobject;eventhoughitisextended,itisstillaDOMelementobject.

SelectingElementswithCSSSelectors

Asmentionedbefore,Prototype’sdollarfunctiondoesnotselectelementsbaseduponCSSselectors;itonlyacceptselementidvaluesandelementobjects.Prototypedoes,however,haveanotherfunctionthatbehavessimilarlytothejQueryfunction:the$$()function.

Youcanusethe$$()functiontolocateandretrieveelementsthatmatchtheprovidedCSSselector.Forexample,thefollowingcoderetrievesall<div/>elementsinthepageandreturnstheminanarray:

vardivEls=$$("div");

The$$()functionalwaysreturnsanarray—evenifyouuseanidselector.Onedownsideto$$()isthatitreturnsanarrayofextendedelements;soifyouwanttoperformanoperationoneveryelementinthearray,youhavetoiterateoverthearraywitheitheralooporaniterativeArraymethod(fromChapter5).

PerforminganOperationonElementsSelectedwith$$()Because$$()returnsanarray,youcanusetheArraymethodstoperformiterativeoperations.Forexample,thefollowingcodeusestheforEach()methodtoinsertcontentintoeachelementinthearray:

functioninsertText(element){

element.insert("ThistextinsertedusingtheforEach()method.");

}

$$("div").forEach(insertText);

YoucanalsousemultipleCSSselectorstoselectelementswiththe$$()function.Insteadofpassingasinglestringthatcontainsthemultipleselectors,youpasseachselectorasanargumenttothemethod,likethis:

varelements=$$("#myDiv","p>span,.class-one");

Thiscodeselectselementsbasedupontwoselectors:#myDivandp>span,.class-one,anditreturnsanarraythatcontainsalloftheextendedelementobjectsthatmatchthoseselectors.

NOTEFormoreinformationontheCSSselectorssupportedinPrototype,seehttp://prototypejs.org/doc/latest/dom/dollar-dollar/.

ManipulatingStylePrototypegivesyouseveralmethodsyoucanusetochangeanelement’sstyle.ThemostbasicisthesetStyle()method,whichsetsindividualstyleproperties.TousesetStyle(),youcreateanobjectthatcontainstheCSSpropertiesandvaluesthatyouwanttoset.Forexample,thefollowingcodesetsanelement’sforegroundandbackgroundcolors:

varstyles={

color:"red",

backgroundColor:"blue"

};

$("myDiv").setStyle(styles);

Asyouknowfrompreviouschapters,changinganelement’sstyleinthismannerisusuallyundesirable.AbettersolutionistomanipulatetheCSSclassesappliedtoanelement,andPrototypegivesyoufoureasy-to-usemethodstodojustthat.

Thefirstmethod,addClassName(),addsaCSSclasstotheelement.Thefollowingcodeaddstheclass-oneCSSclasstotheelement:

$("myDiv").addClassName("class-one");

Thesecondmethod,removeClassName(),removesthespecifiedclassfromtheelement.Thefollowingcoderemovestheclass-twoCSSclassfromtheelement:

$("myDiv").removeClassName("class-two");

NextisthetoggleClassName()method,andittogglesthespecifiedclass.Thefollowingcodetogglestheclass-threeCSSclass.Ifitisalreadyappliedtotheelement,theclassisremoved.Otherwise,itisappliedtotheelement:

$("myDiv").toggleClassName("class-three");

Thefinalmethod,hasClassName(),checksifthespecifiedclassisappliedtotheelement:

$("myDiv").toggleClassName("class-three");

Naturally,iftheclassexists,thetoggleClassName()methodreturnstrue.Otherwise,itreturnsfalse.

TheseCSSmethodsareverysimilartojQuery’sCSSclassmanipulationmethods,butPrototype’smethodsforcreatingandinsertingelementsdiffergreatlyfromjQuery’smethods.Removingelements,however,isverysimilartojQuery.

Creating,Inserting,andRemovingElementsPrototypemakesiteasytomanipulatetheDOMbecauseitextendstheElementobject.Let’sstartbycreatingelements.

CreatinganElementPrototypeaddsaconstructorfortheElementobject,anditacceptstwoarguments:theelement’stagnameandanobjectcontainingattributesandtheirvalues.Thefollowingcodecreatesan<a/>elementandpopulatesitsidandhrefattributes:

varattributes={

id="myLink",

href="http://prototypejs.org"

};

vara=newElement("a",attributes);

Thefirstfewlinesofthiscodecreateanobjectcalledattributesanddefineitsidandhrefproperties.Theythencreatean<a/>elementbyusingtheElementobject’sconstructor,passing"a"asthefirstargumentandtheattributesobjectasthesecond.

AddingContentPrototypeextendselementobjectswithtwomethodsforaddingcontent:insert()andupdate().Theaptlynamedinsert()methodinsertsnewcontentattheendoftheelement.Thefollowingcodeinsertstheaobjectfromthepreviousexampleintothedocument’sbody:

$(document.body).insert(a);

Theupdate()methodreplacesallexistingcontentwithintheelement.Thefollowingcodeupdatesthedocument’sbodywiththeaobject,therebyreplacingtheexistingcontentwiththe<a/>element:

$(document.body).update(a);

It’simportanttorememberthedistinctionbetweenthetwomethods;otherwise,youmayexperienceunexpectedresultsinyourwebpage.

RemovinganElementPrototypemakesiteasytoremoveanelementfromtheDOM;simplycalltheremove()methodontheelementobjectyouwanttoremove,likethis:

a.remove();

UsingEventsWhenyouextendanElementobjectwiththe$()function,yougainaccesstoitsobserve()method.LikethenativeaddEventListener()method,thisregistersaneventlistenerforaDOMelement,anditacceptstwoarguments:theeventnameandthefunctiontocallwhentheeventfires.Forexample,thefollowingcoderegistersaclickeventlistenerthatexecutesthedivClick()function:

functiondivClick(event){

//dosomething

}

$("myDiv").observe("click",divClick);

Andasyousawearlier,youcanalsousetheEvent.observe()method.ThefollowingcodeachievesthesameresultsusingEvent.observe():

functiondivClick(event){

//dosomething

}

Event.observe("myDiv","click",divClick);

ThiscodeisslightlydifferentfromthefirsttimeyousawEvent.observe()becausethefirstargument,inthiscase,isastring.YoucanpasstheidofanelementoraDOM/BOMobjectasthefirstargumenttoEvent.observe().Thismethodisparticularlyusefulforobjectslikewindow.Youcannotcall$(window).observe()becausethebrowserwillthrowanerror.Instead,youhavetouseEvent.observe().

Prototypedoesn’temulatetheW3CDOMeventmodel.Instead,itextendstheeventobjectsoflegacy-IEandstandards-compliantbrowserstogiveyouasetofutilitymethodstoworkwitheventdata.

Forexample,theelement()methodreturnstheeventtarget(thesrcElementpropertyforlegacy-IE,andthetargetpropertyforW3CDOMbrowsers).Thefollowingcodeusestheelement()methodtoretrievethetargetoftheclickeventandtogglestheclass-oneCSSclass:

functiondivClick(e){

vartarget=e.element();

target.toggleClassName("class-one");

}

$("myDiv").observe("click",divClick);

Theelementreturnedbytheelement()methodisalreadyextendedwithPrototype’smethods;so,there’snoneedtopassitto$()togettheextrafunctionality.

RewritingtheTabStripwithPrototypeYounowknowhowtoretrieveandmanipulateelements,addandremoveelements,andregistereventlistenerswithPrototype.Let’sadaptthejQueryversionofthetabstripfromch16_example2.html.

TRYITOUTRevisitingtheToolbarwithPrototypeOpenyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example3</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="prototype.1.7.2.js"></script>

<script>

functionhandleEvent(e){

vartarget=e.element();

vartype=e.type;

if(type=="mouseover"||type=="mouseout"){

target.toggleClassName("tabStrip-tab-hover");

}elseif(type=="click"){

target.addClassName("tabStrip-tab-click");

varnum=target.getAttribute("data-tab-number");

showDescription(num);

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("descContainer").update(text);

}

$$(".tabStrip>div").forEach(function(element){

element.observe("mouseover",handleEvent);

element.observe("mouseout",handleEvent);

element.observe("click",handleEvent);

});

</script>

</body>

</html>

Savethisfileasch17_example3.htmlandloaditintoyourbrowser(http://beginningjs.com/examples/ch17_example3.html).You’llnoticeitbehavesthesameastheothertabstripscripts.

BecausetheCSSandmarkupremainsunchangedinthejQueryversion,let’sfocusontheJavaScriptthatchanged—startingwiththehandleEvent()function:

functionhandleEvent(e){

vartarget=e.element();

Here,yougettheeventtargetusingtheelement()extensionmethodandassignittothetargetvariable.

Next,youdeterminethetypeofeventthattookplace.Youfirstcheckformouseoverandmouseoutevents:

if(type=="mouseover"||type=="mouseout"){

target.toggleClassName("tabStrip-tab-hover");

Ifeitheroftheseeventstakesplace,youwanttotogglethetabStrip-tab-hoverCSSclass.Formouseoverevents,thisCSSclassisappliedtothetargetelement,andformouseout,theclassisremoved.

Nowyouneedtodetermineiftheclickeventfired:

}elseif(type=="click"){

target.addClassName("tabStrip-tab-click");

Ifso,youaddthetabStrip-tab-clickCSSclasstothetargetelementtochangeitsstyletothatofaclickedtab.Then,youneedtogetthetab’snumberfromtheelement’sdata-tab-numberattribute:

varnum=target.getAttribute("data-tab-number");

showDescription(num);

}

}

YouusethenativegetAttribute()methodtoretrievethatattribute’svalueandpassittoshowDescription().

Asyouknow,theshowDescription()functionaddsthetab’sdescriptiontothepage.

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("descContainer").update(text);

}

Here,youselecttheelementrepresentingthedescriptioncontainerandreplaceitscontentswiththeupdate()method.

Thefinalbitofcodesetsuptheeventlistenersforthetabelements.Usingthe$$()function,youretrievethemusingthe.tabStrip>divselector:

$$(".tabStrip>div").forEach(function(element){

element.observe("mouseover",handleEvent);

element.observe("mouseout",handleEvent);

element.observe("click",handleEvent);

});

YouusetheArrayobject’sforEach()methodtoiterateoverthearrayreturnedby$$().ThefunctionyoupasstoforEach()isresponsibleforregisteringthemouseover,mouseout,andclickeventlistenersoneachelement,andyouregisterthoseeventsusingtheobserve()extensionmethod.

Prototypeisn’tjustaboutDOMmanipulationandlanguageenhancement.It,too,providesyouwithAjaxcapabilitiesthatareeasytolearnanduse.

UsingAjaxSupportUnfortunately,Prototype’sAjaxsupportisn’tasstraightforwardasjQuery’s.Prototype’sAjaxfunctionalitycentersonitsAjaxobject,whichcontainsavarietyofmethodsyoucanusetomakeAjaxcalls.ThisobjectismuchlikethejQueryobjectinthatyoudonotcreateaninstanceofAjax;youusethemethodsmadeavailablebytheobjectitself.

AttheheartoftheAjaxobjectistheAjax.Request()constructor.Itacceptstwoarguments:theURLandanobjectcontainingasetofoptionsthattheAjaxobjectuseswhenmakingarequest.TheoptionsobjectcancontainavarietyofoptionpropertiestoalterthebehaviorofAjax.Request().Thefollowingtabledescribesjustafewofthem.

OPTION DESCRIPTIONasynchronous DetermineswhetherornottheXMLHttpRequestobjectmakestherequest

inasynchronousmode.Thedefaultistrue.method TheHTTPmethodusedfortherequest.Thedefaultis"post"."get"is

anothervalidvalue.onSuccess AcallbackfunctioninvokedwhentherequestcompletessuccessfullyonFailure Acallbackfunctioninvokedwhentherequestcompletes,butresultsinan

errorstatuscodeparameters Eitherastringcontainingtheparameterstosendwiththerequest,oran

objectcontainingtheparametersandtheirvalues

NOTEForacompletelistofoptions,visitthePrototypedocumentationathttp://prototypejs.org/doc/latest/ajax/.

MakingarequestwithPrototypelookssomethinglikethefollowingcode:

functionrequestSuccess(transport){

alert(transport.responseText);

}

functionrequestFailed(transport){

alert("Anerroroccurred!HTTPstatuscodeis"+transport.status);

}

varoptions={

method:"get",

onSuccess:requestSuccess,

onFailure:requestFailed

};

newAjax.Request("someTextFile.txt",options);

ThefirstfewlinesofcodedefinetherequestSuccess()andrequestFailed()functions.Thesefunctionsacceptaparametercalledtransport—aspecialobjectthatcontainstheserver’sresponse(moreonthislater).

Afterthefunctiondefinitions,youcreateanoptionsobjectthatcontainspropertiesfortheHTTPmethodoption,theonSuccessoption,andtheonFailureoption.Then,youfinallymaketherequestforthesomeTextFile.txtfile,passingtheoptionsobjecttotheAjax.Request()constructor(don’tforgetthenewkeyword!).

Ifyouneedtosendparameterswithyourrequest,you’llhavetodoabitmorepreparationbeforecallingnewAjax.Request().LikejQuery,youcancreateanobjecttocontaintheparameternamesandvalues.Forexample,ifyouneedtosendaparametercalledusernamewithyourrequest,youcandosomethinglikethis:

varparms={

username:"jmcpeak"

};

options.parameters=parms;

WhenyousendtherequestbycreatinganewAjax.Requestobject,theparametersareaddedtotheURLbeforetherequestissenttotheserver.

AllcallbackfunctionsarepassedaparametercontaininganAjax.Responseobject,anobjectthatwrapsaroundthenativeXMLHttpRequestobject.Itcontainsavarietyofusefulpropertiesforworkingwiththeserver’sresponse.ItemulatesthebasicpropertiesofXMLHttpRequest,suchasreadyState,responseText,responseXML,andstatus.Butitalsoexposesafewconvenienceproperties,asoutlinedinthefollowingtable.

PROPERTYNAME

PURPOSE

request TheAjax.RequestobjectusedtomaketherequestresponseJSON AparsedJSONstructureiftheresponse’sContent-Typeheaderis

application/json

statusText TheHTTPstatustextsentbytheservertransport ThenativeXMLHttpRequestobjectusedtomaketherequest

Nowthatyou’vebeengivenacrashcourseinPrototype’sAjaxfunctionality,let’smodifytheAjaxFormValidator.

TRYITOUTRevisitingtheFormValidatorwithPrototypeOpenyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example4</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="prototype.1.7.2.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varoptions={

method:"get",

onSuccess:handleResponse,

parameters:{

username:userValue

}

};

newAjax.Request("ch14_formvalidator.php",options);

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varoptions={

method:"get",

onSuccess:handleResponse,

parameters:{

email:emailValue

}

};

newAjax.Request("ch14_formvalidator.php",options);

}

functionhandleResponse(transport){

varresponse=transport.responseJSON;

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

$("usernameAvailability").observe("click",checkUsername);

$("emailAvailability").observe("click",checkEmail);

</script>

</body>

</html>

Savethisasch17_example4.htmlinyourwebserver’srootdirectory,becausethisfilemustbehostedonawebservertoworkcorrectly.Pointyourbrowsertohttp://yourserver/ch17_example4.htmlandtestouttheform.

Thispageworksexactlylikethepreviousversions.Let’sstartexaminingthisversionwiththecheckUsername()function.Asyouknow,thisfunctionisresponsibleforgatheringtheuserinputandsendingittotheserver.

Togettheuser’sinput,youretrievetheappropriate<input/>elementandgetitsvalue:

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("username").value;

Youcouldusethenativedocument.getElementById()methodtoretrievethe<input/>element,butPrototype’s$()functionismucheasiertotype.ItreturnsanextendedElementobject,butyouusethestandardvaluepropertytoretrievetheelement’svalue.

Next,youchecktheuserinputtoensureyouhaveworkabledata:

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

Ifthefunctionmakesitpastthisifstatement,youneedtoassembletheoptionsobjectthatyoupasstotheAjax.Request()constructor:

varoptions={

method:"get",

onSuccess:handleResponse,

parameters:{

username:userValue

}

};

ThisoptionsobjecthastherequiredmethodandonSuccessproperties,andyoualsoincludetheparameters—settingusernametothevalueobtainedfromtheform.

Nowyou’rereadytosendtherequest.So,youcalltheAjax.Request()constructorandpassittheURLandoptionsobject.

Asthelaststepinthisfunction,youcalltheAjax.Request()constructor,prependedbythenewkeyword,andpasstheURLtoformvalidator.phpandtheoptionsobject:

newAjax.Request("ch14_formvalidator.php",options);

}

ThecheckEmail()functionisalmostidenticaltocheckUsername().First,youretrievethee-mailaddressfromtheformandvalidateit:

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

Next,youbuildtheoptionsobject:

varoptions={

method:"get",

onSuccess:handleResponse,

parameters:{

email:emailValue

}

};

Onceagain,youprovidetheobligatorymethodandonSuccessproperties,aswellastheparametersobject.Yousettheemailparameterpropertytothee-mailaddressfromtheform.

Then,youissuetherequestbycallingtheAjax.Request()constructor:

newAjax.Request("ch14_formvalidator.php",options);

}

ThehandleResponse()functionisnotleftuntouched,butthechangeissubtle:

functionhandleResponse(transport){

varresponse=transport.responseJSON;

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+"isnot

available.");

}

}

ThisnewversionusesPrototype’sresponseJSONpropertytogettheparsedJSON.Youcanusethispropertybecausech14_formvalidator.php’sContent-Typeheaderissettoapplication/json.Ifitwasanyothervalue,liketext/plain,thenresponseJSONwouldbenull,andyouwouldhavetouseresponseTextinconjunctionwithJSON.parse(),likethis:

varresponse=JSON.parse(transport.responseText);

Thefinaltwolinesofcodeinthisexampleregistertheclickeventlistenersonthetwo<a/>elements:

$("usernameAvailability").observe("click",checkUsername);

$("emailAvailability").observe("click",checkEmail);

YouretrievetheelementsusingPrototype’s$()function,andthenyouuseobserve()toregistertheeventlisteners.

PrototypeisapowerfulframeworkthatprovidesarichsetofutilitiestochangethewayyouwriteJavaScript.Butasimplesectionsuchasthisisfartoosmalltocovertheframeworkadequately.ForfurtherinformationonPrototypeandtheutilityitoffers,seetheAPIdocumentationathttp://api.prototypejs.org/andthetutorialsathttp://prototypejs.org/learn/.

DELVINGINTOMOOTOOLSAtfirstglance,MooToolslooksidenticaltoPrototype,andrightlyso.MooToolswasfirstdevelopedtoworkwithPrototype,soyoushouldn’tbesurprisedtoseesomestrikingsimilaritiesbetweenthetwo.

However,MooToolsismoreofacrossbetweenjQueryandPrototypeasfarasDOMmanipulationisconcerned.LikePrototype,MooTools’goalistoaugmentthewayyouwriteJavaScript,providingtoolstowriteclassesandinheritfromthem.AlsolikePrototype,MooToolsaddsinarichsetofextensionstomakeDOMmanipulationeasier,andyou’llfindthatselectingDOMobjectsinMooToolsisexactlythesameasPrototype.Butasyou’llseeinthefollowingsections,theextensionmethodnamesandthewayinwhichyouusethemisreminiscentofjQuery.

GettingMooToolsYoucandownloadMooToolsintwoways:Youcandownloadthecore,oryoucancustomizeyourownbuild.TheMooTools’corecontainseverythingyouneedtoperformcommonDOMandAjaxoperations,butifyoudon’tneedthefullpowerofcore,youcanpickandchoosewhichpiecesyouneedforyourpageorapplication.

Regardlessoftheversionyouwant,youcandownloadbothathttp://mootools.net/core/builder.Additionally,youcanchoosetodownloadthecompressedoruncompressedJavaScriptfile.Thecodedownloadincludesthecompressedcoreofversion1.5.1.

TestingYourMooTools’InstallationAswementionedearlier,manysimilaritiesexistbetweenMooToolsandPrototype;so,testingyourMooTools’installationwilllookverysimilartothePrototypetest.

MooToolshasa$()function,justlikePrototype’s:

varbuttonObj=$("theButton");

Itacceptseitherastringcontaininganelement’sidoraDOMelementandreturnstheDOMobjectwithanextendedsetofmethodsandproperties.OnesuchmethodistheaddEvent()methodwhich,asyouprobablydeduced,registersaneventlistener.

TheaddEvent()methodacceptstwoarguments:theeventnameandthefunction.So,youcanregisteraneventlistenerlikethis:

functionbuttonClick(){

alert("Youclickedthebutton!");

}

buttonObj.addEvent("click",buttonClick);

MooTools’extensionmethodsprovideavarietyofmethodsandpropertiesformanipulatingelementsinthepage.Mostofthemethodsarechainable,thereforeallowing

youtoperformmultipleoperationswithlesscode.Forexample:

functionbuttonClick(){

$(document.body).setProperty("bgColor","yellow")

.appendHTML("<h1>Hello,MooTools!</h1>");

}

buttonObj.addEvent("click",buttonClick);

Youcansetanelement’sattributeswiththesetProperty()method,asdemonstratedinthiscode.Thismethodreturnstheelementobject,soyoucanthenimmediatelyappendcontenttotheelementbycallingtheappendHTML()method.

UsethiscodetotestyourMooTools’installation.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example5</title>

</head>

<body>

<buttonid="theButton">ClickMe!</button>

<scriptsrc="mootools-core-1.5.1-compressed.js"></script>

<script>

varbuttonObj=$("theButton");

functionbuttonClick(){

$(document.body).setProperty("bgColor","yellow")

.appendHTML("<h1>Hello,MooTools!</h1>");

}

buttonObj.addEvent("click",buttonClick);

</script>

</body>

</html>

Savethisasch17_example5.htmlandloaditinyourbrowser.Whenyouclickthebutton,thebackgroundcolorshouldchangetoyellow,and“Hello,MooTools!”shoulddisplayinthepage.Ifnot,makesuretheMooTools’JavaScriptfileislocatedinthesamedirectoryasyourHTMLpage.

FindingElementsEarlier,wementionedthatMooTools’$()functionissimilartoPrototype’s.Well,let’sclearitupnow;theyareexactlythesame.TheyfindtheelementobjectintheDOMandextendit,albeitwithdifferentmethodsthatyou’llseeinthefollowingsections.Forexample,thefollowingcodefindsanelementwithanidofmyDiv,extendsitwithMooTools’methodsandproperties,andreturnsit:

varelement=$("myDiv");

Withthisobject,youcanuseMooTools’extensionmethodsaswellasthenativeDOMmethodsandproperties:

vartagName=element.tagName;//standardDOM

element.appendHTML("NewContent");//extension

Ifanelementwiththegiveniddoesnotexist,$()returnsnull.

YoucanalsopassaDOMobjecttothe$()functiontoextenditaswell:

varbody=$(document.body);

SelectingElementswithCSSSelectorsMooToolshasthe$$()functiontoselectelementswithCSSselectors,andyoucanpassmultipleCSSselectorstoretrieveawidevarietyofelements.LikePrototype,youpasseachselectorasanargumenttothefunction:

varclassOne=$$(".class-one");

varmultiple=$$("div",".class-one","p>div")

The$$()functionreturnsanarrayofextendedDOMelementobjects.ThisiswhereMooToolsandPrototypestarttodifferbecausewhilebothframeworksextendtheArrayobjectreturnedby$$(),MooToolsaddsextensionmethodsthatmanipulatetheelementswithinthearray.

PerformingOperationsonElementsMooTools’$$()isacrossbetweenjQuery’s$()andPrototype’s$$()inthatitreturnsanarrayofextendedelementobjects(likePrototype),butyoucanuseavarietyofmethodstoworkwiththoseelementswithouthavingtomanuallyiteratethearray.Forexample,youcanchangethestyleofallelementswithinanarraybycallingthesetStyle()method,likethis:

$$("div",".class-one").setStyle("color","red");

Thiscodeselectsmultipletypesofelementsandsetstheirtextcolortored.ContrastthatwithPrototype:

//Prototype

functionchangeColor(item){

varstyles{

color:"red"

};

item.setStyle(styles);

}

$$("div",".class-one").forEach(changeColor);

NotethatyoucouldusethistechniqueinMooTools.Infact,youwanttodosowhenperformingmultipleoperationstothesamesetofelements.RememberthatmethodslikeMooTools’setStyle()andjQuery’scss()areiterative;theyloopoverthearray.

Chainingiterativemethodstogethermeansyouareexecutingmultipleloops,whichisinefficient.

ChangingStyleThepreviousMooTools’codeexampleintroducedyoutothesetStyle()method.Itacceptstwoarguments:thefirstistheCSSproperty,andthesecondisitsvalue.LikejQuery,youcanusetheCSSpropertyusedinastylesheetorthecamel-caseversionusedinscript:

$("myDiv").setStyle("background-color","red");//valid

$("myDiv").setStyle("backgroundColor","red");//valid,too

Bothlinesofthiscodesettheelement’sbackgroundcolortored;soyoucanuseeitherpropertynametosetindividualstyleproperties.

MooToolsalsohasasetStyles()methodforchangingmultipleCSSproperties.Tousethismethod,passanobjectthatcontainstheCSSpropertiesandvalues,likethis:

$("myDiv").setStyles({

backgroundColor:"red",

color:"blue"

});

Thisis,ofcourse,nottheidealwaytochangeanelement’sstyle.So,MooToolsaddstheaddClass(),removeClass(),toggleClass(),andhasClass()extensionmethodstoDOMelementobjects.

TheaddClass()andremoveClass()methodsdojustwhattheirnamesimply.Theyaddorremovethespecifiedclasstoorfromtheelement:

vardiv=$("myDiv");

div.addClass("class-one");

div.removeClass("class-two");

ThetoggleClass()method,naturally,togglesaclass.

div.toggleClass("class-three");

Thiscodetogglestheclass-threeCSSclass.Iftheelementalreadyhastheclass,itisremovedfromtheelement.Otherwise,itisadded.

ThehasClass()methodreturnstrueorfalsedependingonwhetherornottheelementhastheCSSclass:

div.hasClass("class-four");

Thiscodereturnsfalsebecausetheclass-fourCSSclassisn’tappliedtotheelement.

Ofcourse,changinganelement’sstyleisn’ttheonlyDOM-relatedthingsMooToolscando;youcanalsocreate,insert,andremoveelementsfromtheDOM.

Creating,Inserting,andRemovingElementsLikePrototype,MooToolsletsyoucreateelementswiththeElementconstructor:

varattributes={

id:"myLink",

href:"mootools.net"

};

vara=newElement("a",attributes);

Whenyoucalltheconstructor,youpassthetagnameandanobjectcontainingyourdesiredattributes.Theprecedingcodecreatesanew<a/>elementandpopulatesitsidandhrefproperties.YoucanthensetitscontentwiththeappendText()orappendHTML()methods:

a.appendText("GotoMooTools'Website");

MooToolsalsoaddsaset()extensionmethodthatletsyousetthevalueofaproprietary“property.”ThesearenotpropertiesinthesenseofaJavaScriptpropertyusingobject.propertyNamesyntax;instead,they’remoreofavirtualproperty.Forexample,thereisanhtmlpropertythatsetstheHTMLofanelement,andyousetthispropertywiththeset()method,likethis:

a.set("html","GotoMooTool'sWebsite");

ThisisessentiallythesameasusingthenativeinnerHTMLproperty,andinmostcases,you’dwanttouseinnerHTML.

Whenyou’rereadytoaddtheelementtothepage,usetheadopt()method:

$(document.body).adopt(a);

Thiscodeappendsthenewlycreated<a/>elementtothepage’s<body/>elementwiththeadopt()method.Notethatthisdoesn’treplaceexistingcontent;itsimplyaddsnewcontenttothepage.Ifyouneedtoemptyanelementofitschildren,calltheempty()method:

$(document.body).empty();

Youcanalsoremoveanindividualelementwiththedispose()method:

a.dispose();

UsingEventsAsyouknow,the$()functionreturnsanextendedelementobject.OneoftheextensionmethodsistheaddEvent()method,whichregistersaneventlistener:

functiondivClick(e){

alert("Youclickedme!");

}

$("myDiv").addEvent("click",divClick);

TheaddEvent()methodacceptstwoarguments:theeventnameandthefunctiontoexecutewhentheeventfires.

YoucanalsoregistermultipleeventlistenerswiththeaddEvents()method.Insteadofpassingasingleeventnameandfunction,youpassanobjectthatcontainstheeventnamesaspropertiesandthefunctionsasvalues.Forexample,thefollowingcoderegisterseventhandlersforthemouseoverandmouseouteventsonanelement:

functioneventHandler(e){

//dosomethingwiththeeventhere

}

varhandlers={

mouseover:eventHandler,

mouseout:eventHandler

};

$("myDiv").addEvents(handlers);

Whenaneventfires,MooToolspassesitsowneventobject(oftypeDOMEvent)totheevent-handlingfunction.Thisobjecthasahybridsetofpropertiesandmethods:Someareproprietarybutmostarestandards-compliant.ThefollowingtablelistssomeofthepropertiesavailablewithMooTools’Eventobject.

PROPERTY DESCRIPTIONpage.x Thehorizontalpositionofthemouserelativetothebrowserwindowpage.y Theverticalpositionofthemouserelativetothebrowserwindowclient.x Thehorizontalpositionofthemouserelativetotheclientareaclient.y Theverticalpositionofthemouserelativetotheclientareatarget TheextendedeventtargetrelatedTarget Theextendedelementrelatedtotheeventtargettype Thetypeofeventthatcalledtheeventhandler

NOTEVisithttp://mootools.net/core/docs/1.5.1/Types/DOMEventforacompletelistofpropertiesofMooTools’DOMEventobject.

Forexample,thefollowingcoderegistersaclickeventlisteneronanelementwithanidofmyDiv:

functiondivClick(e){

vartarget=e.target.addClass("class-one");

alert("YouclickedatX:"+e.client.x+"Y:"+e.client.y);

}

$("myDiv").addEvent("click",divClick);

Whentheclickeventfires,MooToolspassesitsowneventobjecttodivClick().ThefirstlineofthefunctioncallstheaddClass()method,addingtheclass-oneCSSclasstotheelement.

TheaddClass()methodreturnsanextendedelementobject,lettingyoubothaddtheCSSclassandassignthetargetvariablewiththeextendedeventtarget.Youthenuseanalertboxtodisplaythemousepointer’scoordinatesbyusingtheclient.xandclient.yproperties.

RewritingtheTabStripwithMooToolsNowthatyou’vehadacrashcourseinMooTools,let’srewritethetabstrip!

TRYITOUTRevisitingtheToolbarwithMooToolsOpenyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example6</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="mootools-core-1.5.1-compressed.js"></script>

<script>

functionhandleEvent(e){

vartarget=e.target;

vartype=e.type;

if(type=="mouseover"||type=="mouseout"){

target.toggleClass("tabStrip-tab-hover");

}elseif(type=="click"){

target.addClass("tabStrip-tab-click");

varnum=target.getAttribute("data-tab-number");

showDescription(num);

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("descContainer").set("html",text);

}

$$(".tabStrip>div").addEvents({

mouseover:handleEvent,

mouseout:handleEvent,

click:handleEvent

});

</script>

</body>

</html>

Savethisfileasch17_example6.html,andopenitinyourbrowser(http://beginningjs.com/examples/ch17_example6.htmlisavailable,too).Noticethatthispageworksjustlikealltheotherversions.

Let’sjumprightintothecode,startingwiththehandleEvent()function:

functionhandleEvent(e){

vartarget=e.target;

vartype=e.type;

Everythingisstandards-compliantcodeuntilyougettotheifstatement;that’swhenyouuseMooTools’toggleClass()methodinthecaseofmouseoverandmouseoutevents:

if(type=="mouseover"||type=="mouseout"){

target.toggleClass("tabStrip-tab-hover");

Ifitisoneoftheseevents,youaddthetabStrip-tab-hoverCSSclasstotheeventtarget.Butiftheeventisaclickevent,youneedtodoafewthings.First,youaddthetabStrip-tab-clickCSSclasstotheelement.Then,yougetthevalueofthedata-tab-numberattributebecauseyou’llneedtopassthattotheshowDescription()function:

}elseif(type=="click"){

target.addClass("tabStrip-tab-click");

varnum=target.getAttribute("data-tab-number");

showDescription(num);

}

}

TheshowDescription()functionchangedveryslightly;infact,justonestatementneedsyourattention:

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("descContainer").set("html",text);

}

Youneedtochangethecontentofthedescriptioncontainerelement.Now,youcandothatinavarietyofways,andaswementionedearlier,thenativeinnerHTMLpropertywouldbeideal.However,forthesakeofthisexample,youuseMooTools’set()methodtosetthevirtualhtmlproperty.

Finally,youregisteryourlistenersforthemouseover,mouseout,andclickevents:

$$(".tabStrip>div").addEvents({

mouseover:handleEvent,

mouseout:handleEvent,

click:handleEvent

});

Here,youuseMooTools’$$()methodtoselectthe<div/>elementswithinthetabstrip.ThenyouusetheaddEvents()methodtoregisterthethreeeventlisteners.Asanalternative,youcouldusethetechniquedemonstratedinthePrototypeexample:

$$(".tabStrip>div").forEach(function(item){

item.addEvents({

mouseover:handleEvent,

mouseout:handleEvent,

click:handleEvent

});

});

However,there’snorealneedtodosointhisexample.Butthiswouldbethebestwayifyouneededtoperformotherprocessesoneachelement.Thatway,youiterateovertheelementsonceasopposedtomultipletimes.

AjaxSupportinMooToolsMooToolshasthreeobjectsformakingHTTPrequests,eachtargetingaspecificpurpose:

Request:Usedforgeneralrequests

Request.HTML:UsedspecificallyforreceivingHTML

Request.JSON:SpecificallyusedforreceivingJSON

EachoftheseobjectsissimilartoPrototype’sAjax.Request,inthatyoudirectlycreatethembycallingtheirconstructorfunctionswiththenewoperatorandpassinganobjectthatcontainsvariousoptions:

varrequest=newRequest({

method:"get",

url:"someFile.txt",

onSuccess:requestSuccess

});

ThiscodecreatesaRequestobjectthatmakesaGETrequestforsomeFile.txtandcallstherequestSuccess()functiononasuccessfulrequest.

Youcanpassmanymoreoptionstotheconstructor;thefollowingtablelistssomeofthem.

OPTION DESCRIPTIONasync DetermineswhetherornottheXMLHttpRequestobjectmakestherequestin

asynchronousmode.Thedefaultistrue.data Anobjectcontainingthekey/valuepairstosendwiththerequestmethod TheHTTPmethodusedfortherequest.Thedefaultis"post".onSuccess AcallbackfunctioninvokedwhentherequestcompletessuccessfullyonFailure Acallbackfunctioninvokedwhentherequestcompletes,butresultsinan

errorstatuscodeurl TheURLtosendtherequestto

NOTEVisithttp://mootools.net/core/docs/1.5.1/Request/Requestforacompletelistofoptionsandcallbackfunctions.

Unfortunately,creatingaRequestobjectdoesn’tautomaticallysendtherequest;youmustexplicitlysenditwiththesend()method:

request.send();

Buttosavesometyping,youcanchainthesend()methodtotheRequestconstructor,likethis:

varrequest=newRequest({

method:"get",

url:"someFile.txt",

onSuccess:requestSuccess

}).send();

Youcanalsouseoneofthemanyaliasesforsend().TheirnamesmirrorthoseofthedifferentHTTPmethods,andtheysendtherequestwiththegivenmethod.Forexample,theget()methodsendsaGETrequest,post()sendsPOST,put()isaPUTrequest,andsoon.Usinganaliaseliminatestheneedtospecifythemethodoption.Forexample:

varrequest=newRequest({

url:"someFile.txt",

onSuccess:requestSuccess

});

request.get();//sendstherequestasGET

request.post();//sendsasPOST

Youcansenddatawithyourrequestintwodifferentways.First,youcanmakeitpartoftheRequestobject.ThisisusefulifyouneedtosendthesamedatawitheveryrequestyoumakewithasingleRequestobject.Todothis,youaddadatapropertytotheoptionsobjectyoupasstotheconstructor.Anexampleofthisis:

varrequest=newRequest({

url:"ch14_formvalidator.php",

data:{

username:userValue//assuminguserValueisassignedavalue

},

onSuccess:requestSuccess

});

ThesecondapproachdecouplesthedatafromtheRequestobjectsothatyoucanreusethesameRequestobjectforsendingdifferentdata.Tousethisapproach,youpassthedatatothesend(),orotheralias,methodlikethis:

varrequest=newRequest({

url:"ch14_formvalidator.php",

onSuccess:requestSuccess

}).get({

data:{

username:userValue

}

});

TheonSuccesscallbackfunctionvariesbetweenthedifferenttypesofrequests.ForordinaryRequestobjects,theonSuccesscallbackfunctioniscalledwithtwoarguments—theresponseTextandresponseXML:

functionrequestSuccess(responseText,responseXML){

//dosomethingwitheithersuppliedvalue

}

TheresponseTextistheplaintextualrepresentationoftheserver’sresponse.IftheresponseisavalidXMLdocument,theresponseXMLparameterisaDOMtreecontainingtheparsedXML.

TheonSuccesscallbackisabitmorecomplicatedforRequest.HTMLobjects:

functionrequestHTMLSuccess(responseTree,responseElements,

responseHTML,responseJavaScript){

//dosomethingwiththedata

}

Thefourparametersare:

responseTree:Thenodelistoftheresponse

responseElements:Anarraycontainingtheelementsoftheresponse

responseHTML:Thestringcontentoftheresponse

responseJavaScript:TheJavaScriptoftheresponse

TheonSuccesscallbackforRequest.JSONobjectsismuchsimplerthanRequest.HTML’s:

functionrequestJSONSuccess(responseJSON,responseText){

//dosomethingwiththeprovideddata

}

TheresponseJSONparameterisanobject—theparsedJSONstructure.Soyouwon’tneedtocallJSON.parse().TheresponseTextparameteristheplaintextJSONstructure.Honestly,yourauthorsdon’tknowwhyyouwouldneedtheresponseTextwithRequest.JSON,butit’stherejustincaseyouneedit(wedon’tthinkyouwill).

Let’suseMooTools’Ajaxutilitiestomodifytheformvalidatorfromthepreviouschapteronelasttime!

TRYITOUTRevisitingtheFormValidatorwithMooToolsOpenyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Example7</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="mootools-core-1.5.1-compressed.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varoptions={

url:"ch14_formvalidator.php",

data:{

username:userValue

},

onSuccess:handleResponse

};

newRequest.JSON(options).get();

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varoptions={

url:"ch14_formvalidator.php",

data:{

email:emailValue

},

onSuccess:handleResponse

};

newRequest.JSON(options).get();

}

functionhandleResponse(data,json){

if(data.available){

alert(data.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+data.searchTerm+"isnot

available.");

}

}

$("usernameAvailability").addEvent("click",checkUsername);

$("emailAvailability").addEvent("click",checkEmail);

</script>

</body>

</html>

Savethisfileasch17_example7.html,andsaveitinyourwebserver’srootdirectory.Openandpointyourbrowsertohttp://yourserver/ch17_example7.htmlandtestit.You’llfindthatitbehavesjustasallthepreviousversionsdid.

ThisversionisverysimilartoExample4—thePrototypeversion.Infact,checkUsername()andcheckEmail()areidenticaltoExample4exceptfortherequestcode.Solet’sjustlookatthat,startingwithcheckUsername().

Afteryougetandvalidatetheuserinputfortheusername,youbuildyouroptionsobject:

varoptions={

url:"ch14_formvalidator.php",

data:{

username:userValue

},

onSuccess:handleResponse

};

Yousettheurl,data,andonSuccesspropertiesandpasstheobjecttotheRequest.JSON()constructor:

newRequest.JSON(options).get();

Andtosavesometyping,youchaintheget()calltotheRequest.JSONconstructor.

ThecodeinsidecheckEmail()isunsurprisinglysimilar(atthispoint,whatisaboutthisexample?).First,youbuildyouroptionsobject:

varoptions={

url:"ch14_formvalidator.php",

data:{

email:emailValue

},

onSuccess:handleResponse

};

Thenyousendtherequest:

newRequest.JSON(options).get();

ThehandleResponse()functionalsosawafewchanges.ThankstoMooTools’built-insupportforJSON,thefunctionhasbeensimplified:

functionhandleResponse(data,json){

if(data.available){

alert(data.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+data.searchTerm+"isnot

available.");

}

}

Thedatapassedtothefirstparameter,data,isalreadyparsedintoaJavaScriptobject.Soyousimplyuseittocheckiftheusernameore-mailisavailableanddisplaythecorrectinformationtotheuser.

Finally,youwireuptheevents:

$("usernameAvailability").addEvent("click",checkUsername);

$("emailAvailability").addEvent("click",checkEmail);

Youfindthe<a/>elementsinthedocumentandregistertheirclickeventlistenerswithMooTools’addEvent()method.

MooToolsisapopularframeworkbecauseitoffersyouutilitysimilartojQuerywhilemaintainingaspectsoftraditionalDOMprogramming.MooToolsalsohasananimation/effectscomponent,makingitawell-roundedframework.Thissectioncanhardlydotheframeworkjustice,somakesuretovisittheAPIdocumentationathttp://mootools.net/core/docs/.

SUMMARYThischapterintroducedyouintotheratherlargeworldofJavaScriptframeworksandlibraries.

Youlearnedthattwotypesoflibrariesandframeworksexist:generalandspecific.Youwerealsogivenashortlistofthepopularsolutionsavailabletoday.

YoulearnedwheretoobtainthefilesneededtouseModernizr,Prototype,andMooTools.

YoulearnedhowModernizrhelpsyouwritefeature-specificcode,andhowtoloadexternalresources,likepolyfills,forbrowsersthatdon’tsupportcertainfeatures.

YoulearnedthebasicsofthePrototypeframework—howtoretrieve,create,andmanipulateelements.YoualsolearnedhowtoregistereventlistenersandsendAjaxrequests.

YoulearnedhowtouseMooToolstocreate,select,andmodifyelements,aswellaswireupeventlistenersandmakeAjaxrequests.

EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.

1. ModifytheanswertoChapter14’sQuestion2usingPrototype.AlsoadderrorreportingforwhenanerroroccurswiththeAjaxrequest.

2. Ifyouguessedthatthisquestionwouldbe:“ChangetheanswertoChapter14’sQuestion2usingMooTools,andadderrorreportingforwhenanerroroccurswiththeAjaxrequest”thenyouwon!!Yourprizeis…completingtheexercise.

18CommonMistakes,Debugging,andErrorHandlingWHATYOUWILLLEARNINTHISCHAPTER:

Spottingcommonmistakesthateveryonemakes—evenpros!

Handlingruntimeerrors,orexceptions,withthetry…catchstatement

DebuggingJavaScriptwiththedevelopmenttoolsofvariousbrowsers

WROX.COMCODEDOWNLOADSFORTHISCHAPTER

Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.

EvenaJavaScriptgurumakesmistakes,eveniftheyarejustannoyingtypos.Inparticular,whencodeexpandstohundredsorthousandsoflines,thechanceofsomethinggoingwrongbecomesmuchgreater.Inproportion,thedifficultyinfindingthesemistakes,orbugs,alsoincreases.Inthischapteryoulookatvarioustechniquesthatwillhelpyouminimizetheproblemsthatarisefromthissituation.

YoustartbytakingalookatthetopsevenJavaScriptcodingmistakes.Afteryouknowwhattheyare,you’llbeabletolookoutforthemwhenwritingcode,hopefully,sothatyouwon’tmakethemsooften!

Thenyoulookathowyoucancopewitherrorswhentheydohappen,sothatyoupreventusersfromseeingyourcodingmistakes.

Finally,youlookatthedebuggingtoolsinMicrosoft’sInternetExplorer(IE11),Firebug(anadd-onforFirefox),Chrome’sWebInspector,andOpera’sDragonfly.Youseehowyoucanusethesetoolstostepthroughyourcodeandcheckthecontentsofvariableswhilethecodeisrunning,aprocessthatenablesyoutohuntfordifficultbugs.YoualsotakeabrieferlookatthedebuggingtoolsavailableforFirefox.

D’OH!ICAN’TBELIEVEIJUSTDIDTHAT:SOMECOMMONMISTAKESSeveralcommonmistakesaremadebyprogrammers.Someoftheseyou’lllearntoavoidasyoubecomemoreexperienced,butothersmayhauntyouforever!

UndefinedVariablesJavaScriptisactuallyveryeasygoingwhenitcomestodefiningyourvariablesbeforeassigningvaluestothem.Forexample,thefollowingwillimplicitlycreatethenewglobalvariableabcandassignittothevalue23:

abc=23;

Althoughstrictlyspeaking,youshoulddefinethevariableexplicitlywiththevarkeywordlikethis:

varabc=23;

Yourchoiceofwhethertousethevarkeywordtodeclareavariablehasaconsequenceonthevariable’sscope;soitisalwaysbesttousethevarkeyword.Ifavariableisusedbeforeithasbeendefined,anerrorwillarise.Forexample,thefollowingcodewillcausetheerrorshowninFigure18.1inIE11ifthevariableabchasnotbeenpreviouslydefined(explicitlyorimplicitly):

Figure18.1

alert(abc);

Inotherbrowsers,you’llneedtolookintheJavaScriptconsole,whichyoucanviewby

pressingCtrl+Shift+Jonyourkeyboard.Youcanalsoviewtheconsolebynavigatingthroughthebrowser’smenu.Youlearnhowtodothislater.

Inaddition,youmustrememberthatfunctiondefinitionsalsohaveparameters,whichifnotdeclaredcorrectlycanleadtothesametypeoferror.

Takealookatthefollowingcode:

functionfoo(parametrOne){

alert(parameterOne);

}

Ifyoucallthisfunction,yougetanerrormessagesimilartotheoneshowninFigure18.2.

Figure18.2

Theerrorhereisactuallyasimpletypointhefunctiondefinition.Thefunction’sparametershouldreadparameterOne,notparametrOne.Whatcanbeconfusingwiththistypeoferroristhatalthoughthebrowsertellsustheerrorisononeline,thesourceoftheerrorisonanotherline.

CaseSensitivityThisisamajorsourceoferrors,particularlybecauseitcanbedifficulttospotattimes.

Forexample,spotthethreecaseerrorsinthefollowingcode:

varmyName="Jeremy";

If(myName=="jeremy"){

alert(myName.toUppercase());

}

Thefirsterroristheifkeyword;thecodeabovehasIfratherthanif.However,JavaScriptwon’ttellusthattheerrorisanincorrectuseofcase,butinsteadthebrowser

willtellusObjectexpectedorthatIfisnotdefined.Althougherrormessagesgiveussomeideaofwhat’sgonewrong,theyoftendosoinanobliqueway.InthiscasethebrowserthinksyouareeithertryingtouseanobjectcalledIforuseanundefinedfunctioncalledIf.

NOTEDifferentbrowsersusedifferentwordingwhendisplayingerrors.Theoverallmeaningisthesame,however,soyoucanidentifywhattheproblemis.

Okay,withthaterrorclearedup,youcometothenexterror,notoneofJavaScriptsyntax,butalogicerror.RememberthatJeremydoesnotequaljeremyinJavaScript,somyName=="jeremy"isfalse,eventhoughit’squitelikelythatyoudidn’tcarewhetherthewordisJeremyorjeremy.ThistypeoferrorwillresultinnoerrormessageatallbecauseitisvalidJavaScript;youronlyclueisthatyourcodewillnotexecuteasyou’dplanned.

ThethirdfaultiswiththetoUpperCase()methodoftheStringobject.ThepreviouscodeusestoUppercase,withtheCinlowercase.IEgivesusthemessageObjectdoesn'tsupportthispropertyormethodandFirefoxreportsthatmyName.toUppercaseisnotafunction.OnfirstglanceitwouldbeeasytomisssuchasmallmistakeandstartcheckingyourJavaScriptreferenceguideforthatmethod.Youmightwonderwhyit’sthere,butyourcodeisnotworking.Again,youalwaysneedtobeawareofcase,somethingthatevenexpertsgetwrongfromtimetotime.

IncorrectNumberofClosingBracesInthefollowingcode,youdefineafunctionandthencallit.However,there’sadeliberatemistake.Seeifyoucanspotwhereitis:

functionmyFunction()

{

varx=1;

vary=2;

if(x<=y)

{

if(x==y)

{

alert("xequalsy");

}

}

myFunction();

Thisiswhyformattingyourcodeisimportant—you’llhaveamucheasiertimespottingerrorssuchasthis:

functionmyFunction(){

varx=1;

vary=2;

if(x<=y){

if(x==y){

alert("xequalsy");

}

}

myFunction();

Nowyoucanseethattheendingcurlybraceofthefunctionismissing.Whenyouhavealotofif,for,ordowhilestatements,it’seasytohavetoomanyortoofewclosingbraces.Thistypeofproblemismucheasiertospotwithformattedcode.

IncorrectNumberofClosingParenthesesSimilarly,nothavingthecorrectnumberofclosingparenthesescanbeproblematic.Takealookatthefollowingcode:

if(myVariable+12)/myOtherVariable<myString.length)

Spotthemistake?Theproblemisthemissingparenthesisatthebeginningofthecondition.YouwantmyVariable+12tobecalculatedbeforethedivisionbymyOtherVariableiscalculated,soquiterightlyyouknowyouneedtoputitinparentheses:

(myVariable+12)/myOtherVariable

However,theifstatement’sconditionmustalsobeinparentheses.Notonlyistheinitialparenthesismissing,butthereisonemoreclosingparenthesisthanopeningparentheses.Likecurlybraces,eachopeningparenthesismusthaveaclosingparenthesis.Thefollowingcodeiscorrect:

if((myVariable+12)/myOtherVariable<myString.length)

It’sveryeasytomissaparenthesisorhaveonetoomanywhenyouhavemanyopeningandclosingparentheses.

UsingEquals(=)RatherthanEquality(==)Theequalityoperatorisacommonlyconfusedoperator.Considerthefollowingcode:

varmyNumber=99;

if(myNumber=101){

alert("myNumberis101");

}else{

alert("myNumberis"+myNumber);

}

Atfirstglance,you’dexpectthatthecodeinsidetheelsestatementwouldexecute,tellingusthatthenumberinmyNumberis99.Itwon’t.Thiscodemakestheclassicmistakeofusingtheassignmentoperator(=)insteadoftheequalityoperator(==).Hence,insteadofcomparingmyNumberwith101,thiscodesetsmyNumbertoequal101.

WhatmakesthingseventrickieristhatJavaScriptdoesnotreportthisasanerror;it’svalidJavaScript!Theonlyindicationthatsomethingisn’tcorrectisthatyourcodedoesn’twork.Assigningavariableavalueinanifstatementmaylooklikeanerror,butit’sperfectlylegal.

Whenembeddedinalargechunkofcode,amistakelikethisiseasilyoverlooked.Justrememberit’sworthcheckingforthiserrorthenexttimeyourprogramdoesn’tdowhatyouexpect.Debuggingyourcodecanhelpeasilyspotthistypeoferror.Youlearnhowtodebugyourcodelaterinthischapter.

UsingaMethodasaPropertyandViceVersaAnothercommonerroriswhereeitheryouforgettoputparenthesesafteramethodwithnoparameters,oryouuseapropertyanddoputparenthesesafterit.

Whencallingamethod,youmustalwayshaveparenthesesfollowingitsname;otherwise,JavaScriptthinksthatitmustbeapointertothemethodoraproperty.Forexample,examinethefollowingcode:

varnowDate=newDate();

alert(nowDate.getMonth);

ThefirstlinecreatesaDateobject,andthesecondlineusesitsgetMonthproperty.ButyouknowthatDateobjectsdonothaveagetMonthproperty;it’ssupposedtobeamethod.Now,thisisvalidJavaScriptbecauseyoucanpassafunctionpointer—whichiswhatnowDate.getMonthis—toanotherfunction,andassuch,thebrowserwillnothaveanyissuesexecutingthiscode.Andinmanycases,youwanttodothat(likewhenregisteringeventlisteners).ButchancesareverygoodthatweintendedtocallgetMonth().Therefore,thefollowingisthecorrectedcode:

varnowDate=newDate();

alert(nowDate.getMonth());

NOTEToperhapsconfusetheissue:technically,JavaScriptdoesn’thavemethods.Whatwethinkofasmethodsareactuallyfunctionsassignedtoanobject’sproperties.Butit’sgenerallyacceptedtousethetermmethodtodescribesuchproperties.

Similarly,anothercommonmistakeistotypeparenthesesafteraproperty,makingJavaScriptthinkthatyouaretryingtouseamethodofthatobject:

varmyString="Hello,World!";

alert(myString.length());

Thesecondlineusesthelengthpropertyasamethod,andJavaScriptwillattempttotreatitasone.Whenthiscodeexecutes,youwillseeanerrorbecauselengthcannotbecalledasamethod.Thiscodeshouldhavebeenwrittenlikethis:

varmyString=newString("Hello");

alert(myString.length);

MissingPlusSignsDuringConcatenationOrdinarily,stringconcatenationisastraightforwardprocess,butitcanbecomeconfusingwhenworkingwithmanyvariablesandvalues.Forexample,there’sadeliberate

concatenationmistakeinthefollowingcode.Spotit:

varmyName="Jeremy";

varmyString="Hello";

varmyOtherString="World";

myString=myName+"said"+myString+""myOtherString;

alert(myString);

Thereshouldbea+operatorbetween""andmyOtherStringinthefinallineofcode.

Althougheasytospotinjustafewlines,thiskindofmistakecanbemoredifficulttospotinlargechunksofcode.Also,theerrormessagethistypeofmistakecausescanbemisleading.Loadthiscodeintoabrowserandyouyou’llbetoldError:Expected';'byIE,Missing;beforestatementbyFirefox,andSyntaxError:UnexpectedidentifierinChrome.It’ssurprisinghowoftenthiserrorcropsup.

Thesemostcommonmistakesareerrorscausedbytheprogrammer.Othertypesoferrors,calledruntimeerrors,occurwhenyourcodeexecutesinthebrowser,andtheyaren’tnecessarilycausedbyatypooramissingcurlybraceorparenthesis.Runtimeerrorscanstillbeplannedfor,asyouseeinthenextsection.

ERRORHANDLINGWhenwritingyourprograms,youwanttobeinformedofeveryerror.However,thelastthingsyouwanttheusertoseeareerrormessageswhenyoufinallydeploythecodetoawebserverforthewholeworldtoaccess.Ofcourse,writingbug-freecodewouldbeagoodstart,butkeepthefollowingpointsinmind:

Conditionsbeyondyourcontrolcanleadtoerrors.AgoodexampleofthisiswhenyouarerelyingonAjaxtotalktothewebserver,andsomethinghappenstotheuser’snetworkconnection.

Murphy’sLawstatesthatanythingthatcangowrongwillgowrong!

PreventingErrorsThebestwaytohandleerrorsistostopthemfromoccurringinthefirstplace.Thatseemslikestatingtheobvious,butyoushoulddoanumberofthingsifyouwanterror-freepages:

Thoroughlycheckpagesinasmanybrowsersaspossible.Thisiseasiersaidthandoneonsomeoperatingsystems.Thealternativeisforyoutodecidewhichbrowsersyouwanttosupportforyourwebpage,andthenverifythatyourcodeworksinthem.

Validateyourdata.Ifuserscanenterduddatathatwillcauseyourprogramtofail,thentheywill.Makesurethatatextboxhasdataenteredintoitifyourcodefailswhenthetextboxisempty.Ifyouneedawholenumber,makesurethattheuserenteredone.Isthedatetheuserjustenteredvalid?Isthee-mailaddressmindyourownbusinesstheuserjustenteredlikelytobevalid?No,[email protected].

Okay,solet’ssayyoucarefullycheckedyourpagesandthereisnotasyntaxorlogicerrorinsight.Youaddeddatavalidationthatconfirmsthateverythingtheuserentersisinavalidformat.Thingscanstillgowrong,andproblemsmayarisethatyoucandonothingabout.Here’sareal-worldexampleofsomethingthatcanstillgowrong.

OneprofessionalcreatedanonlinemessageboardthatreliesonasmallJavaapplettoenablethetransferofdatatoandfromtheserverwithoutreloadingthepage(thiswasbeforeAjax).Hecheckedthecodeandeverythingwasfine,anditcontinuedtoworkfineafterlaunchingtheboard,exceptthatinaboutfivepercentofcasestheJavaappletinitializedbutthencausedanerrorduetotheuserbeingbehindaparticulartypeoffirewall(afirewallisameansofstoppingintrudersfromgettingintoalocalcomputernetwork,andmanyblockJavaappletsbecauseofJava’ssecurityissues).It’simpossibletodeterminewhetherauserisbehindacertaintypeoffirewall,sothereisnothingthatcanbedoneinthatsortofexceptionalcircumstance.Oristhere?

Infact,JavaScriptincludessomethingcalledthetry…catchstatement.Thisenablesyoutotrytorunyourcode;ifitfails,theerroriscaughtbythecatchclauseandcanbedealtwithasyouwish.Forthemessageboard,thisprofessionalusedatry…catchclausetocatchtheJavaapplet’sfailureandredirectedtheusertoamorebasicpagethatstill

displayedmessages,butwithoutusingtheapplet.

Thetry…catchStatementsThetry…catchstatementsworkasapair;youcan’thaveonewithouttheother.Youusethetrystatementtodefineablockofcodethatyouwanttotrytoexecute,andusethecatchstatementtodefineablockofcodethatexecuteswhenanexceptionoccursinthetrystatement.Thetermexceptioniskeyhere;itmeansacircumstancethatisextraordinaryandunpredictable.Comparethatwithanerror,whichissomethinginthecodethathasbeenwrittenincorrectly.Ifnoexceptionoccurs,thecodeinsidethecatchstatementneverexecutes.Thecatchstatementalsoenablesyoutogetthecontentsoftheexceptionmessagethatwouldhavebeenshowntotheuserhadyounotcaughtitfirst.

Let’screateasimpleexampleofatry…catchclause:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Example1</title>

</head>

<body>

<script>

try{

alert("Thisiscodeinsidethetryclause");

alert("NoErrorssocatchcodewillnotexecute");

}catch(exception){

alert("Theerroris"+exception.message);

}

</script>

</body>

</html>

Savethisasch18_example1a.htmlandopenitinyourbrowser.

Thiscodedefinesthetrystatement,andaswithallotherblocksofcode,youmarkoutthetryblockbyenclosingitincurlybraces.

Immediatelyfollowingthetryblockisthecatchstatement,andnoticethatitincludesexceptioninsideasetofparentheses.Thisexceptionissimplyavariablename,anditstoresanobjectthatcontainsinformationaboutanyexceptionthatmayoccurinsidethetrycodeblock.We’llcallthisobjecttheexceptionobject.Althoughthewordexceptionisusedhere,youcanuseanyvalidvariablename.Forexample,catch(ex)wouldbefine.

Theexceptionobjectcontainsseveralpropertiesthatprovideinformationabouttheexceptionthatoccurred,butthemostcommonlyusedpropertiesarenameandmessage.Theaptlynamednamepropertycontainsthenameoftheerrortype,andthemessagepropertycontainstheerrormessagetheuserwouldnormallysee.

Backtothecodeathand,withinthecatchblockisthecodethatexecuteswhenanexceptionoccurs.Inthiscase,thecodewithinthetryblockwillnotthrowanexception,andsothecodeinsidethecatchblockwillneverexecute.

Butlet’sinsertadeliberateerror.Changethehighlightedlineinthefollowingcode:

try{

alert("Thisiscodeinsidethetryclause");

ablert("NoErrorssocatchcodewillnotexecute");

}catch(exception){

alert("Theerroris"+exception.message);

}

Savethedocumentasch18_example1b.htmlandopenitinyourbrowser.

Thebrowserwillstartexecutingthiscodeasnormal.Itwillexecutethefirstcalltoalert()insidethetryblockanddisplaythemessagetotheuser.However,thecalltoablert()willcauseanexception.Thebrowserwillstopexecutingthetryblock,andinsteadwillstartexecutingthecatchblock.You’llseeamessagesimilarto“Theerrorisablertisnotdefined.”

Let’schangethiscodeonceagaintointroduceadifferenterror.Asbefore,modifythehighlightedlineinthefollowingcode:

try{

alert("Thisiscodeinsidethetryclause");

alert('Thiscodewon'twork');

}catch(exception){

alert("Theerroris"+exception.message);

}

Savethisasch18_example1c.htmlandopenitinyourbrowser.Youwillnotseeanyalertboxbecausethiscodecontainsasyntaxerror;thefunctionsandmethodsarevalid,butyouhaveaninvalidcharacter.Thesinglequoteinthewordwon'thasendedthestringvaluebeingpassedtoalert().

Beforeexecutinganycode,theJavaScriptenginegoesthroughallthecodeandchecksforsyntaxerrors,orcodethatbreachesJavaScript’srules.Iftheenginefindsasyntaxerror,thebrowserdealswithitasusual;yourtryclauseneverrunsandthereforecannothandlesyntaxerrors.

ThrowingErrorsYoucanusethethrowstatementtocreateyourownruntimeexceptions.Whycreateastatementtogenerateanexception,whenabitofbadcodingwilldothesame?

Throwingerrorscanbeveryusefulforindicatingproblemssuchasinvaliduserinput.Ratherthanusinglotsofif…elsestatements,youcancheckthevalidityofuserinput,thenusethrowtostopcodeexecutioninitstracksandcausetheerror-catchingcodeinthecatchblockofcodetotakeover.Inthecatchclause,youcandeterminewhethertheerrorisbasedonuserinput,inwhichcaseyoucannotifytheuserwhatwentwrongandhowtocorrectit.Alternatively,ifit’sanunexpectederror,youcanhandleitmoregracefullythanwithlotsofJavaScripterrors.

Youcanthrowanything;fromasimplestringornumbertoanobject.Inmostcases,however,you’llthrowanobject.Tousethrow,typethrowandincludetheobjectafterit.Forexample,ifyouarevalidatingasetofformfields,yourexceptionobjectcouldcontain

notonlythemessage,buttheidoftheelementthathasinvaliddata.Anexamplecouldlooklikethis:

throw{

message:"Pleasetypeavalidemailaddress",

elementId:"txtEmail"

};

Theobjectsyouthrowshouldincludeatleastamessageproperty;mosterror-handlingcodewillbelookingforit.

TRYITOUTtry…catchandThrowingErrorsInthisexampleyoumodifych16_example2.htmltousethetry…catchandthrowstatementstovalidatethee-mailandusernamefields.Feelfreetousech16_example2.htmlasabasisforthisnewfile.Foryourconvenience,thefollowingcodelistinghighlightsthekeychanges:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Example2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="jquery-2.1.1.min.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("#username").val();

try{

if(!userValue){

throw{

message:"Pleaseenterausernametocheck!"

};

}

varparms={

username:userValue

};

$.getJSON("ch14_formvalidator.php",

parms).done(handleResponse);

}catch(ex){

alert(ex.message);

}

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("#email").val();

try{

if(!emailValue){

throw{

message:"Pleaseenteranemailaddressto

check!"

};

}

varparms={

email:emailValue

};

$.getJSON("ch14_formvalidator.php",

parms).done(handleResponse);

}catch(ex){

alert(ex.message);

}

}

functionhandleResponse(response){

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

$("#usernameAvailability").on("click",checkUsername);

$("#emailAvailability").on("click",checkEmail);

</script>

</body>

</html>

RememberthatthisexamplereliesuponAjaxinordertowork;so,besuretosavethispageasch18_example2.htmlinyourwebserver’sroot.Incaseyouhaven’tsetupawebserveryet,seeChapter14formoreinformation.

Youknowhowthisexampleworks,sowe’llfocusonlyonthehighlightedcode.

Let’sfirstlookatthecheckUsername()function.Ithasbeenrewrittentousethetry…catchandthrowstatementsforvalidatingtheusername<input/>element,andthemajorityofthisfunction’scoderesideswithinthetryblock:

try{

if(!userValue){

throw{

message:"Pleaseenterausernametocheck!"

};

}

varparms={

username:userValue

};

$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);

}

BeforeyoumaketheAjaxrequest,youfirstensuretheuserprovidedavaluetotheusernamefield.IfuserValueisblank,youthrowanewobjectdetailingthecauseoftheexceptionwithitsmessageproperty.ThiscausestheJavaScriptenginetostopexecutingcodeinthistryblockandstartsexecutingthecatchblock:

catch(ex){

alert(ex.message);

}

Here,yousimplyalerttheexception’smessageproperty,displayingthe“Pleaseenterausernametocheck!”messagetotheuser.

Naturally,thechangesmadetothecheckEmail()functionarealmostidenticaltocheckUsername():

try{

if(!emailValue){

throw{

message:"Pleaseenteranemailaddresstocheck!"

};

}

varparms={

email:emailValue

};

$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);

}catch(ex){

alert(ex.message);

}

Onceagain,themajorityofthefunctioncoderesideswithinatrycodeblock.Ifthee-mailfieldvalidationfails,youthrowanobjectcontainingtheexceptionmessageanddisplaythatmessageinanalertbox—theresultofexecutingthecodeinthecatchblock.

Nestedtry…catchStatementsSofaryou’vebeenusingjustonetry…catchstatement,butit’spossibletoincludeatry…catchstatementinsideanothertrystatement.Indeed,youcangofurtherandhaveatry…catchinsidethetrystatementofthisinnertry…catch,orevenanotherinsidethat,thelimitbeingwhatit’sactuallysensibletodo.

Sowhywouldyouusenestedtry…catchstatements?Well,youcandealwithcertainerrorsinsidetheinnertry…catchstatement.If,however,you’redealingwithamoreseriouserror,theinnercatchclausecouldpassthaterrortotheoutercatchclausebythrowingtheerrortoit.

Here’sanexample:

try{

try{

ablurt("Thiscodehasanerror");

}catch(exception){

varname=exception.name;

if(name=="TypeError"||name=="ReferenceError"){

alert("Innertry…catchcandealwiththiserror");

}else{

throwexception;

}

}

}catch(exception){

alert("Theinnertry…catchcouldnothandletheexception.");

}

Inthiscodeyouhavetwotry…catchpairs,onenestedinsidetheother.

Theinnertrystatementcontainsalineofcodethatcontainsanerror.Thecatchstatementoftheinnertry…catchchecksthevalueoftheerror’sname.Iftheexception’snameiseitherTypeErrororReferenceError,theinnertry…catchdealswithitbywayofanalertbox(seeAppendixBforafulllistoferrortypesandtheirdescriptions).Unfortunately,andunsurprisingly,thetypeoferrorthrownbythebrowserdependsonthebrowseritself.Intheprecedingexample,IEreportstheerrorasaTypeErrorwhereastheotherbrowsersreportitasaReferenceError.

Iftheerrorcaughtbytheinnercatchstatementisanyothertypeoferror,itisthrownupintheairagainforthecatchstatementoftheoutertry…catchtodealwith.

finallyClausesThetry…catchstatementhasafinallyclausethatdefinesablockofcodethatalwaysexecutes—evenifanexceptionwasn’tthrown.Thefinallyclausecan’tappearonitsown;itmustbeafteratryblock,whichthefollowingcodedemonstrates:

try{

ablurt("Anexceptionwilloccur");

}catch(exception){

alert("Exceptionoccurred");

}finally{

alert("Thislinealwaysexecutes");

}

Thefinallypartisagoodplacetoputanycleanupcodethatneedstoexecuteregardlessofanyexceptionsthatpreviouslyoccurred.

You’veseenthetopmistakesmadebydevelopers,andyou’vealsoseenhowtohandle

errorsinyourcode.Unfortunately,errorswillstilloccurinyourcode,solet’stakealookatonewaytomakeremedyingthemeasierbyusingadebugger.

DEBUGGINGJavaScriptistraditionallylookeduponasadifficultlanguagetowriteanddebugduetothelackofdecentdevelopmenttools.This,however,isnolongerthecasethankstothetoolsmadeavailablethroughthebrowser:thedebuggingtoolsavailableforInternetExplorer,Firefox,Chrome,andOpera.Withthesetools,youcanhalttheexecutionofyourscriptwithbreakpointsandthenstepthroughcodelinebylinetoseeexactlywhatishappening.

Youcanalsofindoutwhatdataisbeingheldinvariablesandexecutestatementsonthefly.Withoutdebuggers,thebestyoucandoisusethealert()methodinyourcodetoshowthestateofvariablesatvariouspoints.

Debuggingisgenerallyuniversalacrossallbrowsers,andevenlanguages.Somedebuggingtoolsmayoffermorefeaturesthanothers,butforthemostpart,thefollowingconceptsapplytoanydebugger:

Breakpointstellthedebuggeritshouldbreak,orpausecodeexecution,atacertainpoint.YoucansetabreakpointanywhereinyourJavaScriptcode,andthedebuggerwillhaltcodeexecutionwhenitreachesthebreakpoint.

Watchesenableyoutospecifyvariablesthatyouwanttoinspectwhenyourcodepausesatabreakpoint.

Thecallstackisarecordofwhatfunctionsandmethodshavebeenexecutedtothebreakpoint.

TheconsoleenablesyoutoexecuteJavaScriptcommandsinthecontextofthepageandwithinthescopeofthebreakpoint.Inaddition,itcatalogsallJavaScripterrorsfoundinthepage.

Steppingisthemostcommonprocedureindebugging.Itenablesyoutoexecuteonelineofcodeatatime.Youcanstepthroughcodeinthreeways:

StepIntoexecutesthenextlineofcode.Ifthatlineisafunctioncall,thedebuggerexecutesthefunctionandhaltsatthefirstlineofthefunction.

StepOver,likeStepInto,executesthenextlineofcode.Ifthatlineisafunction,StepOverexecutestheentirefunctionandhaltsatthefirstlineoutsidethefunction.

StepOutreturnstothecallingfunctionwhenyouareinsideacalledfunction.StepOutresumestheexecutionofcodeuntilthefunctionreturns.Itthenbreaksatthereturnpointofthefunction.

Beforedelvingintothevariousdebuggers,let’screateapageyoucandebug:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Example3</title>

</head>

<body>

<script>

functionwriteTimesTable(timesTable){

varwriteString;

for(varcounter=1;counter<12;counter++){

writeString=counter+"*"+timesTable+"=";

writeString=writeString+(timesTable*counter);

writeString=writeString+"<br/>";

document.write(writeString);

}

}

writeTimesTable(2);

</script>

</body>

</html>

Savethisasch18_example3.html.Youwillneedtoopenthisfileineachbrowserinordertodebugit.

ThenextsectionwalksyouthroughthefeaturesandfunctionalityofChrome’sJavaScriptdebugger.Becauseoftheuniversalnatureofdebugginganddebuggers,thesectionsforInternetExplorer,Firefox,andSafariwillmerelyfamiliarizeyouwiththeUIforeachbrowser’sdebuggerandpointoutanydifferences.

DebugginginChrome(andOpera)ChromeandOperausethesamerenderingandJavaScriptengine,andassuch,theyalsosharethesamedevelopmenttools.Forthesakeofsimplicity,thissectionfocusesonChrome,butkeepinmindthatOperaisexactlythesame.

YoucanaccessChrome’sdevelopertoolsacoupleofways.Youcanclickthe“hamburgermenu”inthetopright-handcornerofthewindowandselectMoreTools➢Developerstools.YoucanalsoopenthembypressingtheF12key.

NOTEYou’llfindthatF12opensthedevelopertoolsinalmosteverybrowser.

Bydefault,theDevelopertoolsopensasapanelinChrome(seeFigure18.3).

Figure18.3

YoucanpopitouttoitsownwindowbyclickingtheiconnexttotheClosebutton.

Opench18_example3.html(eitherfromyourcomputerortheweb)inChromeandopenChrome’sdevelopertools.

TheJavaScriptdebuggeriscontainedintheSourcestab,anditismadeupofthreepanels(Figure18.4).Theleftpanelcontainsthelistofsourcestochoosefrom.You’llonlyseeonesourceavailableinthischapterbecausethereisonlyonefileloadedbythebrowser.ButifyouloadapagewithmultipleexternalJavaScriptfiles,you’llfindeachofthemlistedintheleftpanel.

Figure18.4

Thecenterpanelcontainsthesourcecodeoftheselectedfile,andit’sherethatyou’llsetbreakpointsandstepthroughcode.Thecodedisplayedinthispanelisread-only;ifyouwanttochangeit,youhavetoeditthefileinyourtexteditorandreloadthepage.

Therightpanelcontainsseveraldifferentsubpanels.Inthischapter,wefocusonBreakpoints,ScopeVariables,WatchExpressions,andCallStack:

Breakpoints:Listsallbreakpointsthatyou’vecreatedforthecodeinthecurrentpage

ScopeVariables:Liststhevariablesandtheirvaluesinscopeofthebreakpoint

WatchExpressions:Liststhe“watches”thatyouspecify.Thesearetypicallyvariablesand/orexpressionsthatyouwanttoinspectatabreakpoint.

CallStack:Displaysthecallstack

SettingBreakpointsAsmentionedearlier,breakpointstellthedebuggertopausecodeexecutionataspecificpointinyourcode.Thisisusefulwhenyouwanttoinspectyourcodewhileitexecutes.

Creatingbreakpointsisstraightforward.Simplyleft-clickthelinenumber,andChromehighlightsthelinenumberwithabluetagicon.ThishighlightdenotesabreakpointinChrome.

Youcanalsohard-codeabreakpointbyusingthedebuggerkeyworddirectlyinyourcode(we’llusethisabitlater).

Setabreakpointonline13:

writeString=writeString+(timesTable*counter);

Reloadthepage,andnoticeChromepausedcodeexecutionatthenewlycreatedbreakpoint.Chromehighlightsthecurrentlineofcodeinblue.Thislinehasn’tbeenexecutedyet.

LookattheBreakpointsintherightpanel;itshowsyouthelistofbreakpoints(onlyoneinthiscase).Eachentryinthelistconsistsofacheckboxtoenable/disablethebreakpoint,thefilenameandlinenumberofthesourcefile,andthesourcetextofthebreakpoint.

NowlookattheScopeVariables.

ScopeVariablesandWatchesTheScopeVariablespanedisplaysvariablesandtheirvaluescurrentlyinscopeatthecurrentline.Figure18.5showsthecontentsoftheScopeVariablespaneatthisbreakpoint.

Figure18.5

Noticethatthecounter,timesTable,andwriteStringvariablesarevisible(asisthis).

NowlookattheWatchExpressionspane.Therearecurrentlynowatchexpressions,butyoucanaddthembysimplyclickingtheaddicon(theplussign).Typethevariablenameorexpressionyouwanttowatch,andpresstheEnterkey.

Goaheadandcreateawatchexpressionforcounter==1.You’llseeyourexpressionfollowedbyacolonandthevalueoftheexpression.Atthispointintime,youshouldseethefollowingasshowninFigure18.6:

Figure18.6

counter==1:true

Ifthewatchisinscope,theexpression’svalueisdisplayed.Ifthevariableisoutofscope,

you’llsee“notavailable.”

Althoughthisinformationishelpfulwhenyouwanttoseewhatexactlyisgoingoninyourcode,it’snotveryhelpfulifyoucan’tcontrolcodeexecution.It’simpracticaltosetabreakpointandreloadthepagemultipletimesjusttoadvancetothenextline,soweuseaprocesscalledstepping.

SteppingthroughCodeCodesteppingiscontrolledbyfourbuttonsintheupper-rightofthedevelopertools(Figure18.7).

Continue(shortcutkeyisF8):Itsfunctionistocontinuecodeexecutionuntileitherthenextbreakpointortheendofallcodeisreached.

StepOver(F10):Thisexecutesthecurrentlineofcodeandmovestothenextstatement.However,ifthestatementisafunction,itexecutesthefunctionandstepstothenextlineafterthefunctioncall.

StepInto(shortcutkeyisF11):Executesthecurrentlineofcodeandmovestothenextstatement.Ifthecurrentlineisafunction,itstepstothefirstlineofthefunction.

StepOut(Shift-F11):Returnstothecallingfunction.

Figure18.7

Let’sdosomestepping;followthesesteps:

1. StepIntothecodebyclickingtheiconorpressingF11.Thedebuggerexecutesthecurrentlyhighlightedlineofcodeandmovestothenextline.

2. LookatthevalueofwriteStringintheScopeVariablespane;itis"1*2=2".Asyoucansee,thevaluesdisplayedintheWatchtabareupdatedinrealtime.

3. OnenicefeatureofChrome’sdevelopertoolsisthepageupdates,ifnecessary,asyoustepthroughcode.ClickStepIntotwomoretimestoseethisinaction.Figure18.8showsthepageupdatedwhilesteppingthroughcode.

Figure18.8

Youmayfindthatthefunctionyousteppedintoisnotthesourceofthebug,inwhichcaseyouwanttoexecutetheremaininglinesofcodeinthefunctionsothatyoucancontinuesteppingafterthefunction.DosobyclickingtheStepOuticontostepoutofthecode.However,ifyou’reinaloopandthebreakpointissetinsidetheloop,youwillnotstepoutofthefunctionuntilyouiteratethroughtheloop.

Theremayalsobetimeswhenyouhavesomebuggycodethatcallsanumberoffunctions.Ifyouknowthatsomeofthefunctionsarebug-free,youmaywanttojustexecutethosefunctionsinsteadofsteppingintothem.UseStepOverinthesesituationstoexecutethecodewithinafunctionbutwithoutgoingthroughitlinebyline.

Alteryourtimes-tablecodeinch18_example3.htmlasfollowssoyoucanuseitforthethreekindsofstepping:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Example4</title>

</head>

<body>

<script>

functionwriteTimesTable(timesTable){

varwriteString;

for(varcounter=1;counter<12;counter++){

writeString=counter+"*"+timesTable+"=";

writeString=writeString+(timesTable*counter);

writeString=writeString+"<br/>";

document.write(writeString);

}

}

for(vartimesTable=1;timesTable<=12;timesTable++){

document.write("<p>");

writeTimesTable(timesTable);

document.write("</p>");

}

</script>

</body>

</html>

Savethisasch18_example4.htmlandopenitinyourbrowser.Thefollowinginstructionswalkyouthroughtheprocessofsteppingthroughcode:

1. Setabreakpointinline19,theforloopinthebodyofthepage,andreloadthepage.

2. ClicktheStepIntoiconandcodeexecutionmovestothenextstatement.Nowthefirststatementinsidetheforloop,document.write("<p>"),isupforexecution.

3. WhenyouclicktheStepIntoiconagain,ittakesyoutothenextline(thefirstcallingofthewriteTimesTable()function).

4. Youwanttoseewhat’shappeninginsidethatfunction,soclickStepIntoagaintostepintothefunction.YourscreenshouldlooksimilartoFigure18.9.

5. ClicktheStepIntoiconafewtimestogetthegistoftheflowofexecutionofthefunction.Infact,steppingthroughcodelinebylinecangetalittletedious.Solet’simagineyou’rehappywiththisfunctionandwanttoruntherestofit.

6. UseStepOuttoruntherestofthefunction’scode.You’rebacktotheoriginalforloop,andthedebuggerispausedonline22,asyoucanseefromFigure18.10.

7. ClicktheStepIntoicontoexecutedocument.write()(itwon’tbevisiblebecauseit’saclosingtag).

8. ClickStepIntofourmoretimes.Executioncontinuesthroughtheconditionandincrementspartsoftheforloop,endingbackatthelinethatcallswriteTimesTable().

9. You’vealreadyseenthiscodeinaction,soyouwanttostepoverthisfunction.Well,noprizesforguessingthatStepOveriswhatyouneedtodo.ClicktheStepOvericon(orpresstheF10key)andthefunctionexecutes,butwithoutsteppingthroughitstatementbystatement.Youshouldfindyourselfbackatthedocument.write("</p>")line.

Figure18.9

Figure18.10

Ifyou’vefinisheddebugging,youcanruntherestofthecodewithoutsteppingthrougheachlinebyclickingtheContinueicon(orpressingF8)onthetoolbar.Youshouldseeapageoftimestablesfrom1*1=1to11*12=132inthebrowser.

TheConsoleWhileyou’resteppingthroughcodeandcheckingitsflowofexecution,itwouldbereally

usefultoevaluateconditionsandeventochangethingsonthefly.Youcandothesethingsusingtheconsole.Followthesesteps:

1. Removethepreviouslysetbreakpointbyclickingitandsetanewbreakpointatline15:

document.write(writeString);

2. Let’sseehowyoucanfindoutthevaluecurrentlycontainedinthevariablewriteString.Reloadthepage.Whenthedebuggerstopsatthebreakpoint,clicktheConsoletabandtypethenameofthevariableyouwanttoexamine,inthiscasewriteString.PresstheEnterkey.Thiscausesthevaluecontainedinthevariabletobeprintedbelowyourcommandinthecommandwindow,asshowninFigure18.11.

3. Ifyouwanttochangeavariable,youcanwritealineofJavaScriptintothecommandwindowandpressEnter.Tryitwiththefollowingcode:

writeString="ChangedontheFly<br/>";

4. ClicktheSourcestab,removethebreakpoint,andthenclicktheContinueicon.Youseetheresultsofyouractions:Wherethe1*1timestableresultshouldbe,thetextyouchangedontheflyhasbeeninserted.

Figure18.11

NOTEThisalterationdoesnotchangeyouractualHTMLsourcefile.

Theconsolecanalsoevaluateconditions.Setabreakpointonline20andreloadthepage.Leaveexecutionstoppedatthebreakpoint,andStepIntotheforloop’scondition.

GototheConsole,typethefollowing,andpressEnter:

timesTable<=12

Becausethisisthefirsttimetheloophasbeenrun,asshowninFigure18.12,timesTableisequalto1sotheconditiontimesTable<=12evaluatestotrue.

Figure18.12

YoucanalsousetheconsoletoaccesspropertiesoftheBOMandDOM.Forexample,ifyoutypelocation.hrefintotheconsoleandpressEnter,itwilltellyouthewebpage’sURL.

NOTEYoucanevaluateanyJavaScriptintheconsole,anditexecuteswithinthescopeofthepageand/orbreakpoint.Thismakestheconsoleanextremelypowerfultool.

CallStackWindowWhenyouaresingle-steppingthroughthecode,thecallstackwindowkeepsarunninglistofwhichfunctionshavebeencalledtogettothecurrentpointofexecutioninthecode.

Let’screateanexamplewebpagetodemonstratethecallstack.Openyourtexteditorandtypethefollowing:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Example5</title>

</head>

<body>

<inputtype="button"value="Button"name="button1"id="button1"/>

<script>

functionfirstCall(){

secondCall();

}

functionsecondCall(){

thirdCall();

}

functionthirdCall(){

//

}

functionbuttonClick(){

debugger;

firstCall();

}

document.getElementById("button1")

.addEventListener("click",buttonClick);

</script>

</body>

</html>

Savethisfileasch18_example5.htmlandopenitinChrome.You’llseeapagewithasimplebutton.Withthedevelopmenttoolsopen,clickthebuttonandexaminetheCallStackpane.YoushouldseesomethinglikeFigure18.13.

Figure18.13

Chromeaddsthefunctiontothetopofthecallstackforeveryfunctioncall.Itdisplaysthenameofthefunction,thefilethefunctionresidesin,andthelinenumberofthecurrentlyexecutingstatementwithinthefunction.YoucanalreadyseethatthefirstfunctioncalledwasbuttonClick(),itisinsidech18_example5.html,andtheexecutionisatline24.

NowStepIntotwice,andyou’llbetakeninsidethefirstCall()function.Onceagain,examinetheCallStackpane,andyou’llseesomethingsimilartoFigure18.14.

Figure18.14

YoucanclickeachentryintheCallStackpanetoexaminewheretheJavaScriptengineiscurrentlyexecutingineachofthefunctions.IfyouclickthebuttonClickentry,thedevelopertoolshighlightline25,thelineinsideofbuttonClick()thatiscurrentlyexecuting.

NowstepintosecondCall(),andanotherentryisaddedtothecallstack.OnemoresteptakesyouintothirdCall(),againwithitsnamebeingaddedtothetopofthecallstack.

StepIntoagain,andasyouleavethethirdCall()youwillseethatitscorrespondingentryisremovedfromthetopofthecallstack.YetanothersteptakesyououtofsecondCall().Eachadditionalsteptakesyououtofafunctionandremovesitsnamefromthecallstack,untileventuallyallthecodehasbeenexecuted.

Thisdemopagewasverysimpletofollow,butwithcomplexpages,thecallstackcanproveveryusefulfortrackingwhereyouare,whereyouhavebeen,andhowyougotthere.

Asmentionedearlier,mostotherdevelopertoolsforotherbrowsersaresimilartoChrome’sdevelopertoolsinfunctionality,butasyou’llsoonseewithIE11,thetoolscanlookabitdifferent.

DebugginginInternetExplorerBeforeversion8,developershadtodownloadandinstalltheMicrosoftScriptDebuggerforanytypeofscriptdebugging.Thankfully,MicrosoftbuiltadebuggerintoIE8,andeverysubsequentversionincludesasuiteoftoolstoeaseourlives.

Youcanaccessthedebuggerinacoupleofways,theeasiestbeingtopresstheF12key.However,youcanalsobringupthedevelopmenttoolsbyclickingthe“gear”menuandchoosingtheF12DeveloperToolsoption.

Bydefault,theF12DeveloperToolsopensasapanelwithinthebrowserwindow(Figure18.15),butaswithChrome’stools,youcanpopitoutwiththeiconnexttotheClosebutton.

Figure18.15

AsyoucantellfromFigure18.15,IE’stoolsarelaidoutmuchdifferentlythanChrome’s.Ontheleft-handside,youseealistoficons.Thetwoweareconcernedwitharethesecondandthirdicons:theconsole(Figure18.16)anddebugger(Figure18.17),respectively.

Figure18.16

Figure18.17

AsyoucanseeinFigure18.17,thedebuggerismadeupoftwopanels.Theleftdisplaysthesourcecodeofthefile,anditusesatabbedinterfacetodisplaythesourceofmultiplefiles.IfmultiplefilescontainJavaScript,youcanopentheminanewtabusingthefileselectionbutton.

Therightpanelcontainstwosubpaneltabs:

Watches:Liststhevariables/expressionsandtheirvaluesyouspecifytowatchatthebreakpoint.Thisalsodisplaysthevariablesinscope.

Breakpoints/CallStack:Listsallbreakpointsthatyou’vecreatedforthecodeinthecurrentpage.Youcanclick“CallStack”todisplaythecallstack.

Nowloadch18_example4.html,andyou’llseethetimestableinyourwebpage.

SettingBreakpointsCreatingabreakpointintheF12DeveloperToolsisassimpleandstraightforwardasitisinChrome,exceptthatinsteadofclickingthelinenumber,youwanttoclickthegrayareatotheleftofthelinenumber(thegutter).

Setabreakpointonline12.Breakpointsaredenotedbyaredcircleinthegutter,andnoticethatanentrywasaddedinthelistofbreakpointsinthebreakpointssubpanel(Figure18.18).Eachentryconsistsofacheckboxtoenable/disablethebreakpoint,thefilenameofthesourcefile,andthelinenumberthebreakpointison(italsodisplaysthecolumnofthatline).

Figure18.18

AddingWatchesTheWatchespanelliststhevariablesandexpressionsyouwanttowatch,aswellasthevariablesinscope.AddingawatchisverysimilartoChrome;simplyclickthenewwatchiconandtypethevariableorexpressionyouwanttowatch.Figure18.19showsawatchfortheexpressioncounter==1whenthedebuggerispausedonline12.

Figure18.19

SteppingthroughCodeAtthetopofthedebuggerwindowisasetofbuttonsthatcontrolcodeexecution(seeFigure18.20).

Figure18.20

TheContinueoption(shortcutkeyF5orF8)continuescodeexecutionuntileitherthenext

breakpointortheendofallcode.Thesecondoption,Break,letsyoupauseexecution.Thisisusefulifyoufindyourselfinaninfiniteloop.NextaretheStepInto(F11),StepOver(F10),andStepOut(Shift+11)buttons.

TheF12DeveloperToolsdebuggerdenotesthecurrentlinebyhighlightingthelineinyellowandaddsayellowarrowinthegutter.ButunlikeChrome,steppingthroughcodedoesnotupdatethewebpage.TheJavaScriptexecutes,butyouwillnotseetheresultsuntilallcodeisexecuted.

TheConsoleTheconsolelogsJavaScripterrorsandenablesyoutoexecutecodewithinthecontextofthelineatwhichthedebuggerisstopped.Figure18.21showsthe“ChangedontheFly”example.

Figure18.21

DebugginginFirefoxwithFirebugFirefox’sstoryisaninterestingonebecauseitstoolsetisrelativelynewtothebrowser.Formanyyears,Firefoxdidnothavenativedevelopertools.Instead,developersrelieduponaFirefoxextensioncalledFirebug,whichwasthefirstsuiteofbrowser-baseddevelopertools.ThetoolsweuseineverybrowsertodayaredirectlyinspiredbyFirebug.

EventhoughFirefoxhasitsownsetofbuilt-intools,theystilllackalotoffeaturesfoundinFirebug(andotherbrowsers’tools).Soforthissection,youneedtodownloadandinstalltheFirebugextension.

ToinstallFirebug,openFirefoxandgotohttp://www.getfirebug.com.ClicktheInstallbuttononthewebpageandfollowtheinstructions.Inmostcases,youwillnotneedto

restartFirefox.

YoucanaccessFirebugbyclickingtheFirebugiconinthetoolbar(Figure18.22).YoucanalsoaccessadropdownmenubyclickingthedownarrownexttotheFirebugicontorevealadditionalsettings.Manypanelsaredisabledbydefault,soclickingontheEnableAllPanelsoptionisveryuseful.

Figure18.22

TheJavaScriptdebuggeriscontainedintheScripttab,anditismadeupoftwopanels.Theleftpanelcontainsthesourcecode,andtherightpanelcontainsthreedifferentviewstochoosefrom:Watch,Stack,andBreakpoints.

SettingBreakpointsCreatingbreakpointsinFirebugiseasy;simplyleft-clickthelinenumberorthegutter.Breakpointsaredenotedbyaredcircleinthegutter.

TheBreakpointstabintherightpanedisplaysthelistofbreakpointsyouhavecreated,anditshowsalltheinformationyouexpect:thefilename,thecodeatthatbreakpoint,andthelinenumber.Figure18.23showsabreakpointonline12.

Figure18.23

NowclicktheWatchtab.

WatchesTheWatchtabdisplaysvariablesandtheirvaluescurrentlyinscopeatthecurrentline,andyoucanaddyourownwatchbyclicking“Newwatchexpression…,”typingthevariableorexpressionyouwanttowatch,andpressingtheEnterkey.Watchesthatyouaddhaveagraybackground,andmovingyourmouseoverthemrevealsaredDeletebutton(Figure18.24).

Figure18.24

SteppingthroughCodeAtthetopofthedebuggerwindowaretheiconsforsteppingthroughcode(seeFigure18.25).

Figure18.25

TheContinuebutton(F8)isfirst,followedbyStepInto(F11).NextaretheStepOver(F10)andStepOut(Shift+11)buttons.

Asyoustepthroughcode,youcantellthecurrentstatementbyitsyellowhighlight.Firebugalsousesayellowarrowintheguttertoindicatethecurrentline.LikeChrome,steppingthroughcodeupdatesthewebpage.

TheConsoleFirebugprovidesaconsolewindowwiththeConsoletab(Figure18.26),anditworksliketheconsolefoundinChromeandIE.Youcaninspectanyvariableorexpressionwithinthecontextofthescopeorpage,andyoucanuseittoexecuteJavaScript.

Figure18.26

DebugginginSafariSafari’sstoryissimilartoIE’s.Safari’srenderingengineiscalledWebkit,andthefolksthatwriteandmaintainWebkitbuiltaseparatetool,codenamedDrosera,thatcontainedthetoolssimilartotheotherbrowsers.Itwasaseparatedownload,anditrequiredyouto

attachittoaspecificSafari/Webkitwindow.Today,SafariincludesatoolcalledWebInspector,anditprovidesthefunctionalityyouwouldexpectfromabrowser-basedsuiteoftools.

Safari’sWebInspectorisdisabledbydefault.Toenableit,followthesesteps:

1. ClicktheSettingsmenubuttonandchoosethePreferencesoption(seeFigure18.27).

2. InthePreferenceswindow,clicktheAdvancedtabandselecttheShowDevelopMenuinMenuBaroption(seeFigure18.28).ClosethePreferenceswindow.

3. ClicktheSettingsmenubuttonandselecttheShowMenuBaroption.Thisdisplaysthetraditionalmenusatthetopofthewindow.

4. Toopenthedebugger,selectDevelop➢StartDebuggingJavaScriptfromthemenubar.

Figure18.27

Figure18.28

Let’slookatthewindowandidentifytheseparateparts.Figure18.29showstheJavaScriptdebuggerwhenitwasfirstopenedonthech18_example4.htmlfile.

Figure18.29

Safari’sWebInspectorlooksalotlikeChrome’s,doesn’tit?That’sbecauseChromeisbuiltusingaheavilymodifiedversionofWebKit.TheScriptstabismuchlikeChrome’sSourcestab;youcanseethecode,watchexpressions,callstack,scopevariables,andbreakpointsallatonetime.

SettingBreakpointsCreatingabreakpointfollowsthesameprocedureinWebInspectorasChrome:Clickthelinenumberatwhichyouwantthedebuggertobreak.BreakpointsinWebInspectorare

denotedbythesamebluetagusedinChrome.Createoneonline12.Thebreakpoints’subsectionliststhebreakpointsyoucreate,anditdisplaysthesameinformationyouexpectitto.

AddingWatchesInearlierversions,WebInspectordidnotallowyoutoaddwatches.ButinSafari5,youcancreatewatchestoinspectvariablesandexpressions.SimplyclicktheAddbuttontocreateyourwatch.Figure18.30showsthewatchcounter==1whenthedebuggerispausedonline12.

Figure18.30

Toremoveawatch,clicktheredXnexttoit.

SteppingthroughCodeThecode-steppingbuttonsareatthetopoftherightpanelandunderneaththesearchbox(seeFigure18.31).

Figure18.31

Thesebuttonsperformthesamefunctionsastheotherbrowsertools.Youhavethe

Continuebutton,followedbyStepOver,thenStepIn,andfinallyStepOut.

LikeChromeandFirebug,WebInspectorupdatesthepageasyoustepthroughcode.Soyoucanseetheresultsaseachlineexecutes.

TheConsoleTheconsoleservesthesamepurposeasitdoesintheprevioustools.YoucancheckthevalueofavariablebytypingthevariableandpressingtheEnterkey.Youcanalsoexecutecodeinthecontextofthecurrentlineofcode.Trythe“ChangedontheFly”exampletoseeitinaction.

SUMMARYInthischapteryoulookedatthelessexcitingpartofcoding,namelybugs.Inanidealworldyou’dgetthingsrightthefirsttime,everytime,butinrealityanycodemorethanafewlineslongislikelytosufferfrombugs.

Youfirstlookedatsomeofthemorecommonerrors,thosemadenotjustbyJavaScriptbeginners,butalsobyexpertswithlotsofexperience.

Someerrorsarenotnecessarilybugsinyourcode,butinfactexceptionstothenormalcircumstancesthatcauseyourcodetofail.Yousawthatthetry…catchstatementsaregoodfordealingwiththissortoferror,andthatyoucanusethecatchclausewiththethrowstatementtodealwithlikelyerrors,suchasthosecausedbyuserinput.Finally,yousawthatifyouwantablockofcodetoexecuteregardlessofanyerror,youcanusethefinallyclause.

YoulookedatthedebuggingtoolsfoundinChrome(andbyextensionOpera),InternetExplorer,FirebugforFirefox,andSafari.Withthesetoolsyoucananalyzecodeasitexecutes,whichenablesyoutoseeitsflowstepbystep,andtocheckvariablesandconditions.Andalthoughthesedebuggershavedifferentinterfaces,theirprinciplesareidentical.

EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.

1. Theexamplech18_example4.htmlhasadeliberatebug.Foreachtimestableitcreatesonlymultiplierswithvaluesfrom1to11.

Usethescriptdebuggertoworkoutwhythisishappening,andthencorrectthebug.

2. Thefollowingcodecontainsanumberofcommonerrors.Seeifyoucanspotthem:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Question2</title>

</head>

<body>

<formname="form1"action="">

<inputtype="text"id="text1"name="text1"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>

<br/>

<inputtype="text"id="text2"name="text2"/>

<p>

<inputtype="submit"value="Submit"id="submit1"name="submit1"

/>

</p>

</form>

<script>

functioncheckForm(e){

varelementCount=0;

vartheForm=document.form1;

while(elementCount=<=theForm.length){

if(theForm.elements[elementcount].type=="text"){

if(theForm.elements[elementCount].value()="")

alert("Pleasecompleteallformelements");

theForm.elements[elementCount].focus;

e.preventDefault();

break;

}

}

}

document.form1.addEventListener("submit",checkForm);

</script>

</body>

</html>

AAnswerstoExercisesThisappendixprovidestheanswerstothequestionsyoufindattheendofeachchapterinthisbook.

CHAPTER2

Exercise1QuestionWriteaJavaScriptprogramtoconvertdegreescentigradeintodegreesFahrenheit,andtowritetheresulttothepageinadescriptivesentence.TheJavaScriptequationforFahrenheittocentigradeisasfollows:

degFahren=9/5*degCent+32

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2:Question1</title>

</head>

<body>

<script>

vardegCent=prompt("Enterthedegreesincentigrade",0);

vardegFahren=9/5*degCent+32;

document.write(degCent+"degreescentigradeis"+degFahren+

"degreesFahrenheit");

</script>

</body>

</html>

Savethisasch2_question1.html.

Exercise2QuestionThefollowingcodeusestheprompt()functiontogettwonumbersfromtheuser.Itthenaddsthosetwonumbersandwritestheresulttothepage:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2,Question2</title>

</head>

<body>

<script>

varfirstNumber=prompt("Enterthefirstnumber","");

varsecondNumber=prompt("Enterthesecondnumber","");

vartheTotal=firstNumber+secondNumber;

document.write(firstNumber+"addedto"+secondNumber+

"equals"+theTotal);

</script>

</body>

</html>

However,ifyoutryoutthecode,you’lldiscoverthatitdoesn’twork.Whynot?Changethecodesothatitdoeswork.

Exercise2SolutionThedatathattheprompt()actuallyobtainsisastring.SobothfirstNumberandsecondNumbercontaintextthathappenstobenumbercharacters.Whenyouusethe+symboltoaddthetwovariablestogether,JavaScriptassumesthatbecauseit’sstringdata,youmustwanttoconcatenatethetwoandnotsumthem.

TomakeitexplicittoJavaScriptthatyouwanttoaddthenumbers,youneedtoconvertthedatatonumbersusingtheparseFloat()function:

varfirstNumber=parseFloat(prompt("Enterthefirstnumber",""));

varsecondNumber=parseFloat(prompt("Enterthesecondnumber",""));

vartheTotal=firstNumber+secondNumber;

document.write(firstNumber+"addedto"+secondNumber+"equals"+

theTotal);

Savethisasch2_question2.html.

Nowthedatareturnedbytheprompt()functionisconvertedtoafloating-pointnumberbeforebeingstoredinthefirstNumberandsecondNumbervariables.Then,whenyoudotheadditionthatisstoredintheTotal,JavaScriptmakesthecorrectassumptionthat,becauseboththevariablesarenumbers,youmustmeantoaddthemupandnotconcatenatethem.

Thegeneralruleisthatwhereyouhaveexpressionswithonlynumericaldata,the+operatormeans“doaddition.”Ifthereisanystringdata,the+meansconcatenate.

CHAPTER3

Exercise1QuestionAjuniorprogrammercomestoyouwithsomecodethatappearsnottowork.Canyouspotwherehewentwrong?Givehimahandandcorrectthemistakes.

varuserAge=prompt("Pleaseenteryourage");

if(userAge=0){;

alert("Soyou'reababy!");

}elseif(userAge<0|userAge>200)

alert("Ithinkyoumaybelyingaboutyourage");

else{

alert("That'sagoodage");

}

Exercise1SolutionOhdear,ourjuniorprogrammerishavingabadday!Therearetwomistakesontheline:

if(userAge=0){;

First,hehasonlyoneequalssigninsteadoftwointheif’scondition,whichmeansuserAgewillbeassignedthevalueof0ratherthanuserAgebeingcomparedto0.Thesecondfaultisthesemicolonattheendoftheline—statementssuchasifandloopssuchasforandwhiledon’trequiresemicolons.Thegeneralruleisthatifthestatementhasanassociatedblock(thatis,codeincurlybraces),nosemicolonisneeded.Sothelineshouldbe:

if(userAge==0){

Thenextfaultiswiththeselines:

elseif(userAge<0|userAge>200)

alert("Ithinkyoumaybelyingaboutyourage");

else{

Thejuniorprogrammer’sconditionisaskingifuserAgeislessthan0ORuserAgeisgreaterthan200.ThecorrectoperatorforabooleanORis││,buttheprogrammerhasonlyusedone|.

Exercise2QuestionUsingdocument.write(),writecodethatdisplaystheresultsofthe12timestable.Itsoutputshouldbetheresultsofthecalculations.

12*1=12

12*2=24

12*3=36…

12*11=132

12*12=144

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter3:Question2</title>

</head>

<body>

<script>

vartimesTable=12;

for(vartimesBy=1;timesBy<13;timesBy++){

document.write(timesTable+"*"+

timesBy+"="+

timesBy*timesTable+"<br/>");

}

</script>

</body>

</html>

Savethisasch3_question2.html.

Youuseaforlooptocalculatefrom1*12upto12*12.Theresultsarewrittentothepagewithdocument.write().What’simportanttonotehereistheeffectoftheorderofprecedence;theconcatenationoperator(the+)hasalowerorderofprecedencethanthemultiplicationoperator,*.ThismeansthatthetimesBy*timesTableisdonebeforetheconcatenation,whichistheresultyouwant.Ifthiswerenotthecase,you’dhavetoputthecalculationinparenthesestoraiseitsorderofprecedence.

CHAPTER4

Exercise1QuestionChangethecodeofQuestion2fromChapter3sothatit’safunctionthattakesasparametersthetimestablerequiredandthevaluesatwhichitshouldstartandend.Forexample,youmighttrythefourtimestabledisplayedstartingwith4*4andendingat4*9.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter4:Question1</title>

</head>

<body>

<script>

functionwriteTimesTable(timesTable,timesByStart,timesByEnd){

for(;timesByStart<=timesByEnd;timesByStart++){

document.write(timesTable+"*"+timesByStart+"="+

timesByStart*timesTable+"<br/>");

}

}

writeTimesTable(4,4,9);

</script>

</body>

</html>

Savethisasch4_question1.html.

You’vedeclaredyourfunction,callingitwriteTimesTable(),andgivenitthreeparameters.Thefirstisthetimestableyouwanttowrite,thesecondisthestartpoint,andthethirdisthenumberitshouldgoupto.

You’vemodifiedyourforloop.Firstyoudon’tneedtoinitializeanyvariables,sotheinitializationpartisleftblank—youstillneedtoputasemicolonin,butthere’snocodebeforeit.TheforloopcontinueswhilethetimesByStartparameterislessthanorequaltothetimesByEndparameter.Youcanseethat,aswithavariable,youcanmodifyparameters—inthiscase,timesByStartisincrementedbyoneforeachiterationthroughtheloop.

Thecodetodisplaythetimestableismuchthesame.Forthefunction’scodetobeexecuted,younowactuallyneedtocallit,whichyoudointheline:

writeTimesTable(4,4,9);

Thiswillwritethe4timestablestartingat4times4andendingat9times4.

Exercise2QuestionModifythecodeofQuestion1torequestthetimestabletobedisplayedfromtheuser;thecodeshouldcontinuetorequestanddisplaytimestablesuntiltheuserenters-1.Additionally,doachecktomakesurethattheuserisenteringavalidnumber;ifthenumberisnotvalid,asktheusertore-enterit.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter4:Question2</title>

</head>

<body>

<script>

functionwriteTimesTable(timesTable,timesByStart,timesByEnd){

for(;timesByStart<=timesByEnd;timesByStart++){

document.write(timesTable+"*"+timesByStart+"="+

timesByStart*timesTable+"<br/>");

}

}

vartimesTable;

while((timesTable=prompt("Enterthetimestable",-1))!=-1){

while(isNaN(timesTable)==true){

timesTable=prompt(timesTable+"isnota"+

"validnumber,pleaseretry",-1);

}

if(timesTable==-1){

break;

}

document.write("<br/>The"+timesTable+

"timestable<br/>");

writeTimesTable(timesTable,1,12);

}

</script>

</body>

</html>

Savethisasch4_question2.html.

Thefunctionremainsthesame,solet’slookatthenewcode.ThefirstchangefromQuestion1isthatyoudeclareavariable,timesTable,andtheninitializeitintheconditionofthefirstwhileloop.Thismayseemlikeastrangethingtodoatfirst,butitdoeswork.Thecodeinparenthesesinsidethewhileloop’scondition:

(timesTable=prompt("Enterthetimestable",-1))

isexecutedfirstbecauseitsorderofprecedencehasbeenraisedbytheparentheses.This

willreturnavalue,anditisthisvaluethatiscomparedto-1.Ifit’snot-1,thenthewhileconditionistrue,andthebodyoftheloopexecutes.Otherwiseit’sskippedover,andnothingelsehappensinthispage.

Inasecondwhileloopnestedinsidethefirst,youchecktoseethatthevaluetheuserhasenteredisactuallyanumberusingthefunctionisNaN().Ifit’snot,youprompttheusertotryagain,andthiswillcontinueuntilavalidnumberisentered.

Iftheuserhadenteredaninvalidvalueinitially,theninthesecondwhileloop,thatusermayhaveentered-1,sofollowingthewhileisanifstatementthatcheckstoseeif-1hasbeenentered.Ifithas,youbreakoutofthewhileloop;otherwisethewriteTimesTable()functioniscalled.

CHAPTER5

Exercise1QuestionUsingtheDatetype,calculatethedate12monthsfromnowandwritethisintoawebpage.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5:Question1</title>

</head>

<body>

<script>

varmonths=["Jan","Feb","Mar","Apr","May","Jun",

"Jul","Aug","Sep","Oct","Nov","Dec"];

varnowDate=newDate();

nowDate.setMonth(nowDate.getMonth()+12);

document.write("Date12monthsaheadis"+nowDate.getDate());

document.write(""+months[nowDate.getMonth()]);

document.write(""+nowDate.getFullYear());

</script>

</body>

</html>

Savethisasch5_question1.html.

BecausethegetMonth()methodreturnsanumberbetween0and11forthemonthratherthanitsname,anarraycalledmonthshasbeencreatedthatstoresthenameofeachmonth.YoucanusegetMonth()togetthearrayindexforthecorrectmonthname.

ThevariablenowDateisinitializedtoanewDateobject.Becausenoinitialvalueisspecified,thenewDateobjectwillcontaintoday’sdate.

Toadd12monthstothecurrentdateyousimplyusesetMonth().YougetthecurrentmonthvaluewithgetMonth(),andthenadd12toit.

Finallyyouwritetheresultouttothepage.

Exercise2QuestionObtainalistofnamesfromtheuser,storingeachnameenteredinanarray.Keepgettinganothernameuntiltheuserentersnothing.Sortthenamesinascendingorderandthenwritethemouttothepage,witheachnameonitsownline.

Exercise2Solution

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5:Question2</title>

</head>

<body>

<script>

varinputName="";

varnamesArray=[];

while((inputName=prompt("Enteraname",""))!=""){

namesArray[namesArray.length]=inputName;

}

namesArray.sort();

varnamesList=namesArray.join("<br/>");

document.write(namesList);

</script>

</body>

</html>

Savethisasch5_question2.html.

Firstyoudeclaretwovariables:inputName,whichholdsthenameenteredbytheuser,andnamesArray,whichholdsanArrayobjectthatstoreseachofthenamesentered.

Youuseawhilelooptokeepgettinganothernamefromtheuseraslongastheuserhasn’tleftthepromptboxblank.Notethattheuseofparenthesesinthewhileconditionisessential.Byplacingthefollowingcodeinsideparentheses,youensurethatthisisexecutedfirstandthatanameisobtainedfromtheuserandstoredintheinputNamevariable:

(inputName=prompt("Enteraname",""))

Thenyoucomparethevaluereturnedinsidetheparentheses—whateverwasenteredbytheuser—withanemptystring(denotedby"").Iftheyarenotequal—thatis,iftheuserdidenteravalue,youlooparoundagain.

Now,tosortthearrayintoorder,youusethesort()methodoftheArrayobject:

namesArray.sort();

Finally,tocreateastringcontainingallvaluescontainedinthearrayelementswitheachbeingonanewline,youusetheHTML<br/>elementandwritethefollowing:

varnamesList=namesArray.join("<br/>")

document.write(namesList);

ThecodenamesArray.join("<br/>")createsthestringwherea<br/>isbetweeneachelementinthearray.Finally,youwritethestringintothepagewithdocument.write().

Exercise3Question

Example8usesafunctiontocreateobjectsusingliteralnotation.ModifythisexampletousethePersondatatype.

Exercise3Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter5,Question3</title>

</head>

<body>

<script>

functionPerson(firstName,lastName){

this.firstName=firstName;

this.lastName=lastName;

}

Person.prototype.getFullName=function(){

returnthis.firstName+""+this.lastName;

};

Person.prototype.greet=function(person){

alert("Hello,"+person.getFullName()+

".I'm"+this.getFullName());

};

varjohnDoe=newPerson("John","Doe");

varjaneDoe=newPerson("Jane","Doe");

johnDoe.greet(janeDoe);

</script>

</body>

</html>

Savethisasch5_question3.html.

ThisisasimplematterofreplacingthecreatePerson()functionwiththePersonreferencetypeyoudefinedattheendofChapter5.

TocreateyourPersonobjects,youusethenewoperatorwhencallingthePersonconstructorfunction,passinginthefirstandlastnamesofthepeopleyouwanttorepresent.

CHAPTER6

Exercise1QuestionWhatproblemdoesthefollowingcodesolve?

varmyString="Thissentencehashasafaultandandweneedtofixit."

varmyRegExp=/(\b\w+\b)\1/g;

myString=myString.replace(myRegExp,"$1");

Nowimaginethatyouchangethatcode,sothatyoucreatetheRegExpobjectlikethis:

varmyRegExp=newRegExp("(\b\w+\b)\1");

Whywouldthisnotwork,andhowcouldyourectifytheproblem?

Exercise1SolutionTheproblemisthatthesentencehas“hashas”and“andand”insideit,clearlyamistake.Alotofwordprocessorshaveanautocorrectfeaturethatfixescommonmistakeslikethis,andwhatyourregularexpressiondoesismimicthisfeature.

SotheerroneousmyString:

“Thissentencehashasafaultandandweneedtofixit.”

willbecome:

“Thissentencehasafaultandweneedtofixit.”

Let’slookathowthecodeworks,startingwiththeregularexpression:

/(\b\w+\b)\1/g;

Byusingparentheses,youhavedefinedagroup,so(\b\w+\b)isgroup1.Thisgroupmatchesthepatternofawordboundaryfollowedbyoneormorealphanumericcharacters,thatis,a–z,A–Z,0–9,and_,followedbyawordboundary.Followingthegroupyouhaveaspacethen\1.What\1meansismatchexactlythesamecharactersaswerematchedinpatterngroup1.So,forexample,ifgroup1matched“has,”then\1willmatch“has”aswell.It’simportanttonotethat\1willmatchtheexactpreviousmatchbygroup1.Sowhengroup1thenmatchesthe“and,”the\1nowmatches“and”andnotthe“has”thatwaspreviouslymatched.

Youusethegroupagaininyourreplace()method;thistimethegroupisspecifiedusingthe$symbol,so$1matchesgroup1.It’sthisthatcausesthetwomatched“has”and“and”tobereplacedbyjustone.

Turningtothesecondpartofthequestion,howdoyouneedtochangethefollowingcodesothatitworks?

varmyRegExp=newRegExp("(\b\w+\b)\1");

Easy;nowyouareusingastringpassedtotheRegExpobject’sconstructor,andyouneedtousetwoslashes(\\)ratherthanonewhenyoumeanaregularexpressionsyntaxcharacter,likethis:

varmyRegExp=newRegExp("(\\b\\w+\\b)\\1","g");

Noticeyou’vealsopassedagtothesecondparametertomakeitaglobalmatch.

Exercise2QuestionWritearegularexpressionthatfindsalloftheoccurrencesoftheword“a”inthefollowingsentenceandreplacesthemwith“the”:

“adogwalkedinoffastreetandorderedafinestbeer”

Thesentenceshouldbecome:

“thedogwalkedinoffthestreetandorderedthefinestbeer”

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6:Question2</title>

</head>

<body>

<script>

varmyString="adogwalkedinoffastreetand"+

"orderedafinestbeer";

varmyRegExp=/\ba\b/gi;

myString=myString.replace(myRegExp,"the");

alert(myString);

</script>

</body>

</html>

Savethisasch6_question2.html.

Withregularexpressions,it’softennotjustwhatyouwanttomatch,butalsowhatyoudon’twanttomatchthatisaproblem.Hereyouwanttomatchthelettera,sowhynotjustwrite:

varmyRegExp=/a/gi;

Well,thatwouldwork,butitwouldalsoreplacethe“a”in“walked,”whichyoudon’twant.Youwanttoreplacetheletter“a”butonlywhereit’sawordonitsownandnotinsideanotherword.Sowhendoesaletterbecomeaword?Theansweriswhenit’sbetweentwowordboundaries.Thewordboundaryisrepresentedbytheregularexpressionspecialcharacter\bsotheregularexpressionbecomes:

varmyRegExp=/\ba\b/gi;

Thegiattheendensuresaglobal,case-insensitivesearch.

Nowwithyourregularexpressioncreated,youcanuseitinthereplace()method’sfirstparameter:

myString=myString.replace(myRegExp,"the");

Exercise3QuestionImagineyouhaveawebsitewithamessageboard.Writearegularexpressionthatwouldremovebarredwords.(Youcanmakeupyourownwords!)

Exercise3Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter6:Question3</title>

</head>

<body>

<script>

varmyRegExp=/(sugar)?candy|choc(olate|oholic)?/gi;

varmyString="Mmm,Ilovechocolate,I'machocoholic."+

"Ilovecandytoo,sweet,sugarcandy";

myString=myString.replace(myRegExp,"salad");

alert(myString);

</script>

</body>

</html>

Savethisasch6_question3.html.

Forthisexample,pretendyou’recreatingscriptforaboardonadietingsitewheretextrelatingtocandyisbarredandwillbereplacedwithamuchhealthieroption,salad.

Thebarredwordsare

chocolate

choc

chocoholic

sugarcandy

candy

Let’sexaminetheregularexpressiontoremovetheoffendingwords:

1. Startwiththetwobasicwords,sotomatch“choc”or“candy,”youuse:

candy|choc

2. Addthematchingfor“sugarcandy.”Becausethe“sugar”bitisoptional,yougroupit

byplacingitinparenthesesandaddingthe“?”afterit.Thismeansmatchthegroupzerotimesoronetime:

(sugar)?candy|choc

3. Youneedtoaddtheoptional“olate”and“oholic”endbits.Youaddtheseasagroupafterthe“choc”wordandagainmakethegroupoptional.Youcanmatcheitheroftheendingsinthegroupbyusingthe|character:

(sugar)?candy|choc(olate|oholic)?/gi

4. Youthendeclareitas:

varmyRegExp=/(sugar)?candy|choc(olate|oholic)?/gi

Thegiattheendmeanstheregularexpressionwillfindandreplacewordsonaglobal,case-insensitivebasis.

So,tosumup:

/(sugar)?candy|choc(olate|oholic)?/gi

readsas:

Eithermatchzerooroneoccurrencesof“sugar”followedby“candy.”Oralternativelymatch“choc”followedbyeitheroneorzerooccurrencesof“olate”ormatch“choc”followedbyzerooroneoccurrenceof“oholic.”

Finally,thefollowing:

myString=myString.replace(myRegExp,"salad");

replacestheoffendingwordswith“salad”andsetsmyStringtothenewcleanversion:

"Mmm,Ilovesalad,I'masalad.Ilovesaladtoo,sweet,salad."

CHAPTER7

Exercise1QuestionCreateapagethatgetstheuser’sdateofbirth.Then,usingthatinformation,tellheronwhatdayoftheweekshewasborn.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7:Question1</title>

</head>

<body>

<script>

vardays=["Sunday","Monday","Tuesday","Wednesday",

"Thursday","Friday","Saturday"];

varyear=prompt("Enterthefourdigityearyouwereborn.");

varmonth=prompt("Enteryourbirthmonth(1-12).");

vardate=prompt("Enterthedayyouwereborn.");

varbirthDate=newDate(year,month-1,date);

alert(days[birthDate.getDay()]);

</script>

</body>

</html>

Savethisasch7_question1.html.

Thesolutionisrathersimple.YoucreateanewDateobjectbasedontheyear,month,anddayenteredbytheuser.ThenyougetthedayoftheweekusingtheDateobject’sgetDay()method.Thisreturnsanumber,butbydefininganarrayofdaysoftheweektomatchthisnumber,youcanusethevalueofgetDay()astheindextoyourdaysarray.

Exercise2QuestionCreateawebpagesimilartoExample4,butmakeitdisplayonlythehour,minutes,andseconds.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter7,Question2</title>

</head>

<body>

<divid="output"></div>

<script>

functionupdateTime(){

vardate=newDate();

varvalue=date.getHours()+":"+

date.getMinutes()+":"+

date.getSeconds();

document.getElementById("output").innerHTML=value;

}

setInterval(updateTime,1000);

</script>

</body>

</html>

Savethisasch7_question2.html.

Displayingonlythehour,minutes,andsecondsisaneasytask;itjustrequiresalittleextracode.YoumodifytheupdateTime()functiontofirstcreateaDateobjecttogetthetimeinformationfrom.

vardate=newDate();

Thenyoubuildastringinhh:mm:ssformat:

varvalue=date.getHours()+":"+

date.getMinutes()+":"+

date.getSeconds();

Finally,yououtputthatstringtothepage:

document.getElementById("output").innerHTML=value;

CHAPTER8

Exercise1QuestionCreatetwopages,onecalledlegacy.htmlandtheothercalledmodern.html.Eachpageshouldhaveaheadingtellingyouwhatpageisloaded.Forexample:

<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>

Usingfeaturedetectionandthelocationobject,sendbrowsersthatdonotsupportgeolocationtolegacy.html;sendbrowsersthatdosupportgeolocationtomodern.html.

Exercise1SolutionThemodern.htmlpageisasfollows:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2:Question1</title>

</head>

<body>

<h2>WelcometotheModernpage!</h2>

<script>

if(!navigator.geolocation){

location.replace("legacy.html");

}

</script>

</body>

</html>

Thelegacy.htmlpageisverysimilar:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter2:Question1</title>

</head>

<body>

<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>

<script>

if(navigator.geolocation){

location.replace("modern.html");

}

</script>

</body>

</html>

Thesetwopagesareincrediblysimple.Startingwiththelegacy.htmlpage,youcheckifnavigator.geolocationisatruthyvalue:

if(navigator.geolocation){

location.replace("modern.html");

}

Ifitis,youredirecttheusertothemodern.htmlpage.Notethatyouusereplace()ratherthanhref,becauseyoudon’twanttheusertobeabletoclickthebrowser’sBackbutton.Thiswayit’slesseasytospotthatanewpageisbeingloaded.

Themodern.htmlpageisalmostidentical,exceptthatinyourifstatementyoucheckifnavigator.geolocationisfalsey:

if(!navigator.geolocation){

location.replace("legacy.html");

}

Ifso,youredirecttolegacy.html.

Exercise2QuestionModifyExample3todisplayoneofthefourimagesrandomly.Hint:refertoChapter5andtheMath.random()method.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter8,Question2</title>

</head>

<body>

<imgsrc=""width="200"height="150"alt="MyImage"/>

<script>

functiongetRandomNumber(min,max){

returnMath.floor(Math.random()*max)+min;

}

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

varrandom=getRandomNumber(0,myImages.length);

document.images[0].src=myImages[random];

</script>

</body>

</html>

Savethisasch8_question2.html.

Thekeytothissolutionisgettingarandomnumberbetween0andthelengthofthe

myImagesarray,andwritingafunctiontogeneratearandomnumberwouldgreatlyhelpwiththat.So,youwriteafunctioncalledgetRandomNumber():

functiongetRandomNumber(min,max){

returnMath.floor(Math.random()*max)+min;

}

Itgeneratesarandomnumberwithintherangeofminandmax.ThealgorithmwascopiedfromChapter5.

NowyoucanusegetRandomNumber()togenerateanumberforyou,passing0astheminandthelengthofthearrayasthemax:

varrandom=getRandomNumber(0,myImages.length);

Youthenusetherandomnumbertogettheimage:

document.images[0].src=myImages[random];

CHAPTER9

Exercise1QuestionHere’ssomeHTMLcodethatcreatesatable.Re-createthistableusingonlyJavaScriptandthecoreDOMobjectstogeneratetheHTML.Testyourcodeinallbrowsersavailabletoyoutomakesureitworksinthem.Hint:Commenteachlineasyouwriteittokeeptrackofwhereyouareinthetreestructure,andcreateanewvariableforeveryelementonthepage(forexample,notjustoneforeachoftheTDcellsbutninevariables).

<table>

<tr>

<td>Car</td>

<td>TopSpeed</td>

<td>Price</td>

</tr>

<tr>

<td>Chevrolet</td>

<td>120mph</td>

<td>$10,000</td>

</tr>

<tr>

<td>Pontiac</td>

<td>140mph</td>

<td>$20,000</td>

</tr>

</table>

Exercise1SolutionItseemsaratherdauntingexample,butratherthanbeingdifficult,itisjustaconjunctionoftwoareas,onebuildingatreestructureandtheothernavigatingthetreestructure.Youstartatthe<body/>elementandcreatea<table/>element.Nowyoucannavigatetothenew<table/>elementyou’vecreatedandcreateanew<tr/>elementandcarryonfromthere.It’salengthy,repetitious,andtediousprocess,sothat’swhyit’sagoodideatocommentyourcodetokeeptrackofwhereyouare.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9:Question1</title>

</head>

<body>

<script>

vartableElem=document.createElement("table");

vartrElem1=document.createElement("tr");

vartrElem2=document.createElement("tr");

vartrElem3=document.createElement("tr");

vartdElem1=document.createElement("td");

vartdElem2=document.createElement("td");

vartdElem3=document.createElement("td");

vartdElem4=document.createElement("td");

vartdElem5=document.createElement("td");

vartdElem6=document.createElement("td");

vartdElem7=document.createElement("td");

vartdElem8=document.createElement("td");

vartdElem9=document.createElement("td");

vartextNodeA1=document.createTextNode("Car");

vartextNodeA2=document.createTextNode("TopSpeed");

vartextNodeA3=document.createTextNode("Price");

vartextNodeB1=document.createTextNode("Chevrolet");

vartextNodeB2=document.createTextNode("120mph");

vartextNodeB3=document.createTextNode("$10,000");

vartextNodeC1=document.createTextNode("Pontiac");

vartextNodeC2=document.createTextNode("140mph");

vartextNodeC3=document.createTextNode("$14,000");

vardocNavigate=document.body;//Startswithbodyelement

docNavigate.appendChild(tableElem);//Addsthetableelement

docNavigate=docNavigate.lastChild;//Movestothetableelement

docNavigate.appendChild(trElem1);//AddstheTRelement

docNavigate=docNavigate.firstChild;//MovestheTRelement

docNavigate.appendChild(tdElem1);//AddsthefirstTDelementinthe

//heading

docNavigate.appendChild(tdElem2);//AddsthesecondTDelementin

the

//heading

docNavigate.appendChild(tdElem3);//AddsthethirdTDelementinthe

//heading

docNavigate=docNavigate.firstChild;//MovestothefirstTDelement

docNavigate.appendChild(textNodeA1);//Addsthesecondtextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeA2);//Addsthesecondtextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeA3);//Addsthethirdtextnode

docNavigate=docNavigate.parentNode;//MovesbacktotheTRelement

docNavigate=docNavigate.parentNode;//Movesbacktothetableelement

docNavigate.appendChild(trElem2);//AddsthesecondTRelement

docNavigate=docNavigate.lastChild;//MovestothesecondTRelement

docNavigate.appendChild(tdElem4);//AddstheTDelement

docNavigate.appendChild(tdElem5);//AddstheTDelement

docNavigate.appendChild(tdElem6);//AddstheTDelement

docNavigate=docNavigate.firstChild;//MovestothefirstTDelement

docNavigate.appendChild(textNodeB1);//Addsthefirsttextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeB2);//Addsthesecondtextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeB3);//Addsthethirdtextnode

docNavigate=docNavigate.parentNode;//MovesbacktotheTRelement

docNavigate=docNavigate.parentNode;//Movesbacktothetableelement

docNavigate.appendChild(trElem3);//AddstheTRelement

docNavigate=docNavigate.lastChild;//MovestotheTRelement

docNavigate.appendChild(tdElem7);//AddstheTDelement

docNavigate.appendChild(tdElem8);//AddstheTDelement

docNavigate.appendChild(tdElem9);//AddstheTDelement

docNavigate=docNavigate.firstChild;//MovestotheTDelement

docNavigate.appendChild(textNodeC1);//Addsthefirsttextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeC2);//Addsthesecondtextnode

docNavigate=docNavigate.nextSibling;//MovestothenextTDelement

docNavigate.appendChild(textNodeC3);//Addsthethirdtextnode

</script>

</body>

</html>

Savethisasch9_question1.html.

Exercise2QuestionModifyExample6sothattheamountofpixelsmovedineitherdirectioniscontrolledbyaglobalvariable.Callitdirection.RemovetheswitchDirectionvariable,andchangethecodetousethenewdirectionvariabletodeterminewhentheanimationshouldchangedirections.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter9,Question2</title>

<style>

#divAdvert{

position:absolute;

font:12pxArial;

top:4px;

left:0px;

}

</style>

</head>

<body>

<divid="divAdvert">

Hereisanadvertisement.

</div>

<script>

vardirection=2;

functiondoAnimation(){

vardivAdvert=document.getElementById("divAdvert");

varcurrentLeft=divAdvert.offsetLeft;

if(currentLeft>400||currentLeft<0){

direction=-direction;

}

varnewLocation=currentLeft+direction;

divAdvert.style.left=newLocation+"px";

}

setInterval(doAnimation,10);

</script>

</body>

</html>

Savethisasch9_question2.html.

Thismodificationsoundscomplexatfirst,butitactuallysimplifiesthedoAnimation()functionbecauseonevariableisresponsiblefor:

theamountofpixelsmoved

thedirectiontheelementismoved

First,youremovetheswitchDirectionvariableandcreateanewonecalleddirection,initializingitwiththevalueof2:

vardirection=2;

TheninsidethedoAnimation()function,youchangethevalueofdirectionwhenthe<div/>elementreachesoneofitsbounds(0pixelsor400pixels):

if(currentLeft>400||currentLeft<0){

direction=-direction;

}

Thenewdirectionvalueissimple;yousimplymakedirectionnegative.Soifdirectionispositive,itbecomesnegative.Ifdirectionisnegative,itbecomespositive(remember:anegativetimesanegativeisapositive).

Youthencalculatethenewleftpositionandchangetheelement’sstyle:

varnewLocation=currentLeft+direction;

divAdvert.style.left=newLocation+"px";

CHAPTER10

Exercise1QuestionAddamethodtotheeventutilityobjectcalledisOldIE()thatreturnsabooleanvalueindicatingwhetherornotthebrowserisold-IE.

Exercise1Solutionvarevt={

addListener:function(obj,type,fn){

if(typeofobj.addEventListener!="undefined"){

obj.addEventListener(type,fn);

}else{

obj.attachEvent("on"+type,fn);

}

},

removeListener:function(obj,type,fn){

if(typeofobj.removeEventListener!="undefined"){

obj.removeEventListener(type,fn);

}else{

obj.detachEvent("on"+type,fn);

}

},

getTarget:function(e){

if(e.target){

returne.target;

}

returne.srcElement;

},

preventDefault:function(e){

if(e.preventDefault){

e.preventDefault();

}else{

e.returnValue=false;

}

},

isOldIE:function(){

returntypeofdocument.addEventListener=="undefined";

}

};

Savethisasch10_question1.html.

YouhavemanywaystodetermineifthebrowserisanolderversionofInternetExplorer.Yourauthorchosetocheckifdocument.addEventListener()isundefined.IE9+supportsthemethod,whereasIE8andbelowdonot.

Exercise2Question

Example15exhibitssomebehaviorinconsistenciesbetweenstandards-compliantbrowsersandold-IE.Rememberthattheeventhandlersexecuteinreverseorderinold-IE.ModifythisexampletousethenewisOldIE()methodsothatyoucanwritespecificcodeforold-IEandstandards-compliantbrowsers(hint:youwillcalltheaddListener()methodfourtimes).

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Question2</title>

</head>

<body>

<imgid="img0"src="usa.gif"/>

<divid="status"></div>

<scriptsrc="ch10_question1.js"></script>

<script>

varmyImages=[

"usa.gif",

"canada.gif",

"jamaica.gif",

"mexico.gif"

];

functionchangeImg(e){

varel=evt.getTarget(e);

varnewImgNumber=Math.round(Math.random()*3);

while(el.src.indexOf(myImages[newImgNumber])!=-1){

newImgNumber=Math.round(Math.random()*3);

}

el.src=myImages[newImgNumber];

}

functionupdateStatus(e){

varel=evt.getTarget(e);

varstatus=document.getElementById("status");

status.innerHTML="Theimagechangedto"+el.src;

if(el.src.indexOf("mexico")>-1){

evt.removeListener(el,"click",changeImg);

evt.removeListener(el,"click",updateStatus);

}

}

varimgObj=document.getElementById("img0");

if(evt.isOldIE()){

evt.addListener(imgObj,"click",updateStatus);

evt.addListener(imgObj,"click",changeImg);

}else{

evt.addListener(imgObj,"click",changeImg);

evt.addListener(imgObj,"click",updateStatus);

}

</script>

</body>

</html>

Savethisasch10_question2.html.

ThemajorityofthecodeisidenticaltoExample15.Theonlydifferenceishowyouregistertheeventlisteners.WithyournewisOldIE()method,youcanregistertheclickeventlistenersinthecorrectorder(forold-IE).Forstandards-compliantbrowsers,youregistertheeventlistenersinthesameorderasExample15.

Exercise3QuestionExample17hadyouwriteacross-browsertabscript,butasyouprobablynoticed,itbehavespeculiarly.Thebasicideaisthere,butthetabsremainactiveasyouclickanothertab.Modifythescriptsothatonlyonetabisactiveatatime.

Exercise3SolutionExample17isincompletebecausethescriptdoesn’tkeeptrackofwhichtabisactive.Probablythesimplestwaytoaddstaterecognitiontothescriptistoaddaglobalvariablethatkeepstrackofthetabthatwaslastclicked.Thisparticularsolutionusesthisidea.Changedlinesofcodearehighlighted.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter10:Question3</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="ch10_question1.js"></script>

<script>

varactiveTab=null;

functionhandleEvent(e){

vartarget=evt.getTarget(e);

switch(e.type){

case"mouseover":

if(target.className=="tabStrip-tab"){

target.className="tabStrip-tab-hover";

}

break;

case"mouseout":

if(target.className=="tabStrip-tab-hover"){

target.className="tabStrip-tab";

}

break;

case"click":

if(target.className=="tabStrip-tab-hover"){

if(activeTab){

activeTab.className="tabStrip-tab";

}

varnum=target.getAttribute("data-tab-number");

target.className="tabStrip-tab-click";

showDescription(num);

activeTab=target;

}

break;

}

}

functionshowDescription(num){

vardescContainer=document.getElementById("descContainer");

vartext="DescriptionforTab"+num;

descContainer.innerHTML=text;

}

evt.addListener(document,"mouseover",handleEvent);

evt.addListener(document,"mouseout",handleEvent);

evt.addListener(document,"click",handleEvent);

</script>

</body>

</html>

Savethisasch10_question3.html.

ThissolutionstartswithanewglobalvariablecalledactiveTab.Itspurposeistocontainareferencetothetabelementthatwaslastclicked,andyouinitializeitasnull.

Whenyouclickatabelement,youfirstneedtodeactivatethecurrentlyactivetab:

if(activeTab){

activeTab.className="tabStrip-tab";

}

Todothat,youfirstcheckifyouhaveanactivetab,andifso,yousetitsclassNamepropertybacktotheoriginaltabStrip-tab.Thenafteryouactivatethenewtab,youassignittotheactiveTabvariable:

activeTab=target;

Simple,buteffective.

CHAPTER11

Exercise1QuestionUsingthecodefromthetemperatureconverterexampleyousawinChapter2,createauserinterfaceforitandconnectittotheexistingcodesothattheusercanenteravalueindegreesFahrenheitandconvertittocentigrade.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Question1</title>

</head>

<body>

<formaction=""name="form1">

<p>

<inputtype="text"name="txtCalcBox"value="0.0"/>

</p>

<inputtype="button"value="Converttocentigrade"

id="btnToCent"name="btnToCent"/>

</form>

<script>

functionconvertToCentigrade(degFahren){

vardegCent=5/9*(degFahren-32);

returndegCent;

}

functionbtnToCentClick(){

varcalcBox=document.form1.txtCalcBox;

if(isNaN(calcBox.value)==true||calcBox.value==""){

calcBox.value="ErrorInvalidValue";

}else{

calcBox.value=convertToCentigrade(calcBox.value);

}

}

document.getElementById("btnToCent")

.addEventListener("click",btnToCentClick);

</script>

</body>

</html>

Savethisasch11_question1.html.

TheinterfacepartissimplyaformcontainingatextboxintowhichusersentertheFahrenheitvalueandabuttontheyclicktoconvertthatvaluetocentigrade.ThebuttonhasaclickeventlistenerthatexecutesbtnToCentClick()whentheeventfires.

ThefirstlineofbtnToCentClick()declaresavariableandsetsittoreferencetheobjectrepresentingthetextbox:

varcalcBox=document.form1.txtCalcBox;

Whydothis?Well,inyourcodewhenyouwanttousedocument.form1.txtCalcBox,youcannowjustusethemuchshortercalcBox;itsavestypingandkeepsyourcodeshorterandeasiertoread.

So:

alert(document.form1.txtCalcBox.value);

isthesameas:

alert(calcBox.value);

Intheremainingpartofthefunctionyoudoasanitycheck—ifwhattheuserhasenteredisanumber(thatis,itisnotNotANumber)andthetextboxdoescontainavalue,youusetheFahrenheit-to-centigradeconversionfunctionyousawinChapter2todotheconversion,theresultsofwhichareusedtosetthetextbox’svalue.

Exercise2QuestionCreateauserinterfacethatallowsuserstopickthecomputersystemoftheirdreams,similarinprincipletothee-commercesitessellingcomputersovertheInternet.Forexample,theycouldbegivenachoiceofprocessortype,speed,memory,andharddrivesize,andtheoptiontoaddadditionalcomponentslikeaDVD-ROMdrive,asoundcard,andsoon.Astheuserschangetheirselections,thepriceofthesystemshouldupdateautomaticallyandnotifythemofthecostofthesystemastheyspecifiedit,eitherbyusinganalertboxorbyupdatingthecontentsofatextbox.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter11:Question2</title>

</head>

<body>

<formaction=""name="form1">

<p>

Choosethecomponentsyouwantincludedonyourcomputer

</p>

<p>

<labelfor="cboProcessor">Processor</label>

<selectname="cboProcessor"id="cboProcessor">

<optionvalue="100">Dual-core2GHz</option>

<optionvalue="101">Quad-core2.4GHz</option>

<optionvalue="102">Eight-core3GHz</option>

</select>

</p>

<p>

<labelfor="cboSsd">Solid-stateDrive</label>

<selectname="cboSsd"id="cboSsd">

<optionvalue="200">250GB</option>

<optionvalue="201">512GB</option>

<optionvalue="202">1TB</option>

</select>

</p>

<p>

<labelfor="chkDVD">DVD-ROM</label>

<inputtype="checkbox"id="chkDVD"name="chkDVD"value="300"/>

</p>

<p>

<labelfor="chkBluRay">Blu-ray</label>

<inputtype="checkbox"id="chkBluRay"name="chkBluRay"

value="301"/>

</p>

<fieldset>

<legend>Case</legend>

<p>

<labelfor="desktop">Desktop</label>

<inputtype="radio"id="desktop"

name="radCase"checkedvalue="400"/>

</p>

<p>

<labelfor="minitower">Mini-tower</label>

<inputtype="radio"id="minitower"

name="radCase"value="401"/>

</p>

<p>

<labelfor="fulltower">Full-tower</label>

<inputtype="radio"id="fulltower"

name="radCase"value="402"/>

</p>

</fieldset>

<p>

<inputtype="button"value="Update"

id="btnUpdate"name="btnUpdate"/>

</p>

<p>

<labelfor="txtOrder">OrderSummary:</label>

</p>

<p>

<textarearows="20"cols="35"id="txtOrder"

name="txtOrder"></textarea>

</p>

</form>

<script>

varproductDb=[];

productDb[100]=150;

productDb[101]=350;

productDb[102]=700;

productDb[200]=100;

productDb[201]=200;

productDb[202]=500;

productDb[300]=50;

productDb[301]=75;

productDb[400]=75;

productDb[401]=50;

productDb[402]=100;

functiongetDropDownInfo(element){

varselected=element[element.selectedIndex];

return{

text:selected.text,

price:productDb[selected.value]

};

}

functiongetCheckboxInfo(element){

return{

checked:element.checked,

price:productDb[element.value]

};

}

functiongetRadioInfo(elements){

for(vari=0;i<elements.length;i++){

if(!elements[i].checked){

continue;

}

varselected=elements[i];

varlabel=document.querySelector(

"[for="+selected.id+"]");

return{

text:label.innerHTML,

price:productDb[selected.value]

};

}

}

functionbtnUpdateClick(){

vartotal=0;

varorderDetails="";

vartheForm=document.form1;

varselectedProcessor=getDropDownInfo(theForm.cboProcessor);

total=selectedProcessor.price;

orderDetails="Processor:"+selectedProcessor.text;

orderDetails=orderDetails+"$"+

selectedProcessor.price+"\n";

varselectedSsd=getDropDownInfo(theForm.cboSsd);

total=total+selectedSsd.price;

orderDetails=orderDetails+"Solid-stateDrive:"+

selectedSsd.text;

orderDetails=orderDetails+"$"+selectedSsd.price+"\n";

vardvdInfo=getCheckboxInfo(theForm.chkDVD);

if(dvdInfo.checked){

total=total+dvdInfo.price;

orderDetails=orderDetails+"DVD-ROM:$"+

dvdInfo.price+"\n";

}

varbluRayInfo=getCheckboxInfo(theForm.chkBluRay);

if(bluRayInfo.checked){

total=total+bluRayInfo.price;

orderDetails=orderDetails+"Blu-ray:$"+

bluRayInfo.price+"\n";

}

varcaseInfo=getRadioInfo(theForm.radCase);

total=total+caseInfo.price;

orderDetails=orderDetails+caseInfo.text+":$"+

caseInfo.price;

orderDetails=orderDetails+"\n\nTotalOrderCostis"+

"$"+total;

theForm.txtOrder.value=orderDetails;

}

document.getElementById("btnUpdate")

.addEventListener("click",btnUpdateClick);

</script>

</script>

</body>

</html>

Savethisasch11_question2.html.

Thisisjustoneofmanywaystotacklethisquestion—youmaywellhavethoughtofabetterway.

Hereyouaredisplayingtheresultsoftheuser’sselectionastextinatextareabox,witheachitemanditscostdisplayedonseparatelinesandafinaltotalattheend.

EachformelementhasavaluesettoholdastockIDnumber.Forexample,afulltowercaseisstockID402.TheactualcostoftheitemisheldinanarraycalledproductDb.Whynotjuststorethepriceinthevalueattributeofeachformelement?Well,thiswayismoreflexible.Currentlyyourarrayjustholdspricedetailsforeachitem,butyoucouldmodify

itthatsoitholdsmoredata—forexampleprice,description,numberinstock,andsoon.Also,ifthisformispostedtoaserverthevaluespassedwillbestockIDs,whichyoucouldthenuseforalookupinastockdatabase.Ifthevaluesweresettopricesandtheformwasposted,you’dhavenowayoftellingwhatthecustomerordered—allyou’dknowishowmuchitallcost.

ThissolutionincludesanUpdatebuttonwhich,whenclicked,updatestheorderdetailsinthetextareabox.However,youmaywanttoaddeventhandlerstoeachformelementandupdatewhenanythingchanges.

Turningtothefunctionthatactuallydisplaystheordersummary,btnUpdateClick(),youcanseethatthereisalotofcode,andalthoughitlookscomplex,it’sactuallyfairlysimple.Alotofitisrepeatedwithslightmodification.Italsoreliesuponseveralhelperfunctionstopullvariousinformationfromtheselectedformelements.

Tosaveontypingandmakethecodealittlemorereadable,thissolutiondeclaresthetheFormvariabletocontaintheFormobjectAfterthevariable’sdeclaration,youthenfindoutwhichprocessorhasbeenselectedandgetitscostandtextwiththegetDropDownInfo()function:

functiongetDropDownInfo(element){

varselected=element[element.selectedIndex];

return{

text:selected.text,

price:productDb[selected.value]

};

}

TheselectedIndexpropertytellsyouwhichOptionobjectinsidetheselectcontrolhasbeenselectedbytheuser.YoureturnanewobjectthatcontainstheselectedOption’stextandthepricefromtheproductdatabase.

Sotogettheprocessorinformation,youpasstheForm.cboProcessortogetDropDownInfo()andassigntheresultingobjecttoselectedProcessor.Youthencalculatethetotalandupdatetheorderdetails:

varselectedProcessor=getDropDownInfo(theForm.cboProcessor);

total=selectedProcessor.price;

orderDetails="Processor:"+selectedProcessor.text;

orderDetails=orderDetails+"$"+selectedProcessor.price+"\n";

Thesameprincipleapplieswhenyoufindtheselectedsolid-statedrive,solet’sturnnexttothecheckboxesfortheoptionalextraitems,lookingfirstattheDVD-ROMcheckbox:

vardvdInfo=getCheckboxInfo(theForm.chkDVD);

if(dvdInfo.checked){

total=total+dvdInfo.price;

orderDetails=orderDetails+"DVD-ROM:$"+

dvdInfo.price+"\n";

}

Again,youuseahelperfunction—thisone’scalledgetCheckboxInfo()—toretrievetheinformationaboutthegivencheckbox:

functiongetCheckboxInfo(element){

return{

checked:element.checked,

price:productDb[element.value]

};

}

Thisreturnsanewobjectthattellsyouthepriceofthecomponent,aswellasifthecheckboxischecked.

Ifthecheckboxischecked,youaddaDVD-ROMtotheorderdetailsandupdatetherunningtotal.ThesameprincipleappliesfortheBlu-raycheckbox.

Finally,youhavethecomputer’scase.Becauseonlyonecasetypeoutoftheoptionscanbeselected,youusedaradiobuttongroup.Unfortunately,thereisnoselectedIndexforradiobuttonsasthereisforcheckboxes,soyouhavetogothrougheachradiobuttoninturnandfindoutifithasbeenselected.ThegetRadioInfo()helperfunctiondoesjustthat:

functiongetRadioInfo(elements){

for(vari=0;i<elements.length;i++){

if(!elements[i].checked){

continue;

}

varselected=elements[i];

varlabel=document.querySelector("[for="+selected.id+"]");

return{

text:label.innerHTML,

price:productDb[selected.value]

};

}

}

Itloopsthroughtheradiobuttongroupandcheckseachradiobutton’scheckedproperty.Ifit’sfalse,theloopiterateswiththecontinueoperator.Butiftheradiobuttonischecked,youneedtogetthetextassociatedwiththelabelfortheselectedradiobuttonandthecomponent’spricefromtheproductDbarray.

So,insidethebtnUpdateClick()function,youcanusethishelperfunctiontogeteverythingyouneedtoaddtheselectedcomputercasetothetotalanddescription:

varcaseInfo=getRadioInfo(theForm.radCase);

total=total+caseInfo.price;

orderDetails=orderDetails+caseInfo.text+":$"+

caseInfo.price;

Finally,setthetextareatothedetailsofthesystemtheuserhasselected:

orderDetails=orderDetails+"\n\nTotalOrderCostis"+total;

theForm.txtOrder.value=orderDetails;

CHAPTER12

Exercise1QuestionThecodeforalertingasinglemessageinExample1isn’tveryexciting.Modifythecodetodisplayarandommessagefromasetofthreepossiblemessages.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter12:Question1</title>

<style>

[data-drop-target]{

height:400px;

width:200px;

margin:2px;

background-color:gainsboro;

float:left;

}

.drag-enter{

border:2pxdashed#000;

}

.box{

width:200px;

height:200px;

}

.navy{

background-color:navy;

}

.red{

background-color:red;

}

</style>

</head>

<body>

<divdata-drop-target="true">

<divid="box1"draggable="true"class="boxnavy"></div>

<divid="box2"draggable="true"class="boxred"></div>

</div>

<divdata-drop-target="true"></div>

<script>

functiongetRandomMessage(){

varmessages=[

"Youmovedanelement!",

"Movedandelement,youhave!Mmmmmmm?",

"Elementoverboard!"

];

returnmessages[Math.floor((Math.random()*3)+0)];

}

functionhandleDragStart(e){

vardata={

elementId:this.id,

message:getRandomMessage()

};

e.dataTransfer.setData("text",JSON.stringify(data));

}

functionhandleDragEnterLeave(e){

if(e.type=="dragenter"){

this.className="drag-enter";

}else{

this.className="";

}

}

functionhandleOverDrop(e){

e.preventDefault();

if(e.type!="drop"){

return;

}

varjson=e.dataTransfer.getData("text");

vardata=JSON.parse(json);

vardraggedEl=document.getElementById(data.elementId);

if(draggedEl.parentNode==this){

this.className="";

return;

}

draggedEl.parentNode.removeChild(draggedEl);

this.appendChild(draggedEl);

this.className="";

alert(data.message);

}

vardraggable=document.querySelectorAll("[draggable]");

vartargets=document.querySelectorAll("[data-drop-target]");

for(vari=0;i<draggable.length;i++){

draggable[i].addEventListener("dragstart",handleDragStart);

}

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

targets[i].addEventListener("dragover",handleOverDrop);

targets[i].addEventListener("drop",handleOverDrop);

targets[i].addEventListener("dragenter",handleDragEnterLeave);

targets[i].addEventListener("dragleave",handleDragEnterLeave);

}

</script>

</body>

</html>

Savethisasch12_question1.html.

Thissolutionisrathersimple.ItintroducesanewfunctioncalledgetRandomMessage(),whichreturnsoneofthreemessages:

functiongetRandomMessage(){

varmessages=[

"Youmovedanelement!",

"Movedandelement,youhave!Mmmmmmm?",

"Elementoverboard!"

];

returnmessages[Math.floor((Math.random()*3)+0)];

}

AndyouusethisfunctionwhenyouassignthemessagepropertytothedataobjectinhandleDragStart():

vardata={

elementId:this.id,

message:getRandomMessage()

};

Sadly,thissolutionstilldoesn’taddmuchexcitementtotheexample.Butsomeisbetterthannone,right?

CHAPTER13

Exercise1QuestionUsinglocalstorage,createapagethatkeepstrackofhowmanytimesthepagehasbeenvisitedbytheuserinthelastmonth.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Question1</title>

</head>

<body>

<script>

varpageViewCount=localStorage.getItem("pageViewCount");

varpageFirstVisited=localStorage.getItem("pageFirstVisited");

varnow=newDate();

if(pageViewCount==null){

pageViewCount=0;

pageFirstVisited=now.toUTCString();

}

varoneMonth=newDate(pageFirstVisited);

oneMonth.setMonth(oneMonth.getMonth()+1);

if(now>oneMonth){

pageViewCount=0;

pageFirstVisited=now.toUTCString();

}

pageViewCount=parseInt(pageViewCount,10)+1;

localStorage.setItem("pageViewCount",pageViewCount);

localStorage.setItem("pageFirstVisited",pageFirstVisited);

varoutput="You'vevisitedthispage"+pageViewCount+

"timessince"+pageFirstVisited;

document.write(output);

</script>

</body>

</html>

Savethisasch13_question1.html.

ThefirsttwolinesgettwovaluesfromlocalStorageandstoretheminvariables.Thefirstholdsthenumberofvisits,thesecondthedatethepagewasfirstvisited.Youalsocreateavariabletocontainthecurrentdate:

varpageViewCount=localStorage.getItem("pageViewCount");

varpageFirstVisited=localStorage.getItem("pageFirstVisited");

varnow=newDate();

IfthepageViewCountkeydoesnotexistinlocalStorage,thevariableofthesamenameisnull,andyou’llneedtoinitializethepageViewcountandpageFirstVisitedvariableswith0andthecurrentdate,respectively.RememberthatlocalStoragecontainsonlystringdata,soyouusetheDateobject’stoUTCString()methodtoconvertthedatetoastring:

if(pageViewCount==null){

pageViewCount=0;

pageFirstVisited=now.toUTCString();

}

You’reonlytrackingthenumberofvisitswithinamonth’stimespan.So,nextyouneedavariabletocontainaDateobjectonemonthfromthefirstvisit:

varoneMonth=newDate(pageFirstVisited);

oneMonth.setMonth(oneMonth.getMonth()+1);

IfthecurrentdateandtimeislaterthanoneMonth,it’stimetoresetthecounterandvisitedvariables:

if(now>oneMonth){

pageViewCount=0;

pageFirstVisited=now.toUTCString();

}

ThenyouincrementthecounterandstoreitandthefirstvisitvalueinlocalStorage:

pageViewCount=parseInt(pageViewCount,10)+1;

localStorage.setItem("pageViewCount",pageViewCount);

localStorage.setItem("pageFirstVisited",pageFirstVisited);

Finally,writeinformationtothepage:

varoutput="You'vevisitedthispage"+pageViewCount+

"timessince"+pageFirstVisited;

document.write(output);

Exercise2QuestionUsecookiestoloadadifferentadvertisementeverytimeauservisitsawebpage.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter13:Question2</title>

</head>

<body>

<script>

varads=[

"BuyProductA!Youwon'tbesorry!",

"YouneedProductB!Buybuybuy!",

"Don'tbuyProductAorB!ProductCistheonlyoptionfor

you!"

];

functiongetRandomNumber(min,max){

returnMath.floor((Math.random()*max)+min);

}

varlastAdNumber=localStorage.getItem("lastAdNumber");

varnextNumber=getRandomNumber(0,ads.length);

if(lastAdNumber==null){

lastAdNumber=nextNumber;

}else{

lastAdNumber=parseInt(lastAdNumber,10);

while(lastAdNumber==nextNumber){

nextNumber=getRandomNumber(0,ads.length);

}

}

localStorage.setItem("lastAdNumber",nextNumber);

document.write(ads[nextNumber]);

</script>

</body>

</html>

Savethisasch13_question2.html.

Thissolutionislooselybasedonsimilarquestionsinpreviouschapterswhereyouhavedisplayedrandomimagesormessages.Inthiscaseyoudisplayadifferentmessageinthepageeachtimetheuservisitsit;you’llneverseethesamemessagedisplayedtwotimesinarowinthesamebrowser.

YoustorethelastnumberofthepreviouslydisplayedadinlocalStoragewiththekeylastAdNumber.So,youretrievethatvalueandgeneratethenextnumberwithagetRandomNumber()helperfunction(youknowthisalgorithm):

varlastAdNumber=localStorage.getItem("lastAdNumber");

varnextNumber=getRandomNumber(0,ads.length);

IflastAdNumberisnull,youcanusethevalueinnextNumber:

if(lastAdNumber==null){

lastAdNumber=nextNumber;

}

ButiflastAdNumberisnotnull,youneedtogeneratearandomnumberthatisnotlastAdNumber.Sofirst,youconvertlastAdNumbertoanumberwiththeparseInt()

function:

else{

lastAdNumber=parseInt(lastAdNumber,10);

while(lastAdNumber==nextNumber){

nextNumber=getRandomNumber(0,ads.length);

}

}

Thenyouuseawhilelooptogenerateauniquerandomnumber.TheloopiteratesiflastAdNumberisequaltonextNumber,anditcontinuestodosountilthenextnumberisdifferentthanlastAdNumber.

Onceyouhaveauniquenextnumber,youstoreitinlocalStorageanddisplaytheadinthepage:

localStorage.setItem("lastAdNumber",nextNumber);

document.write(ads[nextNumber]);

CHAPTER14

Exercise1QuestionExtendtheHttpRequestmoduletoincludesynchronousrequestsinadditiontotheasynchronousrequeststhemodulealreadymakes.You’llhavetomakesomeadjustmentstoyourcodetoincorporatethisfunctionality.(Hint:Createanasyncpropertyforthemodule.)

Exercise1SolutionfunctionHttpRequest(url,callback){

this.url=url;

this.callBack=callback;

this.async=true;

this.request=newXMLHttpRequest();

};

HttpRequest.prototype.send=function(){

this.request.open("GET",this.url,this.async);

if(this.async){

vartempRequest=this.request;

varcallback=this.callBack;

functionrequestReadystatechange(){

if(tempRequest.readyState==4){

if(tempRequest.status==200){

callback(tempRequest.responseText);

}else{

alert("Anerroroccurredwhileattemptingto"+

"contacttheserver.");

}

}

}

this.request.onreadystatechange=requestReadystatechange;

}

this.request.send(null);

if(!this.async){

this.callBack(this.request.responseText);

}

};

It’spossibletoaddsynchronouscommunicationtoyourHttpRequestmoduleinavarietyofways.Theapproachinthissolutionrefactorsthecodetoaccommodateanewpropertycalledasync,whichcontainseithertrueorfalse.Ifitcontainstrue,theunderlyingXMLHttpRequestobjectusesasynchronouscommunicationtoretrievethefile.Iffalse,themoduleusessynchronouscommunication.

Thefirstchangemadetothemoduleisintheconstructoritself.TheoriginalconstructorinitializesandreadiestheXMLHttpRequestobjecttosenddata.Thiswillnotdoforthisnewversion,however.Instead,theconstructormerelyinitializesalltheproperties:

functionHttpRequest(url,callback){

this.url=url;

this.callBack=callback;

this.async=true;

this.request=newXMLHttpRequest();

};

Youhavethreenewpropertieshere.Thefirst,url,containstheURLthattheXMLHttpRequestobjectshouldattempttorequestfromtheserver.ThecallBackpropertycontainsareferencetothecallbackfunction,andtheasyncpropertydeterminesthetypeofcommunicationtheXMLHttpRequestobjectuses.Settingasynctotrueintheconstructorgivesthepropertyadefaultvalue.Therefore,youcansendtherequestinasynchronousmodewithoutsettingthepropertyexternally.

Thenewconstructorandpropertiesareactuallydesirable,becausetheyenableyoutoreusethesameHttpRequestobjectformultiplerequests.IfyouwantedtomakearequesttoadifferentURL,allyouwouldneedtodoisassigntheurlpropertyanewvalue.Thesamecanbesaidforthecallbackfunctionaswell.

Themajorityofchangestothemoduleareinthesend()method.Itisherethatthemoduledecideswhethertouseasynchronousorsynchronouscommunication.Bothtypesofcommunicationhaveverylittleincommonwhenitcomestomakingarequest;asynchronouscommunicationusestheonreadystatechangeeventhandler,andsynchronouscommunicationallowsaccesstotheXMLHttpRequestobject’spropertieswhentherequestiscomplete.Therefore,codebranchingisrequired:

HttpRequest.prototype.send=function(){

this.request.open("GET",this.url,this.async);

if(this.async){

//morecodehere

}

this.request.send(null);

if(!this.async){

//morecodehere

}

}

Thefirstlineofthismethodusestheopen()methodoftheXMLHttpRequestobject.Theasyncpropertyisusedasthefinalparameterofthemethod.ThisdetermineswhetherornottheXHRobjectusesasynchronouscommunication.Next,anifstatementteststoseeifthis.asyncistrue;ifitis,theasynchronouscodewillbeplacedinthisifblock.Next,theXMLHttpRequestobject’ssend()methodiscalled,sendingtherequesttotheserver.Thefinalifstatementcheckstoseewhetherthis.asyncisfalse.Ifitis,synchronouscodeisplacedwithinthecodeblocktoexecute.

HttpRequest.prototype.send=function(){

this.request.open("GET",this.url,this.async);

if(this.async){

vartempRequest=this.request;

varcallback=this.callBack;

functionrequestReadystatechange(){

if(tempRequest.readyState==4){

if(tempRequest.status==200){

callback(tempRequest.responseText);

}else{

alert("Anerroroccurredwhileattemptingto"+

"contacttheserver.");

}

}

}

this.request.onreadystatechange=requestReadystatechange;

}

this.request.send(null);

if(!this.async){

this.callBack(this.request.responseText);

}

};

Thisnewcodefinishesoffthemethod.Startingwiththefirstifblock,anewvariablecalledcallbackisassignedthevalueofthis.callBack.ThisisdoneforthesamereasonsaswiththetempRequestvariable—scopingissues—becausethispointstotherequestReadystatechange()functioninsteadoftheHttpRequestobject.Otherthanthischange,theasynchronouscoderemainsthesame.TherequestReadystatechange()functionhandlesthereadystatechangeeventandcallsthecallbackfunctionwhentherequestissuccessful.

Thesecondifblockismuchsimpler.Becausethiscodeexecutesonlyifsynchronouscommunicationisdesired,allyouhavetodoiscallthecallbackfunctionandpasstheXMLHttpRequestobject’sresponseTextproperty.

Usingthisnewlyrefactoredmoduleisquitesimple.Thefollowingcodemakesanasynchronousrequestforafictitioustextfilecalledtest.txt:

functionrequestCallback(responseText){

alert(responseText);

}

varhttp=newHttpRequest("test.txt",requestCallback);

http.send();

Nothinghasreallychangedforasynchronousrequests.Thisistheexactsamecodeusedearlierinthechapter.Ifyouwanttousesynchronouscommunication,simplysetasynctofalse,likethis:

functionrequestCallback(responseText){

alert(responseText);

}

varhttp=newHttpRequest("test.txt",requestCallback);

http.async=false;

http.send();

YounowhaveanAjaxmodulethatrequestsinformationinbothasynchronousandsynchronouscommunication!

Exercise2QuestionItwasmentionedearlierinthechapterthatyoucouldmodifythesmartformstonotusehyperlinks.ChangetheformthatusestheHttpRequestmodulesothattheUsernameandEmailfieldsarecheckedwhentheusersubmitstheform.Listenfortheform’ssubmiteventandcancelthesubmissionifausernameore-mailistaken.

Exercise2SolutionFirst,adisclaimer:Ideally,theserviceprovidedbych14_formvalidator.phpshouldallowyoutocheckboththeusernameande-mailaddresswithasinglerequest.Thatwouldgreatlysimplifythissolution.However,sometimesyouneedtomakemultiplerequests,andeachrequestissometimesdependentupontheoutcomeofapreviousrequest.Thisquestionandsolutionismeanttoemulatethat.

Additionally,issuingmultiple(andlinked)asynchronousoperationsisarathercomplexordeal—aconditionreferredto”callbackhell.”You’llgetatasteofthatinthissolution.

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter14:Question2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<formname="theForm">

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputid="btnSubmit"type="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="ch14_question1.js"></script>

<script>

functionbtnSubmitClick(e){

e.preventDefault();

checkUsername();

}

functioncheckUsername(){

varuserValue=document.getElementById("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varurl="ch14_formvalidator.php?username="+userValue;

varrequest=newHttpRequest(url,handleUsernameResponse);

request.send();

}

functioncheckEmail(){

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_formvalidator.php?email="+emailValue;

varrequest=newHttpRequest(url,handleEmailResponse);

request.send();

}

functionhandleUsernameResponse(responseText){

varresponse=JSON.parse(responseText);

if(!response.available){

alert("Theusername"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

checkEmail();

}

functionhandleEmailResponse(responseText){

varresponse=JSON.parse(responseText);

if(!response.available){

alert("Theemailaddress"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

document.theForm.submit();

}

document.getElementById("btnSubmit")

.addEventListener("click",btnSubmitClick);

</script>

</body>

</html>

Savethisasch14_question2.html.

IntheHTML,noticethatthelinksforcheckingtheusernameande-mailaddressaregone.Thereisnoneedforthem,becausethosevaluesarecheckedwhentheuserclickstheSubmitbutton.ThelaststatementoftheJavaScriptcoderegistersthateventlistener:

document.getElementById("btnSubmit")

.addEventListener("click",btnSubmitClick);

Thefunctionthathandlesthebutton’sclickeventiscalledbtnSubmitClick().It’sasimplefunctionthatkicksoffthewholeprocess:

functionbtnSubmitClick(e){

e.preventDefault();

checkUsername();

}

Itsfirststatementpreventstheformfromsubmitting.Thisisimportantbecause,duetothenatureofasynchronousprocesses,btnSubmitClick()cannotberesponsibleforsubmittingtheform.Therefore,anotherfunctionwillneedtosubmittheformifboththeusernameande-mailaddressvalidateandareavailable.

ThesecondstatementcallscheckUsername(),whichisleftmostlyunchanged:

functioncheckUsername(){

varuserValue=document.getElementById("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varurl="ch14_formvalidator.php?username="+userValue;

varrequest=newHttpRequest(url,handleUsernameResponse);

request.send();

}

Infact,theonlychangetothisfunctionisthecallbackpassedtotheHttpRequestconstructor.It’sanewcallbackfunctioncalledhandleUsernameResponse(),anditsomewhatresemblestheoriginalhandleResponse()function:

functionhandleUsernameResponse(responseText){

varresponse=JSON.parse(responseText);

if(!response.available){

alert("Theusername"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

checkEmail();

}

ThisfunctiontakestheresponseandparsesitintoaJavaScriptobject.Iftheusernameisnotavailable,itdisplaystheerrormessagetotheuserandreturns.Nothingelseisprocessedwhentheusernameisunavailable,butifitisavailable,itcallscheckEmail():

functioncheckEmail(){

varemailValue=document.getElementById("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varurl="ch14_formvalidator.php?email="+emailValue;

varrequest=newHttpRequest(url,handleEmailResponse);

request.send();

}

Thisfunctionisalsolargelythesame.TheonlydifferenceisthecallbackfunctionpassedtotheHttpRequestconstructor;it’scalledhandleEmailResponse().Itparsestherequest,anditisthelaststepintheprocess:

functionhandleEmailResponse(responseText){

varresponse=JSON.parse(responseText);

if(!response.available){

alert("Theemailaddress"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

document.theForm.submit();

}

Onceagain,ifthee-mailaddressisnotavailable,thisfunctiondisplaystheerrormessagetotheuserandreturns.Butifthee-mailaddressisavailable,theformisfinallysubmitted.

CHAPTER15

Exercise1QuestionBeingabletocontrolplaybackiscool,butyourcustomUIneedstoalsocontrolvolume.Addan<inputtype="range"/>elementtoExample3tocontrolthevolume.Rememberthattherangeofvolumesupportedbymediaelementsis0.0to1.0.LookbackatChapter11ifyouneedarefresheroftherangeinputtype.ThisunfortunatelywillnotworkinIE.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter15:Question1</title>

</head>

<body>

<div>

<buttonid="playbackController">Play</button>

<buttonid="muteController">Mute</button>

<inputtype="range"id="volumeController"

min="0"max="1"step=".1"value="1"/>

</div>

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

<script>

functionpauseHandler(e){

playButton.innerHTML="Resume";

}

functionplayingHandler(e){

playButton.innerHTML="Pause";

}

functionvolumechangeHandler(e){

muteButton.innerHTML=video.muted?"Unmute":"Mute";

}

functionplaybackClick(e){

video.paused?video.play():video.pause();

}

functionmuteClick(e){

video.muted=!video.muted;

}

functionvolumeInput(e){

video.volume=volumeSlider.value;

}

varvideo=document.getElementById("bbbVideo");

varplayButton=document.getElementById("playbackController");

varmuteButton=document.getElementById("muteController");

varvolumeSlider=document.getElementById("volumeController");

video.addEventListener("pause",pauseHandler);

video.addEventListener("playing",playingHandler);

video.addEventListener("volumechange",volumechangeHandler);

playButton.addEventListener("click",playbackClick);

muteButton.addEventListener("click",muteClick);

volumeSlider.addEventListener("input",volumeInput);

</script>

</body>

</html>

Savethisasch15_question1.html.

ThissolutionisbuiltonExample3.Theadditionsarehighlightedforyourconvenience.

Thevolumewillbecontrolledbyan<input/>element:

<inputtype="range"id="volumeController"

min="0"max="1"step=".1"value="1"/>

It’sarangecontrol,andit’ssettoaminimumvalueof0,amaximumvalueof1,andthestepis.1.Itsinitialvalueissetto1,meaningfullvolume.

IntheJavaScriptcode,youretrievethiselementandstoreitinthevolumeSlidervariable:

varvolumeSlider=document.getElementById("volumeController");

Andyouregisteraninputeventlistener:

volumeSlider.addEventListener("input",volumeInput);

ThevolumeInput()functionhandlesthisevent,anditisresponsibleforsettingthemedia’svolumetotheslider’scorrespondingvalue:

functionvolumeInput(e){

video.volume=volumeSlider.value;

}

Exercise2QuestionAddanotherrangeformcontroltoQuestion1’sanswer,andprogramittoseekthemedia.Itshouldalsoupdateasthemediaplays.Usethedurationchangeeventtosettheslider’smaxvalue,andthetimeupdateeventtoupdatetheslider’svalue.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter15:Question2</title>

</head>

<body>

<div>

<buttonid="playbackController">Play</button>

<buttonid="muteController">Mute</button>

<inputtype="range"id="volumeController"

min="0"max="1"step=".1"value="1"/>

</div>

<videoid="bbbVideo">

<sourcesrc="bbb.mp4"/>

<sourcesrc="bbb.webm"/>

</video>

<div>

<inputtype="range"id="seekController"

min="0"step="1"value="0"/>

</div>

<script>

functionpauseHandler(e){

playButton.innerHTML="Resume";

}

functionplayingHandler(e){

playButton.innerHTML="Pause";

}

functionvolumechangeHandler(e){

muteButton.innerHTML=video.muted?"Unmute":"Mute";

}

functiondurationchangeHandler(e){

seekSlider.max=video.duration;

}

functiontimeupdateHandler(e){

seekSlider.value=video.currentTime;

}

functionplaybackClick(e){

video.paused?video.play():video.pause();

}

functionmuteClick(e){

video.muted=!video.muted;

}

functionvolumeInput(e){

video.volume=volumeSlider.value;

}

functionseekInput(e){

video.currentTime=seekSlider.value;

}

varvideo=document.getElementById("bbbVideo");

varplayButton=document.getElementById("playbackController");

varmuteButton=document.getElementById("muteController");

varvolumeSlider=document.getElementById("volumeController");

varseekSlider=document.getElementById("seekController");

video.addEventListener("pause",pauseHandler);

video.addEventListener("playing",playingHandler);

video.addEventListener("volumechange",volumechangeHandler);

video.addEventListener("durationchange",durationchangeHandler);

video.addEventListener("timeupdate",timeupdateHandler);

playButton.addEventListener("click",playbackClick);

muteButton.addEventListener("click",muteClick);

volumeSlider.addEventListener("input",volumeInput);

seekSlider.addEventListener("input",seekInput);

</script>

</body>

</html>

Savethisasch15_question2.html.

Onceagain,thechangesarehighlighted.Youaddanotherrangecontroltothepage:

<div>

<inputtype="range"id="seekController"

min="0"step="1"value="0"/>

</div>

ThisoneiscalledseekController.Itissettoaminimumvalueof0,astepof1,andaninitialvalueof0.Amaximumvalueisnotsetbecauseyoudonotyetknowthedurationofthevideo.Youwill,however,whenthemedia’sdurationchangeeventfires.Youregisteralistenerforthisevent;itcallsthedurationchangeHandler()functionwhenitfires.

functiondurationchangeHandler(e){

seekSlider.max=video.duration;

}

Itsimplysetstheslider’smaxpropertytothemedia’sduration.

Youalsoregisteralistenerforthemedia’stimeupdateeventwiththetimeupdateHandler()function.Youusethistoupdatetheslider’svaluewhenthemedia’scurrenttimechanges:

functiontimeupdateHandler(e){

seekSlider.value=video.currentTime;

}

Butyoualsowanttocontrolthemedia’sseekwiththeslider,soyoulistenfortherangecontrol’sinputevent:

functionseekInput(e){

video.currentTime=seekSlider.value;

}

Andyousetthemedia’scurrentTimepropertytotheslider’svalue.

CHAPTER16

Exercise1QuestionExample1isbasedonChapter10’sExample17,andasyouprobablyremember,youmodifiedthatexampleinresponsetooneofChapter10’sexercisequestions.Modifythischapter’sExample1sothatonlyonetabisactiveatatime.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter16:Question1</title>

<style>

.tabStrip{

background-color:#E4E2D5;

padding:3px;

height:22px;

}

.tabStripdiv{

float:left;

font:14pxarial;

cursor:pointer;

}

.tabStrip-tab{

padding:3px;

}

.tabStrip-tab-hover{

border:1pxsolid#316AC5;

background-color:#C1D2EE;

padding:2px;

}

.tabStrip-tab-click{

border:1pxsolid#facc5a;

background-color:#f9e391;

padding:2px;

}

</style>

</head>

<body>

<divclass="tabStrip">

<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>

<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>

<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>

</div>

<divid="descContainer"></div>

<scriptsrc="jquery-2.1.1.min.js"></script>

<script>

varactiveTab=null;

functionhandleEvent(e){

vartarget=$(e.target);

vartype=e.type;

if(type=="mouseover"||type=="mouseout"){

target.toggleClass("tabStrip-tab-hover");

}elseif(type=="click"){

if(activeTab){

activeTab.removeClass("tabStrip-tab-click");

}

target.addClass("tabStrip-tab-click");

varnum=target.attr("data-tab-number");

showDescription(num);

activeTab=target;

}

}

functionshowDescription(num){

vartext="DescriptionforTab"+num;

$("#descContainer").text(text);

}

$(".tabStrip>div").on("mouseovermouseoutclick",handleEvent);

</script>

</body>

</html>

Savethisasch16_question1.html.

TheoveralllogicofthissolutionisidenticaltoChapter10’sSolution3.Youdefineavariabletotracktheactivetab:

varactiveTab=null;

Thenwhentheuserclicksoneofthetabs,youremovethetabStrip-tab-clickCSSclassfromtheactivetab(ifoneexists):

if(activeTab){

activeTab.removeClass("tabStrip-tab-click");

}

Andthenyousetthecurrenttabastheactivetab:

activeTab=target;

Exercise2QuestionThereissomerepetitivecodeinExample2.Refactorthecodetoreducetheduplication.Additionally,addafunctiontohandleanyerrorsthatmayoccurwiththerequest.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter16:Question2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<form>

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td>

<aid="usernameAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td>

<aid="emailAvailability"href="#">Check

Availability</a>

</td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputtype="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="jquery-2.1.1.min.js"></script>

<script>

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("#username").val();

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

makeRequest({

username:userValue

});

}

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("#email").val();

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

makeRequest({

email:emailValue

});

}

functionmakeRequest(parameters){

$.getJSON("ch14_formvalidator.php",parameters)

.done(handleResponse)

.fail(handleError);

}

functionhandleError(){

alert("Anetworkerroroccurred.Pleasetryagain"+

"inafewmoments.");

}

functionhandleResponse(response){

if(response.available){

alert(response.searchTerm+"isavailable!");

}else{

alert("We'resorry,but"+response.searchTerm+

"isnotavailable.");

}

}

$("#usernameAvailability").on("click",checkUsername);

$("#emailAvailability").on("click",checkEmail);

</script>

</body>

</html>

Savethisasch16_question2.html.

Themainsourceofduplicationisthecodethatmakestheactualrequest:

$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);

Althoughit’sasinglelineofcode,itcanbemovedintoaseparatefunctiontomakeiteasiertomaintain.Plus,whenyouaddafunctionforhandlingAjaxerrors,youhavetovisitonlyonefunctionasopposedtotwo.

FirstwriteafunctionthatdisplaysamessagetotheuserwhentheAjaxrequestfails.CallithandleError():

functionhandleError(){

alert("Anetworkerroroccurred.Pleasetryagain"+

"inafewmoments.");

}

NowwriteafunctionthatperformstheAjaxrequest,andchainafail()calltodone():

functionmakeRequest(parameters){

$.getJSON("ch14_formvalidator.php",parameters)

.done(handleResponse)

.fail(handleError);

}

YoucannowusethismakeRequest()functioninsidethecheckUsername()function:

functioncheckUsername(e){

e.preventDefault();

varuserValue=$("#username").val();

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

makeRequest({

username:userValue

});

}

AndthecheckEmail()function:

functioncheckEmail(e){

e.preventDefault();

varemailValue=$("#email").val();

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

makeRequest({

email:emailValue

});

}

Youcanalsoeliminatetheparmsvariableinbothofthefunctions,asshowninthissolution.JustpasstheobjectliteraldirectlytomakeRequest()tomakeyourcodemoreconcise.

CHAPTER17

Exercise1QuestionModifytheanswertoChapter14’sQuestion2usingPrototype.AlsoadderrorreportingforwhenanerroroccurswiththeAjaxrequest.

Exercise1Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Question1</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<formname="theForm">

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td></td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td></td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputid="btnSubmit"type="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="prototype.1.7.2.js"></script>

<script>

functionbtnSubmitClick(e){

e.preventDefault();

checkUsername();

}

functioncheckUsername(){

varuserValue=$("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varoptions={

method:"get",

onSuccess:handleUsernameResponse,

onFailure:handleError,

parameters:{

username:userValue

}

};

newAjax.Request("ch14_formvalidator.php",options);

}

functioncheckEmail(){

varemailValue=$("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varoptions={

method:"get",

onSuccess:handleEmailResponse,

onFailure:handleError,

parameters:{

email:emailValue

}

};

newAjax.Request("ch14_formvalidator.php",options);

}

functionhandleUsernameResponse(transport){

varresponse=transport.responseJSON;

if(!response.available){

alert("Theusername"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

checkEmail();

}

functionhandleEmailResponse(transport){

varresponse=transport.responseJSON;

if(!response.available){

alert("Theemailaddress"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

document.theForm.submit();

}

functionhandleError(){

alert("Anetworkerroroccurred.Pleasetryagain"+

"inafewmoments.");

}

$("btnSubmit").observe("click",btnSubmitClick);

</script>

</body>

</html>

Savethisasch17_question1.html.

ThissolutionisbasedonChapter14’sSolution2,butthecodehaschangedtousePrototype’sAPI.There’salsoanewfunctioncalledhandleError()forhandlingerrors:

functionhandleError(){

alert("Anetworkerroroccurred.Pleasetry"+

"againinafewmoments.");

}

ThisfunctioniscalledhandleError(),anditsimplydisplaysamessagetotheuser.You’llassignthisfunctiontotheonFailureoptionwhenyoumakeyourAjaxrequests.

MakingarequestismanymorelinesofcodeduetoPrototype’sAjaxAPI:

varoptions={

method:"get",

onSuccess:handleEmailResponse,

onFailure:handleError,

parameters:{

email:emailValue

}

};

newAjax.Request("ch14_formvalidator.php",options);

ThisexcerptistakenfromcheckUsername().Youcreateyouroptionsobjectcontainingthemethod,onSuccess,onFailure,andparametersproperties,andthenyouissuetherequest.

Onasuccessfulrequest,thehandleUsernameResponse()andhandleEmailResponse()functionsexecute.TheynolongermanuallyparsetheJSONdataintoaJavaScriptobject;instead,theyusetheresponseJSONproperty:

varresponse=transport.responseJSON;

Andfinally,youregisterthebutton’sclickeventlistenerusingtheobserve()method:

$("btnSubmit").observe("click",btnSubmitClick);

Exercise2QuestionIfyouguessedthatthisquestionwouldbe:“ChangetheanswertoChapter14’sQuestion2usingMooTools,andadderrorreportingforwhenanerroroccurswiththeAjaxrequest”thenyouwon!!Yourprizeis…completingtheexercise.

Exercise2Solution<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter17:Question2</title>

<style>

.fieldname{

text-align:right;

}

.submit{

text-align:right;

}

</style>

</head>

<body>

<formname="theForm">

<table>

<tr>

<tdclass="fieldname">

Username:

</td>

<td>

<inputtype="text"id="username"/>

</td>

<td></td>

</tr>

<tr>

<tdclass="fieldname">

Email:

</td>

<td>

<inputtype="text"id="email"/>

</td>

<td></td>

</tr>

<tr>

<tdclass="fieldname">

Password:

</td>

<td>

<inputtype="text"id="password"/>

</td>

<td/>

</tr>

<tr>

<tdclass="fieldname">

VerifyPassword:

</td>

<td>

<inputtype="text"id="password2"/>

</td>

<td/>

</tr>

<tr>

<tdcolspan="2"class="submit">

<inputid="btnSubmit"type="submit"value="Submit"/>

</td>

<td/>

</tr>

</table>

</form>

<scriptsrc="mootools-core-1.5.1-compressed.js"></script>

<script>

functionbtnSubmitClick(e){

e.preventDefault();

checkUsername();

}

functioncheckUsername(){

varuserValue=$("username").value;

if(!userValue){

alert("Pleaseenterausernametocheck!");

return;

}

varoptions={

url:"ch14_formvalidator.php",

data:{

username:userValue

},

onSuccess:handleUsernameResponse,

onFailure:handleError

};

newRequest.JSON(options).get();

}

functioncheckEmail(){

varemailValue=$("email").value;

if(!emailValue){

alert("Pleaseenteranemailaddresstocheck!");

return;

}

varoptions={

url:"ch14_formvalidator.php",

data:{

email:emailValue

},

onSuccess:handleEmailResponse,

onFailure:handleError

};

newRequest.JSON(options).get();

}

functionhandleUsernameResponse(response){

if(!response.available){

alert("Theusername"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

checkEmail();

}

functionhandleEmailResponse(response){

if(!response.available){

alert("Theemailaddress"+response.searchTerm+

"isunavailable.Tryanother.");

return;

}

document.theForm.submit();

}

functionhandleError(){

alert("Anetworkerroroccurred.Pleasetryagain"+

"inafewmoments.");

}

$("btnSubmit").addEvent("click",btnSubmitClick);

</script>

</body>

</html>

CHAPTER18

Exercise1QuestionTheexamplech18_example4.htmlhasadeliberatebug.Foreachtimestableitcreatesonlymultiplierswithvaluesfrom1to11.

Usethescriptdebuggertoworkoutwhythisishappening,andthencorrectthebug.

Exercise1SolutionTheproblemiswiththecode’slogicratherthanitssyntax.Logicerrorsaremuchhardertospotanddealwithbecause,unlikewithsyntaxerrors,thebrowserwon’tinformyouthatthere’ssuchandsucherroratlinesoandsobutinsteadjustfailstoworkasexpected.Theerroriswiththisline:

for(varcounter=1;counter<12;counter++)

Youwantthelooptogofrom1to12inclusive.Yourcounter<12statementwillbetrueuptoandincluding11butwillbefalsewhenthecounterreaches12;hence12getsleftoff.Tocorrectthis,youcouldchangethecodetothefollowing:

for(varcounter=1;counter<=12;counter++)

Exercise2QuestionThefollowingcodecontainsanumberofcommonerrors.Seeifyoucanspotthem:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Question2</title>

</head>

<body>

<formname="form1"action="">

<inputtype="text"id="text1"name="text1"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>

<br/>

<inputtype="text"id="text2"name="text2"/>

<p>

<inputtype="submit"value="Submit"id="submit1"

name="submit1"/>

</p>

</form>

<script>

functioncheckForm(e){

varelementCount=0;

vartheForm=document.form1;

while(elementCount=<=theForm.length){

if(theForm.elements[elementcount].type=="text"){

if(theForm.elements[elementCount].value()="")

alert("Pleasecompleteallformelements");

theForm.elements[elementCount].focus;

e.preventDefault();

break;

}

}

}

document.form1.addEventListener("submit",checkForm);

</script>

</body>

</html>

Exercise2SolutionThebug-freeversionlookslikethis:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<title>Chapter18:Question2</title>

</head>

<body>

<formname="form1"action="">

<inputtype="text"id="text1"name="text1"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>

<br/>

CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>

<br/>

<inputtype="text"id="text2"name="text2"/>

<p>

<inputtype="submit"value="Submit"id="submit1"

name="submit1"/>

</p>

</form>

<script>

functioncheckForm(e){

varelementCount=0;

vartheForm=document.form1;

while(elementCount<theForm.length){

if(theForm.elements[elementCount].type=="text"){

if(theForm.elements[elementCount].value==""){

alert("Pleasecompleteallformelements");

theForm.elements[elementCount].focus();

e.preventDefault();

break;

}

}

elementCount++;

}

}

document.form1.addEventListener("submit",checkForm);

</script>

</body>

</html>

Let’slookateacherrorinturn.Thefirsterrorisalogicerror:

while(elementCount=<theForm.length)

Arraysstartat0sothefirstelementobjectisatindexarray0,thesecondat1,andsoon.Thelastobjecthasanindexvalueof4.However,theForm.lengthwillreturn5becausetherearefiveelementsintheform.SothewhileloopwillcontinueuntilelementCountislessthanorequalto5,butbecausethelastelementhasanindexof4,thisisonepastthelimit.Youshouldwriteeitherthis:

while(elementCount<theForm.length)

orthis:

while(elementCount<=theForm.length-1)

Eitherisfine,thoughthefirstisshorter.

Youcometoyourseconderrorinthefollowingline:

if(theForm.elements[elementcount].type=="text")

Onaquickglanceitlooksfine,butit’sJavaScript’sstrictnessoncasesensitivitythathascausedthedownfall.ThevariablenameiselementCount,notelementcountwithalowercasec.Sothislineshouldreadasfollows:

if(theForm.elements[elementCount].type=="text")

Thenextlinewithanerroristhis:

if(theForm.elements[elementCount].value()="")

Thishastwoerrors.First,valueisapropertyandnotamethod,sothereisnoneedforparenthesesafterit.Second,youhavetheall-timeclassicerrorofoneequalssigninsteadoftwo.Rememberthatoneequalssignmeans“Makeitequalto,”andtwoequalssignsmean“Checkifitisequalto.”Sowiththechanges,thelineis:

if(theForm.elements[elementCount].value=="")

Thenexterroristhefailuretoputyourblockofifcodeincurlybraces.EventhoughJavaScriptwon’tthrowanerrorbecausethesyntaxisfine,thelogicisnotsofine,andyou

won’tgettheresultsyouexpect.Withthebraces,theifstatementshouldbeasfollows:

if(theForm.elements[elementCount].value==""){

alert("Pleasecompleteallformelements")

theForm.elements[elementCount].focus;

formValid=false;

break;

}

Thepenultimateerrorisinthisline:

theForm.elements[elementCount].focus;

Thistimeyouhaveamethodbutwithnoparenthesesafterit.Evenmethodsthathavenoparametersmusthavetheemptyparenthesesafterthemifyouintendtoexecutethatmethod.So,corrected,thelineisasfollows:

theForm.elements[elementCount].focus();

Nowyou’realmostdone;thereisjustonemoreerror.Thistimeit’snotsomethingwrongwithwhat’sthere,butrathersomethingveryimportantthatshouldbetherebutismissing.Whatisit?It’sthis:

elementCount++;

Thislineshouldbeinyourwhileloop,otherwiseelementCountwillnevergoabove0andthewhileloop’sconditionwillalwaysbetrue,resultingintheloopcontinuingforever:aclassicinfiniteloop.

BJavaScriptCoreReferenceThisappendixoutlinesthesyntaxofalltheJavaScriptcorelanguagefunctionsandobjectswiththeirpropertiesandmethods.Ifchangeshaveoccurredbetweenversions,theyhavebeennoted.

BROWSERREFERENCEThefollowingtableoutlineswhichJavaScriptversionisinuseandinwhichbrowseritisused.NotethatearlierversionsofInternetExplorerimplementedJscript,Microsoft’sversionofJavaScript.However,Jscript’sfeaturesarerelativelythesameasJavaScript.

JAVASCRIPTVERSION

MOZILLAFIREFOX

INTERNETEXPLORER

CHROME SAFARI OPERA

1.0 3.01.11.21.3 4.01.41.5 1.0 5.5,6,7,8 1–10 3-5 6,7,8,91.6 1.51.7 2.0 281.8 3.0 11.51.8.1 3.51.8.2 3.61.8.5 4 9 32 6 11.6

RESERVEDWORDSVariouswordsandsymbolsarereservedbyJavaScript.Thesewordscannotbeusedasvariablenames,norcanthesymbolsbeusedwithinthem.Theyarelistedinthefollowingtable.

abstract boolean break

byte case catch

char class const

continue debugger default

delete do double

else enum export

extends false final

finally float for

function goto if

implements import in

instanceof int interface

let long native

new null package

private protected public

return short static

super switch synchronized

this throw throws

transient true try

typeof var void

volatile while with

- ! ~

% / *

> < =

& ^ |

+ ?

OtherIdentifierstoAvoidItisbesttoavoidtheuseofthefollowingidentifiersasvariablenames.

JavaScript1.0absacosanchorasinatanatan2bigblinkboldceilcharAtcommentcosDate

EescapeevalexpfixedfloorfontcolorfontsizegetDategetDaygetHours

getMinutesgetMonthgetSecondsgetTimegetTimezoneOffsetgetYearindexOf

isNaNitalicslastIndexOflinklogLOG10ELOG2ELN10LN2Mathmaxmin

ObjectparseparseFloatparseIntPIpowrandomround,setDatesetHours

setMinutessetMonthsetSecondssetTimesetYearsinslicesmallsqrtSQRT1_2

SQRT2strikeStringsubsubstrsubstringsuptantoGMTStringtoLocaleString

toLowerCasetoUpperCaseunescapeUTC

JavaScript1.1callerclassNameconstructorjavaJavaArrayJavaClassJavaObject

JavaPackagejoinlengthMAX_VALUEMIN_VALUENaNNEGATIVE_INFINITYnetscape

NumberPOSITIVE_INFINITYprototypereversesortsplitsuntoStringvalueOf

JavaScript1.2aritycalleecharCodeAtcompileconcatexecfromCharCodeglobalignoreCase

indexinputlabellastIndexlastMatchlastParenleftContextmatchmultiline

NumberPackagespoppushRegExpreplacerightContextsearchshiftslice

splicesourceStringtestunshiftunwatchwatch

JavaScript1.3applycallgetFullYeargetMillisecondsgetUTCDategetUTCDaygetUTCFullYear

getUTCHoursgetUTCMillisecondsgetUTCMinutesgetUTCMonthgetUTCSeconds

InfinityisFiniteNaNsetFullYearsetMillisecondssetUTCDatesetUTCFullYear

setUTCHourssetUTCMillisecondssetUTCMinutessetUTCMonthsetUTCSeconds

toSourcetoUTCStringundefined

JAVASCRIPTOPERATORSThefollowingsectionslistthevariousoperatorsavailabletoyouinJavaScript.

AssignmentOperatorsAssignmentoperatorsallowyoutoassignavaluetoavariable.Thefollowingtableliststhedifferentassignmentoperatorsyoucanuse.

NAME INTRODUCED MEANINGAssignment JavaScript1.0 Setsvariablev1tothe

valueofvariablev2.varv1=v2;

ShorthandadditionorShorthandconcatenationsameasv1=v1+v2

JavaScript1.0 v1+=v2

Shorthandsubtractionsameasv1=v1−v2

JavaScript1.0 v1−=v2

Shorthandmultiplicationsameasv1=v1*v2

JavaScript1.0 v1*=v2

Shorthanddivisionsameasv1=v1/v2 JavaScript1.0 v1/=v2

Shorthandmodulussameasv1=v1%v2 JavaScript1.0 v1%=v2

Shorthandleft-shiftsameasv1=v1<<v2

JavaScript1.0 v1<<=v2

Shorthandright-shiftsameasv1=v1>>v2

JavaScript1.0 v1>>=v2

Shorthandzero-fillright-shiftsameasv1=v1>>>v2

JavaScript1.0 v1>>>=v2

ShorthandANDsameasv1=v1&v2 JavaScript1.0 v1&=v2

ShorthandXORsameasv1=v1^v2 JavaScript1.0 v1^=v2

ShorthandORsameasv1=v1|v2 JavaScript1.0 v1|=v2

ComparisonOperatorsComparisonoperatorsallowyoutocompareonevariableorvaluewithanother.Anycomparisonstatementreturnsabooleanvalue.

NAME INTRODUCED MEANING

Equal JavaScript1.0 v1==v2

Trueiftwooperandsarestrictlyequalorequaloncecasttothesametype.

Notequal JavaScript1.0 v1!=v2

Trueiftwooperandsarenotstrictlyequalornotequaloncecasttothesametype.

Greaterthan JavaScript1.0 v1>v2

Trueifleft-handside(LHS)operandisgreaterthanright-handside(RHS)operand.

Greaterthanorequalto

JavaScript1.0 v1>=v2

TrueifLHSoperandisgreaterthanorequaltoRHSoperand.

Lessthan JavaScript1.0 v1<v2

TrueifLHSoperandislessthanRHSoperand.

Lessthanorequalto

JavaScript1.0 v1<=v2

TrueifLHSoperandislessthanorequaltoRHSoperand.

Strictlyequal JavaScript1.3 v1===v2

Trueifoperandsareequalandofthesametype.

Notstrictlyequal

JavaScript1.3 v1!==v2

Trueifoperandsarenotstrictlyequal.

ArithmeticOperatorsArithmeticoperatorsallowyoutoperformarithmeticoperationsbetweenvariablesorvalues.

NAME INTRODUCED MEANING

Addition JavaScript1.0 v1+v2

Sumofv1andv2.(Concatenationofv1andv2,ifeitheroperandisastring.)

Subtraction JavaScript1.0 v1−v2

Differencebetweenv1andv2.

Multiplication JavaScript1.0 v1*v2

Productofv1andv2.

Division JavaScript1.0 v1/v2

Quotientofv2intov1.

Modulus JavaScript1.0 v1%v2

Integerremainderofdividingv1byv2

.

Prefixincrement

JavaScript1.0 ++v1*v2(v1+1)*v2

Note:v1willbeleftasv1+1.

Postfixincrement

JavaScript1.0 v1++*v2(v1*v2)

v1isthenincrementedby1.

Prefixdecrement

JavaScript1.0 --v1*v2(v1–1)*v2Note:v1isleftasv1-1.

Postfixdecrement

JavaScript1.0 v1—*v2(v1*v2)

v1isthendecrementedby1.

BitwiseOperatorsBitwiseoperatorsworkbyconvertingvaluesinv1andv2to32-bitbinarynumbersandthencomparingtheindividualbitsofthesetwobinarynumbers.Theresultisreturnedasanormaldecimalnumber.

NAME INTRODUCED MEANING

BitwiseAND

JavaScript1.0 v1&v2

ThebitwiseANDlinesupthebitsineachoperandandperformsanANDoperationbetweenthetwobitsinthesameposition.Ifbothbitsare1,theresultingbitinthispositionofthereturnednumberis1.Ifeitherbitis0,theresultingbitinthispositionofthereturnednumberis0.

BitwiseOR

JavaScript1.0 v1|v2

ThebitwiseORlinesupthebitsineachoperandandperformsanORoperationbetweenthetwobitsinthesameposition.Ifeitherbitis1,theresultingbitinthispositionofthereturnednumberis1.Ifbothbitsare0,theresultingbitinthispositionofthereturnednumberis0.

BitwiseXOR

JavaScript1.0 v1^v2

ThebitwiseXORlinesupthebitsineachoperandandperformsanXORoperationbetweenthetwobitsinthesameposition.Theresultingbitinthispositionis1onlyifonebitfrombothoperandsis1.Otherwise,theresultingbitinthispositionofthereturnednumberis0.

BitwiseNOT

JavaScript1.0 v1~v2

Invertsallthebitsinthenumber.

BitwiseShiftOperatorsTheseworkbyconvertingvaluesinv1to32-bitbinarynumbersandthenmovingthebitsinthenumbertotheleftortherightbythespecifiednumberofplaces.

NAME INTRODUCED MEANING

Left-shift JavaScript1.0 v1<<v2

Shiftsv1totheleftbyv2places,fillingthenewgapsinwithzeros.

Sign-propagatingright-shift

JavaScript1.4 v1>>v2

Shiftsv1totherightbyv2places,ignoringthebitsshiftedoffthenumber.

Zero-fillright-shift

JavaScript1.0 v1>>>v2

Shiftsv1totherightbyv2places,ignoringthebitsshiftedoffthenumberandaddingv2zerostotheleftofthenumber.

LogicalOperatorsTheseshouldreturnoneofthebooleanliterals,trueorfalse.However,thismaynothappenifv1orv2isneitherabooleanvaluenoravaluethateasilyconvertstoabooleanvalue,suchas0,1,null,theemptystring,orundefined.

NAME INTRODUCED MEANING

LogicalAND

JavaScript1.0 v1&&v2

Returnstrueifbothv1andv2aretrue,orfalseotherwise.Willnotevaluatev2ifv1isfalse.

LogicalOR

JavaScript1.0 v1││v2

Returnsfalseifbothv1andv2arefalse,ortrueifoneoperandistrue.Willnotevaluatev2ifv1istrue.

LogicalNOT

JavaScript1.0 !v1

Returnsfalseifv1istrue,ortrueotherwise.

ObjectOperators

JavaScriptprovidesanumberofoperatorstoworkwithobjects.Thefollowingtableliststhem.

NAME INTRODUCED MEANING

delete JavaScript1.2 deleteobj

Deletesanobject,oneofitsproperties,ortheelementofanarrayatthespecifiedindex.Alsodeletesvariablesnotdeclaredwiththevarkeyword.

in JavaScript1.4 for(propinsomObj)

ReturnstrueifsomeObjhasthenamedproperty.

instanceof JavaScript1.4 someObjinstanceofObjType

ReturnstrueifsomeObjisoftypeObjType;otherwise,returnsfalse.

new JavaScript1.0 newObjType()

CreatesanewinstanceofanobjectwithtypeObjType.

this JavaScript1.0 this.property

Referstothecurrentobject.

MiscellaneousOperatorsThefollowingtablelistsmiscellaneousoperators.

NAME INTRODUCED MEANING

Conditionaloperator

JavaScript1.0 (evalquery)?v1:v2

Ifevalqueryistrue,theoperatorreturnsv1;otherwiseitreturnsv2.

Commaoperator

JavaScript1.0 varv3=(v1+2,v2*2)

Evaluatesbothoperandswhiletreatingthetwoasoneexpression.Returnsthevalueofthesecondoperand.Inthisexample,v3holdstheresultingvalueofv2*2.

typeof JavaScript1.1 typeofv1

Returnsastringholdingthetypeofv1,whichisnotevaluated.

void JavaScript1.1 void(eva1)

Evaluateseval1butdoesnotreturnavalue.

OperatorPrecedenceDoes1+2*3=1+(2*3)=7ordoesitequal(1+2)*3=9?

Operatorprecedencedeterminestheorderinwhichoperatorsareevaluated.Forexample,themultiplicativeoperator(*)hasahigherprecedencethantheadditiveoperator(+).Therefore,thecorrectanswertothepreviousquestionis:

1+(2*3)

ThefollowingtableliststheoperatorprecedenceinJavaScriptfromhighesttolowest.Thethirdcolumnexplainswhethertoread1+2+3+4as((1+2)+3)+4(lefttoright)or1+(2+(3+(4)))(righttoleft).

OPERATORTYPE

OPERATORS EVALUATIONORDERFORLIKEELEMENTS

Member .or[] LefttorightCreateinstance

new Righttoleft

Functioncall () LefttorightIncrement ++ N/aDecrement -- N/aLogicalnot ! RighttoleftBitwisenot ~ RighttoleftUnary+ + RighttoleftUnary– – RighttoleftTypeof typeof RighttoleftVoid void RighttoleftDelete delete RighttoleftMultiplication * LefttorightDivision / LefttorightModulus % LefttorightAddition + LefttorightSubtraction − LefttorightBitwiseshift <<,>>,>>> LefttorightRelational <,<=,>,>= LefttorightIn in LefttorightInstanceof instanceof LefttorightEquality ==,!=,===,!=== LefttorightBitwiseAND & LefttorightBitwiseXOR ^ LefttorightBitwiseOR | LefttorightLogicalAND && LefttorightLogicalOR ││ LefttorightConditional ?: RighttoleftAssignment =,+=,-=,*=,/=,%=,<<=,>>=,

>>>=,&=,^=,|=

Righttoleft

Comma , Lefttoright

JAVASCRIPTSTATEMENTSThefollowingtablesdescribecoreJavaScriptstatements.

BlockJavaScriptblocksstartwithanopeningcurlybrace({)andendwithaclosingcurlybrace(}).Blockstatementsaremeanttomakethecontainedsinglestatementsexecutetogether,suchasthebodyofafunctionoracondition.

STATEMENT INTRODUCED DESCRIPTION{} JavaScript1.5 Usedtogroupstatementsasdelimitedbythecurly

brackets.

ConditionalThefollowingtablelistsconditionalstatementsforJavaScriptaswellastheversioninwhichtheywereintroduced.

STATEMENT INTRODUCED DESCRIPTIONif JavaScript1.2 Executesablockofcodeifaspecifiedconditionis

true.else JavaScript1.2 Thesecondhalfofanifstatement.Executesablock

ofcodeiftheresultoftheifstatementisfalse.switch JavaScript1.2 Specifiesvariousblocksofstatementstobeexecuted

dependingonthevalueoftheexpressionpassedinastheargument.

DeclarationsThesekeywordsdeclarevariablesorfunctionsinJavaScriptcode.

STATEMENT INTRODUCED DESCRIPTIONvar JavaScript1.0 Usedtodeclareavariable.Initializingittoavalueis

optionalatthetimeofdeclaration.function JavaScript1.0 Usedtodeclareafunctionwiththespecified

parameters,whichcanbestrings,numbers,orobjects.Toreturnavalue,thefunctionmustusethereturnstatement.

LoopLoopsexecuteablockofcodewhileaspecifiedconditionistrue.

STATEMENT INTRODUCED DESCRIPTIONdo…while JavaScript1.2 Executesthestatementsspecifieduntilthetest

conditionafterthewhileevaluatestofalse.Thestatementsareexecutedatleastoncebecausethetestconditionisevaluatedlast.

for JavaScript1.0 Createsaloopcontrolledaccordingtothethreeoptionalexpressionsenclosedintheparenthesesaftertheforandseparatedbysemicolons.Thefirstofthesethreeexpressionsistheinitial-expression,thesecondisthetestcondition,andthethirdistheincrement-expression.

for…in JavaScript1.0 Usedtoiterateoverallthepropertiesofanobjectusingavariable.Foreachpropertythespecifiedstatementswithintheloopareexecuted.

while JavaScript1.0 Executesablockofstatementsifatestconditionevaluatestotrue.Theloopthenrepeats,testingtheconditionwitheachrepeat,ceasingiftheconditionevaluatestofalse.

break JavaScript1.0 Usedwithinawhileorforlooptoterminatetheloopandtransferprogramcontroltothestatementfollowingtheloop.Canalsobeusedwithalabeltobreaktoaparticularprogrampositionoutsideoftheloop.

label JavaScript1.2 Anidentifierthatcanbeusedwithbreakorcontinuestatementstoindicatewheretheprogramshouldcontinueexecutionaftertheloopexecutionisstopped.

ExecutionControlStatementsCodeexecutioniscontrolledinavarietyofways.Inadditiontotheconditionalandloopstatements,thefollowingstatementsalsocontributetoexecutioncontrol.

STATEMENT INTRODUCED DESCRIPTIONcontinue JavaScript1.0 Usedtostopexecutionoftheblockofstatementsinthe

currentiterationofawhileorforloop;executionoftheloopcontinueswiththenextiteration.

return JavaScript1.0 Usedtospecifythevaluetobereturnedbyafunction.with JavaScript1.0 Specifiesthedefaultobjectforablockofcode.

ExceptionHandlingStatementsErrorsareanaturalpartofprogramming,andJavaScriptprovidesyouwiththemeanstocatcherrorsandhandlethemgracefully.

STATEMENT INTRODUCED DESCRIPTIONThrow JavaScript1.4 Throwsacustomexceptiondefinedbytheuser.try…catch…

finally

JavaScript1.4 Executesthestatementsinthetryblock;ifanyexceptionsoccur,thesearehandledinthecatchblock.Thefinallyblockallowsyoutostipulatestatementsthatwillbeexecutedafterboththetryandcatchstatements.

OtherStatementsThefollowingtablelistsotherJavaScriptstatementsandwhentheywereintroduced.

STATEMENT INTRODUCED DESCRIPTION//singleline

comment

JavaScript1.0 Singlelinesofnotesthatareignoredbythescriptengineandthatcanbeusedtoexplainthecode.

/*multi-line

comment*/

JavaScript1.0 Multiplelinesofnotesthatareignoredbythescriptengineandthatcanbeusedtoexplainthecode.

TOP-LEVELPROPERTIESANDFUNCTIONSThesearecorepropertiesandfunctions,whicharenotassociatedwithanylower-levelobject,althoughintheterminologyusedbyECMAScriptandbyJscript,theyaredescribedaspropertiesandmethodsoftheglobalobject.

Thetop-levelpropertieswereintroducedinJavaScript1.3,butinpreviousversions,InfinityandNaNexistedaspropertiesoftheNumberobject.

Top-LevelProperties

PROPERTY INTRODUCED DESCRIPTIONInfinity JavaScript1.3 Returnsinfinity.NaN JavaScript1.3 Returnsavaluethatisnotanumber.undefined JavaScript1.3 Indicatesthatavaluehasnotbeenassignedtoavariable.

Top-LevelFunctions

FUNCTION INTRODUCED DESCRIPTIONdecodeURI() JavaScript1.5 UsedtodecodeaURIencodedwith

encodeURI().decodeURIcomponent() JavaScript1.5 UsedtodecodeaURIencodedwith

encodeURIComponent().encodeURI() JavaScript1.5 Usedtocomposeanewversionofacomplete

URI,replacingeachinstanceofcertaincharacters.ItisbasedontheUTF-8encodingofthecharacters.

encodeURIComponent() JavaScript1.5 UsedtocomposeanewversionofacompleteURIbyreplacingeachinstanceofthespecifiedcharacterwithescapesequences.RepresentationisviatheUTFencodingofthecharacters.

escape() JavaScript1.0 UsedtoencodeastringintheISOLatin-1characterset;forexample,toaddtoaURL.

eval() JavaScript1.0 ReturnstheresultoftheJavaScriptcode,whichispassedinasastringparameter.

isFinite() JavaScript1.3 Indicateswhethertheargumentisafinitenumber.

isNaN() JavaScript1.1 Indicatesiftheargumentisnotanumber.Number() JavaScript1.2 Convertsanobjecttoanumber.parseFloat() JavaScript1.0 Parsesastringandreturnsitasafloating-

pointnumber.parseInt() JavaScript1.0 Parsesastringandreturnsitasaninteger.An

optionalsecondparameterspecifiesthebaseofthenumbertobeconverted.

String() JavaScript1.2 Convertsanobjecttoastring.unescape() JavaScript1.0 ReturnstheASCIIstringforthespecified

hexadecimalencodingvalue.

JAVASCRIPTCOREOBJECTSThissectiondescribestheobjectsavailableintheJavaScriptcorelanguageandtheirmethodsandproperties.

ArrayTheArrayobjectrepresentsanarrayofvariables.ItwasintroducedinJavaScript1.1.AnArrayobjectcanbecreatedwiththeArrayconstructor:

varobjArray=newArray(10);//anarrayof11elements

varobjArray=newArray("1","2","4");//anarrayof3elements

Arrayscanalsobecreatedusingarrayliteralsyntax:

varobjArray=[];

Literalsyntaxisthepreferredmethodofcreatinganarray.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.length JavaScript1.1 Returnsthenumberofelementsinthearray.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.

NOTESquarebrackets([])surroundingaparametermeansthatparameterisoptional.

Methods

METHOD INTRODUCED DESCRIPTIONconcat(value1[,

value2,...])

JavaScript1.2 Concatenatestwoarraysandreturnsthenewarraythusformed.

every(testFn(element,

index,array))

JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.Returnstrueifalliterationsreturntrue.Otherwise,itreturnsfalse.

filter(testFn(element,

index,array))

JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.ReturnsanewarrayofelementsthatpasstestFn().

foreach(fn(element,

index,array))

JavaScript1.6 Iteratesoverthearray,executingfn()oneveryelement.

indexOf(element[,

startIndex])JavaScript1.6 Returnsanindexofthespecifiedelementif

found,or-1ifnotfound.StartsatstartIndexifspecified.

join([separator]) JavaScript1.1 Joinsalltheelementsofanarrayintoasinglestringdelimitedbyaseparatorifspecified.

lastIndexOf(element[,

startIndex])

JavaScript1.6 Searchesanarraystartingatthelastelementandmovesbackwards.Returnsanindexofthespecifiedelementiffound,or–1ifnotfound.StartsatstartIndexifspecified.

map(fn(element,index,

array))

JavaScript1.6 Iteratesoverthearray,executingfn()oneveryelement.Returnsanewarraybasedontheoutcomeoffn().

pop() JavaScript1.2 Popsthelastelementfromtheendofthearrayandreturnsthatelement.

push(value1[,value2,

...])

JavaScript1.2 Pushesoneormoreelementsontotheendofthearrayandreturnsthenewlengthofthearray.Thearray’snewlengthisreturned.

reverse() JavaScript1.1 Reversestheorderoftheelementsinthearray,sothefirstelementbecomesthelastandthelastbecomesthefirst.

shift() JavaScript1.2 Removesthefirstelementfromthebeginningofthearrayandreturnsthatelement.

slice(startIndex[,

endIndex])

JavaScript1.2 Returnsasliceofthearraystartingatthestartindexandendingattheelementbeforetheendindex.

some(testFn(element,

index,array))

JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.ReturnstrueifatleastoneresultoftestFn()istrue.

sort([sortFn(a,b)]) JavaScript1.1 Sortstheelementsofthearray.ExecutessortFn()forsortingifitisprovided.

splice(startIndex[,

length,value1,...)

JavaScript1.2 RemovestheamountofelementsdenotedbylengthstartingatstartIndex.Providedvaluesreplacethedeletedelements.Returnsthedeletedelements.

toString() JavaScript1.1 ConvertstheArrayobjectintoastring.unshift(value1[,

value2,...])

JavaScript1.2 Addselementstothebeginningofthearrayandreturnsthenewlength.

valueOf() JavaScript1.1 Returnstheprimitivevalueofthearray.

BooleanTheBooleanobjectisusedasawrapperforabooleanvalue.ItwasintroducedinJavaScript1.1.ItiscreatedwiththeBooleanconstructor,whichtakesasaparametertheinitialvaluefortheobject(ifthisisnotabooleanvalue,itwillbeconvertedintoone).

Falseyvaluesarenull,undefined,"",and0.Allothervaluesareconsideredtruthy.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Specifiesthefunctionthatcreatesanobject’sprototype.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONtoString() JavaScript1.1 ConvertstheBooleanobjectintoastring.valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheBooleanobject.

DateTheDateobjectisusedtorepresentagivendate-time.ItwasintroducedinJavaScript1.0.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONgetDate() JavaScript1.0 Retrievesthedateinthemonth

fromtheDateobject.getDay() JavaScript1.0 Retrievesthedayoftheweek

fromtheDateobject.getFullYear() JavaScript1.3 Retrievesthefullyearfromthe

Dateobject.getHours() JavaScript1.0 Retrievesthehouroftheday

fromtheDateobject.getMilliseconds() JavaScript1.3 Retrievesthenumberof

millisecondsfromtheDateobject.

getMinutes() JavaScript1.0 RetrievesthenumberofminutesfromtheDateobject.

getMonth() JavaScript1.0 RetrievesthemonthfromtheDateobject.

getSeconds() JavaScript1.0 RetrievesthenumberofsecondsfromtheDateobject.

getTime() JavaScript1.0 RetrievesthenumberofmillisecondssinceJanuary1,197000:00:00fromtheDateobject.

getTimezoneOffset() JavaScript1.0 Retrievesthedifferenceinminutesbetweenthelocaltimezoneanduniversaltime(UTC).

getUTCDate() JavaScript1.3 RetrievesthedateinthemonthfromtheDateobjectadjustedtouniversaltime.

getUTCDay() JavaScript1.3 RetrievesthedayoftheweekfromtheDateobjectadjustedtouniversaltime.

getUTCFullYear() JavaScript1.3 RetrievestheyearfromtheDateobjectadjustedtouniversaltime.

getUTCHours() JavaScript1.3 RetrievesthehourofthedayfromtheDateobjectadjustedtouniversaltime.

getUTCMilliseconds() JavaScript1.3 RetrievesthenumberofmillisecondsfromtheDateobjectadjustedtouniversaltime.

getUTCMinutes() JavaScript1.3 RetrievesthenumberofminutesfromtheDateobjectadjustedtouniversaltime.

getUTCMonth() JavaScript1.3 RetrievesthemonthfromtheDateobjectadjustedtouniversaltime.

getUTCSeconds() JavaScript1.3 RetrievesthenumberofsecondsfromtheDateobjectadjustedtouniversaltime.

getYear() JavaScript1.0 RetrievestheyearfromtheDateobject.

parse(dateString) JavaScript1.0 Retrievesthenumberofmillisecondsinadatesince

January1,197000:00:00,localtime.

setDate(dayOfMonth) JavaScript1.0 SetsthedateinthemonthfortheDateobject.

setFullYear(year[,month,day]) JavaScript1.3 SetsthefullyearfortheDateobject.

setHours(hours[,minutes,

seconds,milliseconds])

JavaScript1.0 SetsthehourofthedayfortheDateobject.

setMilliseconds(milliseconds) JavaScript1.3 SetsthenumberofmillisecondsfortheDateobject.

setMinutes(minutes[,seconds,

milliseconds])

JavaScript1.0 SetsthenumberofminutesfortheDateobject.

setMonth(month[,day]) JavaScript1.0 SetsthemonthfortheDateobject.

setSeconds(seconds[,

milliseconds])

JavaScript1.0 SetsthenumberofsecondsfortheDateobject.

setTime(milliseconds) JavaScript1.0 SetsthetimefortheDateobjectaccordingtothenumberofmillisecondssinceJanuary1,197000:00:00.

setUTCDate(dayOfMonth) JavaScript1.3 SetsthedateinthemonthfortheDateobjectaccordingtouniversaltime.

setUTCFullYear(year[,month,

day])

JavaScript1.3 SetsthefullyearfortheDateobjectaccordingtouniversaltime.

setUTCHours(hours[,minutes,

seconds,milliseconds])

JavaScript1.3 SetsthehourofthedayfortheDateobjectaccordingtouniversaltime.

setUTCMilliseconds(milliseconds) JavaScript1.3 SetsthenumberofmillisecondsfortheDateobjectaccordingtouniversaltime.

setUTCMinutes(mintes[,seconds,

milliseconds])

JavaScript1.3 SetsthenumberofminutesfortheDateobjectaccordingtouniversaltime.

setUTCMonth(month[,day]) JavaScript1.3 SetsthemonthfortheDateobjectaccordingtouniversaltime.

setUTCSeconds() JavaScript1.3 SetsthenumberofsecondsfortheDateobjectaccordingtouniversaltime.

setYear(year) JavaScript1.0 SetstheyearfortheDateobject.DeprecatedinfavorofsetFullYear().

toGMTString() JavaScript1.0 ConvertstheDateobjecttoastringaccordingtoGreenwichMeanTime.ReplacedbytoUTCString.

toLocaleString() JavaScript1.0 ConvertstheDateobjecttoastringaccordingtothelocaltimezone.

toString() JavaScript1.1 ConvertstheDateobjectintoastring.

toUTCString() JavaScript1.3 ConvertstheDateobjecttoastringaccordingtouniversaltime.

UTC(year,month[,day,hours,

minutes,seconds,milliseconds])

JavaScript1.0 RetrievesthenumberofmillisecondsinadatesinceJanuary1,197000:00:00,universaltime.

valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheDateobject.

FunctionIntroducedinJavaScript1.1,aFunctionobjectiscreatedwiththeFunctionconstructor.

Functionscanbedefinedinavarietyofways.Youcancreateafunctionusingthefollowingstandardfunctionstatement:

functionfunctionName(){

//codehere

}

Youcanalsocreateananonymousfunctionandassignittoavariable.Thefollowingcodedemonstratesthisapproach:

varfunctionName=function(){

//codehere

};

Thetrailingsemicolonisnotatypobecausethisstatementisanassignmentoperation,andallassignmentoperationsshouldendwithasemicolon.

Functionsareobjects,andthustheyhaveaconstructor.It’spossibletocreateafunctionusingtheFunctionobject’sconstructorasshowninthefollowingcode:

varfunctionName=newFunction("arg1","arg2","returnarg1+arg2");

Thefirstargumentstotheconstructorarethenamesofthefunction’sparameters—youcanaddasmanyparametersasyouneed.Thelastparameteryoupasstotheconstructoristhefunction’sbody.Thepreviouscodecreatesafunctionthatacceptstwoargumentsandreturnstheirsum.

ThereareveryfewinstanceswhereyouwillusetheFunctionconstructor.Itispreferredtodefineafunctionusingthestandardfunctionstatementorbycreatingananonymousfunctionandassigningittoavariable.

Properties

PROPERTY INTRODUCED DESCRIPTIONarguments JavaScript1.1 Anarraycontainingtheparameterspassedintothe

function.arguments.length JavaScript1.1 Returnsthenumberofparameterspassedintothe

function.constructor JavaScript1.1 Usedtoreferencetheconstructorfunctionforthe

object.length JavaScript1.1 Returnsthenumberofparametersexpectedbythe

function.Thisdiffersfromarguments.length,whichreturnsthenumberofparametersactuallypassedintothefunction.

prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeusedtoextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONapply(thisObj,

arguments)

JavaScript1.3 CallsafunctionormethodasifitbelongedtothisObjandpassesargumentstothefunctionormethod.argumentsmustbeanarray.

call(thisObj,

arg1,...)

JavaScript1.3 Identicaltoapply(),exceptargumentsarepassedindividuallyinsteadofinanarray.

toString() JavaScript1.1 ConvertstheFunctionobjectintoastring.valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheFunctionobject.

JSONTheJSONobjectcontainsmethodsforparsingJavaScriptObjectNotation(JSON)intoobjectsandserializingJavaScriptobjectsintoJSON.IntroducedinJavaScript1.8.5,theJSONobjectisatop-levelobject,whichcanbeaccessedwithoutaconstructor.

Methods

METHOD INTRODUCED DESCRIPTIONparse(json) JavaScript1.8.5 TransformsJSONintoaJavaScriptobjectorvalue.stringify(obj) JavaScript1.8.5 TransformsaJavaScriptobjectorvalueintoJSON.

MathTheMathobjectprovidesmethodsandpropertiesusedformathematicalcalculations.IntroducedinJavaScript1.0,theMathobjectisatop-levelobject,whichcanbeaccessedwithoutaconstructor.

Properties

PROPERTY INTRODUCED DESCRIPTIONE JavaScript1.0 ReturnsEuler’sconstant(thebaseofnaturallogarithms;

approximately2.718).LN10 JavaScript1.0 Returnsthenaturallogarithmof10(approximately

2.302).LN2 JavaScript1.0 Returnsthenaturallogarithmof2(approximately

0.693).LOG10E JavaScript1.0 ReturnstheBase10logarithmofE(approximately

0.434).LOG2E JavaScript1.0 ReturnstheBase2logarithmofE(approximately

1.442).PI JavaScript1.0 Returnspi,theratioofthecircumferenceofacircleto

itsdiameter(approximately3.142).SQRT1_2 JavaScript1.0 Returnsthesquarerootof1/2(approximately0.707).SQRT2 JavaScript1.0 Returnsthesquarerootof2(approximately1.414).

Methods

METHOD INTRODUCED DESCRIPTIONabs(x) JavaScript1.0 Returnstheabsolute(positive)valueofanumber.acos(x) JavaScript1.0 Returnsthearccosineofanumber(inradians).asin(x) JavaScript1.0 Returnsthearcsineofanumber(inradians).atan(x) JavaScript1.0 Returnsthearctangentofanumber(inradians).atan2(y,

x)

JavaScript1.0 Returnstheangle(inradians)betweenthex-axisandthepositionrepresentedbytheyandxcoordinatespassedinasparameters.

ceil(x) JavaScript1.0 Returnsthevalueofanumberroundeduptothenearestinteger.

cos(x) JavaScript1.0 Returnsthecosineofanumber.exp(x) JavaScript1.0 ReturnsEtothepoweroftheargumentpassedin.floor(x) JavaScript1.0 Returnsthevalueofanumberroundeddowntothenearest

integer.log(x) JavaScript1.0 Returnsthenaturallogarithm(baseE)ofanumber.max(a,b) JavaScript1.0 Returnsthegreateroftwonumberspassedinas

parameters.min(a,b) JavaScript1.0 Returnsthelesseroftwonumberspassedinasparameters.pow(x,y) JavaScript1.0 Returnsthefirstparameterraisedtothepowerofthe

second.random() JavaScript1.1 Returnsapseudo-randomnumberbetween0and1.round(x) JavaScript1.0 Returnsthevalueofanumberroundedupordowntothe

nearestinteger.sin(x) JavaScript1.0 Returnsthesineofanumber.sqrt(x) JavaScript1.0 Returnsthesquarerootofanumber.tan(x) JavaScript1.0 Returnsthetangentofanumber.

NumberTheNumberobjectactsasawrapperforprimitivenumericvalues.IntroducedinJavaScript1.1,aNumberobjectiscreatedusingtheNumberconstructorwiththeinitialvalueforthenumberpassedinasaparameter.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionforthe

object.MAX_VALUE JavaScript1.1 Returnsthelargestnumberthatcanbe

representedinJavaScript(approximately1.79E+308).

MIN_VALUE JavaScript1.1 ReturnsthesmallestnumberthatcanberepresentedinJavaScript(5E–324).

NaN JavaScript1.1 Returnsavaluethatis“notanumber.”NEGATIVE_INFINITY JavaScript1.1 Returnsavaluerepresentingnegativeinfinity.POSITIVE_INFINITY JavaScript1.1 Returnsavaluerepresenting(positive)infinity.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbe

usedtoextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONtoExponential(fractionDigits) JavaScript1.5 Returnsastringcontainingthe

exponentnotationofanumber.Theparametershouldbebetween0and20anddeterminesthenumberofdigitsafterthedecimal.

toFixed([digits]) JavaScript1.5 Theformatnumberfordigitsnumberofdigits.Thenumberisroundedup,and0sareaddedafterthedecimalpointtoachievethedesireddecimallength.

toPrecision([precision]) JavaScript1.5 ReturnsastringrepresentingtheNumberobjecttothespecifiedprecision.

toString() JavaScript1.1 ConvertstheNumberobjectintoastring.

valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheNumberobject.

ObjectObjectistheprimitivetypeforJavaScriptobjects,fromwhichallotherobjectsaredescended(thatis,allotherobjectsinheritthemethodsandpropertiesoftheObjectobject).IntroducedinJavaScript1.0,youcancreateanObjectobjectusingtheObjectconstructorasfollows:

varobj=newObject();

Youcanalsocreateanobjectusingobjectliteralnotationlikethis:

varobj={};

Literalnotationisthepreferredmethodofcreatinganobject.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONhasOwnProperty(propertyName) JavaScript1.5 Checkswhetherthespecified

propertyisinherited.Returnstrueifnotinherited;falseifinherited.

isPrototypeOf(obj) JavaScript1.5 Determinesifthespecifiedobjectistheprototypeofanotherobject.

propertyIsEnumerable(propertyName) JavaScript1.5 Determinesifthespecifiedpropertycanbeseenbyaforinloop.

toString() JavaScript1.0 ConvertstheObjectobjectintoastring.

valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheObjectobject.

RegExpTheRegExpobjectisusedtofindpatternswithinstringvalues.RegExpobjectscanbecreatedintwoways:usingtheRegExpconstructororatextliteral.ItwasintroducedinJavaScript1.2.

Someofthepropertiesinthefollowingtablehavebothlongandshortnames.TheshortnamesarederivedfromthePerlprogramminglanguage.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.2 Usedtoreferencetheconstructorfunctionfortheobject.global JavaScript1.2 Indicateswhetherallpossiblematchesinthestringareto

bemade,oronlythefirst.Correspondstothegflag.ignoreCase JavaScript1.2 Indicateswhetherthematchistobecase-insensitive.

Correspondstotheiflag.input JavaScript1.2 Thestringagainstwhichtheregularexpressionis

matched.lastIndex JavaScript1.2 Thepositioninthestringfromwhichthenextmatchis

tobestarted.multiline JavaScript1.2 Indicateswhetherstringsaretobesearchedacross

multiplelines.Correspondswiththemflag.prototype JavaScript1.2 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.source JavaScript1.2 Thetextofthepatternfortheregularexpression.

Methods

METHOD INTRODUCED DESCRIPTIONexec(stringToSearch) JavaScript1.2 Executesasearchforamatchinthestring

parameterpassedin.test(stringToMatch) JavaScript1.2 Testsforamatchinthestringparameter

passedin.toString() JavaScript1.2 ConvertstheRegExpobjectintoastring.valueOf() JavaScript1.2 ReturnstheprimitivevalueoftheRegExp

object.

SpecialCharactersUsedinRegularExpressions

CHARACTER EXAMPLES FUNCTION\ /n/matchesn;/\n/

matchesalinefeedcharacter;/^/matchesthestartofaline;and/\^/matches^.

Forcharactersthatarebydefaulttreatedasnormalcharacters,thebackslashindicatesthatthenextcharacteristobeinterpretedwithaspecialvalue.Forcharactersthatareusuallytreatedasspecialcharacters,thebackslashindicatesthatthenextcharacteristobeinterpretedasanormalcharacter.

^ /^A/matchesthefirstbutnotthesecondAin“AmancalledAdam.”

Matchesthestartofalineoroftheinput.

$ /r$/matchesonlythelastrin“horror.”

Matchestheendofalineoroftheinput.

* /ro*/matchesrin“right,”roin“wrong,”and“roo”in“room.”

Matchestheprecedingcharacterzeroormoretimes.

+ /l+/matcheslin“life,”llin“still,”andlllin“stilllife.”

Matchestheprecedingcharacteroneormoretimes.Forexample,/a+/matchestheain“candy”andalltheasin“caaaaaaandy.”

? /Smythe?/matches“Smyth”and“Smythe.”

Matchestheprecedingcharacteronceorzerotimes.

. /.b/matchesthesecondbutnotthefirstobin“blob.”

Matchesanycharacterapartfromthenewlinecharacter.

(x) /(Smythe?)/matches“Smyth”and“Smythe”in“JohnSmythandRobSmythe”andallowsthesubstringstoberetrievedasRegExp.$1andRegExp.$2,respectively.

Matchesxandremembersthematch.Thematchedsubstringcanberetrievedfromtheelementsofthearraythatresultsfromthematch,orfromtheRegExpobject’sproperties$1,$2…$9,orlastParen.

x|y /Smith|Smythe/

matches“Smith”and“Smythe.”

Matcheseitherxory(wherexandyareblocksofcharacters).

{n} /l{2}/matchesllin“still”andthefirsttwolsin“stilllife.”

Matchesexactlyninstancesoftheprecedingcharacter(wherenisapositiveinteger).

{n,} /l{2,}/matchesllin“still”andlllin“stilllife.”

Matchesnormoreinstancesoftheprecedingcharacter(wherenisapositiveinteger).

{n,m} /l{1,2}/matcheslin“life,”llin“still,”andthefirsttwolsin“stilllife.”

Matchesbetweennandminstancesoftheprecedingcharacter(wherenandmarepositiveintegers).

[xyz] [ab]matchesaandb;[a-c]matchesa,bandc.

Matchesanyoneofthecharactersinthesquarebrackets.Arangeofcharactersinthealphabetcanbematchedusingahyphen.

[^xyz] [^aeiouy]matchessin“easy”;[^a-y]matcheszin“lazy.”

Matchesanycharacterexceptthoseenclosedinthesquarebrackets.Arangeofcharactersinthealphabetcanbespecifiedusingahyphen.

[\b] Matchesabackspace.\b /t\b/matchesthefirstt

in“abouttime.”Matchesawordboundary(forexample,aspaceortheendofaline).

\B /t\Bi/matchestiin Matcheswhenthereisnowordboundaryin

“itistime.” thisposition.\cX /\cA/matchesCtrl+A. Matchesacontrolcharacter.\d /IE\d/matchesIE4,

IE5,etc.Matchesadigitcharacter.Thisisidenticalto[0-9].

\D /\D/matchesthedecimalpointin“3.142.”

Matchesanycharacterthatisnotadigit.Thisisidenticalto[^0-9].

\f Matchesaform-feedcharacter.\n Matchesaline-feedcharacter.\r Matchesacarriagereturncharacter.\s /\s/matchesthespace

in“notnow.”Matchesanywhitespacecharacter,includingspace,tab,line-feed,etc.Thisisidenticalto[\f\n\r\t\v].

\S /\S/matchesain“a.” Matchesanycharacterotherthanawhitespacecharacter.Thisisidenticalto[^\f\n\r\t\v].

\t Matchesatabcharacter.\v Matchesaverticaltabcharacter.\w /\w/matchesOin“O?!”

and1in“$1.”Matchesanyalphanumericcharacterortheunderscore.Thisisidenticalto[A-Za-z0-9_].

\W /\W/matches$in“$10million”and@in“j_smith@wrox.”

Matchesanynon-alphanumericcharacter(excludingtheunderscore).Thisisidenticalto[^A-Za-z0-9_].

()\n /(Joh?n)and\1/matchesJohnandJohnin“JohnandJohn'sfriend”butdoesnotmatch“JohnandJon.”

Matchesthelastsubstringthatmatchedthenthmatchplacedinparenthesesandremembered(wherenisapositiveinteger).

\octal\xhex /\x25/matches%. Matchesthecharactercorrespondingtothespecifiedoctalorhexadecimalescapevalue.

StringTheStringobjectisusedtocontainastringofcharacters.ItwasintroducedinJavaScript1.0.Thismustbedistinguishedfromastringliteral,butthemethodsandpropertiesoftheStringobjectcanalsobeaccessedbyastringliteral,becauseatemporaryobjectwillbecreatedwhentheyarecalled.

TheHTMLmethodsinthelasttablearenotpartofanyECMAScriptstandard,buttheyhavebeenpartoftheJavaScriptlanguagesinceversion1.0.TheycanbeusefulbecausetheydynamicallygenerateHTML.

Properties

PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.length JavaScript1.0 Returnsthenumberofcharactersinthestring.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused

toextendtheobject’sinterface.

Methods

METHOD INTRODUCED DESCRIPTIONcharAt(index) JavaScript1.0 Returnsthecharacteratthespecifiedposition

inthestring.charCodeAt(index) JavaScript1.2 ReturnstheUnicodevalueofthecharacterat

thespecifiedpositioninthestring.concat(value1,

value2,...)

JavaScript1.2 Concatenatesthestringssuppliedasargumentsandreturnsthestringthusformed.

fromCharCode(value1,

value2,...)

JavaScript1.2 ReturnsthestringformedfromtheconcatenationofthecharactersrepresentedbythesuppliedUnicodevalues.

indexOf(substr[,

startIndex])

JavaScript1.0 ReturnsthepositionwithintheStringobjectofthefirstmatchforthesuppliedsubstring.Returns-1ifthesubstringisnotfound.StartsthesearchatstartIndexifspecified.

lastIndexOf(substr

[,startIndex])

JavaScript1.0 ReturnsthepositionwithintheStringobjectofthelastmatchforthesuppliedsubstring.Returns-1ifthesubstringisnotfound.StartsthesearchatstartIndexifspecified.

match(regexp) JavaScript1.2 Searchesthestringforamatchtothesuppliedpattern.Returnsanarrayornullifnotfound.

replace(regexp,

newValue)

JavaScript1.2 Usedtoreplaceasubstringthatmatchesaregularexpressionwithanewvalue.

search(regexp) JavaScript1.2 Searchesforamatchbetweenaregularexpressionandthestring.Returnstheindexofthematch,or-1ifnotfound.

slice(startIndex[,

endIndex])

JavaScript1.0 ReturnsasubstringoftheStringobject.

split(delimiter) JavaScript1.1 SplitsaStringobjectintoanarrayofstringsbyseparatingthestringintosubstrings.

substr(startIndex[,

length])

JavaScript1.0 Returnsasubstringofthecharactersfromthegivenstartingpositionandcontainingthespecifiednumberofcharacters.

substring(startIndex

[,endIndex])

JavaScript1.0 Returnsasubstringofthecharactersbetweentwopositionsinthestring.ThecharacteratendIndexisnotincludedinthesubstring.

toLowerCase() JavaScript1.0 Returnsthestringconvertedtolowercase.toUpperCase() JavaScript1.0 Returnsthestringconvertedtouppercase.

HTMLMethods

METHOD INTRODUCED DESCRIPTIONanchor(name) JavaScript1.0 Returnsthestringsurroundedby<a>...</a>tags

withthenameattributeassignedthepassedparameter.

big() JavaScript1.0 Enclosesthestringin<big>…</big>tags.blink() JavaScript1.0 Enclosesthestringin<blink>…</blink>tags.bold() JavaScript1.0 Enclosesthestringin<b>…</b>tags.fixed() JavaScript1.0 Enclosesthestringin<tt>…</tt>tags.fontcolor(color) JavaScript1.0 Enclosesthestringin<font>…</font>tagswith

thecolorattributeassignedaparametervalue.fontsize(size) JavaScript1.0 Enclosesthestringin<font>…</font>tagswith

thesizeattributeassignedaparametervalue.italics() JavaScript1.0 Enclosesthestringin<i>…</i>tags.link(url) JavaScript1.0 Enclosesthestringin<a>…</a>tagswiththe

hrefattributeassignedaparametervalue.small() JavaScript1.0 Enclosesthestringin<small>…</small>tags.strike() JavaScript1.0 Enclosesthestringin<strike>…</strike>tags.sub() JavaScript1.0 Enclosesthestringin<sub>…</sub>tags.sup() JavaScript1.0 Enclosesthestringin<sup>…</sup>tagsand

causesastringtobedisplayedassuperscript.

CW3CDOMReferenceBecauseJavaScriptisprimarilyusedtoprogramthebrowserandaddbehaviortowebpages,it’sonlynaturaltoincludeareferencetotheW3CDOM.

ThefollowingpageslisttheobjectsmadeavailablebytheW3CDOM.

DOMCOREOBJECTSThissectiondescribesandlistsobjectsdefinedbytheDOMstandards—startingwiththelowestlevelofDOMobjects.Allobjectsareinalphabeticalorder.

Low-LevelDOMObjectsTheDOMspecificationdescribestheNode,NodeList,andNamedNodeMapobjects.Thesearethelowest-levelobjectsintheDOM,andaretheprimarybuildingblocksofhigher-levelobjects.

NodeDefinedinDOMLevel1,theNodeobjectistheprimarydatatypefortheentireDOM.AllobjectsintheDOMinheritfromNode.Thereare12differenttypesofNodeobjects;eachtypehasanassociatedintegervalue.ThefollowingtableslisttheNodeobject’stypevalues,properties,andmethods.

NodeTypes

TYPENAME INTEGERVALUE

INTRODUCED ASSOCIATEDDATATYPE

ELEMENT_NODE 1 Level1 Element

ATTRIBUTE_NODE 2 Level1 Attr

TEXT_NODE 3 Level1 Text

CDATA_SECTION_NODE 4 Level1 CDATASection

ENTITY_REFERENCE_NODE 5 Level1 EntityReference

ENTITY_NODE 6 Level1 Entity

PROCESSING_INSTRUCTION_NODE 7 Level1 ProcessingInstruction

COMMENT_NODE 8 Level1 Comment

DOCUMENT_NODE 9 Level1 Document

DOCUMENT_TYPE_NODE 10 Level1 DocumentType

DOCUMENT_FRAGMENT_NODE 11 Level1 DocumentFragment

NOTATION_NODE 12 Level1 Notation

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

attributes ANamedNodeMapcontainingtheattributesofthisnodeifitisanElement,ornullotherwise.

Level1

childNodes ANodeListcontainingallchildrenofthisnode. Level1firstChild Getsthefirstchildofthisnode.Returnsnullifno

childexists.Level1

lastChild Getsthelastchildofthisnode.Returnsnullifnochildexists.

Level1

localName Returnsthelocalpartofthenode’squalifiedname(thepartafterthecolonofthequalifiednamewhennamespacesareused).UsedprimarilyinXMLDOMs.

Level2

namespaceURI ThenamespaceURIofthenode,ornullifnotspecified.

Level2

nextSibling Getsthenodeimmediatelyfollowingthisnode.Returnsnullifnofollowingsiblingexists.

Level1

nodeName Getsthenameofthisnode. Level1nodeType Anintegerrepresentingthetypeofthisnode.See

previoustable.Level1

nodeValue Getsthevalueofthisnode,dependingonthetype. Level1ownerDocument GetstheDocumentobjectthisnodeiscontainedin.

IfthisnodeisaDocumentnode,itreturnsnull.Level1

parentNode Getstheparentnodeofthisnode.ReturnsnullfornodesthatarecurrentlynotintheDOMtree.

Level1

prefix Returnsthenamespaceprefixofthisnode,ornullifnotspecified.

Level2

previousSibling Getsthenodeimmediatelybeforethisnode.Returnsnullifnoprevioussibling.

Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDappendChild(newChild) AddsthenewChildtotheendofthelistof

children.Level1

cloneNode(deep) Returnsaduplicateofthenode.Thereturnednodehasnoparent.Ifdeepistrue,thisclonesallnodescontainedwithinthenode.

Level1

hasAttributes() Returnsabooleanvaluebasedonifthenodehasanyattributes(ifthenodeisanelement).

Level2

hasChildNodes() Returnsabooleanvaluebasedonwhetherthenodehasanychildnodes.

Level1

insertBefore(newChild,

refChild)

InsertsthenewChildnodebeforetheexistingchildreferencedbyrefChild.IfrefChildisnull,newChildisaddedattheendofthelistofchildren.

Level1

removeChild(oldChild) Removesthespecifiedchildnodeandreturnsit.

Level1

replaceChild(newChild,

oldChild)

ReplacesoldChildwithnewChildandreturnsoldChild.

Level1

NodeListTheNodeListobjectisanorderedcollectionofnodes.TheitemscontainedintheNodeListareaccessibleviaanindexstartingfrom0.

ANodeListisalivesnapshotofnodes.AnychangesmadetothenodeswithintheDOMareimmediatelyreflectedineveryreferenceoftheNodeList.

Properties

PROPERTYNAME DESCRIPTION INTRODUCEDlength Thenumberofnodesinthelist. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

item(index) Returnstheitematthespecifiedindex.Returnsnulliftheindexisgreaterthanorequaltothelist’slength.

Level1

NamedNodeMapObjectsreferredtoasNamedNodeMapsrepresentcollectionsofnodesthatcanbeaccessedbyname.ThisobjectdoesnotinheritfromNodeList.Anelement’sattributelistisanexampleofaNamedNodeMap.

Properties

PROPERTYNAME DESCRIPTION INTRODUCEDlength Thenumberofnodesinthemap. Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDgetNamedItem(name) Retrievesanodebythespecifiedname. Level1removeNamedItem(name) Removesanitembythespecifiedname. Level1setNamedItem(node) AddsanodetothelistbyusingitsnodeName

propertyasitskey.Level1

High-LevelDOMObjectsTheseobjectsinheritNodeandarethebasisforevenhigher-levelDOMobjectsasspecifiedbytheHTMLDOM.Theseobjectsmirrorthedifferentnodetypes.

Thefollowingobjectsarelistedinalphabeticalorder.TheCDATASection,Comment,DocumentType,Entity,EntityReference,Notation,andProcessingInstructionobjectsarepurposefullyomittedfromthissection.

AttrTheAttrobjectrepresentsanElementobject’sattribute.EventhoughAttrobjectsinheritfromNode,theyarenotconsideredchildrenoftheelementtheydescribe,andthusarenotpartoftheDOMtree.TheNodepropertiesofparentNode,previousSibling,andnextSiblingreturnnullforAttrobjects.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

ownerElement ReturnstheElementobjecttheattributeisattachedto.

Level2

name Returnsthenameoftheattribute. Level1value Returnsthevalueoftheattribute. Level1

DocumentTheDocumentobjectrepresentstheentireHTMLorXMLdocument.Itistherootofthedocumenttree.TheDocumentisthecontainerforallnodeswithinthedocument,andeachNodeobject’sownerDocumentpropertypointstotheDocument.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

docType TheDocTypeobjectassociatedwiththisdocument.ReturnsnullforHTMLandXMLdocumentswithoutadocumenttypedeclaration.

Level1

documentElement Returnstherootelementofthedocument.ForHTMLdocuments,thedocumentElementisthe<html/>element.

Level1

implementation TheDOMImplementationobjectassociatedwiththeDocument.

Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDcreateAttribute(name) ReturnsanewAttrobject

withthespecifiedname.Level1

createAttributeNS(namespaceURI,

qualifiedName)

ReturnsanattributewiththegivenqualifiednameandnamespaceURI.NotforHTMLDOMs.

Level2

createComment(data) ReturnsanewCommentobjectwiththespecifieddata.

Level1

createCDATASection(data) ReturnsanewCDATASectionobjectwhosevalueisthespecifieddata.

Level1

createDocumentFragment() ReturnsanemptyDocumentFragmentobject.

Level1

createElement(tagName) ReturnsanewElementobjectwiththespecifiedtagname.

Level1

createElementNS(namespaceURI,

qualifiedName)

ReturnsanelementofthespecifiedqualifiednameandnamespaceURI.NotforHTMLDOMs.

Level2

createTextNode(text) ReturnsanewTextobjectcontainingthespecifiedtext.

Level1

getElementById(elementId) ReturnstheElementwiththespecifiedIDvalue.Returnsnulliftheelementdoesnotexist.

Level2

getElementsByTagName(tagName) ReturnsaNodeListofallElementobjectswiththespecifiedtagnameintheorderinwhichtheyappearintheDOMtree.

Level1

getElementsByTagNameNS(namespaceURI,

localName)

ReturnsaNodeListofallelementswiththespecifiedlocalnameandnamespaceURI.ElementsreturnedareintheordertheyappearintheDOM.

Level2

importNode(importedNode,deep) Importsanodefromanotherdocument.Thesourcenodeisnotalteredorremovedfromitsdocument.Acopyofthesourceiscreated.Ifdeepistrue,allchildnodesoftheimportednodeareimported.Iffalse,onlythenodeisimported.

Level2

DocumentFragmentTheDocumentFragmentobjectisalightweightDocumentobject.Itsprimarypurposeisefficiency.MakingmanychangestotheDOMtree,suchasappendingseveralnodesindividually,isanexpensiveprocess.ItispossibletoappendNodeobjectstoaDocumentFragmentobject,whichallowsyoutoeasilyandefficientlyinsertallnodescontainedwithintheDocumentFragmentintotheDOMtree.

ThefollowingcodeshowstheuseofaDocumentFragment:

vardocumentFragment=document.createDocumentFragment();

for(vari=0;i<1000;i++){

varelement=document.createElement(“div”);

vartext=document.createTextNode(“Hereistestfordiv#”+i);

element.setAttribute(“id”,i);

documentFragment.appendChild(element);

}

document.body.appendChild(documentFragment);

WithouttheDocumentFragmentobject,thiscodewouldupdatetheDOMtree1,000times,thusdegradingperformance.WiththeDocumentFragmentobject,theDOMtreeisupdatedonlyonce.

TheDocumentFragmentobjectinheritstheNodeobject,andassuchhasNode’sproperties

andmethods.Itdoesnothaveanyotherpropertiesormethods.

ElementElementsarethemajorityofobjects,otherthantext,thatyouwillencounterintheDOM.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

tagName Returnsthenameoftheelement.ThesameasNode.nodeNameforthisnodetype.

Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDgetAttribute(name) Retrievestheattribute’s

valuebythespecifiedname.

Level1

getAttributeNS(namespaceURI,

localName)

ReturnstheAttrobjectbylocalnameandnamespaceURI.NotforHTMLDOMs.

Level2

getAttributeNode(name) ReturnstheAttrobjectassociatedwiththespecifiedname.Returnsnullifnoattributebythatnameexists.

Level1

getElementsByTagName(tagName) ReturnsaNodeListofalldescendantelementswiththespecifiedtagNameintheorderinwhichtheyappearinthetree.

Level1

getElementsByTagNameNS(namespaceURI,

localName)

ReturnsaNodeListofallthedescendantElementobjectswiththespecifiedlocalnameandnamespaceURI.NotforHTMLDOMs.

Level2

hasAttribute(name) Returnsabooleanvaluebasedonwhetherornottheelementhasanattributewiththespecifiedname.

Level2

hasAttributeNS(namespaceURI,

localName)

Returnsabooleanvaluebasedonwhetherthe

Level2

ElementhasanattributewiththegivenlocalnameandnamespaceURI.NotforHTMLDOMs.

querySelector(selector) Retrievesthefirstchildelementthatmatchesthespecifiedselector.

Level3

querySelectorAll(selector) Retrievesallchildelementsthatmatchthespecifiedselector.

Level3

removeAttribute(name) Removestheattributewiththespecifiedname.

Level1

removeAttributeNS(namespaceURI,

localName)

RemovesanattributespecifiedbythelocalnameandnamespaceURI.NotforHTMLDOMs.

Level2

removeAttributeNode(oldAttr) Removesandreturnsthespecifiedattribute.

Level1

setAttribute(name,value) Createsandaddsanewattribute,orchangesthevalueofanexistingattribute.Thevalueisasimplestring.

Level1

setAttributeNS(namespaceURI,

qualifiedName,value)

CreatesandaddsanewattributewiththespecifiednamespaceURI,qualifiedname,andvalue.

Level2

setAttributeNode(newAttr) Addsthespecifiedattributetotheelement.Replacestheexistingattributewiththesamenameifitexists.

Level1

setAttributeNodeNS(newAttr) Addsthespecifiedattributetotheelement.

Level2

TextTheTextobjectrepresentstextcontentofanElementorAttrobject.

Methods

METHODNAME DESCRIPTION INTRODUCEDsplitText(indexOffset) BreakstheTextnodeintotwonodesatthe

specifiedoffset.ThenewnodesstayintheDOMtreeassiblings.

Level1

HTMLDOMOBJECTSInordertoadequatelyinterfacewiththeDOM,theW3CextendstheDOMLevel1and2specificationstodescribeobjects,properties,andmethods,specifictoHTMLdocuments.

Mostoftheobjectsyou’llinterfacewithasafront-enddeveloperarecontainedinthissection.

MiscellaneousObjects:TheHTMLCollectionTheHTMLCollectionobjectisalistofnodes,muchlikeNodeList.ItdoesnotinheritfromNodeList,butHTMLCollectionsareconsideredlive,likeNodeLists,andareautomaticallyupdatedwhenchangesaremadetothedocument.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

length Returnsthenumberofelementsinthecollection.

Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

item(index) Returnstheelementatthespecifiedindex.Returnsnullifindexislargerthanthecollection’slength.

Level1

namedItem(name) Returnstheelementusinganame.Itfirstsearchesforanelementwithamatchingidattributevalue.Ifnonearefound,itsearchesforelementswithamatchingnameattributevalue.

Level1

HTMLDocumentObjects:TheHTMLDocumentTheHTMLDocumentobjectistherootofHTMLdocumentsandcontainstheentirecontent.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

anchors ReturnsanHTMLCollectionofall<a/>elementsinthedocumentthathaveavalueassignedtotheirnameattribute.

Level1

applets ReturnsanHTMLCollectionofall<applet/>elementsand<object/>elementsthatincludeappletsinthedocument.

Level1

body Returnstheelementthatcontainsthedocument’scontent.Returnsthe<body/>element,ortheoutermost<frameset/>elementdependingonthedocument.

Level1

cookie Returnsthecookiesassociatedwiththedocument.Returnsanemptystringifnone.

Level1

domain Returnsthedomainnameoftheserverthatservedthedocument.Returnsnullifthedomainnamecannotbeidentified.

Level1

forms ReturnsanHTMLCollectionofall<form/>elementsinthedocument.

Level1

images ReturnsanHTMLCollectionobjectcontainingall<img/>elementsinthedocument.

Level1

links ReturnsanHTMLCollectionofall<area/>and<a/>elements(withanhrefvalue)inthedocument.

Level1

referrer ReturnstheURLofthepagethatlinkedtothepage.Returnsanemptystringiftheusernavigateddirectlytothepage.

Level1

title Thetitleofthedocumentasspecifiedbythe<title/>elementinthedocument’s<head/>element.

Level1

URL ThecompleteURLofthedocument. Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDclose() Closesadocument. Level1getElementById(elementId) Returnstheelementwiththegiven

elementIdornullifnoelementcouldbefound.RemovedinDOMLevel2andaddedtotheDocumentobject.

Level1

getElementsByName(name) ReturnsanHTMLCollectionofelementswiththespecifiednameattributevalue.

Level1

open() Opensadocumentforwriting. Level1write() Writesastringoftexttothedocument. Level1writeln() Writesastringoftexttothedocument

followedbyanewline.Level1

HTMLElementObjectsHTMLelementattributesareexposedaspropertiesofthevariousHTMLelementobjects.Theirdatatypeisdeterminedbytheattribute’stypeintheHTML4.0specification.

OtherthanHTMLElement,allHTMLelementobjectsaredescribedhereinalphabeticalorder.ThefollowingpagesdonotcontainacompletelistofHTMLelementobjecttypes.Instead,onlythefollowingelementobjecttypesarelisted:

HTMLAnchorElement

HTMLBodyElement

HTMLButtonElement

HTMLDivElement

HTMLFormElement

HTMLFrameElement

HTMLFrameSetElement

HTMLIFrameElement

HTMLImageElement

HTMLInputElement

HTMLOptionElement

HTMLParagraphElement

HTMLSelectElement

HTMLTableCellElement

HTMLTableElement

HTMLTableRowElement

HTMLTableSectionElement

HTMLTextAreaElement

HTMLElementHTMLElementisthebaseobjectforallHTMLelements,muchlikehowNodeisthebaseobjectforallDOMnodes.Therefore,allHTMLelementshavethefollowingproperties.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

className Getsorsetsthevalueoftheelement’sclassattribute.

Level1

id Getsorsetsthevalueoftheelement’sidattribute. Level1

HTMLAnchorElementRepresentstheHTML<a/>element.

Properties

PROPERTYNAME DESCRIPTION INTRODUCEDaccessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1href Getsorsetsthevalueofthehrefattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1target Getsorsetthevalueofthetargetattribute. Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDblur() Removesthekeyboardfocusfromtheelement. Level1focus() Giveskeyboardfocustotheelement. Level1

HTMLBodyElementRepresentsthe<body/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

aLink Deprecated.Getsorsetsthevalueofthealinkattribute.

Level1

background Deprecated.Getsorsetsthevalueofthebackgroundattribute.

Level1

bgColor Deprecated.GetsorsetsthevalueofthebgColorattribute.

Level1

link Deprecated.Getsorsetsthevalueofthelinkattribute.

Level1

text Deprecated.Getsorsetsthevalueofthetextattribute.

Level1

vLink Deprecated.Getsorsetsthevalueofthevlinkattribute.

Level1

HTMLButtonElementRepresents<button/>elements.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthebutton.

Returnsnullifthebuttonisnotinsideaform.Level1

name Getsorsetsthevalueofthenameattribute. Level1type Getsthevalueofthetypeattribute. Level1value Getsorsetsthevalueofthevalueattribute. Level1

HTMLDivElementRepresentsthe<div/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

HTMLFormElementRepresentsthe<form/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

action Getsorsetsthevalueoftheactionattribute. Level1elements ReturnsanHTMLCollectionobjectcontainingallform

controlelementsintheform.Level1

enctype Getsorsetsthevalueoftheenctypeattribute. Level1length Returnsthenumberofformcontrolswithintheform. Level1method Getsorsetsthevalueofthemethodattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1target Getsorsetsthevalueofthetargetattribute. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

reset() Resetsallformcontrolelementscontainedwithintheformtotheirdefaultvalues.

Level1

submit() Submitstheform.Doesnotfirethesubmitevent. Level1

HTMLFrameElementRepresentsthe<frame/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

contentDocument GetstheDocumentobjectfortheframe.Returnsnullifoneisn’tavailable.

Level2

frameBorder GetsorsetsthevalueoftheframeBorderattribute. Level1marginHeight GetsorsetsthevalueofthemarginHeightattribute. Level1marginWidth GetsorsetsthevalueofthemarginWidthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1noResize GetsorsetsthevalueofthenoResizeattribute. Level1scrolling Getsorsetsthevalueofthescrollingattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1

HTMLFrameSetElementRepresentsthe<frameset/>element.

Properties

PROPERTYNAME DESCRIPTION INTRODUCEDcols Getsorsetsthevalueofthecolsattribute. Level1rows Getsorsetsthevalueoftherowsattribute. Level1

HTMLIFrameElementRepresentsthe<iframe/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

contentDocument GetstheDocumentobjectoftheframe.Returnsnullifonedoesn’texist.

Level2

frameBorder GetsorsetsthevalueoftheframeBorderattribute. Level1height Getsorsetsthevalueoftheheightattribute. Level1marginHeight GetsorsetsthevalueofthemarginHeightattribute. Level1marginWidth GetsorsetsthevalueofthemarginWidthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1noResize GetsorsetsthevalueofthenoResizeattribute. Level1scrolling Getsorsetsthevalueofthescrollingattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1width Getsorsetsthevalueofthewidthattribute. Level1

HTMLImageElementRepresentsthe<img/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

alt Getsorsetsthevalueofthealtattribute. Level1border Deprecated.Getsorsetsthevalueoftheborder

attribute.Level1

height Getsorsetsthevalueoftheheightattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1width Getsorsetsthevalueofthewidthattribute. Level1

HTMLInputElementRepresentsthe<input/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1align Deprecated.Getsorsetsthevalueofthealign

attribute.Level1

alt Getsorsetsthevalueofthealtattribute. Level1checked Usedwhentypeischeckboxorradio.Returnsa

booleanvaluedependingonwhetherornotthecheckboxorradiobuttonischecked.

Level1

defaultChecked Usedwhentypeischeckboxorradio.Getsorsetsthecheckedattribute.Thevaluedoesnotchangewhenothercheckboxesorradiobuttonsarechecked.

Level1

disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe

<input/>element.Returnsnulliftheelementisnotinsideaform.

Level1

maxLength GetsorsetsthevalueofthemaxLengthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1readOnly Usedonlyiftypeistextorpassword.Getsorsets

thevalueofthereadonlyattribute.Level1

size Getsorsetsthevalueofthesizeattribute. Level1src Iftypeisimage,thisgetsorsetsthevalueofthesrc

attribute.Level1

type Getsthevalueofthetypeattribute. Level1value Getsorsetsthevalueofthevalueattribute. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

blur() Removeskeyboardfocusfromtheelement. Level1click() Simulatesamouseclickfor<input/>elementswithtype

button,checkbox,radio,reset,andsubmit.Level1

focus() Giveskeyboardfocustotheelement. Level1select() Selectscontentof<input/>elementswithtypetext,

password,andfile.Level1

HTMLOptionElementRepresentsthe<option/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

defaultSelected Getsorsetstheselectedattribute.Thevalueofthispropertydoesnotchangeasother<option/>elementsinthe<select/>elementareselected.

Level1

disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe

<option/>element.Returnsnulliftheelementisnotinsideaform.

Level1

index Getstheindexpositionofthe<option/>elementinitscontaining<select/>element.Startsat0.

Level1

label Getsorsetsthevalueofthelabelattribute. Level1selected Returnsabooleanvaluedependingonwhetheror

notthe<option/>elementiscurrentlyselected.Level1

text Getsthetextcontainedwithinthe<option/>element.

Level1

value Getsorsetsthevalueofthevalueattribute. Level1

HTMLOptionCollectionTheHTMLOptionCollectionobjectwasintroducedinDOMLevel2.Itcontainsalistof<option/>elements.

PROPERTYNAME

DESCRIPTION INTRODUCED

length Getsthenumberof<option/>elementsinthelist.

Level2

Methods

METHODNAME

DESCRIPTION INTRODUCED

item(index) Retrievesthe<option/>elementatthespecifiedindex.

Level2

namedItem(name) Retrievesthe<option/>elementbythespecifiedname.Itfirstattemptstofindan<option/>elementwiththespecifiedid.Ifnonecanbefound,itlooksfor<option/>elementswiththespecifiednameattribute.

Level2

HTMLParagraphElementRepresentsthe<p/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

HTMLSelectElementRepresentsthe<select/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe

<select/>element.Returnsnulliftheelementisnotinsideaform.

Level1

length Returnsthenumberof<option/>elements. Level1multiple Getsorsetsthevalueofthemultipleattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1options ReturnsanHTMLOptionsCollectionobjectcontaining

thelistofthe<option/>elements.Level1

selectedIndex Returnstheindexofthecurrentlyselected<option/>element.Returns-1ifnothingisselectedandreturnsthefirst<option/>elementselectedifmultipleitemsareselected.

Level1

size Getsorsetsthevalueofthesizeattribute. Level1type Getsthevalueofthetypeattribute. Level1value Getsorsetsthecurrentformcontrol’svalue. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

add(element[,

before])

Addsan<option/>elementtothe<select/>element.Ifbeforeisnull,thenelementisaddedattheendofthelist.

Level1

blur() Removeskeyboardfocusfromtheelements. Level1focus() Giveskeyboardfocustotheelement. Level1remove(index) Removesthe<option/>elementatthegivenindex.

Doesnothingifindexisoutofrange.Level1

HTMLTableCellElement

Representsthe<td/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

bgColor Deprecated.Getsorsetsthevalueofthebgcolorattribute.

Level1

cellIndex TheindexofthecellintherowinDOMtreeorder. Level1colSpan Getsorsetsthevalueofthecolspanattribute. Level1height Deprecated.Getsorsetsthevalueoftheheight

attribute.Level1

noWrap Deprecated.Getsorsetsthevalueofthenowrapattribute.

Level1

rowSpan GetsorsetsthevalueoftherowSpanattribute. Level1vAlign Getsorsetsthevalueofthevalignattribute. Level1width Deprecated.Getsorsetsthevalueofthewidth

attribute.Level1

HTMLTableElementRepresentsthe<table/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute. Level1bgColor Deprecated.Getsorsetsthevalueofthebgcolor

attribute.Level1

border Getsorsetsthevalueoftheborderattribute. Level1cellPadding GetsorsetsthevalueofthecellPaddingattribute. Level1cellSpacing GetsorsetsthevalueofthecellSpacingattribute. Level1rows ReturnsanHTMLCollectioncontainingallrowsinthe

table.Level1

tBodies ReturnsanHTMLCollectionofthedefined<tbody/>elementobjectsinthetable.

Level1

tFoot Returnsthetable’s<tfoot/>elementobject(HTMLTableSectionElement),ornullifonedoesn’texist.

Level1

tHead Returnsthetable’s<thead/>elementobject(HTMLTableSectionElement),ornullifonedoesn’texist.

Level1

width Getsorsetsthevalueofthewidthattribute. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

createTFoot() Createsandreturnsa<tfoot/>elementifonedoesnotexist.Returnstheexisting<tfoot/>elementifitexists.

Level1

createTHead() Createsandreturnsa<thead/>elementifonedoesnotexist.Returnstheexisting<thead/>elementifitexists.

Level1

deleteRow(index) Deletestherowatthespecifiedindex. Level1deleteTFoot() Deletesthetable’sfooterifoneexists. Level1deleteTHead() Deletesthetable’sheaderifoneexists. Level1insertRow(index) Insertsandreturnsanewrowatthespecified

index.Ifindexis-1orequaltothenumberofrows,thenewrowisappendedtotheendoftherowlist.

Level1

HTMLTableRowElementRepresentsthe<tr/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

bgColor Deprecated.Getsorsetsthevalueofthebgcolorattribute.

Level1

cells ReturnsanHTMLCollectioncontainingthecellsintherow.

Level1

rowIndex Theindexoftherowinthetable. Level1sectionRowIndex Theindexoftherowrelativetothesectionit

belongsto(<thead/>,<tfoot/>,or<tbody/>).Level1

vAlign Getsorsetsthevalueofthevalignattribute. Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDdeleteCell(index) Deletesthecellatthespecifiedindex. Level1insertCell(index) Insertsandreturnsanempty<td/>element.If

indexis-1orequaltothenumberofcellsintherow,thenewcellisappendedtotheendofthelist.

Level1

HTMLTableSectionElementRepresentsthe<thead/>,<tbody/>,and<tfoot/>elements.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

align Deprecated.Getsorsetsthevalueofthealignattribute.

Level1

rows ReturnsanHTMLCollectioncontainingtherowsofthesection.

Level1

vAlign Getsorsetsthevalueofthevalignattribute. Level1

Methods

METHODNAME

DESCRIPTION INTRODUCED

deleteRow(index) Deletestherowatthespecifiedindexrelativetothesection.

Level1

insertRow(index) Insertsandreturnsanewrowintothesectionatthespecifiedindex(relativetothesection).Ifindexis-1orequaltothenumberofrows,therowisappendedtotheendofthelist.

Level1

HTMLTextAreaElementRepresentsthe<textarea/>element.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1cols Getsorsetsthevalueofthecolsattribute. Level1defaultValue Getsorsetsthecontentsoftheelement.Thevaluedoes

notchangewhenthecontentchanges.Level1

disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe

<textarea/>element.Returnsnulliftheelementisnotinsideaform.

Level1

name Getsorsetsthevalueofthenameattribute. Level1readOnly Usedonlyiftypeistextorpassword.Getsorsetsthe

valueofthereadonlyattribute.Level1

rows Getsorsetsthevalueoftherowsattribute. Level1type Getsthevalueofthetypeattribute.Alwayssetto

textarea.Level1

value Getsorsetsthecurrentvalueoftheelement. Level1

Methods

METHODNAME DESCRIPTION INTRODUCEDblur() Removeskeyboardfocusfromtheelement. Level1focus() Giveskeyboardfocustotheelement. Level1select() Selectsthecontentsoftheelement. Level1

HTMLMediaObjectsTheHTMLMediaElementobjectisthebasetypeforboth<video/>and<audio/>elements.

HTMLMediaElementProperties

PROPERTYNAME DESCRIPTION INTRODUCEDautoplay Reflectstheautoplayattribute,anddetermines

whereplaybackshouldautomaticallybeginassoonasenoughmediaisavailable.

HTML5

buffered Getstherangesofthemediasourcethatthebrowserhasbuffered.

HTML5

controller Getsorsetsthemediacontrollerassociatedwiththeelement;returnsnullifnoneislinked.

HTML5

controls Getsorsetsthecontrolsattribute,determiningifthebrowser’sdefaultcontrolsaredisplayed.

HTML5

currentSrc GetstheabsoluteURLofthemedia. HTML5currentTime Thecurrentplaybacktimeinseconds.Setting

seeksthemediatothespecifiedtime.HTML5

defaultMuted Getsorsetsthemutedattribute.Thisdoesnotaffecttheaudioafterplaybackstarts.Usethemutedpropertyforthat.

HTML5

defaultPlaybackRate Thespeedofplayback.1.0isnormal. HTML5duration Getsthelengthofthemediainseconds. HTML5ended Indicateswhetherthemediaelementhasended

playback.HTML5

error Themostrecenterror;nullifnoerrorhasoccurred.

HTML5

loop Getsorsetstheloopattribute;indicateswhetherthemediashouldstartoverwhenitreachestheend.

HTML5

mediaGroup Getsorsetsthemediagroupattribute. HTML5muted Mutesorunmutestheaudio. HTML5networkState Thecurrentstateoffetchingthemediaoverthe

network.HTML5

paused Indicateswhetherthemediaelementispaused. HTML5

playbackRate Getsorsetsthecurrentplaybackrate. HTML5played Getstherangesthatthemediasourcehas

played,ifany.HTML5

preload Getsorsetsthepreloadattribute. HTML5readyState Getsthereadinessofthemedia. HTML5seekable Getsthetimerangesthattheusercanseek. HTML5

seeking Indicateswhetherthemediaisintheprocessofseekingtoanewposition.

HTML5

src Getsorsetsthesrcattribute. HTML5volume Getsorsetsthevolumeoftheaudio.0.0(silent)

to1.0(loudest)HTML5

Methods

METHODNAME

DESCRIPTION INTRODUCED

canPlayType() Determinesthelikelihoodthebrowsercanplaythegivenmediatype.

HTML5

load() Beginsloadingthemediacontentfromtheserver. HTML5pause() Pausesthemediaplayback. HTML5play() Beginsorresumesthemediaplayback. HTML5

HTMLAudioElementThe<audio/>elementdoesnothaveanyuniquepropertiesormethodsfromHTMLMediaElement.

HTMLVideoElementThe<video/>elementhasafewuniqueproperties.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

height Getsorsetstheheightattribute,determiningthesizeofthedisplayarea.

HTML5

poster Getsorsetstheposterattribute,specifyingtheimagetoshowwhilenovideodataisavailable.

HTML5

videoHeight GetstheintrinsicheightoftheresourceinCSSpixels. HTML5videoWidth GetstheintrinsicwidthoftheresourceinCSSpixels. HTML5width Getsorsetsthewidthattribute,determinethesizeofthe

displayarea.HTML5

DOMEVENTMODELANDOBJECTSTheDOMeventmodelwasintroducedinDOMLevel2.Itdescribesaneventsystemwhereeveryeventhasaneventtarget.Whenaneventreachesaneventtarget,allregisteredeventhandlersontheeventtargetaretriggeredforthatspecificevent.ThefollowingobjectsaredescribedbytheDOMeventmodel.

EventTargetTheEventTargetobjectisinheritedbyallHTMLElementobjectsintheDOM.Thisobjectprovidesthemeansfortheregistrationandremovalofeventhandlersontheeventtarget.

Methods

METHODName DESCRIPTIONaddEventListener(type,

listener,useCapture)

Registersaneventhandleronanelement.typeistheeventtypetolistenfor,listeneristheJavaScriptfunctiontocallwhentheeventisfired,anduseCapturedetermineswhethertheeventiscapturedorbubbles.

removeEventListener(type,

listener,useCapture)

Removesalistenerfromtheelement.

EventWhenaneventfires,anEventobjectispassedtotheeventhandlerifoneisspecified.Thisobjectcontainscontextualinformationaboutanevent.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

bubbles Indicateswhetherornottheeventisabubblingevent.

Level2

cancelable Indicateswhetherornottheeventcanhaveitsdefaultactionprevented.

Level2

currentTarget IndicatestheEventTargetwhoselistenersarecurrentlybeingprocessed.

Level2

target IndicatestheEventTargetobjecttowhichtheeventwasoriginallyfired.

Level2

timeStamp Specifiesthetime(inmilliseconds)atwhichtheeventwasfired.

Level2

type Thenameoftheevent(remember:thisisthenamewithouttheonprefix).

Level2

Methods

METHODNAME DESCRIPTION INTRODUCEDpreventDefault() Cancelstheevent,preventingthedefaultaction

fromtakingplace,onlyiftheeventiscancelable.Level2

stopPropagation() Preventsfurtherpropagationofanevent. Level2

MouseEventTheMouseEventobjectprovidesspecificinformationassociatedwithmouseevents.MouseEventobjectscontainnotonlythefollowingproperties,butalsothepropertiesandmethodsoftheEventobject.

Validmouseeventsareshowninthefollowingtable.

EVENTNAME

DESCRIPTION

click Occurswhenthemousebuttonisclickedoveranelement.Aclickisdefinedasamousedownandmouseupoverthesamescreenlocation.

mousedown Occurswhenthemousebuttonispressedoveranelement.mouseup Occurswhenthemousebuttonisreleasedoveranelement.mouseover Occurswhenthemousepointermovesontoanelement.mousemove Occurswhenthemousepointermoveswhileitisovertheelement.mouseout Occurswhenthemousepointermovesawayfromanelement.

Properties

PROPERTYNAME

DESCRIPTION INTRODUCED

altKey ReturnsabooleanvalueindicatingwhetherornottheAltkeywaspressedduringtheevent’sfiring.

Level2

button Indicateswhichmousebuttonwaspressed,ifapplicable.Thenumber0representstheleftbutton,1indicatesthemiddlebutton,and2indicatestherightbutton.Left-hand-configuredmicereversethebuttons(rightis0,middleis1,andleftis2).

Level2

clientX Thehorizontalcoordinaterelativetotheclientarea. Level2clientY Theverticalcoordinaterelativetotheclientarea. Level2ctrlKey Returnsabooleanvalueindicatingwhetherornotthe

Ctrlkeywaspressedwhentheeventfired.Level2

relatedTarget IndentifiesasecondaryEventTarget.Currently,thispropertyisusedwiththemouseovereventtoindicatetheEventTargetthatthemousepointerexitedandwiththemouseouteventtoindicatewhichEventTargetthepointerentered.

Level2

screenX Thehorizontalcoordinaterelativetothescreen. Level2screenY Theverticalcoordinaterelativetothescreen. Level2shiftKey Returnsabooleanvalueindicatingwhetherornotthe

Shiftkeywaspressedwhentheeventfired.Level2

MISCELLANEOUSEVENTSThefollowingtablesdescribetheeventsavailableinclient-sideJavaScript.

MouseEvents

EVENT DESCRIPTIONclick RaisedwhentheuserclicksanHTMLcontrol.dblclick Raisedwhentheuserdouble-clicksanHTMLcontrol.mousedown Raisedwhentheuserpressesamousebutton.mousemove Raisedwhentheusermovesthemousepointer.mouseout RaisedwhentheusermovesthemousepointeroutfromwithinanHTML

control.mouseover RaisedwhentheusermovesthemousepointeroveranHTMLcontrol.mouseup Raisedwhentheuserreleasesthemousebutton.

KeyboardEvents

EVENT DESCRIPTIONkeydown Raisedwhentheuserpressesakeyonthekeyboard.keypress Raisedwhentheuserpressesakeyonthekeyboard.Thiseventwillberaised

continuallyuntiltheuserreleasesthekey.keyup Raisedwhentheuserreleasesakeythathadbeenpressed.

HTMLControlEvents

EVENT DESCRIPTIONblur RaisedwhenanHTMLcontrollosesfocus.change RaisedwhenanHTMLcontrollosesfocusanditsvaluehaschanged.focus RaisedwhenfocusissettotheHTMLcontrol.reset Raisedwhentheuserresetsaform.select RaisedwhentheuserselectstextinanHTMLcontrol.submit Raisedwhentheusersubmitsaform.

WindowEvents

EVENT DESCRIPTIONload Raisedwhenthewindowhascompletedloading.resize Raisedwhentheuserresizesthewindow.unload ExecutesJavaScriptcodewhentheuserexitsadocument.

MediaEvents

EVENT DESCRIPTIONabort Raisedwhenplaybackisaborted.canplay Sentwhenenoughdataisavailablethatthemediacanbeplayed.canplaythrough Firedwhentheentiremediacanbeplayedwithoutinterruption.durationchange Raisedwhenthemetadatahaschanged.emptied Fireswhenthemediahasbecomeempty.ended Sentwhenplaybackcompletes.error Sentwhenanerroroccurs.loadeddata Themedia’sfirstframehasbeenloaded.loadedmetadata Firedwhenthemedia’smetadataisloaded.loadstart Sentwhendownloadingbegins.pause Playbackhasbeenpaused.play Playbackbeginsafterapause.playing Raisedwhenmediabeginstoplay.progress Indicatestheprogressofthemediadownload.ratechange Fireswhentheplaybackratechanges.seeked Seekinghasended.seeking Playbackisbeingmovedtoanewposition.stalled Raisedwhenthebrowsertriestodownloadthemedia,butreceivesno

data.suspend Sentwhentheloadingofthemediaissuspended.timeupdate Themedia’scurrentTimehaschanged.volumechange Fireswhentheaudiovolumechanges(bothwhenvolumeissetand

whenmuted).waiting Raisedwhenplaybackispausedinordertodownloadmoredata.

OtherEvents

EVENT DESCRIPTIONabort Raisedwhentheuserabortsloadinganimage.error Raisedwhenanerroroccursloadingthepage.

DLatin-1CharacterSetThisappendixcontainstheLatin-1charactersetandthecharactercodesinbothdecimalandhexadecimalformats.AsexplainedinChapter2,theescapesequence\xNN,whereNNisahexadecimalcharactercodefromtheLatin-1charactersetshownhere,canbeusedtorepresentcharactersthatcan’tbetypeddirectlyinJavaScript.

DECIMALCHARACTERCODE

HEXADECIMALCHARACTERCODE

SYMBOL

32 20 Space33 21 !34 22 “35 23 #36 24 $37 25 %38 26 &39 27 ‘40 28 (41 29 )42 2A *43 2B +44 2C ,45 2D -46 2E .47 2F /48 30 049 31 150 32 251 33 352 34 453 35 554 36 655 37 756 38 8

57 39 958 3A :59 3B ;60 3C <61 3D =62 3E >63 3F ?64 40 @65 41 A66 42 B67 43 C68 44 D69 45 E70 46 F71 47 G72 48 H73 49 I74 4A J75 4B K76 4C L77 4D M78 4E N79 4F O80 50 P81 51 Q82 52 R83 53 S84 54 T85 55 U86 56 V87 57 W88 58 X89 59 Y90 5A Z91 5B [

92 5C \93 5D ]

94 5E ^95 5F _96 60 `97 61 a98 62 b99 63 c100 64 d101 65 e102 66 f103 67 g104 68 h105 69 i106 6A j107 6B k108 6C l109 6D m110 6E n111 6F o112 70 p113 71 q114 72 r115 73 s116 74 t117 75 u118 76 v119 77 w120 78 x121 79 y122 7A z123 7B {124 7C |125 7D }126 7E ~

160 A0 Non-breakingspace

161 A1 ¡

162 A2 ¢163 A3 £164 A4 ¤165 A5 ¥166 A6 ¦167 A7 §168 A8 ¨169 A9 ©170 AA ª171 AB «172 AC ¬173 AD Softhyphen174 AE ®175 AF ¯176 B0 °177 B1 ±

178 B2 2

179 B3 3

180 B4 ´181 B5 μ182 B6 ¶183 B7 ·184 B8 ¸185 B9 1186 BA °187 BB »188 BC ~QF189 BD ~HF190 BE ~TQF191 BF ¿192 C0 À193 C1 Á

194 C2 Â195 C3 Ã196 C4 Ä197 C5 Å198 C6 Æ199 C7 Ç200 C8 È201 C9 É202 CA Ê203 CB Ë204 CC Ì205 CD Í206 CE Î207 CF Ï208 D0 Ð209 D1 Ñ210 D2 Ò211 D3 Ó212 D4 Ô213 D5 Õ214 D6 Ö215 D7 ∞216 D8 Ø217 D9 Ù218 DA Ú219 DB Û220 DC Ü221 DD Ý222 DE þ223 DF ß224 E0 à225 E1 á226 E2 â227 E3 ã228 E4 ä

229 E5 å230 E6 æ231 E7 ç

232 E8 è

233 E9 é234 EA ê235 EB ë236 EC ì237 ED í238 EE î239 EF ï240 F0 ð241 F1 ñ242 F2 ò243 F3 ó244 F4 ô245 F5 õ246 F6 ö247 F7 ÷248 F8 ø249 F9 ù250 FA ú251 FB û252 FC ü253 FD ý254 FE þ255 FF ÿ

BEGINNINGJavaScript®

FifthEdition

JeremyMcPeak

PaulWilton

BeginningJavaScript®5e

PublishedbyJohnWiley&Sons,Inc.10475CrosspointBoulevardIndianapolis,IN46256www.wiley.com

Copyright©2015byJohnWiley&Sons,Inc.,Indianapolis,Indiana

PublishedsimultaneouslyinCanada

ISBN:978-1-118-90333-9ISBN:978-1-118-90343-8(ebk)ISBN:978-1-118-90374-2(ebk)

Nopartofthispublicationmaybereproduced,storedinaretrievalsystemortransmittedinanyformorbyanymeans,electronic,mechanical,photocopying,recording,scanningorotherwise,exceptaspermittedunderSections107or108ofthe1976UnitedStatesCopyrightAct,withouteitherthepriorwrittenpermissionofthePublisher,orauthorizationthroughpaymentoftheappropriateper-copyfeetotheCopyrightClearanceCenter,222RosewoodDrive,Danvers,MA01923,(978)750-8400,fax(978)646-8600.RequeststothePublisherforpermissionshouldbeaddressedtothePermissionsDepartment,JohnWiley&Sons,Inc.,111RiverStreet,Hoboken,NJ07030,(201)748-6011,fax(201)748-6008,oronlineathttp://www.wiley.com/go/permissions.

LimitofLiability/DisclaimerofWarranty:Thepublisherandtheauthormakenorepresentationsorwarrantieswithrespecttotheaccuracyorcompletenessofthecontentsofthisworkandspecificallydisclaimallwarranties,includingwithoutlimitationwarrantiesoffitnessforaparticularpurpose.Nowarrantymaybecreatedorextendedbysalesorpromotionalmaterials.Theadviceandstrategiescontainedhereinmaynotbesuitableforeverysituation.Thisworkissoldwiththeunderstandingthatthepublisherisnotengagedinrenderinglegal,accounting,orotherprofessionalservices.Ifprofessionalassistanceisrequired,theservicesofacompetentprofessionalpersonshouldbesought.Neitherthepublishernortheauthorshallbeliablefordamagesarisingherefrom.ThefactthatanorganizationorWebsiteisreferredtointhisworkasacitationand/orapotentialsourceoffurtherinformationdoesnotmeanthattheauthororthepublisherendorsestheinformationtheorganizationorWebsitemayprovideorrecommendationsitmaymake.Further,readersshouldbeawarethatInternetWebsiteslistedinthisworkmayhavechangedordisappearedbetweenwhenthisworkwaswrittenandwhenitisread.

ForgeneralinformationonourotherproductsandservicespleasecontactourCustomerCareDepartmentwithintheUnitedStatesat(877)762-2974,outsidetheUnitedStatesat(317)572-3993orfax(317)572-4002.

Wileypublishesinavarietyofprintandelectronicformatsandbyprint-on-demand.Somematerialincludedwithstandardprintversionsofthisbookmaynotbeincludedine-booksorinprint-on-demand.IfthisbookreferstomediasuchasaCDorDVDthatisnotincludedintheversionyoupurchased,youmaydownloadthismaterialathttp://booksupport.wiley.com.FormoreinformationaboutWileyproducts,visitwww.wiley.com.

LibraryofCongressControlNumber:2014958440

Trademarks:Wiley,theWileylogo,Wrox,theWroxlogo,ProgrammertoProgrammer,andrelatedtradedressaretrademarksorregisteredtrademarksofJohnWiley&Sons,Inc.and/oritsaffiliates,intheUnitedStatesandothercountries,andmaynotbeusedwithoutwrittenpermission.JavaScriptisaregisteredtrademarkofOracle,Inc.Allothertrademarksarethepropertyoftheirrespectiveowners.JohnWiley&Sons,Inc.,isnotassociatedwithanyproductorvendormentionedinthisbook.

Thisbookisdedicatedtomywife,Starla,andmysons,Hayden,Evan,andJordan.Thankyouforyourlove,support,andpatienceduringthewritingofthisbook.Tomyparents:JerryandJudy.Thankyoufor

yourloveandsupport.

—JeremyMcPeak

Inmemoryofmymum,JuneWilton,whoin2006lostherbravebattleagainstcancer.Shewasalwaysveryproudofmeandmybooksandshowedmybookstoanyoneandeveryoneshehappenedtomeethoweverbrieflyandwhethertheywantedtoseethemornot!

She’sverymuchmissed.

—PaulWilton

CreditsProjectEditorKellyTalbot

TechnicalEditorRussMullen

ProductionManagerKathleenWisor

CopyEditorKimCofer

ManagerofContentDevelopment&AssemblyMaryBethWakefield

MarketingDirectorDavidMayhew

MarketingManagerCarrieSherrill

ProfessionalTechnology&StrategyDirectorBarryPruett

BusinessManagerAmyKnies

AssociatePublisherJimMinatel

ProjectCoordinator,CoverPatrickRedmond

ProofreaderNancyCarrasco

IndexerJohnnaVanHooseDinse

CoverDesignerWiley

CoverImage©iStock.com/hamikus

AbouttheAuthorsJeremyMcPeakisaself-taughtprogrammerwhobeganhiscareerbytinkeringwithwebsitesin1998.HeistheauthorofJavaScript24-HourTrainer(Wiley2010)andco-authorofProfessionalAjax,2ndEdition(Wiley2007).HealsocontributestoTuts+Code(http://code.tutsplus.com),providingarticles,videotutorials,andcoursesforJavaScript,C#,andASP.NET.Heiscurrentlyemployedbyanoilandgascompanybuildingin-houseconventionalandwebapplications.Jeremycanbecontactedviathep2pforums,hiswebsite(http://www.wdonline.com),andTwitter(@jwmcpeak).

PaulWiltonstartedasaVisualBasicapplicationsprogrammerattheMinistryofDefenseintheUKandthenfoundhimselfpulledintotheNet.HavingjoinedanInternetdevelopmentcompany,hespentthreeyearshelpingcreateInternetsolutions.He’snowrunninghisownsuccessfulandrapidlygrowingcompanydevelopingonlineholidaypropertyreservationsystems.

AcknowledgmentsFirstandforemost,IwanttothankGodfortheblessingshehasbestoweduponme,andthankyou,dearreader,forwithoutyouthisbookwouldnotbepossible.Also,ahugethankyougoestomywifeandfamilyforputtingupwithmeasIspentmyavailableweekendfree-timeupdatingthisbook.

Writingandproducingabookrequiresalotofpeople,andIknowIcannotnameeveryonewhohashadahandinthisproject.ButaverybigthankyougoestoJimMinatelandRobertElliottforgreen-lightingthisproject.ThankyouKellyTalbotforkeepingmeontrackandputtingupwithme.Totheeditingteam,thankyouformakingmytextlookgood.AndtoRussMullen,thanksforkeepingmehonest.

—JEREMYMCPEAK

First,abigthankyoutomypartnerBeci,who,nowthatthebook’sfinished,willgettoseemeformorethan10minutesaweek.

I’dalsoliketosayaverybigthankyoutotheeditors,whoworkedveryefficientlyongettingthisbookintoprint.

ThanksalsotoJimMinatelformakingthisbookhappen.

Manythankstoeveryonewho’ssupportedandencouragedmeovermymanyyearsofwritingbooks.Yourhelpwillalwaysberemembered.

Finally,patsandtreatstomyGermanShepherdDog,Katie,whodoesanexcellentjobofwardingoffdisturbancesfromdoor-to-doorsalespeople.

—PAULWILTON

WILEYENDUSERLICENSEAGREEMENTGotowww.wiley.com/go/eulatoaccessWiley’sebookEULA.