dl.ebooksworld.irdl.ebooksworld.ir/motoman/packt.jquery.design.patterns.pdf · table of contents...

358

Upload: others

Post on 19-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 2: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 3: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jQueryDesignPatterns

Page 4: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TableofContents

jQueryDesignPatterns

Credits

AbouttheAuthor

AbouttheReviewer

www.PacktPub.com

eBooks,discountoffers,andmore

Whysubscribe?

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Errata

Piracy

Questions

1.ARefresheronjQueryandtheCompositePattern

jQueryandDOMscripting

ManipulatingtheDOMusingjQuery

MethodChainingandFluentInterfaces

TheCompositePattern

HowtheCompositePatternisusedbyjQuery

ComparingthebenefitsovertheplainDOMAPI

UsingtheCompositePatterntodevelopapplications

Asampleusecase

TheCompositeCollectionImplementation

Anexampleexecution

Page 5: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Alternativeimplementations

TheIteratorPattern

HowtheIteratorPatternisusedbyjQuery

HowitpairswiththeCompositePattern

Wherecanitbeused

Summary

2.TheObserverPattern

IntroducingtheObserverPattern

HowitisusedbyjQuery

ThejQueryonmethod

Thedocument-readyobserver

Demonstrateasampleusecase

Howitiscomparedwitheventattributes

Avoidmemoryleaks

IntroducingtheDelegatedEventObserverPattern

Howitsimplifiesourcode

Comparethememoryusagebenefits

Summary

3.ThePublish/SubscribePattern

IntroducingthePublish/SubscribePattern

HowitdiffersfromtheObserverPattern

HowitisadoptedbyjQuery

CustomeventsinjQuery

ImplementingaPub/Subschemeusingcustomevents

Demonstratingasampleusecase

UsingPub/Subonthedashboardexample

Extendingtheimplementation

Usinganyobjectasabroker

Usingcustomeventnamespacing

Summary

4.DivideandConquerwiththeModulePattern

Page 6: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ModulesandNamespaces

Encapsulatinginternalpartsofanimplementation

AvoidingglobalvariableswithNamespaces

Thebenefitsofthesepatterns

Thewideacceptance

TheObjectLiteralPattern

TheModulePattern

TheIIFEbuildingblock

ThesimpleIIFEModulePattern

HowitisusedbyjQuery

TheNamespaceParameterModulevariant

TheIIFE-containedModulevariant

TheRevealingModulePattern

UsingES5StrictMode

IntroducingES6Modules

UsingModulesinjQueryapplications

Themaindashboardmodule

Thecategoriesmodule

TheinformationBoxmodule

Thecountermodule

Overviewoftheimplementation

Summary

5.TheFacadePattern

IntroducingtheFacadePattern

Thebenefitsofthispattern

HowitisadoptedbyjQuery

ThejQueryDOMTraversalAPI

ThepropertyaccessandmanipulationAPI

UsingFacadesinourapplications

Summary

6.TheBuilderandFactoryPatterns

Page 7: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheFactoryPattern

HowitisadoptedbyjQuery

UsingFactoriesinourapplications

IntroducingtheBuilderPattern

HowitisadoptedbyjQuery’sAPI

HowitisusedbyjQueryinternally

Howtouseitinourapplications

Summary

7.AsynchronousControlFlowPatterns

Programmingwithcallbacks

UsingsimplecallbacksinJavaScript

Settingcallbacksasobjectproperties

UsingcallbacksinjQueryapplications

Writingmethodsthatacceptcallbacks

Orchestratingcallbacks

Queuinginorderexecution

AvoidingtheCallbackHellanti-pattern

Runningconcurrently

IntroducingtheconceptofPromises

UsingPromises

UsingthejQueryPromiseAPI

UsingPromises/A+

ComparingjQueryandA+Promises

Advancedconcepts

ChainingPromises

Handlingthrownerrors

JoiningPromises

HowjQueryusesPromises

TransformingPromisestoothertypes

TransformingtoPromises/A+

TransformingtojQueryPromises

Page 8: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummarizingthebenefitsofPromises

Summary

8.MockObjectPattern

IntroducingtheMockObjectPattern

UsingMockObjectsinjQueryapplications

Definingtheactualservicerequirements

ImplementingaMockService

UsingtheMockService

Summary

9.Client-sideTemplating

IntroducingUnderscore.js

UsingUnderscore.jstemplatesinourapplications

SeparatingHTMLtemplatesfromJavaScriptcode

IntroducingHandlebars.js

UsingHandlebars.jsinourapplications

SeparatingHTMLtemplatesfromJavaScriptcode

Pre-compilingtemplates

RetrievingHTMLtemplatesasynchronously

Adoptingitinanexistingimplementation

Moderationisbestinallthings

Summary

10.PluginandWidgetDevelopmentPatterns

IntroducingjQueryPlugins

FollowingjQueryprinciples

WorkingonCompositeCollectionObjects

Allowingfurtherchaining

Workingwith$.noConflict()

WrappingwithanIIFE

Creatingreusableplugins

Acceptingconfigurationparameters

WritingstatefuljQueryplugins

Page 9: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImplementingastatefuljQueryPlugin

Destroyingaplugininstance

Implementinggetterandsettermethods

UsingourplugininourDashboardapplication

UsingthejQueryPluginBoilerplate

Addingmethodstoyourplugin

Choosinganame

Summary

11.OptimizationPatterns

Placingscriptsneartheendofthepage

Bundlingandminifyingresources

UsingIIFEparameters

UsingCDNs

UsingJSDelivrAPI

OptimizingcommonJavaScriptcode

Writingbetterforloops

WritingperformantCSSselectors

WritingefficientjQuerycode

MinimizingDOMtraversals

CachingjQueryobjects

Scopingelementtraversals

ChainingjQuerymethods

Don’toverdoit

ImprovingDOMmanipulations

CreatingDOMelements

Stylingandanimating

Manipulatingdetachedelements

IntroducingtheFlyweightPattern

UsingDelegateObservers

Using$.noop()

Usingthe$.singleplugin

Page 10: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

LazyLoadingModules

Summary

Index

Page 11: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 12: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jQueryDesignPatterns

Page 13: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 14: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jQueryDesignPatternsCopyright©2016PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:February2016

Productionreference:1230216

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78588-868-7

www.packtpub.com

Page 15: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 16: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

CreditsAuthor

ThodorisGreasidis

Reviewer

AamirAfridi

CommissioningEditor

NeilAlexander

AcquisitionEditor

AaronLazar

ContentDevelopmentEditor

RiddhiTuljapurkar

TechnicalEditor

PramodKumavat

CopyEditors

TrishyaHazare

KevinMcGowan

ProjectCoordinator

SanchitaMandal

Proofreader

SafisEditing

Indexer

RekhaNair

Graphics

AbhinashSahu

ProductionCoordinator

ShantanuN.Zagade

CoverWork

ShantanuN.Zagade

Page 17: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 18: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AbouttheAuthorThodorisGreasidisisaseniorwebengineerfromGreece.HegraduatedwithhonorsfromtheUniversityofThessaly,holdsapolytechnicdiplomaincomputer,networking,andcommunicationsengineering,andamaster’sdegreeincomputerscience.Heisafull-stackdeveloper,responsibleforimplementinglarge-scalewebapplicationswithintuitiveinterfacesandhigh-availabilitywebservices.

ThodorisispartoftheAngular-UIteamandhasmademanyopensourcecontributions,withaspecialinterestinMozillaprojects.HeisalsoanactivememberoftheAthensAngularJSMeetupandatechnicalreviewerofMasteringjQueryUI,PacktPublishing.

HeisaJavaScriptenthusiastandlovesbitwiseoperations.HisinterestsalsoincludeNodeJS,Python,projectscaffolding,automation,andartificialintelligence,especiallymulti-agentsystems.

Abigthankstoeveryonewhosupportedmeandshowedunderstandingformylimitedfreetimewhilewritingthisbook.

Page 19: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 20: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AbouttheReviewerAamirAfridihasbeenpassionateabouttheInternetandwebdevelopmentsince2002.Heholdsamaster’sdegreeine-commerce.Overtheyearsthathavefollowed,hehasworkedforvariouscompaniesandprovidedfrontendengineering,includingmobilewebappsandarchitectureserviceswithafocusonsemanticHTML,CSS,andJavaScript/jQueryandanythingelsehecangethishandson.HehascontributedtoJavaScriptbooksasatechnicalreviewer.Thesedays,heisexploringthemicroservicesarchitecturewithNodeJS,MongoDB,andReactJSatwww.tes.com.Heblogsonhttp://aamirafridi.com.

Page 21: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 22: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

www.PacktPub.com

Page 23: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

eBooks,discountoffers,andmoreDidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

Page 24: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

Page 25: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 26: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

PrefaceSinceitsintroductionin2006,thejQuerylibraryhasmadeDOMtraversalsandmanipulationsmucheasier.ThishasresultedintheappearanceofWebpageswithincreasinglycomplexuserinteractions,thuscontributingtothematuringofWebasaplatformcapableofsupportinglargeapplicationimplementations.

ThisbookpresentsaseriesofbestpracticesthatmaketheimplementationofWebapplicationsmoreefficient.Moreover,wewillanalyzethemostimportantDesignPatternsthatComputerSciencehastooffer,whichcanbeappliedtoWebdevelopment.Inthisway,wewilllearnhowtoutilizetechniquesthatarethoroughlyusedandtestedinotherfieldsofprogramming,whichwereinitiallycreatedasgenericmethodstomodelsolutionsofcomplexproblems.

InjQueryDesignPatterns,wewillanalyzehowvariousDesignPatternsareutilizedintheimplementationofjQueryandhowtheycanbeusedtoimprovetheorganizationofourimplementations.ByadoptingtheDesignPatternsdemonstratedinthisbook,youwillbeabletocreatebetterorganizedimplementationsthatresolvelargeproblemcategoriesfaster.Moreover,whenusedbyadeveloperteam,theycanimprovethecommunicationbetweenthemandleadtohomogenousimplementation,whereeverypartofthecodeiseasilyunderstoodbyothers.

Page 27: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WhatthisbookcoversChapter1,ARefresheronjQueryandtheCompositePattern,willteachthereaderhowtowritethecodeusingtheCompositePatternandmethodchaining(FluentInterface)byanalyzinghowtheyareusedfortheimplementationofjQueryitself.ItalsodemonstratestheIteratorPatternthatnicelypairswiththeCompositeCollectionobjectsthatjQueryreturns.

Chapter2,TheObserverPattern,willteachyouhowtorespondtouseractionsusingtheObserverPattern.ItalsodemonstrateshowtouseEventDelegationasawaytoreducethememoryconsumptionandcomplexityofthecodethathandlesdynamicallyinjectedpageelements.Finally,itwillteachyouhowtoemitandlistenforCustomEventsinordertoachievegreaterflexibilityandcodedecoupling.

Chapter3,ThePublish/SubscribePattern,willteachyouhowtoutilizethePub/SubPatterntocreateacentralpointtoemitandreceiveapplication-levelevents,asawaytodecoupleyourcodeandbusinesslogicfromtheHTMLthatisusedforpresentation.

Chapter4,DivideandConquerwiththeModulePattern,demonstratesandcomparessomeofthemostcommonlyusedModulePatternsintheindustry.ItwillteachyouhowtostructureyourapplicationinsmallindependentModulesusingNamespacing,leadingtoexpandableimplementationsthatfollowtheSeparationofConcernsprinciple.

Chapter5,TheFacadePattern,willteachyouhowtousetheFacadePatterntowrapcomplexAPIsintosimpleronesthatareabettermatchfortheneedsofyourapplication.Italsodemonstrateshowtochangepartsofyourapplication,whilekeepingthesamemodule-levelAPIsandavoidaffectingtherestofyourimplementation.

Chapter6,TheBuilderandFactoryPatterns,explainstheconceptsofandthedifferencesbetweentheBuilderandFactoryPatterns.Itwillteachyouhowandwhentouseeachofthem,inordertoimprovetheclarityofyourcodebyabstractingthegenerationofcomplexresultsintoseparatededicatedmethods.

Chapter7,AsynchronousControlFlowPatterns,willexplainhowjQuery’sDeferredandPromiseAPIsworkandcomparethemwiththeclassicalCallbacksPattern.YouwilllearnhowtousePromisestocontrolthetheexecutionofasynchronousprocedurestoruneitherinanorderorparalleltoeachother.

Chapter8,MockObjectPattern,teachesyouhowtocreateanduseMockObjectsandServicesasawaytoeasethedevelopmentofyourapplicationandgetasenseofitsfunctionality,longbeforeallitspartsarecompleted.

Chapter9,Client-sideTemplating,demonstrateshowtousetheUnderscore.jsandHandlebars.jstemplatinglibrariesasabetterandfasterwaytocreatecomplexHTMLstructureswithJavaScript.Throughthischapter,youwillgetanoverviewoftheirconventions,evaluatetheirfeatures,andfindtheonethatbestmatchesyourtaste.

Chapter10,PluginandWidgetDevelopmentPatterns,introducesthebasicconceptsandconventionsofjQueryPlugindevelopmentandanalyzesthemostcommonlyuseddesign

Page 28: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

patterns,sothatyouwillbeabletoidentifyandusethebestmatchforanyusecase.

Chapter11,OptimizationPatterns,guidesyouwiththebesttipstocreateahighlyefficientandrobustimplementation.Youwillbeabletousethischapterasachecklistofbestpracticesthatimprovetheperformanceandlowerthememoryconsumptionofyourapplications,beforemovingthemtoaproductionenvironment.

Page 29: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 30: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WhatyouneedforthisbookInordertoruntheexamplesinthisbook,youwillneedtohaveawebserverinstalledonyoursystemtoservethecodefiles.Forexample,youcanuseApacheorIISorNGINX.InordertomaketheinstallationprocessofApacheeasier,youcanusemorecompletedevelopmentenvironmentsolutions,suchasXAMPPorWAMPServer.

Intermsoftechnicalproficiency,thisbookassumesthatyoualreadyhavesomeexperienceofworkingwithjQuery,HTML,CSS,andJSON.AllthecodesamplesinthebookusejQueryv2.2.0andsomeofthechaptersalsodiscusstherespectiveimplementationinjQueryv1.12.0,whichcanbeusedincasesupportforolderbrowsersisneeded.

Page 31: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 32: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WhothisbookisforThisbooktargetsexistingjQuerydevelopersornewdeveloperswhowanttotaketheirskillsandunderstandingtoanadvancedlevel.ItisadetailedintroductiontohowthevariousindustrystandardpatternscanbeappliedtojQueryapplications,andalongwithasetofthebestpractices,itcanhelplargeteamscollaborateandcreatewellorganizedandextendableimplementations.

Page 33: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 34: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“IntheprecedingCSScode,wefirstdefinedsomebasicstylesforthebox,boxsizer,andclearCSSclasses.”

Ablockofcodeissetasfollows:

$.each([3,5,7],function(index){

console.log(this+1+'!');

});

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

$('#categoriesSelector').change(function(){

var$selector=$(this);

varmessage={categoryID:$selector.val()};

broker.trigger('dashboardCategorySelect',[message]);

});

WearefollowingGoogle’sJavaScriptStyleGuide,exceptfromusingfourspacesforindentation,inordertoimprovethereadabilityofthecodeinthebook.Inshort,weareplacingcurlybracketsontopandusesinglequotesforstringliterals.

NoteFormoreinformationonGoogle’sJavaScriptStyleGuideyoucanvisitthefollowingURL:https://google.github.io/styleguide/javascriptguide.xml

Anycommand-lineinputoroutputiswrittenasfollows:

npminstalljquery

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:“ThejQueryObjectreturnedisanArray-likeobjectthatactsasawrapperobjectandcarriesthecollectionoftheretrievedelements.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

Page 35: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 36: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

Page 37: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 38: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

Page 39: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

Page 40: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

Page 41: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

Page 42: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,andwewilldoourbesttoaddresstheproblem.

Page 43: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 44: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter1.ARefresheronjQueryandtheCompositePatternUntiltheWeb2.0erastarted,theWebwasjustadocument-basedmediaandallitofferedwasjustinterconnectingdifferentpages/documentsandclient-sidescriptingthatwasmostlylimitedtoformvalidation.By2005,GmailandGoogleMapswerereleased,andJavaScriptproveditselfasalanguageusedbybigenterprisestocreatelarge-scaleapplicationsandproviderichuserinterfaceinteractions.

EventhoughJavaScripthashadveryfewchangessinceitsoriginalrelease,therewasatremendouschangeintheexpectationsthattheEnterpriseworldhadaboutwhatwebpagesshouldbecapableofdoing.Sincethen,webdeveloperswererequiredtodelivercomplexuserinteractionsand,finally,theterm“webapplication”appearedonthemarket.Asaresult,itstartedtobecomeobviousthattheyshouldcreatesomecodeabstractions,definesomebestpractices,andadoptalltheapplicableDesignPatternsthatcomputersciencehadtooffer.ThewideadoptionofJavaScriptforenterprise-gradeapplicationshelpedtheevolutionofthelanguage,whichwiththeEcmaScript2015/EcmaScript6(ES6)specificationwasexpandedinawaythatallowedevenmoreDesignPatternstobeeasilyutilized.

InAugust2006,thejQuerylibrarywasfirstreleasedbyJohnResigathttp://jquery.com,asanefforttocreateaconvenientAPItolocateDOMelements.Sincethen,ithasbeenanintegralpartofawebdeveloper’stoolkit.jQueryinitscoreusesseveralDesignPatternsandtriestourgetheirusetothedeveloperthroughthemethodsthatitprovides.TheCompositePatternisoneofthemanditisexposedtothedeveloperthroughtheverycorejQuery()method,whichisusedforDOMtraversal,oneofthehighlightsofthejQuerylibrary.

Inthischapter,wewill:

HavearefresheronDOMscriptingusingjQueryIntroducetheCompositePatternSeehowtheCompositePatternisusedbyjQueryDiscussthegainsofferedbyjQueryoverplainJavaScriptDOMmanipulationsIntroducetheIteratorPatternUsetheIteratorPatterninanexampleapplication

Page 45: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jQueryandDOMscriptingByDOMscripting,werefertoanyprocedurethataltersormanipulatestheelementsofawebpageafterithasbeenloadedbythebrowser.TheDOMAPIisaJavaScriptAPIthatwasstandardizedin1998anditprovidestowebdevelopersacollectionofmethodsthatallowthemanipulationoftheDOMtreeelementsthatthebrowsercreatesafterloadingandparsingthewebpage’sHTMLcode.

NoteFormoreinformationontheDocumentObjectMode(DOM)anditsAPIs,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction.

ByutilizingtheDOMAPIintheirJavaScriptcode,webdeveloperscanmanipulatetheDOM’snodesandaddnewelementsorremoveexistingelementsfromthepage.TheprimaryusecaseforDOMscriptingwasinitiallylimitedtoclient-sideformvalidation,butastheyearspassedandJavaScriptgainedthetrustoftheEnterpriseworld,morecomplexuserinteractionsstartedtobeimplemented.

TheinitialversionofthejQuerylibrarywasfirstreleasedinAugust2006andittriedtoeasethewaythewebdevelopersweretraversingandmanipulatingtheDOMtree.Oneofitsmaingoalswastoprovideabstractionsthatresultedinshorter,easier-to-read,andlesserror-pronecode,whilealsoensuringcross-browserinteroperability.

ThesecoreprinciplesthatjQueryfollowsareclearlyvisibleinitshomepage,whereitpresentsitselfas:

…afast,small,andfeature-richJavaScriptlibrary.ItmakesthingslikeHTMLdocumenttraversalandmanipulation,eventhandling,animation,andAjaxmuchsimplerwithaneasy-to-useAPIthatworksacrossamultitudeofbrowsers.Withacombinationofversatilityandextensibility,jQueryhaschangedthewaythatmillionsofpeoplewriteJavaScript.

TheabstractedAPIsthatjQueryprovidedfromthebeginning,andthewaythatdifferentDesignPatternswereorchestrated,ledtowideacceptanceamongthewebdevelopers.Asaresult,thejQuerylibraryisreferencedbymorethan60%ofthemostvisitedwebsitesworldwide,accordingtoseveralsourcessuchasBuiltWith.com(http://trends.builtwith.com/javascript/jQuery).

Page 46: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ManipulatingtheDOMusingjQueryTohavearefresheronjQuery,wewillgothroughanexamplewebpagethatdoessomesimpleDOMmanipulations.Inthisexample,wewillloadasimplystructuredpagethatinitiallylookslikethefollowingfigure:

WewillusesomejQuerycodetochangethepage’scontentandlayoutand,inordertomakeitseffectsclearlyvisible,wewillsetittorunabout700millisecondsafterthepagehasloaded.Theresultofourmanipulationswilllooklikethefollowingfigure:

Page 47: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Nowlet’sreviewtheHTMLcoderequiredfortheprecedingexample:

<!DOCTYPEhtml>

<html>

<head>

<title>DOMManipulations</title>

<linkrel="stylesheet"type="text/css"href="dom-manipulations.css">

</head>

<body>

<h1id="pageHeader">DOMManipulations</h1>

<divclass="boxContainer">

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

<div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

</div>

</div>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

<pclass="box">

DoingDOMManipulationsiseasywithJS!

</p>

<scripttype="text/javascript"src="https://code.jquery.com/jquery-

2.2.0.min.js"></script>

<scripttype="text/javascript"src="jquery-dom-manipulations.js">

</script>

</body>

</html>

TheCSScodeusedisquitesimple,containingonlythreeCSSclassesasfollows:

.box{

padding:7px10px;

border:solid1px#333;

margin:5px3px;

box-shadow:01px2px#777;

}

.boxsizer{

float:left;

width:33.33%;

}

Page 48: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

.clear{clear:both;}

TheprecedingcoderesultsinapagelookinglikethefirstfigurewhenopenedinabrowserandbeforeourJavaScriptcodeisexecuted.IntheprecedingCSScode,wefirstdefinedsomebasicstylesforthebox,boxsizer,andclearCSSclasses.Theboxclassstylestheassociatedelementsfoundinthepagebyusingsomepadding,athinborder,somemarginaround,andasmallshadowbelowtheelementsinordertomakethemlooklikeabox.Theboxsizerclasswillmaketheelementsthatuseittotakejust1/3rdofthewidthoftheirparentelementandcreateathree-columnlayout.Finally,theclearclasswillbeusedonanelementasabreakpointforthecolumnlayoutsothatalltheelementsthatfollowwillbepositionedbelowit.TheboxsizerandclearclassesarenotinitiallyusedbyanyelementdefinedintheHTMLcode,butwillbeusedaftertheDOMmanipulationsthatwewilldoinJavaScript.

Inthe<body>elementofourHTML,weinitiallydefinean<h1>headingelementwithIDpageHeadersothatitiseasilyselectablethroughJavaScript.Rightbelowit,wedefinefiveparagraphelements(<p>)withtheboxclass,havingthefirstthreeofthemwrappedinsidethethree<div>elementsandtheninsideanother<div>elementwiththeboxContainerclass.

Reachingourtwo<script>tags,wefirstincludeareferencetothejQuerylibraryfromjQueryCDN.Formoreinformation,youcanvisithttp://code.jquery.com/.Inthesecond<script>tag,wereferencetheJavaScriptfilewiththerequiredcode,forthisexample,whichlooksasfollows:

setTimeout(function(){

$('#pageHeader').css('font-size','3em');

var$boxes=$('.boxContainer.box');

$boxes.append(

'<br/><br/><i>Incaseweneedsimplethings</i>.');

$boxes.parent().addClass('boxsizer');

$('.boxContainer').append('<divclass="clear">');

},700);

AllourcodeiswrappedinsideasetTimeoutcalltodelayitsexecution,accordingtotheusecasedescribedearlier.ThefirstparameterofthesetTimeoutfunctioncallisananonymousfunctionthatwillbeexecutedafteratimerof700millisecondshasexpired,asdefinedinthesecondargument.

Atthefirstlineofouranonymouscallbackfunction,weusethejQuery$()functiontotraversetheDOMandlocatetheelementwiththeIDpageHeader,andusethecss()methodtoincreaseitsfont-sizeto3em.NextweprovideamorecomplexCSSselectortothe$()function,tolocatealltheelementswiththeboxclassthataredescendantsoftheelementwiththeboxContainerclass,andthenstoretheresultinavariablenamed$boxes.

Tip

Page 49: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Variablenamingconventions

Itisacommonpracticeamongdeveloperstousenamingconventionsforvariablesthatholdobjectsofacertaintype.Usingsuchconventionsnotonlyhelpsyourememberwhatthevariableisholding,butalsomakesyourcodeeasiertounderstandbyotherdevelopersofyourteam.AmongjQuerydevelopers,itiscommontousevariablenamesstartingwitha“$”signwhenthevariablestorestheresultofthe$()function(alsoknowasajQuerycollectionobject).

Afterwegetaholdoftheboxelementsthatweareinterestedin,weappendtwobreakingspacesandsomeextratextinitalics,attheendofeachofthem.Then,weusethe$boxesvariableandtraversetheDOMtreeonelevelup,usingtheparent()method.Theparent()methodreturnsadifferentjQueryobjectholdingtheparent<div>elementsofourinitiallyselectedboxesandthenwechainacalltotheaddClass()methodtoassignthemtheboxsizerCSSclass.

TipIfyouneedtotraversealltheparentnodesofaselectedelement,youcanusethe$.fn.parents()method.IfyoujustneedtofindthefirstancestorelementthatmatchesagivenCSSselector,considerusingthe$.fn.closest()methodinstead.

Finally,sincetheboxsizerclassusesfloatstoachievethethree-columnlayout,weneedtoclearthefloatsintheboxContainer.Onceagain,wetraversetheDOMusingthesimple.boxContainerCSSselectorandthe$()function.Then,wecallthe.append()methodtocreateanew<div>elementwiththe.clearCSSclassandinsertitattheendoftheboxContainer.

After700milliseconds,ourjQuerycodewillhavefinished,resultinginthethree-columnlayoutasshownearlier.Initsfinalstate,theHTMLcodeofourboxContainerelementwilllookasfollows:

<divclass="boxContainer">

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="boxsizer">

<pclass="box">

DoingDOMManipulationsiseasywithJS!

<br><br><i>Incaseweneedsimplethings</i>.

</p>

</div>

<divclass="clear"></div>

Page 50: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

</div>

MethodChainingandFluentInterfacesActually,intheprecedingexample,wecanalsogoonestepfurtherandcombineallthreebox-relatedcodestatementsintojustone,whichlookssomethingasfollows:

$('.boxContainer.box')

.append('<br/><br/><i>Incaseweneedsimplethings</i>.')

.parent()

.addClass('boxsizer');

ThisSyntaxPatterniscalledMethodChaininganditishighlyrecommendedbyjQueryandtheJavaScriptcommunityingeneral.MethodChainingispartoftheObjectOrientedImplementationPatternofFluentInterfaceswhereeachmethodrelaysitsinstructioncontexttothesubsequentone.

MostjQuerymethodsthatapplyonajQueryobjectalsoreturnthesameoranewjQueryelementcollectionobject.Thisallowsustochainseveralmethods,notonlyresultinginamorereadableandexpressivecodebutalsoreducingtherequiredvariabledeclarations.

Page 51: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 52: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheCompositePatternThekeyconceptoftheCompositePatternistoenableustotreatacollectionofobjectsinthesamewayaswetreatasingleobjectinstance.Manipulatingacompositionbyusingamethodonthecollectionwillresultinapplyingthemanipulationtoeachpartofit.Suchmethodscanbeappliedsuccessfully,regardlessofthenumberofelementsthatarepartofthecompositecollection,orevenwhenthecollectioncontainsnoelements.

Also,theobjectsofacompositecollectiondonotnecessarilyhavetoprovidetheexactsamemethods.TheCompositeObjectcaneitherexposeonlythemethodsthatarecommonamongtheobjectsofthecollection,orcanprovideanabstractedAPIandappropriatelyhandlethemethoddifferentiationsofeachobject.

Let’scontinuebyexploringhowtheintuitiveAPIthatjQueryexposesishighlyinfluencedfromtheCompositePattern.

Page 53: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowtheCompositePatternisusedbyjQueryTheCompositePatternisanintegralpartofjQuery’sarchitectureandisappliedfromtheverycore$()functionitself.Eachcalltothe$()functioncreatesandreturnsanelementcollectionobject,whichisoftensimplyreferredasajQueryobject.ThisisexactlywhereweseethefirstprincipleoftheCompositePatterns;infact,insteadofreturningasingleelement,the$()functionreturnsacollectionofelements.

ThejQueryobjectreturnedisanArray-likeobjectthatactsasawrapperobjectandcarriesthecollectionoftheretrievedelements.Italsoexposesanumberofextrapropertiesasfollows:

ThelengthoftheretrievedelementcollectionThecontextthattheobjectwasconstructedTheCSSselectorthatwasusedonthe$()functioncallAprevObjectpropertyincaseweneedtoaccessthepreviouselementcollectionafterchainingamethodcall

TipSimpleArray-likeobjectdefinition

AnArray-likeobjectisaJavaScriptobject{}thathasanumericlengthpropertyandtherespectivenumberofproperties,withsequentialnumericpropertynames.Inotherwords,anArray-likeobjectthathasthelength==2propertyisexpectedtoalsohavetwopropertiesdefined,"0"and"1".Giventheaboveproperties,Array-likeobjectsallowyoutoaccesstheircontentusingsimpleforloops,byutilizingJavaScript’sBracketPropertyAccessor’ssyntax:

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

console.log(obj[i]);

}

WecaneasilyexperimentwiththejQueryobjectsreturnedfromthe$()functionandinspectthepropertiesdescribedabove,byusingthedevelopertoolsofourfavoritebrowser.Toopenthedevelopertoolsonmostofthem,wejustneedtopressF12onWindowsandLinuxorCmd+Opt+IonMac,andrightafterthat,wecanissuesome$()callsintheconsoleandclickonthereturnedobjectstoinspecttheirproperties.

Inthefollowingfigure,wecanseewhattheresultofthe$('#pageHeader')call,whichweusedintheexampleearlier,lookslikeinFirefoxDeveloperTools:

Theresultofthe$('.boxContainer.box')calllooksasfollows:

Page 54: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThefactthatjQueryusesArray-likeobjectsasawrapperforthereturnedelementsallowsittoexposesomeextramethodsthatapplyonthecollectionreturned.ThisisachievedthroughprototypicalinheritanceofthejQuery.fnobject,resultingineachjQueryobjectalsohavingaccesstoallthemethodsthatjQueryprovides.ThiscompletestheCompositePattern,whichprovidesmethodsthat,whenappliedtoacollection,areappropriatelyappliedtoeachofitsmembers.BecausejQueryusesArray-likeobjectswithprototypicalinheritance,thesemethodscanbeeasilyaccessedaspropertiesoneachjQueryobject,asshownintheexampleinthebeginningofthechapter:$('#pageHeader').css('font-size','3em');.Moreover,jQueryaddssomeextragoodiestoitsDOMmanipulatingcode,followingthegoalofsmallerandlesserror-pronecode.Forexample,whenusingthejQuery.fn.html()methodtochangetheinnerHTMLofaDOMnodethatalreadycontainschildelements,jQueryfirsttriestoremoveanydataandeventhandlersthatareassociatedwiththechildelements,beforeremovingthemfromthepageandappendingtheprovidedHTMLcode.

Let’stakealookathowjQueryimplementsthesecollection-applicablemethods.Forthistask,wecaneitherdownloadandviewthesourcecodefromtheGitHubpageofjQuery(https://github.com/jquery/jquery/releases),orwecanuseatoolsuchasthejQuerySourceViewerthatisavailableathttp://james.padolsey.com/jquery.

NoteDependingontheversionyouareusing,youmightgetdifferentresultstosomedegree.ThemostrecentstablejQueryversionthatwasreleasedandusedasareferencewhilewritingthisbook,wasv2.2.0.

Oneofthesimplestmethodstodemonstratehowmethodsthatapplytocollectionsareimplemented,isjQuery.fn.empty().YoucaneasilylocateitsimplementationinjQuery’ssourcecodebysearchingfor"empty:"orusingthejQuerySourceViewerandsearchingfor"jQuery.fn.empty".Usingeitheroneofthewayswillbringustothefollowingcode:

empty:function(){

varelem,i=0;

for(;(elem=this[i])!=null;i++){

if(elem.nodeType===1){

//Preventmemoryleaks

jQuery.cleanData(getAll(elem,false));

//Removeanyremainingnodes

Page 55: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

elem.textContent="";

}

}

returnthis;

}

Asyoucansee,thecodeisnotcomplexatall.jQueryiteratesoveralltheitemsofthecollectionobject(referredtoasthissinceweareinsidethemethodimplementation)byusingaplainforloop.Foreachitemofthecollection,thatis,anElementNode,itclearsanydata-*propertyvaluesusingthejQuery.cleanData()helperfunction,andrightafterthis,itclearsitscontentbysettingittoanemptystring.

NoteFormoreinformationonthedifferentspecifiedNodeTypes,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType.

Page 56: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ComparingthebenefitsovertheplainDOMAPIToclearlydemonstratethebenefitsthattheCompositePatternprovides,wewillrewriteourinitialexamplewithouttheabstractionsthatjQueryoffers.ByusingjustplainJavaScriptandtheDOMAPI,wecanwriteanequivalentcodethatlooksasfollows:

setTimeout(function(){

varheaderElement=document.getElementById('pageHeader');

if(headerElement){

headerElement.style.fontSize='3em';

}

varboxContainerElement=document.getElementsByClassName('boxContainer')

[0];

if(boxContainerElement){

varinnerBoxElements=

boxContainerElement.getElementsByClassName('box');

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

varboxElement=innerBoxElements[i];

boxElement.innerHTML+='<br/><br/><i>Incaseweneedsimple

things</i>.';

boxElement.parentNode.className+='boxsizer';

}

varclearFloatDiv=document.createElement('div');

clearFloatDiv.className='clear';

boxContainerElement.appendChild(clearFloatDiv);

}

},700);

Onceagain,weusesetTimeoutwithananonymousfunctionandset700millisecondsasthesecondparameter.Insidethefunctionitself,weusedocument.getElementByIdtoretrieveelementsthatareknowntohaveauniqueIDinthepage,andlaterdocument.getElementsByClassNamewhenweneedtoretrievealltheelementsthathaveaspecificclass.WealsouseboxContainerElement.getElementsByClassName('box')toretrievealltheelementswiththeboxclassthataredescendantsoftheelementwiththeboxContainerclass.

Themostobviousobservationisthat,inthiscase,weneeded18linesofcodeinordertoachievethesameresults.Forcomparison,whenusingjQuery,weonlyneeded9linesofcode,that’shalfthenumberoflinesofcodecomparedtothelaterimplementation.UsingthejQuery$()functionwithaCSSselectorwasaneasierwaytoretrievetheelementsthatweneeded,anditalsoensurescompatibilitywithbrowsersthatdonotsupportthegetElementsByClassName()method.However,therearemorebenefitsthanjustthecodelinecountandtheimprovedreadability.AsanimplementeroftheCompositePattern,the$()functionalwaysretrieveselementcollections,makingourcodemoreuniformwhencomparedtothedifferentiatedhandlingofeachgetElement*methodweused.Weusethe$()functioninexactlythesameway,regardlessofwhetherwejustwanttoretrieveanelementwithauniqueIDoranumberofelementswithaspecificclass.

AsanextrabenefitofreturningArray-likeobjects,jQuerycanalsoprovidemoreconvenientmethodstotraverseandmanipulatetheDOM,suchasthosewesawinourfirstexample,.css(),.append()and.parent(),whichareaccessibleaspropertiesofthe

Page 57: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

returnedobject.Additionally,jQueryalsooffersmethodsthatabstractmorecomplexusecasessuchas.addClass()and.wrap()thathavenoequivalentmethodsavailableaspartoftheDOMAPI.

SincethereturnedjQuerycollectionobjectsdonotdifferinanythingotherthantheelementstheywrap,wecanuseanymethodofthejQueryAPIinthesameway.Aswesawearlier,thesemethodsapplytoeachelementoftheretrievedcollection,regardlessoftheelementcount.Asaresult,wedonotneedaseparateforlooptoiterateovereachretrievedelementandapplyourmanipulationsindividually;instead,weapplyourmanipulations(forexample,.addClass())directlytothecollectionobject.

Tocontinueprovidingthesameexecutionsafetyguarantiesinthelaterexample,wealsoneedtoaddsomeextraifstatementstocheckfornullvalues.Thisisrequiredbecause,forexample,iftheheaderElementisnotfound,anerrorwilloccurandtherestofthelinesofcodewillneverbeexecuted.Someonecouldarguethatthesechecks,suchasif(headerElement)andif(boxContainerElement),arenotrequiredinthisexampleandcanbeomitted.Thismightappeartobecorrectinthisexample,butactuallythisisamongthetopreasonsforerrorswhiledevelopinglarge-scaleapplications,whereelementsarecreated,inserted,andremovedfromtheDOMtreecontinuously.Unfortunately,programmersinalllanguagesandtargetplatformstendtofirstwritetheirimplementationlogicandfillsuchchecksatalatertime,oftenaftertheygetanerrorwhentestingtheirimplementation.

FollowingtheCompositePattern,evenanemptyjQuerycollectionobject(onethatcontainsnoretrievedelements)isstillavalidcollectionobject,wherewecansafelyapplyanymethodthatjQueryprovides.Asaresult,wedonotneedtheextraifstatementstocheckwhetheracollectionactuallycontainsanyelementbeforeapplyingamethodsuchas.css(),justforthesakeofavoidingaJavaScriptruntimeerror.

Overall,theabstractionsthatjQueryoffersbyusingtheCompositePatternleadtofewerlinesofcode,whichismorereadable,uniform,andwithfewertypo-pronelines(comparetyping$('#elementID')versusdocument.getElementById('elementID')).

Page 58: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingtheCompositePatterntodevelopapplicationsNowthatwehaveseenhowjQueryusestheCompositePatterninitsarchitectureandalsodidacomparisononthebenefitsitprovided,let’strytowriteanexampleusecaseofourown.Wewilltrytocoverallconceptsthatwehaveseenearlierinthischapter.WewillstructureourCompositetobeanArray-likeobject,operateontotallydifferentstructuredobjects,provideaFluentAPItoallowchaining,andhavemethodsthatapplyonalltheitemsofthecollection.

AsampleusecaseLet’ssaythatwehaveanapplicationthatatsomepointneedstoperformoperationsonnumbers.Ontheotherhand,theitemsthatitneedstooperateoncomefromdifferentsourcesandarenotuniformatall.Tomakethisexampleinteresting,let’ssupposethatonesourceofdataprovidesplainnumbersandanotheroneprovidesobjectswithaspecificpropertythatholdsthenumberweareinterestedin:

varnumberValues=[2,5,8];

varobjectsWithValues=[

{value:7},

{value:4},

{value:6},

{value:9}

];

Theobjectsreturnedbythesecondsourceofourusecasecouldhaveamorecomplexstructureandprobablysomeextraproperties.Suchchangeswouldn’tdifferentiateourexampleimplementationinanyway,sincewhendevelopingaCompositeweareonlyinterestedinprovidingauniformhandlingoverthecommonpartsbetweenthetargeteditems.

TheCompositeCollectionImplementationLet’sproceedanddefinetheConstructorFunctionandtheprototypethatwilldescribeourCompositeCollectionObject:

functionValuesComposite(){

this.length=0;

}

ValuesComposite.prototype.append=function(item){

if((typeofitem==='object'&&'value'initem)||

typeofitem==='number'){

this[this.length]=item;

this.length++;

}

returnthis;

};

Page 59: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ValuesComposite.prototype.increment=function(number){

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

varitem=this[i];

if(typeofitem==='object'&&'value'initem){

item.value+=number;

}elseif(typeofitem==='number'){

this[i]+=number;

}

}

returnthis;

};

ValuesComposite.prototype.getValues=function(){

varresult=[];

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

varitem=this[i];

if(typeofitem==='object'&&'value'initem){

result.push(item.value);

}elseif(typeofitem==='number'){

result.push(item);

}

}

returnresult;

};

TheValuesComposite()constructorfunctioninourexampleisquitesimple.Wheninvokedwiththenewoperator,itreturnsanemptyobjectwithalengthpropertyequaltozero,representingthatthecollectionitwrapsisempty.

NoteFormoreinformationonthePrototype-basedprogrammingmodelofJavaScript,visithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript.

Wefirstneedtodefineawaythatwillenableustopopulateourcompositecollectionobjects.Wedefinedtheappendmethodthatcheckswhethertheprovidedparameterisoneofthetypesthatitcanhandle;inthiscase,itappendstheparameterontheCompositeObjectonthenextavailablenumericpropertyandincrementsthelengthpropertyvalue.Forexample,thefirstappendeditem,whetheritisanobjectwithavaluepropertyoraplainnumber,willbeexposedtothe“0”propertyoftheCompositeObjectandwillbeaccessiblewiththeBracketPropertyAccessor’ssyntaxasmyValuesComposition[0].

Theincrementmethodispresentedasasimpleexamplemethodthatcanmanipulatesuchcollectionsbyoperatingoverallthecollectionitems.Itacceptsanumericvalueasaparameterandthenappropriatelyhandlesitbyaddingittoeachitemofourcollection,basedontheirtype.SinceourcompositeisanArray-likeobject,incrementusesaforlooptoiterateoverallthecollectionitemsandeitherincreasestheitem.value(incasetheitemisanobject)ortheactualnumericvaluestored(whenthecollectionitemstoredisanumber).Inthesamemanner,wecancontinueandimplementothermethodsthatwill,

Page 60: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

forexample,enableustomultiplythecollectionitemswithaspecificnumber.

InordertoallowchainingthemethodsofourCompositeObject,allthemethodsoftheprototypeneedtoreturnareferencetotheinstanceoftheobject.Weachievethisgoalbysimplyaddingareturnthis;statementasthelastlineforallthemethodsthatmanipulatethecollection,suchasappendandincrement.KeepinmindthatmethodssuchasgetValuesthatdonotmanipulatethecollectionbutareusedtoreturnaresult,bydefinition,can’tbechainedtorelaythecollectionobjectinstancetosubsequentmethodcalls.

Finally,weimplementthegetValuesmethodasaconvenientwaytoretrievetheactualnumericvaluesofalltheitemsinourcollection.Similartotheincrementmethod,thegetValuesmethodabstractsawaythehandlingbetweenthedifferentitemtypesofourcollection.Ititeratesoverthecollectionitems,extractseachnumericvalue,andappendsthemtoaresultarraythatitreturnstoitscaller.

AnexampleexecutionLet’snowseeanactualexamplethatwillusetheCompositeObjectwejustimplemented:

varvaluesComposition=newValuesComposite();

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

valuesComposition.append(numberValues[i]);

}

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

valuesComposition.append(objectsWithValues[i]);

}

valuesComposition.increment(2)

.append(1)

.append(2)

.append({value:3});

console.log(valuesComposition.getValues());

Whentheprecedingcodeisexecutedinabrowser,bywritingthecodeeitherinanexistingpageordirectlyinthebrowser’sconsole,itwilllogaresultthatlooksasfollows:

►Array[4,7,10,9,6,8,11,1,2,3]

WeareusingourdatasourcessuchasthenumberValuesandobjectsWithValuesvariablesthatwereshownearlier.TheprecedingcodeiteratesoverbothofthemandappendstheiritemstoanewlycreatedCompositeObjectinstance.Wethenproceedbyincrementingthevaluesofourcompositecollectionby2.Rightafterthis,wechainthethreeiteminsertionsusingappend,withthefirsttwoappendingnumericvaluesandthethirdappendinganobjectwithavalueproperty.Finally,weusethegetValuesmethodinordertogetanarraywithallthenumericvaluesofourcollectionandlogitinourbrowser’sconsole.

Alternativeimplementations

Page 61: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

KeepinmindthataCompositedoesnotneedtobeanArray-likeobject,butiscommonlypreferredsinceJavaScriptmakesiteasytocreatesuchanimplementation.Additionally,Array-likeimplementationsalsohavethebenefitofallowingustoiterateoverthecollectionitemsusingasimpleforloop.

Ontheotherhand,incaseanArray-likeobjectisnotpreferred,wecaneasilyuseapropertyontheCompositeObjecttoholdourcollectionitems.Forexample,thispropertycanbenamedasitemsandbeusedtostoreandaccesstheitemsofthecollectioninsideourmethodsusingthis.items.push(item)andthis.items[i],respectively.

Page 62: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 63: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheIteratorPatternThekeyconceptoftheIteratorPatternistheuseofafunctionwiththesingleresponsibilitytotraverseacollectionandprovideaccesstoitsitems.Thisfunctionisknownastheiteratorandprovidesawaytoaccesstheitemsofthecollection,withoutexposingimplementationspecificsandtheunderlyingdatastructureusedbythecollectionobject.

Iteratorsprovidealevelofencapsulationregardingthewaytheiterationoccurs,decouplingtheiterationovertheitemsofacollectionfromtheimplementationlogicoftheirconsumers.

NoteFormoreinformationontheSingleResponsibilityprinciple,youcanvisithttp://www.oodesign.com/single-responsibility-principle.html.

Page 64: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowtheIteratorPatternisusedbyjQueryAswesawearlierinthischapter,thejQuerycore$()functionreturnsanArray-likeobjectthatwrapsacollectionofpageelementsanditalsoprovidesaniteratorfunctiontotraverseitandaccesseachelementindividually.ItactuallygoesonestepfurtherandprovidesagenerichelpermethodjQuery.each()thatcaniterateoverarrays,Array-likeobjects,andalsoobjectproperties.

AmoretechnicaldescriptioncanbefoundinjQueryAPIdocumentationpageathttp://api.jquery.com/jQuery.each/,wherethedescriptionofjQuery.each()readsasfollows:

Agenericiteratorfunction,whichcanbeusedtoseamlesslyiterateoverbothobjectsandarrays.ArraysandArray-likeobjectswithalengthproperty(suchasafunction’sargumentsobject)areiteratedbynumericindex,from0tolength-1.Otherobjectsareiteratedviatheirnamedproperties.

ThejQuery.each()helperfunctionisusedinternallyinseveralplacesofthejQuerysourcecode.OneofitsusesisiteratingovertheitemsofajQueryobjectandapplyingmanipulationsoneachofthem,astheCompositePatternsuggests.Asimplesearchforthekeyword.each(reveals56matches.

NoteAsofwritingthisbook,thelateststableversionisv2.2.0andthiswasusedfortheabovestatistics.

WecaneasilytraceitsimplementationinjQuery’ssource,eitherbysearchingfor"each:"(notethattherearetwooccurrences)orusingthejQuerySourceViewerandsearchingfor"jQuery.each()"(likewedidearlierinthischapter):

each:function(obj,callback){

varlength,i=0;

if(isArrayLike(obj)){

length=obj.length;

for(;i<length;i++){

if(callback.call(obj[i],i,obj[i])===false){

break;

}

}

}else{

for(iinobj){

if(callback.call(obj[i],i,obj[i])===false){

break;

}

}

}

returnobj;

}

Page 65: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThishelperfunctionisalsoaccessibleonanyjQueryobjectbyusingthesameprototypicalinheritancethatwesawearlierformethodssuchas.append().Youcaneasilyfindthecodethatdoesexactlythis,bysearchingfor"jQuery.fn.each()"injQuerySourceViewerordirectlysearchingjQuerysourcecodeforeach:(notethattherearetwooccurrences):

each:function(callback){

returnjQuery.each(this,callback);

}

Usingthemethodversionof".each()"enablesustodirectlyiterateovertheelementsofajQuerycollectionobjectwithamoreconvenientsyntax.

Theexamplecodethatfollowsshowcaseshowthetwoflavorsof.each()canbeusedinourcode:

//usingthehelperfunctiononanarray

$.each([3,5,7],function(index){

console.log(this+1);

});

//usingthemethodonajQueryobject

$('.boxContainer.box').each(function(index){

console.log('I\'mbox#'+(index+1));//indexiszero-based

});

Whenexecuted,theprecedingcodewilllogthefollowingonthebrowser’sconsole:

Page 66: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitpairswiththeCompositePatternSincetheCompositePatternencapsulatesacollectionofitemsintoasingleobjectandtheIteratorPatterncanbeusedtoiterateoveranabstracteddatastructure,wecaneasilycharacterizethesetwopatternsascomplementary.

Page 67: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WherecanitbeusedTheIteratorPatterncanbeusedinourapplicationstoabstractthewayweaccessitemsfromadatastructure.Forexample,let’ssupposeweneedtoretrievealltheitemsthataregreaterthan4fromthefollowingtreestructure:

varcollection={

nodeValue:7,

left:{

nodeValue:4,

left:2,

right:{

nodeValue:6,

left:5,

right:9

}

},

right:{

nodeValue:9,

left:8

}

};

Let’snowimplementouriteratorfunction.Sincetreedatastructurescanhavenesting,weendupwiththefollowingrecursiveimplementation:

functioniterateTreeValues(node,callback){

if(node===null||node===undefined){

return;

}

if(typeofnode==='object'){

if('left'innode){

iterateTreeValues(node.left,callback);

}

if('nodeValue'innode){

callback(node.nodeValue);

}

if('right'innode){

iterateTreeValues(node.right,callback);

}

}else{

//itsaleaf,sothenodeisthevalue

callback(node);

}

}

Finally,weendupwithanimplementationthatlooksasfollows:

varvaluesArray=[];

iterateTreeValues(collection,function(value){

if(value>4){

valuesArray.push(value);

}

});

Page 68: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

console.log(valuesArray);

Whenexecuted,theprecedingcodewilllogthefollowingonthebrowser’sconsole:

►Array[5,6,9,7,8,9]

Wecanclearlyseethattheiteratorsimplifiedourcode.Wenolongerbotherwiththeimplementationspecificsofthedatastructureusedeverytimeweneedtoaccesssomeitemsthatfulfillcertaincriteria.OurimplementationworksontopofthegenericAPIthattheiteratorexposes,andourimplementationlogicappearsinthecallbackthatweprovidetotheiterator.

Thisencapsulationallowsustodecoupleourimplementationfromthedatastructureused,giventhataniteratorwiththesameAPIwillbeavailable.Forinstance,inthisexample,wecaneasilychangethedatastructureusedtoasortedbinarytreeorasimplearrayandpreserveourimplementationlogicthesame.

Page 69: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 70: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,wehadarefresheronJavaScript’sDOMScriptingAPIandjQuery.WewereintroducedtotheCompositePatternandsawhowitisusedbythejQuerylibrary.WesawhowtheCompositePatternsimplifiesourworkflowafterwerewroteourexamplepagewithoutusingjQuery,andlatershowcasedanexampleofusingtheCompositePatterninourapplications.Finally,wewereintroducedtotheIteratorPatternandsawhowwellitpairswhenusedalongwiththeCompositePattern.

NowthatwehavecompletedourintroductiononhowtheCompositePatternplaysanimportantroleinthewayweusejQuerymethodseveryday,wecanmoveontothenextchapterwherewewillshowcasetheObserverPatternandtheconvenientwaytoutilizeitinourpagesusingjQuery.

Page 71: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 72: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter2.TheObserverPatternInthischapter,wewillshowcasetheObserverPatternandtheconvenientwayinwhichwecanutilizeitinourpagesusingjQuery.Lateron,wewillalsoexplaintheDelegatedEventObserverPatternvariant,whichwhenproperlyappliedtowebpagescanleadtocodesimplificationsandalsolessenthememoryconsumptionthatapagerequires.

Inthischapter,wewill:

IntroducetheObserverPatternSeehowtheObserverPatternisusedbyjQueryComparetheObserverPatternwithusingtheeventattributesLearnhowtoavoidmemoryleaksfromobserversIntroducetheDelegatedEventObserverPatternandshowcasingitsbenefits

Page 73: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheObserverPatternThekeyconceptoftheObserverPatternisthatthereisanobject,oftenreferredtoastheobservableorthesubject,whoseinternalstatechangesduringitslifetime.Therearealsoseveralotherobjects,referredastheobservers,thatwanttobenotifiedintheeventthatthestateoftheobservable/subjectchanges,inordertoexecutesomeoperations.

Theobserversmayneedtobenotifiedaboutanykindofstatechangeoftheobservableoronlyspecifictypesofchanges.Inthemostcommonimplementation,theobservablemaintainsalistwithitsobserversandnotifiesthemwhenanappropriatestatechangeoccurs.Incaseastatechangeoccurstotheobservable,ititeratesthroughthelistofobserversthatareinterestedforthattypeofstatechangeandexecutesaspecificmethodthattheyhavedefined.

AccordingtothedefinitionoftheObserverPatternandthereferenceimplementationinComputerSciencebooks,theobserversaredescribedasobjectsthatimplementawell-knownprogramminginterface,inmostcases,specifictoeachobservabletheyareinterestedin.Inthecaseofastatechange,theobservablewillexecutethewell-knownmethodofeachobserverasitisdefinedintheprogramminginterface.

NoteFormoreinformationonhowtheObserverPatternisusedintraditional,object-orientedprogramming,youcanvisithttp://www.oodesign.com/observer-pattern.html.

Inthewebstack,theObserverPatternoftenusesplainanonymouscallbackfunctionsasobserversinsteadofobjectswithwell-knownmethods.Anequivalentresult,asdefinedby

Page 74: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

theObserverPattern,canbeachievedsincethecallbackfunctionkeepsreferencestothevariablesoftheenvironmentthatitwasdefinedin—apatterncommonlyreferencedasaClosure.ThemainbenefitofusingtheObserverPatternovercallbacksasinvocationorinitializationparametersisthattheObserverPatterncansupportseveralindependenthandlersonasingletarget.

NoteFormoreinformationonclosures,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

TipDefiningasimplecallback

Acallbackcanbedefinedasafunctionthatispassedasanargumenttoanotherfunction/methodorisassignedtoapropertyofanobjectandexpectedtobeexecutedatsomelaterpointoftime.Inthisway,thepieceofcodethatwashandedourcallbackwillinvokeorcallit,propagatingtheresultsofanoperationoreventbacktothecontextwherethecallbackwasdefined.

Sincethepatternofregisteringfunctionsasobservershasproventobemoreflexibleandstraightforwardtoprogram,itcanbefoundinprogramminglanguagesoutsidethewebstackaswell.Otherprogramminglanguagesprovideanequivalentfunctionalitythroughlanguagefeaturesorspecialobjectssuchassubroutines,lambdaexpressions,blocks,andfunctionpointers.Forexample,Pythonalsodefinesfunctionsasfirst-classobjectssuchasJavaScript,enablingthemtobeusedascallbacks,whileC#definesDelegatesasaspecialobjecttypeinordertoachievethesameresult.

TheObserverPatternisanintegralpartofdevelopingwebinterfacesthatrespondtouseractions,andeverywebdeveloperhasusedittosomedegree,evenwithoutnoticingit.Thisisbecausethefirstthingthatawebdeveloperneedstodowhilecreatingarichuserinterfaceistoaddeventlistenerstopageelementsanddefinehowthebrowsershouldrespondtothem.

ThisistraditionallyachievedbyusingtheEventTarget.addEventListener()methodonthepageelementsthatweneedtolistentoforeventssuchasa“click”,andprovidingacallbackfunctionwiththecodethatneedstobeexecutedwhenthateventoccurs.ItisworthmentioningthatinordertosupportolderversionsofInternetExplorer,testingfortheexistenceofEventTarget.attachEvent(),andusingthatinstead,isrequired.

NoteFormoreinformationontheaddEventListener()andattachEvent()methods,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListenerandhttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/attachEvent.

Page 75: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisusedbyjQueryThejQuerylibraryheavilyusestheObserverPatterninseveralpartsofitsimplementation,eitherdirectlybyusingtheaddEventListenermethodorcreatingitsownabstractionoverit.Moreover,jQueryoffersaseriesofabstractionsandconvenientmethodstomakeworkingwiththeObserverPatterneasieronthewebandalsousessomeoftheminternallytoimplementothermethodsaswell.

ThejQueryonmethodThejQuery.fn.on()methodisthecentraljQuerymethodforattachingeventhandlerstoelements,providinganeasywaytoadopttheObserverPattern,whilekeepingourcodeeasytoreadandreason.ItattachestherequestedeventhandleroveralltheelementsofacompositejQuerycollectionobjectreturnedbythe$()function.

SearchingforjQuery.fn.oninjQuery’sSourceViewer(whichisavailableathttp://james.padolsey.com/jquery),ordirectlysearchingjQuery’ssourcecodeforon:function(thefirstcharacterisatab),willleadustothemethod’sdefinition,whichcounts67linesofcode.Actually,thefirst55linesoftheinternalonfunctionarejusthandlingallthedifferentwaysthatthejQuery.fn.on()methodcanbeinvoked;nearitsend,wecanseethatitactuallyusestheinternalmethodjQuery.event.add():

jQuery.fn.extend({

on:function(types,selector,data,fn){

returnon(this,types,selector,data,fn);

}

});

functionon(elem,types,selector,data,fn,one){

/*55linesofcodehandlingthemethodoverloads*/

returnelem.each(function(){

jQuery.event.add(this,types,fn,data,selector);

});

}

ThejQuery.eventobjectistheone-placestopforeventhandlinginjQueryanditsimplementationcountsaround443linesofcode.Itholdsseveralhelperfunctionsformanagingeventssuchasadd,dispatch,fix,handlers,remove,simulate,andtrigger.AllthesefunctionsareusedinternallybyjQueryitselfwherevertheObserverPatternappearsormanagingeventsisrequired.

SearchingforjQuery.event.addinjQuery’sSourceViewerorjQuery.event=directlyinjQuery’ssourcecode,willleadustotherelativelylongimplementationofthehelperfunctionthatcountsaround107linesofcodeinjQueryv2.2.0.Thefollowingcodesnippetshowsatrimmeddownversionofthatmethod,wheresomecoderelatedtothetechnicalimplementationofjQueryandnotrelatedtotheObserverPatternhasbeenremovedforclarity:

add:function(elem,types,handler,data,selector){

/*...4linesofcode…*/

Page 76: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

elemData=dataPriv.get(elem);

/*...13linesofcode…*/

//MakesurethatthehandlerhasauniqueID,

//usedtofind/removeitlater

if(!handler.guid){

handler.guid=jQuery.guid++;

}

//Inittheelement'seventstructureandmainhandler,

//ifthisisthefirst

if(!(events=elemData.events)){

events=elemData.events={};

}

/*...9linesofcode…*/

//Handlemultipleeventsseparatedbyaspace

types=(types||"").match(rnotwhite)||[""];

t=types.length;

while(t--){

/*...30linesofcode…*/

//Inittheeventhandlerqueueifwe'rethefirst

if(!(handlers=events[type])){

handlers=events[type]=[];

handlers.delegateCount=0;

//OnlyuseaddEventListenerifthespecialeventshandler

//returnsfalse

if(!special.setup||special.setup.call(elem,data,

namespaces,eventHandle)===false){

if(elem.addEventListener){

elem.addEventListener(type,eventHandle);

}

}

}

/*...9linesofcode…*/

//Addtotheelement'shandlerlist,delegatesinfront

if(selector){

handlers.splice(handlers.delegateCount++,0,handleObj);

}else{

handlers.push(handleObj);

}

/*...3linesofcode…*/

}

}

Now,let’sseehowtheObserverPatternisimplementedbyjQuery.event.add(),byreferringtotheprecedinghighlightedcode.

ThehandlervariableintheargumentsofthejQuery.event.add()methodstoresthefunctionthatwasoriginallypassedasanargumenttothejQuery.fn.on()method.Wecanrefertothisfunctionasourobserverfunction,sinceitisexecutedwhenthe

Page 77: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

appropriateeventfiresontheelementthatitwasattachedto.

Inthefirsthighlightedcodearea,jQuerycreatesandassignsaguidpropertytotheobserverfunctionthatisstoredinthehandlervariable.KeepinmindthatassigningpropertiestofunctionsispossibleinJavaScript,sincefunctionsarefirst-classobjects.ThejQuery.guid++statementisexecutedrightaftertheassignmentoftheoldvalueandisrequiredsincejQuery.guidisapage-widecounterusedbyjQueryandjQuerypluginsinternally.TheguidpropertyontheobserverfunctionisusedasawaytoidentifyandlocatetheobserverfunctioninsidetheobserverlistthatjQueryhasforeachelement.Forexample,itisusedbythejQuery.fn.off()methodtolocateandremoveanobserverfunctionfromtheobserverlistassociatedwithanelement.

TipjQuery.guidisapage-widecounterthatisusedbythepluginsandjQueryitselfasacentralizedwaytoretrieveuniqueintegerIDs.ItisoftenusedtoassignuniqueIDstoelements,objects,andfunctions,inordertomakeiteasiertolocatethemincollections.ItistheresponsibilityofeachimplementerthatretrievesandusesthecurrentvalueofjQuery.guidtoalsoincreasethepropertyvalue(byone)aftereachuse.Otherwise,andsincethisisapage-widecounterthatisusedbybothjQuerypluginsandjQuerythemselvesforidentification,thepagewillprobablyfacemalfunctionsthatarehardtodebug.

Inthesecondandthirdhighlightedcodeareas,jQueryinitializesanarraytoholdtheobserverlistsforeachindividualeventthatmayfireonthatelement.OnethingtonoteinthesecondhighlightedcodeareaisthattheobserverlistsfoundintheelemDatavariablearenotapropertyontheactualDOMelement.AsshowninthedataPriv.get(elem)statement,nearthestartofthejQuery.event.add()method,jQueryusesseparatemappingobjectstoholdtheassociationsbetweenDOMelementsandtheirobserverlists.Byusingthisdatacachemechanism,jQueryisabletoavoidpollutingtheDOMelementswiththeextrapropertiesthatareneededbyitsimplementation.

NoteYoucaneasilylocatethedatacachemechanismimplementationinthesourcecodeofjQuerybysearchingforfunctionData().ThiswillbringyoutotheconstructorfunctionoftheDataclassthatisalsofollowedbytheimplementationoftheclassmethodsthataredefinedintheData.prototypeobject.Formoreinformation,youcanvisithttp://api.jquery.com/data.

ThenexthighlightedcodeareaiswherejQuerycheckswhethertheEventTarget.addEventListener()methodisactuallyavailableforthatelementandthenusesittoaddtheeventlistenertotheelement.Inthefinalhighlightedcodearea,jQueryaddstheobserverfunctiontoitsinternallist,whichholdsalltheobserversofthesameeventtypethatareattachedtothatspecificelement.

NoteDependingontheversionyouareusing,youmightgetdifferentresultstosomedegree.

Page 78: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThemostrecentstablejQueryversionreleasedandusedasreferencewhilewritingthisbookwasv2.2.0.

Incaseyouneedtoprovidesupportforolderbrowsers,forexample,InternetExplorerlowerthanversion9,thenyoushouldusethev1.xversionsofjQuery.Thelatestversionasofthewritingofthisbookwasv1.12.0,whichofferstheexactsameAPIasthev2.2.xversions,butalsohastherequiredcodetoworkonolderbrowsers.

Inordertocovertheimplementationinconsistenciesofolderbrowsers,theimplementationofjQuery.event.add()injQueryv1.xisabitlongerandmorecomplex.OneofthereasonsforthisisbecausejQueryalsoneedstotestwhetherEventTarget.addEventListener()isactuallyavailableinthebrowserthatitisrunningandtrytouseEventTarget.attachEvent()ifthisisnotthecase.

Aswesawintheprecedingcode,thejQueryimplementationfollowstheoperationmodelthattheObserverPatterndescribes,butitalsoincorporatessomeimplementationtricksinordertomakeitworkmoreefficientlywiththeAPIsavailabletowebbrowsers.

Thedocument-readyobserverAnotherconvenientmethodthatjQueryoffers,whichiswidelyusedbydevelopers,isthe$.fn.ready()method.ThismethodacceptsafunctionparameterandexecutesitonlyaftertheDOMtreeofthepagehasbeenfullyloaded.Suchathingcanbeusefulincaseyourcodeisnotloadedlastinthepageandyoudon’twanttoblocktheinitialpagerender,ortheelementsthatitneedstomanipulatearedefinedlaterthanitsown<script>tag.

NoteKeepinmindthatthe$.fn.ready()methodworksslightlydifferentlythanthewindow.onloadcallbackandthe“load”eventofthepage,whichwaituntilalltheresourcesofthepageareloaded.Formoreinformation,youcanvisithttp://api.jquery.com/ready.

Thefollowingcodedemonstratesthemostcommonwaytousethe$.fn.ready()method:

$(document).ready(function(){

/*thiscodewillexecuteonlyafterthepagehasbeenfullyloaded*/

})

IfwetrytolocatetheimplementationofjQuery.fn.ready,wewillseethatitactuallyusesjQuery.ready.promiseinternallytowork:

jQuery.fn.ready=function(fn){

//Addthecallback

jQuery.ready.promise().done(fn);

returnthis;

};

/*…alotlinesofcodeinbetween*/

jQuery.ready.promise=function(obj){

if(!readyList){

readyList=jQuery.Deferred();

Page 79: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

//Catchcaseswhere$(document).ready()iscalled

//afterthebrowsereventhasalreadyoccurred.

//Support:IE9-10only

//OlderIEsometimessignals"interactive"toosoon

if(document.readyState==="complete"||(document.readyState!==

"loading"&&!document.documentElement.doScroll)){

//Handleitasynchronouslytoallow…todelayready

window.setTimeout(jQuery.ready);

}else{

//Usethehandyeventcallback

document.addEventListener("DOMContentLoaded",completed);

//Afallbacktowindow.onload,thatwillalwayswork

window.addEventListener("load",completed);

}

}

returnreadyList.promise(obj);

};

Asyoucanseeintheprecedinghighlightedcodeareasoftheimplementation,jQueryusesaddEventListenertoobservewhentheDOMContentLoadedeventisfiredonthedocumentobject.Moreover,toensurethatitwillworkacrossawiderangeofbrowsers,italsoobservesfortheloadeventtobefiredonthewindowobject.

ThejQuerylibraryalsoprovidesshortermethodstoaddtheabovefunctionalityinyourcode.Sincetheaforementionedimplementationdoesnotactuallyneedareferencetothedocument,wecaninsteadjustwrite$().ready(function(){/*...*/}).Therealsoexistsanoverloadofthe$()functionthatachievesthesameresult,whichisusedlike$(function(){/*...*/}).ThesetwoalternativewaystousejQuery.fn.readyhavebeenheavilycriticizedamongdevelopers,sincetheycommonlyleadtomisunderstandings.Thesecond,shorterversioninparticularcanleadtoconfusion,sinceitlookslikeanImmediatelyInvokedFunctionExpression(IIFE),apatternthatJavaScriptdevelopersuseheavilyandhavelearnedtorecognize.Infact,itonlydiffersbyonecharacter($)andasaresult,itsuseisnotsuggestedbeforeadiscussionwiththerestofyourdeveloperteam.

NoteThe$.fn.ready()methodisalsocharacterizedasamethodthatprovidesaneasywaytoimplementtheLazyInitialization/ExecutionPatterninourcode.Thecoreconceptofthispatternistopostponetheexecutionofapieceofcodeorloadaremoteresourceatalaterpointoftime.Forexample,wecanwaitforthepagetobefullyloadeduntilweaddourobserversorwaitforacertaineventtohappenbeforedownloadingawebresource.

Page 80: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DemonstrateasampleusecaseInordertoseetheObserverPatterninaction,wewillcreateanexampleshowcasingaskeletonimplementationofadashboard.Inourexample,theuserwillbeabletoaddinformationboxestohisdashboardrelatedtosomesampleitemsandcategoriesthatareavailableforselectionontheheader.

Ourexamplewillhavethreepredefinedcategoriesforouritems:Products,Sales,andAdvertisements.Eachofthesecategorieswillhaveaseriesofrelateditemsthatwillappearinthearearightbelowthecategoryselector.Theuserwillbeabletoselectthedesiredcategorybyusingadrop-downselectorandthiswillchangethevisibleselectionitemsofthedashboard.

Ourdashboardwillinitiallycontainahintinformationboxaboutthedashboardusage.Wheneverauserclicksononeofthecategoryitems,anewinformationboxwillappearinourthree-columnlayoutdashboard.Intheprecedingimage,theuserhasaddedtwonewinformationboxesforProductBandProductDbyclickingontheassociatedbuttons.

Page 81: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Theuserwillalsobeabletodismissanyoftheseinformationboxesbyclickingonaredclosebuttononthetop-rightofeachinformationbox.Intheprecedingimage,theuserdismissedtheProductDinformationbox,thenaddedinformationboxesfortheAdvertisement3andlaterthe1st,2nd,and3rdweekitemsoftheSalescategory.

Byjustreadingtheabovedescription,wecaneasilyisolatealltheuserinteractionsthatarerequiredfortheimplementationofourdashboard.WewillneedtoaddobserversforeachoneoftheseuserinteractionsandwritecodeinsidethecallbackfunctionsthatexecutetheappropriateDOMmanipulations.

Indetail,ourcodewillneedto:

ObservechangesdonetothecurrentlyselectedelementandrespondtosucheventbyhidingorrevealingtheappropriateitemsObservetheclicksoneachitembuttonandrespondbyaddinganewinformationboxObservetheclicksontheclosebuttonofeachinformationboxandrespondbyremovingitfromthepage

Nowlet’sproceedandreviewtheHTML,CSS,andJavaScriptcoderequiredfortheprecedingexample.Let’sstartwiththeHTMLcodeandforreference,let’ssaythatwesaveditinafilenamedDashboardExample.html,asfollows:

<!DOCTYPEhtml>

<html>

<head>

<title>DashboardExample</title>

<linkrel="stylesheet"type="text/css"href="dashboard-example.css">

</head>

<body>

<h1id="pageHeader">DashboardExample</h1>

<divclass="dashboardContainer">

<sectionclass="dashboardCategories">

<selectid="categoriesSelector">

<optionvalue="0"selected>Products</option>

<optionvalue="1">Sales</option>

<optionvalue="2">Advertisements</option>

</select>

<sectionclass="dashboardCategory">

<button>ProductA</button>

<button>ProductB</button>

<button>ProductC</button>

<button>ProductD</button>

<button>ProductE</button>

</section>

<sectionclass="dashboardCategoryhidden">

<button>1stweek</button>

<button>2ndweek</button>

<button>3rdweek</button>

<button>4thweek</button>

</section>

<sectionclass="dashboardCategoryhidden">

<button>Advertisement1</button>

Page 82: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

<button>Advertisement2</button>

<button>Advertisement3</button>

</section>

<divclass="clear"></div>

</section>

<sectionclass="boxContainer">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

Hint!

<buttonclass="boxCloseButton">&#10006;</button>

</header>

Pressthebuttonsabovetoaddinformationboxes…

</article>

</div>

</section>

<divclass="clear"></div>

</div>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="dashboard-example.js">

</script>

</body>

</html>

IntheprecedingHTML,weplacedallourdashboard-relatedelementsinsidea<div>elementwiththedashboardContainerCSSclass.Thiswillenableustohaveacentricstartingpointtosearchforourdashboard’selementsandalsoscopeourCSS.Insideit,wedefinetwo<section>elementsinordertodividethedashboardintologicalareasusingsomeHTML5semanticelements.

Thefirst<section>withthedashboardCategoriesclassisusedtoholdthecategoriesselectorofourdashboard.Insideit,wehavea<select>elementwiththeIDcategoriesSelectorthatisusedtofilterthevisiblecategoryitemsandthreesubsectionswiththedashboardCategoryclassthatareusedtowrapthe<button>elementsthatwillpopulatethedashboardwithinformationboxeswhenclicked.Twoofthemalsohavethehiddenclasssothatonlythefirstoneisvisiblewhenthepageloadsbymatchingtheinitiallyselectedoption(<option>)ofthecategoryselector.Also,attheendofthefirstsection,wealsoaddeda<div>withtheclearclassthat,aswesawinthefirstchapter,willbeusedtoclearthefloated<button>elements.

Thesecond<section>withtheboxContainerclassisusedtoholdtheinformationboxesofourdashboard.Initially,itcontainsonlyonewithahintabouthowtousethedashboard.Weusea<div>elementwiththeboxsizerclasstosettheboxdimensionsandanHTML5<article>elementwiththeboxclasstoaddtherequiredborderpaddingandshadow,similartotheboxelementsfromthefirstchapter.

Eachinformationbox,besidesitscontent,alsocontainsa<header>elementwiththeboxHeaderclassanda<button>elementwiththeboxCloseButtonclassthat,whenclicked,removestheinformationboxthatcontainsit.Wealsousedthe&#10006;HTMLcharactercodeasthebutton’scontentinordertogetabetter-looking“x”markandavoid

Page 83: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

usingaseparateimageforthatpurpose.

Lastly,sincetheinformationboxesarealsofloated,wealsoneeda<div>withtheclearclassattheendoftheboxContainer.

Inthe<head>oftheprecedingHTML,wealsoreferenceaCSSfilenamedasdashboard-example.csswiththefollowingcontent:

.dashboardCategories{

margin-bottom:10px;

}

.dashboardCategoriesselect,

.dashboardCategoriesbutton{

display:block;

width:200px;

padding:5px3px;

border:1pxsolid#333;

margin:3px5px;

border-radius:3px;

background-color:#FFF;

text-align:center;

box-shadow:01px1px#777;

cursor:pointer;

}

.dashboardCategoriesselect:hover,

.dashboardCategoriesbutton:hover{

background-color:#DDD;

}

.dashboardCategoriesbutton{

float:left;

}

.box{

padding:7px10px;

border:solid1px#333;

margin:5px3px;

box-shadow:01px2px#777;

}

.boxsizer{

float:left;

width:33.33%;

}

.boxHeader{

padding:3px10px;

margin:-7px-10px7px;

background-color:#AAA;

box-shadow:01px1px#999;

}

.boxCloseButton{

float:right;

Page 84: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

height:20px;

width:20px;

padding:0;

border:1pxsolid#000;

border-radius:3px;

background-color:red;

font-weight:bold;

text-align:center;

color:#FFF;

cursor:pointer;

}

.clear{clear:both;}

.hidden{display:none;}

AsyoucanseeinourCSSfile,firstofallweaddsomespacebelowtheelementwiththedashboardCategoriesclassandalsodefinethesamestylingforthe<select>elementandthebuttonsinsideit.Inordertodifferentiateitfromthedefaultbrowserstyling,weaddsomepadding,aborderwithroundedcorners,adifferentbackgroundcolorwhenhoveringthemousepointer,andsomespaceinbetweenthem.Wealsodefinethatour<select>elementshouldbedisplayedaloneinitsrowasablockandthatthecategoryitembuttonsshouldfloatnexttoeachother.WeagainusetheboxsizerandboxCSSclasses,aswedidinChapter1,ARefresheronjQueryandtheCompositePattern;thefirstonetocreateathree-columnlayoutandthesecondonetoactuallyprovidethestylingofaninformationbox.WecontinuebydefiningtheboxHeaderclassthatisappliedtothe<header>elementsofourinformationboxes,anddefinesomepadding,agreybackgroundcolor,alightshadow,andalsosomenegativemarginssothatitcounterbalancestheeffectofthebox’spaddingsandplacesitselfnexttoitsborder.

Tocompletethestylingoftheinformationboxes,wealsodefinetheboxCloseButtonCSSclassthat(i)floatsthebox’sclosebuttonstotheupper-rightcornerinsidethebox<header>,(ii)definesa20pxwidthandheight,(iii)overridesthedefaultbrowser’s<button>stylingtozeropadding,and(iv)addsasingle-pixelblackborderwithroundedcornersandaredbackgroundcolor.Lastly,likeinChapter1,ARefresheronjQueryandtheCompositePatternwedefinetheclearutilityCSSclasstopreventtheelementfrombeingplacednexttothepreviousfloatingelementsandalsodefinethehiddenclassasaconvenientwayofhidingelementsofthepage.

InourHTMLfile,wereferencethejQuerylibraryitselfandalsoaJavaScriptfilenamedasdashboard-example.jsthatcontainsourdashboardimplementation.Followingthebestpracticesofcreatingperformantwebpages,wehaveplacedthemrightbeforethe</body>tag,inordertoavoiddelayingtheinitialpagerendering:

$(document).ready(function(){

$('#categoriesSelector').change(function(){

var$selector=$(this);

varselectedIndex=+$selector.val();

var$dashboardCategories=$('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

Page 85: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

});

functionsetupBoxCloseButton($box){

$box.find('.boxCloseButton').click(function(){

$(this).closest('.boxsizer').remove();

});

}

//maketheclosebuttonofthehintboxwork

setupBoxCloseButton($('.box'));

$('.dashboardCategorybutton').on('click',function(){

var$button=$(this);

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

$button.text()+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+$button.text()+

'</article></div>';

$('.boxContainer').append(boxHtml);

setupBoxCloseButton($('.box:last-child'));

});

});

Wehaveplacedallourcodeinsidea$(document).ready()call,inordertodelayitsexecutionuntiltheDOMtreeofthepageisfullyloaded.Thiswouldbeabsolutelyrequiredifweplacedourcodeinthe<head>element,butitisalsoabestpracticethatisgoodtofollowinanycase.

WefirstaddanobserverforthechangeeventonthecategoriesSelectorelementusingthe`$.fn.change()`method,whichisactuallyashorthandmethodforthe$.fn.on('change',/*…*/)method.InjQuery,thevalueofthethiskeywordinsideafunctionthatisusedasanobserverholdsareferencetotheDOMelementthattheeventwasfired.ThisappliestoalljQuerymethodsthatregisterobservers,fromthecore$.fn.on()tothe$.fn.change()and$.fn.click()convenientmethods.Soweusethe$()functiontomakeajQueryobjectwiththe<select>elementandstoreitinthe$selectorvariable.Then,weuse$selector.val()toretrievethevalueoftheselected<option>andcastittoanumericvaluebyusingthe+operator.Rightafterthis,weretrievethe<section>elementsofdashboardCategoryandcachetheresulttothe$dashboardCategoriesvariable.Then,weproceedbyfindingandrevealingthecategorywhosepositionisequaltothevalueoftheselectedIndexvariableandalsostoretheresultingjQueryobjecttothe$selectedItemvariable.Finally,weareusingthe$selectedItemvariablewiththe$.fn.not()methodtoretrieveandhideallthecategoryelements,exceptfromtheonewejustrevealed.

Inthenextcodesection,wedefinethesetupBoxCloseButtonfunctionthatwillbeusedtoinitializethefunctionalityoftheclosebutton.ItexpectsajQueryobjectwiththeboxelementsasaparameter,andforeachofthem,searchestheirdescendantsforthe

Page 86: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

boxCloseButtonCSSclassthatweuseontheclosebuttons.Using$.fn.click(),whichisaconvenientmethodfor$.fn.on('click',/*fn*/),weregisterananonymousfunctiontobeexecutedwheneveraclickeventisfiredthatusesthe$.fn.closest()methodtofindthefirstancestorelementwiththeboxsizerclassandremovesitfromthepage.Rightafterthis,wecallthisfunctiononcefortheboxelementsthatalreadyexistedinthepageatthetimewhenthepagewasloaded.Inthiscase,theboxelementwiththeusagehint.

NoteAnextrathingtokeepinmindwhenusingthe$.fn.closest()methodisthatitbeginstestingthegivenselectorfromthecurrentelementofthejQuerycollectionbeforeproceedingwithitsancestorelements.Formoreinformation,youcanvisititsdocumentationathttp://api.jquery.com/closest.

Inthefinalcodesection,weusethe$.fn.on()methodtoaddanobserverfortheclickeventoneachofthecategorybuttons.Inthiscase,insidetheanonymousobserverfunction,weusethethiskeyword,whichholdstheDOMelementofthe<button>thatwasclicked,andusethe$()methodtocreateajQueryobjectandcacheitsreferenceinthe$buttonvariable.Rightafterthis,weretrievethebutton’stextcontentusingthe$.fn.text()methodandalongwithit,constructtheHTMLcodefortheinformationbox.Fortheclosebutton,weusethe&#10006HTMLcharactercodethatwillberenderedasaprettier“X”icon.ThetemplatewecreatedisbasedontheHTMLcodeoftheinitiallyvisiblehintbox;fortheneedsofthischapter’sexample,weuseplainstringconcatenation.Lastly,weappendthegeneratedHTMLcodeforourboxtotheboxContainer,andsinceweexpectittobethelastelement,weusethe$()functiontofinditandprovideitasaparametertothesetupBoxCloseButton.

Page 87: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitiscomparedwitheventattributesBeforetheEventTarget.addEventListener()wasdefinedintheDOMLevel2Eventsspecification,theeventlistenerswereregisteredeitherbyusingtheeventattributesthatareavailableforHTMLelementsortheelementeventpropertiesthatareavailableforDOMnodes.

NoteFormoreinformationontheDOMLevel2Eventspecificationandeventattributes,youcanvisithttp://www.w3.org/TR/DOM-Level-2-Eventsandhttps://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Event_attributes,respectively.

TheeventattributesareasetofattributesthatareavailabletoHTMLelementsandprovideadeclarativewayofdefiningpiecesofJavaScriptcode(preferablyfunctioncalls)thatshouldbeexecutedwhenaspecificeventistriggeredonthatelement.Becauseoftheirdeclarativenatureandhowsimplytheycanbeused,thisisoftenthefirstwaythatnewdevelopersgetintroducedtoeventsinwebdevelopment.

Ifweusedeventattributesintheaboveexample,thentheHTMLcodefortheclosebuttonsintheinformationboxeswilllookasfollows:

<articleclass="box">

<headerclass="boxHeader">

Hint!

<buttononclick="closeInfoBox();"

class="boxCloseButton">&#10006;</button>

</header>

Pressthebuttonsabovetoaddinformationboxes…

</article>

Also,weshouldchangethetemplatethatisusedtocreatenewinformationboxesandexposethecloseInfoBoxfunctiononthewindowobject,inorderforittobeaccessiblefromtheHTMLeventattribute:

window.closeInfoBox=function(){

$(this).closest('.boxsizer').remove();

};

SomeofthedisadvantagesofusingeventattributesovertheObserverPatternare:

ItmakesithardertodefinemultipleseparateactionsthathavetobeexecutedwhenaneventfiresonanelementItmakestheHTMLcodeofthepagebiggerandlessreadableItisagainsttheseparationofconcernsprinciple,sinceitaddsJavaScriptcodeinsideourHTML,possiblymakingabughardertotrackandfixMostofthetime,itleadstothefunctionsbeingcalledintheeventattributegettingexposedtotheglobalwindowobject,thereby“polluting”theglobalnamespace

UsingtheelementeventpropertieswouldnotrequireanychangestoourHTML,keepingalltheimplementationinourJavaScriptfiles.Thechangesrequiredinour

Page 88: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

setupBoxCloseButtonfunctionwillmakeitlookasfollows:

functionsetupBoxCloseButton($box){

var$closeButtons=$box.find('.boxCloseButton');

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

$closeButtons[i].onclick=function(){

this.onclick=null;

$(this).closest('.boxsizer').remove();

};

}

}

Notethat,forconvenience,wearestillusingjQueryforDOMmanipulations,buttheresultingcodestillhassomeoftheaforementioneddisadvantages.Moreimportantly,inordertoavoidmemoryleaks,wearealsorequiredtoremovethefunctionassignedtotheonclickpropertybeforeremovingtheelementfromthepage,ifitcontainsreferencestotheDOMelementthatitisappliedon.

Usingthetoolsthattoday’sbrowsersoffer,wecanevenmatchtheconveniencethatthedeclarativenatureofeventattributesoffers.Inthefollowingimage,youcanseehowtheFirefoxdevelopertoolsprovideuswithhelpfulfeedbackwhenweusethemtoinspectapageelementthathasaneventlistenerattached:

Asyoucanseeintheprecedingimage,alltheelementsthathaveobserversattachedalsohaveanevsignrightnexttothem,whichwhenclicked,displaysadialogshowingalltheeventlistenersthatarecurrentlyattached.Tomakeourdevelopingexperienceevenbetter,wecandirectlyseethefileandthelinethatthesehandlersweredefinedin.Moreover,wecanclickontheminordertoexpandandrevealtheircode,orclickonthesigninfrontofthemtonavigatetotheirsourceandaddbreakpoints.

OneofthebiggestbenefitsofusingtheObserverPatternovereventattributesisclearlyvisibleinthecasewhereweneedtotakemorethanoneactionwhenacertaineventhappens.Supposethatwealsoneedtoaddanewfeatureinourexampledashboard,whichwouldpreventauserfromaccidentallydouble-clickingacategoryitembuttonandaddingthesameinformationboxtwicetothedashboard.Thenewimplementationshouldideallybecompletelyindependentfromtheexistingone.UsingtheObserverPattern,allweneedtodoisaddthefollowingcodethatobservesforbuttonclicksanddisablesthatbuttonfor700milliseconds:

Page 89: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

$(document).ready(function(){

$('.dashboardCategorybutton').on('click',function(){

var$button=$(this);

$button.prop('disabled',true);

setTimeout(function(){

$button.prop('disabled',false);

},700);

});

});

TheprecedingcodeisindeedcompletelyindependentfromthebasicimplementationandwecouldplaceitinsidethesameoradifferentJSfileandloadittoourpage.Thiswouldbemoredifficultwhenusingeventattributes,sinceitwouldrequireustodefinebothactionsatthesametimeinsidethesameeventhandlerfunction;asaresult,itwouldstronglycouplethetwoindependentactions.

Page 90: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AvoidmemoryleaksAswesawearlier,therearesomestrongadvantagesofusingtheObserverPatterntohandleeventsonawebpage.WhenusingtheEventTarget.addEventListener()methodtoaddanobservertoanelement,wealsoneedtokeepinmindthatinordertoavoidmemoryleaks,wealsohavetocalltheEventTarget.removeEventListener()methodbeforeremovingsuchelementsfromthepagesothattheobserversarealsoremoved.

NoteFormoreinformationonremovingeventlistenersfromelements,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener,orforthejQueryequivalentmethod,visithttp://api.jquery.com/off/.

ThejQuerylibrarydevelopersunderstoodthatsuchanimplementationconcerncouldeasilybeforgottenornothandledproperly,therebymakingtheadoptionoftheObserverPatternlookmorecomplex,sotheydecidedtoencapsulatetheappropriatehandlinginsidethejQuery.eventimplementation.Asaresult,whenusinganyeventhandlingjQuerymethod,suchasthecore$.fn.on()oranyoftheconvenientmethodssuchas$.fn.click()or$.fn.change(),theobserverfunctionsaretrackedbyjQueryitselfandareproperlyunregisteredifwelaterdecidetoremovetheelementfromthepage.AswesawearlierintheimplementationofjQuery.event,jQuerystoresareferencetotheobserversofeachelementinaseparatemappingobject.EverytimeweauseajQuerymethodthatremovesDOMelementsfromthepage,itfirstmakessuretoremoveanyobserversattachedtothoseelementsoranyofthedescendantelements,bycheckingthemappingobject.Asaresult,theexamplecodeweusedearlierisnotcausingmemoryleakseventhoughwearenotusinganymethodthatexplicitlyremovestheobserversweaddtothecreatedelements.

TipBecarefulwhenmixingjQueryandplainDOMmanipulations

EventhoughalljQuerymethodskeepyousafefrommemoryleakscausedfromobserversthatareneverunregistered,keepinminditcan’tprotectyouifyouremoveelementsusingplainmethodsfromtheDOMAPI.IfmethodssuchasElement.remove()andElement.removeChild()areusedandtheremovedelementsortheirdescendantshaveobserversattached,thentheyarenotgoingtobeunregisteredautomatically.ThesameapplieswhenassigningtotheElement.innerHTMLproperty.

Page 91: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 92: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheDelegatedEventObserverPatternNowthatwehavelearnedsomeadvanceddetailsabouthowtousetheObserverPatternusingjQuery,wewillgetintroducedtoaspecialvariationofitthatfitsperfectlytothewebplatformandprovidessomeextrabenefits.TheDelegatedEventObserverPattern(orsimplyDelegateObserverPattern)isoftenusedinwebdevelopmentanditutilizesthebubblingfeaturethatmosteventsthatarefiredonDOMelementshave.Forexample,whenweclickonapageelement,theclickeventisimmediatelyfiredonit,andrightafterthisitalsofiresonallitsparentelementsuntilitreachestherootofourHTMLdocument.UsingaslightlydifferentoverloadedversionofthejQuery’s$.fn.onmethod,wecaneasilycreateandattachobserversonpageelementsfordelegatedeventsthatarefiredonspecificchildelements.

NoteTheterm“EventDelegation”describestheprogrammingpatternwherethehandlerofaneventisnotattacheddirectlytotheelementofinterest,butisinsteadattachedtooneofitsancestorelements.

Page 93: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitsimplifiesourcodeReimplementingourdashboardexampleusingtheDelegatedEventObserverPatternwillrequireustochangeonlythecodeoftheincludedJavaScriptfiletothefollowing:

$(document).ready(function(){

$('#categoriesSelector').change(function(){

var$selector=$(this);

varselectedIndex=+$selector.val();

var$dashboardCategories=$('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

});

$('.dashboardCategories').on('click','button',function(){

var$button=$(this);

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

$button.text()+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+$button.text()+

'</article></div>';

$('.boxContainer').append(boxHtml);

});

$('.boxContainer').on('click','.boxCloseButton',function(){

$(this).closest('.boxsizer').remove();

});

});

Themostobviousdifferenceisthatthenewimplementationisshorter.Thebenefitscomebydefiningjustoneobservertoacommonancestorelement,foreachactionthatappliestomorethanonepageelement.Forthisreason,weusethe$.fn.on(events,selector,handler)overloadvariationofthe$.fn.on()method.

Specifically,weaddanobservertothepageelementwiththedashboardCategoriesCSSclassandlistenfortheclickeventsthatoriginatefromanyofits<button>descendants.Similarly,weaddasingleobservertotheboxContainerelementthatwillbeexecutedwheneveraclickeventfiresonanyofitsdescendantsthatmatchthe.boxCloseButtonCSSselector.

Sincetheaboveobserversapplynotonlytotheelementsthatexistedinthepageatthemomenttheywereregistered,butalsotoanyelementthatisaddedatanylaterpointoftimeandmatchesthespecifiedCSSselector;weareabletodecouplethecodethathandlestheclicksontheclosebuttonsandplaceitinaseparateobserver,insteadofregisteringanewoneeverytimeanewinformationboxisadded.Asaresult,theobserverthataddsthenewinformationboxesinthedashboardissimplerandonlyhastodealwithcreatingtheHTMLoftheboxandinsertitintothedashboard,leadingtoagreaterseparationof

Page 94: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

concerns.Moreover,wenolongerneedtohandletheregistrationoftheobserverfortheclosebuttonofthehintboxinaseparatepieceofcode.

Page 95: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ComparethememoryusagebenefitsWewillnowcomparethedifferenceinmemoryusagewhenusingthe$.fn.on()methodwiththesimpleandDelegatedEventObserverPatternvariation.ToachievethiswewillopenthetwoimplementationsofourdashboardexampleandcomparetheirmemoryusageonChrome.ToopenChrome’sdevelopertools,justpressF12andthennavigatetotheTimelinetab.Wepressthe“record”buttonintheChrome’sTimelinetabandthenpresseachcategoryitembutton10times,resultingintheadditionof120informationboxestoourdashboard.Afteraddingalltheboxes,weendupwith121openboxesintotal,sincethehintboxwillstillbeopenandthenstopthetimelinerecording.

TheresultsinthetimelineforourinitialObserverPatternimplementationwilllookasfollows:

RepeatingthesameprocessfortheDelegatedEventObserverPatternimplementationwillgiveasmoothertimeline,revealinglessobjectallocationsandGarbageCollections,asfollows:

Asyoucanseeintheprecedingimages,weendupwith1192pageelementsinbothcases,butinthefirstimplementationweareusing134eventlisteners,ascomparedtotheimplementationwitheventdelegationwhereweinitiallycreatedthreeeventlistenersandneveractuallyaddedanother.

Finally,asyoucanseefromthebluelineinthegraph,thememoryconsumptionofthedelegateversionstayedrelativelythesame,addinguptojustaround200KB.Ontheotherhand,intheoriginalimplementation,theheapsizeincreasedmorethanfivetimes,gainingmorethan1MBofincrease.

Addingsomanyelementsmaynotbeanactualusecase,butthedashboardwillprobablynotbetheonlydynamicpartofyourpage.Asaresult,inarelativelycomplexwebpage,wecouldgetsimilarimprovementsifwereimplementedeveryapplicablepartofitusing

Page 96: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

theDelegatedEventObserverPatternvariant.

Page 97: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 98: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedabouttheObserverPattern,howitcanmaketheHTMLcodeofourwebpagescleaner,andthewaythatdecouplesitfromourapplication’scode.WelearnedhowjQueryaddsaprotectionlayertoitsmethodsinordertoprotectusfromundetectedmemoryleaks,whichmayoccurbyaddingobserverstoelements,whennotusingthejQueryDOMmanipulationmethods.

WealsotriedtheDelegatedEventObserverPatternvariantandusedittorewriteourinitialexample.Wecomparedthetwoimplementationsandsawhowitsimplifieswritingcodethatappliestomanypageelementswhentheyaregeneratedafterthepagehasbeenloaded.Finally,wehadacomparisonregardingthememoryconsumptionoftheplainObserverPatternwithitsdelegatevariantandhighlightedhowitalsolessensthememoryconsumptionofourpagebyreducingtherequirednumberofattachedobservers.

NowthatwehavecompletedourintroductiononhowtheObserverPatternisusedtolistentouseractions,wecanmoveontothenextchapterwherewewilllearnaboutcustomeventsandthePublish/SubscribePatternandthewaytheycanleadtoamoredecoupledimplementation.

Page 99: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 100: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter3.ThePublish/SubscribePatternInthischapter,wewillshowcasethePublish/SubscribePattern,adesignpatternquitesimilartotheObserverPatternbutwithamoredistinctrolethatisabetterfitformorecomplexusecases.WewillseehowitdiffersfromtheObserverPatternandhowjQueryadoptedsomeofitsconceptsandbroughtthemtoitsObserverPatternimplementation.

Later,wewillproceedandrewriteourpreviouschapter’sexampleusingthispattern.Wewillusethispattern’sbenefitstoaddsomeextrafeaturesandalsoreducethecouplingofourcodewiththeelementsofthewebpage.

Inthischapter,wewill:

IntroducethePublish/SubscribePatternLearnhowitdiffersandwhatadvantagesithasovertheObserverPatternLearnhowjQuerybringssomeofitsfeaturestoitsmethodsLearnhowtoemitcustomeventswithjQueryRewriteandextendtheexamplefromChapter2,TheObserverPattern,usingthispattern

Page 101: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingthePublish/SubscribePatternThePublish/SubscribePatternisaMessagingPatternwheretheemittersofthemessages,calledthepublishers,multicastmessagestoanumberofrecipients,calledthesubscribers,thathaveexpressedtheirinterestinreceivingsuchmessages.Thekeyconceptofthispattern,whichisalsocommonlyreferredtoasthePub/SubPatterninshort,istoprovideawaytoavoiddependenciesbetweenthepublishersandtheirsubscribers.

Anextraconceptofthispatternistheuseoftopicsthatareusedbythesubscribersinordertoexpressthattheyareonlyinterestedinmessagesofaspecifictype.Thisway,publishersfiltersubscribersbeforesendingamessageanddistributethatmessageonlytotheappropriateones,therebyreducingtheamountoftrafficandworkrequiredonbothsides.

Anothercommonvariantistouseacentral,application-wideobject,knownasthebroker,thatrelaysmessagesproducedbythepublisherstotherelevantsubscribers.Thebroker,inthiscase,actsasawell-knownmessagehandlertosendandsubscribetomessagetopics.Thisenablesus,insteadofcouplingdifferentapplicationpartstogether,toonlyreferencethebrokeritselfandalsothetopicthatourcomponentsareinterestedin.Eventhoughtopicsmightnotbeanabsoluterequirementinthefirstvariantofthispattern,thisvariantplaysanessentialroleinscalabilitysincetherewillcommonlyexistwaylessbrokers(ifnotjustone)thanpublishersandsubscribers.

Page 102: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Byfollowingasubscriptionscheme,thecodeofthepublisheriscompletelydecoupledfromthesubscribers,meaningthatthepublisherdoesnothavetoknowtheobjectsdependonthem.Asaresult,wedonotneedtohardcodetothepublishereachseparateactionthatshouldbeexecutedonthedifferentpartsofourapplication.Instead,thecomponentsofanapplication,andpossiblythird-partyextensions,subscribetobenotifiedonlyabouttopics/eventsthattheyneedtoknow.Insuchdistributedarchitecture,addinganewfeaturetoanexistingapplicationrequiresminimaltonochangestotheapplicationcomponentsitdependson.

Page 103: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitdiffersfromtheObserverPatternThemostbasicdifferenceisthat,bydefinition,thePub/SubPatternisaone-way-MessagingPatternthatcanalsopassamessage,unliketheObserverPatternthatjustdescribeshowtonotifytheobserversaboutaspecificstatechangeonthesubject.

Moreover,unliketheObserverPattern,thePub/SubPatternwithabrokerresultsinmorelooselycoupledcodeforthedifferentpartsofanimplementation.Thisisbecausetheobserversneedtoknowtheirsubjectthatisemittingtheevents;however,ontheotherhand,thepublishersandtheirsubscribersonlyneedtoknowthebrokerthatisused.

Page 104: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 105: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisadoptedbyjQueryOnceagain,thejQuerylibraryprovidesuswithaconvenientwaytotakeadvantageofthePub/SubPatterninourcode.InsteadofextendingitsAPIbyaddingnewmethodsspecificallynamed“publish”and“subscribe”andintroducingnewconcepts,thedevelopersdecidedtoextendthejQuery.fn.on()andjQuery.fn.trigger()methodswiththeabilitytohandleandemitcustomevents.Thisway,jQuerycanbeusedtoimplementapublisher/subscribercommunicationschemeusingthealreadyknownconvenientmethodsitprovides.

Page 106: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

CustomeventsinjQueryCustomeventsallowustousealmostanyuser-definedstringvalueasacommoneventthatwecanaddlistenersfor,andalsomanuallyfireitonpageelements.Asanextrabutapreciousfeature,customeventscanalsocarrysomeextradatatobedeliveredtothelistenersoftheevent.

ThejQuerylibraryaddeditsowncustomeventsimplementation,beforeitwasactuallyaddedtoanywebspecification.Thisway,itwasprovedhowusefultheycanbewhenusedinwebdevelopment.Aswesawinthepreviouschapter,injQuery,thereisaspecificpartoftheimplementationthathandlesboththecommonelementeventandalsocustomevents.ThejQuery.eventobjectholdsalltheinternalimplementationsrelatedtofiringandlisteningtoevents.Also,thejQuery.EventclassisadedicatedwrapperthatjQueryusesfortheneedsofboththecommonelementeventsanditscustomeventsimplementation.

Page 107: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImplementingaPub/SubschemeusingcustomeventsInthepreviouschapter,wesawhowthejQuery.fn.on()methodcanbeusedtoaddeventlistenersonelements.Wealsosawthatitsimplementationismaintaininglistswiththeaddedhandlersandnotifyingthemwhenrequired.Moreover,theeventnameseemstohavethesamecoordinationpurpose,justlikethetopic.ThisimplementationsemanticsseemtomatchexactlywiththePub/SubPatternaswell.

ThejQuery.fn.trigger()methodactuallyusestheinternaljQuery.event.trigger()methodthatisusedtofireeventsinjQuery.Ititeratesovertheinternalhandlerslistandexecutesthemwiththerequestedeventalongwithanyextraparametersthatthecustomeventdefines.Onceagain,thisalsomatchestheoperationrequirementsofthePub/SubPattern.

Asaresult,jQuery.fn.trigger()andjQuery.fn.on()seemtomatchtheneedsofthePub/SubPatternandcanbeusedinsteadofseparate“publish”and“subscribe”methods,respectively.SincetheyarebothavailableonthejQuery.fnobject,wecanusethesemethodsonanyjQueryobject.ThisjQueryobjectwillactasanintermediateentitybetweenthepublishersandthesubscribers,inawaythatperfectlyalignswiththedefinitionofthebroker.

Agoodcommonpractice,whichisalsousedbyalotofjQueryplugins,istousetheoutermostpageelementthatholdstheimplementationoftheapplicationorthepluginasthebroker.Ontheotherhand,jQueryactuallyallowsustouseanyobjectasabroker,sinceallthatitactuallyneedsisatargettoemitanobserveforourcustomevents.Asaresult,wecouldevenuseanemptyobjectasourbrokersuchas$({}),incaseusingapageelementseemstoorestrictingornotcleanenoughaccordingtothePub/SubPattern.ThisisactuallywhatthejQueryTinyPub/Sublibrarydoes,alongwithsomemethodaliasing,sothatweactuallyusemethodsnamed“publish”and“subscribe”insteadofjQuery’s“on”and“trigger”.FormoreinformationonTiny,youcanvisititsrepositorypageathttps://github.com/cowboy/jquery-tiny-pubsub.

Page 108: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 109: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DemonstratingasampleusecaseInordertoseehowthePub/SubPatternisused,andmakeiteasytocompareitwiththeObserverPattern,wearegoingtorewritethedashboardexamplefromChapter2,TheObserverPattern,usingthispattern.Thiswillalsoclearlydemonstratehowthispatterncanhelpusdecoupletheindividualpartsofanimplementationandmakeitmoreextendableandscalable.

Page 110: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingPub/SubonthedashboardexampleFortheneedsofthisdemonstration,wewillusetheHTMLandCSSfilesexactlyaswesawtheminChapter2,TheObserverPattern.

Toapplythispattern,wewillonlyneedtochangethecodeintheJavaScriptfilewithournewimplementation.Inthefollowingcodesnippet,wecanseehowthecodewaschangedinordertoadapttothePublisher/SubscriberPattern:

$(document).ready(function(){

window.broker=$('.dashboardContainer');

$('#categoriesSelector').change(function(){

var$selector=$(this);

varmessage={categoryID:$selector.val()};

broker.trigger('dashboardCategorySelect',[message]);

});

broker.on('dashboardCategorySelect',function(event,message){

var$dashboardCategories=$('.dashboardCategory');

varselectedIndex=+message.categoryID;

var$selectedItem=$dashboardCategories.eq(selectedIndex).show();

$dashboardCategories.not($selectedItem).hide();

});

$('.dashboardCategory').on('click','button',function(){

var$button=$(this);

varmessage={categoryName:$button.text()};

broker.trigger('categoryItemOpen',[message]);

});

broker.on('categoryItemOpen',function(event,message){

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

message.categoryName+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

Page 111: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

'Informationboxregarding'+message.categoryName+

'</article></div>';

$('.boxContainer').append(boxHtml);

});

$('.boxContainer').on('click','.boxCloseButton',function(){

varboxIndex=$(this).closest('.boxsizer').index();

varmessage={boxIndex:boxIndex};

broker.trigger('categoryItemClose',[message]);

});

broker.on('categoryItemClose',function(event,message){

$('.boxContainer.boxsizer').eq(message.boxIndex).remove();

});

});

Justlikeinourpreviousimplementation,weuse$(document).ready()inordertodelaytheexecutionofourcodeuntilthepagehasbeenfullyloaded.Firstofall,wedeclareourbrokerandassignittoanewvariableonthewindowobjectsothatitisgloballyavailableonthepage.Forourapplication’sbroker,weareusingajQueryobjectwiththeoutermostcontainerofourimplementation,whichinourcaseisthe<div>elementwiththedashboardContainerclass.

TipEventhoughusingglobalvariablesisgenerallyananti-pattern,westorethebrokerintoaglobalvariablesinceitisanimportantsynchronizationpointofthewholeapplicationandmustbeavailableforeverypieceofourimplementation,eventothosethatarestoredinseparate.jsfiles.AswewilldiscussinthenextchapterabouttheModulePattern,theprecedingcodecouldbeimprovedbystoringthebrokerasapropertyoftheapplication’snamespace.

Inordertoimplementthecategoryselector,wearefirstobservingthe<select>elementforthechangeevent.Whentheselectedcategorychanges,wecreateourmessageusingaplainJavaScriptobjectwiththevalueoftheselected<option>storedinthecategoryIDproperty.Then,wepublishitinthedashboardCategorySelecttopicusingthejQueryjQuery.fn.trigger()methodonourbroker.Thisway,wemovefromaUIelementeventtoamessagewithapplicationsemanticsthatcontainsalltherequiredinformation.Rightbelow,inoursubscriber’scode,weareusingthejQuery.fn.on()methodonourbrokerwiththedashboardCategorySelecttopicasaparameter(ourcustomevent),justlikewewoulddotolistenforasimpleDOMevent.ThesubscriberthenusesthecategoryIDfromthereceivedmessage,justlikewedidintheimplementationofthepreviouschapter,todisplaytheappropriatecategoryitems.

Followingthesameapproach,wesplitthecodethathandlesaddingandclosinginformationboxesinourdashboardinpublishersandsubscribers.Fortheneedsofthisdemonstration,themessageofthecategoryItemOpentopiccontainsjustthenameofthecategorywewanttoopen.However,inanapplicationwheretheboxcontentisretrievedfromaserver,wewouldprobablyuseacategoryitemIDinstead.Thesubscriberthenusesthecategoryitemnamefromthemessagetocreateandinserttherequestedinformation

Page 112: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

box.

Similarly,themessageforthecategoryItemClosetopiccontainstheindexoftheboxthatwewantremoved.OurpublisherusesthejQuery.fn.closest()methodtotraversetheDOMandreachthechildelementsofourboxContainerelementandthenusesthejQuery.fn.index()methodtofinditspositionamongitssiblings.ThesubscriberthenusesjQuery.fn.eq()andtheboxIndexpropertyfromthereceivedmessagetofilterandremoveonlytherequestedinformationboxfromthedashboard.

TipInamorecomplexapplication,insteadoftheboxindex,wecanassociateeachinformationboxelementwithanewlyretrievedjQuery.guidusingamappingobject.Thiswillallowourpublishertousethatguidinthemessageinsteadofthe(DOM-related)elementindex.Thesubscriberwillthensearchthemappingobjectforthatguidinordertolocateandremovetheappropriatebox.

SincewearetryingtodemonstratetheadvantagesofthePub/SubPattern,thisimplementationchangewasnotintroducedinordertoeasethecomparisonwiththeObserverPatternandisinsteadleftasarecommendedexerciseforthereader.

Tosummarizetheabove,weusedthedashboardCategorySelect,categoryItemOpen,andcategoryItemClosetopicsasourapplication-leveleventsinordertodecouplethehandlingoftheuseractionsfromtheirorigin(theUIelement).Asaresult,wenowhavededicatedreusablepiecesofcodethatmanipulateourdashboard’scontent,whichisequivalenttoabstractingthemintoseparatefunctions.Thisallowsustoprogrammaticallypublishaseriesofmessagessothatwecan,forexample,removealltheexistinginformationboxesandaddallthecategoryitemsofthecurrentlyselectedcategory.Alternatively,evenbetter,makethedashboardshowalltheitemsofeachcategoryfor10secondsandthenmovetothenextone.

Page 113: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ExtendingtheimplementationInordertodemonstratethescalabilitythatthePub/SubPatternbringswithit,wewillextendourcurrentexamplebyaddingacounterwiththenumberofboxesthatarecurrentlyopeninthedashboard.

Forthecounterimplementation,wewillneedtoaddsomeextraHTMLtoourpageandalsocreateandreferenceanewJavaScriptfiletoholdthecounterimplementation:

...

</section>

<divstyle="margin-left:5px;">

Openboxes:

<outputid="dashboardItemCounter">1</output>

</div>

<sectionclass="boxContainer">

...

IntheHTMLpageoftheexample,wewillneedtoaddanextra<div>elementtoholdourcounterandsomedescriptiontext.Forourcounter,weareusingan<output>element,whichisasemanticHTML5elementidealtopresentresultsofuseractions.Thebrowserwilluseitjustlikeanormal<span>element,soitwillappearrightnexttoitsdescription.Also,sincethereisinitiallyahintboxopeninourdashboard,weusea1foritsinitialcontent:

$(document).ready(function(){

broker.on('categoryItemOpencategoryItemClose',function(event,

message){

var$counter=$('#dashboardItemCounter');

varcount=parseInt($counter.text());

if(event.type==='categoryItemOpen'){

$counter.text(count+1);

}elseif(event.type==='categoryItemClose'&&count>0){

$counter.text(count-1);

}

});

});

Page 114: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Forthecounterimplementationitself,allweneedtodoisaddanextrasubscribertothedashboard’sbroker,whichisgloballyavailabletootherJavaScriptfilesloadedinthepage,sincewehaveattachedittothewindowobject.Wearesimultaneouslysubscribingtotwotopics,bypassingthemspacedelimitedtothejQuery.fn.on()method.Rightafterthis,welocatethecounter<output>elementthathastheIDdashboardItemCounterandparseitstextcontentasanumber.Inordertodifferentiateouraction,basedonthetopicthatthemessagehasreceived,weusetheeventobjectthatjQuerypassesasthefirstparametertoouranonymousfunction,whichisoursubscriber.Specifically,weusethetypepropertyoftheeventobjectthatholdsthetopicnameofthemessagethatwasreceivedandbasedonitsvalue,wechangethecontentofthecounter.

NoteFormoreinformationontheeventobjectthatjQueryprovides,youcanvisithttp://api.jquery.com/category/events/event-object/.

Similarly,wecouldalsorewritethecodethatpreventsaccidentaldouble-clicksonthecategoryitembuttons.AllthatisneededistoaddanextrasubscriberforthecategoryItemOpentopicandusethecategoryNamepropertyofthemessagetolocatethepressedbutton.

Page 115: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsinganyobjectasabrokerWhileinourexampleweusedtheoutermostcontainerelementofourdashboardforourbroker,itisalsocommontousethe$(document)objectasabroker.Usingtheapplication’scontainerelementisconsideredagoodsemanticpractice,whichalsoscopestheemittedevents.

Aswedescribedearlierinthischapter,jQueryactuallyallowsustouseanyobjectasabroker,evenanemptyone.Asaresult,wecouldinsteadusesomethingsuchaswindow.broker=$({});forourbroker,incasewepreferitoverusingapageelement.

Byusingnewlyconstructedemptyobjects,wecanalsoeasilycreateseveralbrokers,incasesuchathingwouldbepreferredforaspecificimplementation.Moreover,incaseacentralizedbrokerisnotpreferred,wecouldjustmakeeachpublisherthebrokerofitself,leadingtoanimplementationmorelikethefirst/basicvariantofthePub/SubPattern.

Sinceinmostcases,adeclaredvariableisusedtoaccesstheapplication’sbrokerwithinapage,thereislittledifferencebetweentheaboveapproaches.Justchoosetheonethatbettermatchesyourteam’staste,andincaseyouchangeyourmindatalaterpoint,allyouhavetodoisuseadifferentassignmentonyourbrokervariable.

Page 116: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 117: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingcustomeventnamespacingAsaclosingnoteforthischapter,wewillpresent,inshort,themechanismthatjQueryprovidesfornamespacingcustomevents.Themainbenefitofeventnamespacingisthatitallowsustousemorespecificeventnamesthatbetterdescribetheirpurpose,whilealsohelpingustoavoidconflictsbetweendifferentimplementationpartsandplugins.Italsoprovidesaconvenientwaytounbindalltheeventsofagivennamespacefromanytarget(elementorbroker).

Asimpleexampleimplementationwilllookasfollows:

varbroker=$({});

broker.on('close.dialog',function(event,message){

console.log(event.type,event.namespace);

});

broker.trigger('close.dialog',['messageEmitted']);

broker.off('.dialog');

//removesalleventhandlersofthe"dialog"namespace

Formoreinformation,youcanvisitthedocumentationpageathttp://docs.jquery.com/Namespaced_Eventsandthearticleathttps://css-tricks.com/namespaced-events-jquery/fromtheCSS-Trickswebsite.

Page 118: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 119: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,wewereintroducedtothePublish/SubscribePattern.WesawitssimilaritieswiththeObserverPatternandalsolearneditsbenefitsbydoingacomparisonofthetwo.WeanalyzedhowthemoredistinctrolesandtheextrafeaturesthatthePublish/SubscribePatternoffersmakeitanidealpatternformorecomplexusecases.WesawhowjQuerydevelopersadoptedsomeofitsconceptsandbroughtthemtotheirObserverPatternimplementationascustomevents.Finally,werewrotetheexamplefromthepreviouschapterusingthePublish/SubscribePattern,addingsomeextrafeaturesandalsoachievinggreaterdecouplingbetweenthedifferentpartsandpageelementsofourapplication.

NowthatwehavecompletedourintroductiontohowthePublish/SubscribePatterncanbeusedasafirststeptodecouplethedifferentpartsofanimplementation,wecanmoveontothenextchapterwherewewillbeintroducedtotheModulePattern.Inthenextchapter,wewilllearnhowtoseparatethedifferentpartsofanimplementationintoindependentmodulesandhowtousenamespacingtoachievebettercodeorganizationanddefineastrictAPItoachievecommunicationbetweenthedifferentmodules.

Page 120: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 121: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter4.DivideandConquerwiththeModulePatternInthischapter,wewillbeintroducedtotheconceptsofModulesandNamespacingandseehowtheycanleadtomorerobustimplementations.Wewillshowcasehowthesedesignprinciplescanbeusedinapplications,bydemonstratingsomeofthemostcommonlyuseddevelopmentpatternstocreateModulesinJavaScript.

Inthischapter,wewill:

ReviewtheconceptofModulesandNamespacingIntroducetheObjectLiteralPatternIntroducetheModulePatternanditsvariantsIntroducetheRevealingModulePatternanditsvariantsHaveasmalldiveintoES5StrictModeandES6ModulesExplainhowModulescanbeusedandbenefitjQueryapplications

Page 122: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ModulesandNamespacesThetwomainpracticesofthischapterareModulesandNamespaces,whichareusedtogetherinordertostructureandorganizeourcode.WewillfirstanalyzethemainconceptofModulesthatiscodeencapsulationandrightafterthis,wewillproceedtoNamespacing,whichisusedtologicallyorganizeanimplementation.

Page 123: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

EncapsulatinginternalpartsofanimplementationWhiledevelopingalarge-scaleandcomplexwebapplication,theneedforawell-defined,structuredarchitecturebecomesclearfromthebeginning.Inordertoavoidcreatingaspaghetticodeimplementation,wheredifferentpartsofourcodecalleachotherinachaoticway,wehavetosplitourapplicationintosmall,self-containedparts.

Theseself-containedpiecesofcodecanbedefinedasModules.Todocumentthisarchitectureprinciple,ComputerSciencehasdefinedconceptssuchasSeparationofConcerns,wheretherole,operation,andtheexposedAPIofeachModuleshouldbestrictlydefinedandfocusedonprovidingagenericsolutiontoaspecificproblem.

NoteFormoreinformationonEncapsulationandSeparationofConcerns,youcanvisithttps://developer.mozilla.org/en-US/docs/Glossary/Encapsulationandhttp://aspiringcraftsman.com/2008/01/03/art-of-separation-of-concerns/.

Page 124: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AvoidingglobalvariableswithNamespacesInJavaScript,thewindowobjectisalsoknownastheGlobalNamespace,whereeachdeclaredvariableandfunctionidentifierisattachedbydefault.ANamespacecanbedefinedasanamingcontextwhereeachidentifierhastobeunique.ThemainconceptofNamespacingistoprovideawaytologicallygroupalltherelatedpiecesofadistinctandself-containedpartofanapplication.Inotherwords,itsuggeststhatwecreategroupswithrelatedfunctionsandvariablesandmakethemaccessibleunderthesameumbrellaidentifier.ThishelpstoavoidnamingcollisionsbetweendifferentpartsofanapplicationandotherJavaScriptlibrariesthatareused,sinceweonlyneedtokeepalltheidentifiersuniqueundereachdifferentNamespace.

AgoodexampleofNamespacingisthemathematicalfunctionsandconstantsthatJavaScriptprovides,whicharegroupedunderthebuilt-inJavaScriptobjectcalledMath.SinceJavaScriptprovidesmorethan40short-namedmathematicalidentifiers,suchasE,PI,andfloor(),inordertoavoidnamingconflictsandgroupingthemtogether,itwasdesignedtomakethemaccessibleaspropertiesoftheMathobjectthatactsastheNamespaceofthisbuilt-inlibrary.

WithoutproperNamespacing,eachfunctionandvariableneedstobeuniquelynamedthroughtheentireapplication,andcollisionscouldhappenbetweentheidentifiersofdifferentapplicationpartsorevenwiththoseofathird-partylibrarythatanapplicationuses.Finally,whileModulesprovideawaytoisolateeachindependentpartofyourapplication,NamespacingprovidesawaytostructureyourdifferentModulestowhatbecomesthearchitectureoftheapplication.

Page 125: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThebenefitsofthesepatternsDesigninganapplicationarchitecturebasedonModulesandnamespacingleadstobettercodeorganizationandclearlyseparatedparts.Insucharchitectures,Modulesareusedtogrouptogetherpartsoftheimplementationthatarerelated,whileNamespacesconnectthemtoeachothertocreatetheapplicationstructure.

Thisarchitecturehelpstocoordinatelargedeveloperteams,enablingtheimplementationofindependentpartstotakeplaceinparallel.Itcanalsoshortenthedevelopmenttimeneededtoaddanewfunctionalitytotheexistingimplementation.Thisisbecausetheexistingpiecesthatareusedcanbelocatedeasilyandtheaddedimplementationhaslesschanceofconflictingwiththeexistingcode.

Theresultingcodestructuresarenotonlycleanlyseparated,butsinceeachModuleisdesignedtoachieveasinglegoal,thereisagoodchancethatitcanalsobeusedinothersimilarapplications.Asanaddedbenefit,sincetheroleofeachModuleisstrictlydefined,italsomakestracingtheoriginofabugaloteasierinalargecodebase.

Page 126: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThewideacceptanceBoththecommunityandtheenterpriseworldrealizedthat,inordertohavemaintainable,largefrontendapplicationswritteninJavaScript,theyshouldendupwithasetofbestpracticesthatshouldbeincorporatedineverypartoftheirimplementations.

TheacceptanceandadoptionofModulesandNamespacinginJavaScriptimplementationsisclearlyvisibleinthebestpracticesandcodingstyleguidesthatthecommunityandenterpriseshavereleased.

Forexample,Google’sJavaScriptStyleGuide(availableathttps://google.github.io/styleguide/javascriptguide.xml#Naming)describesandsuggestsadoptingnamespacinginourimplementations:

ALWAYSprefixidentifiersintheglobalscopewithauniquepseudonamespacerelatedtotheprojectorlibrary.

Moreover,thejQueryJavaScriptStyleGuide(availableathttps://contribute.jquery.org/style-guide/js/#global-variables)suggestsusingglobalvariablessothat:

Eachprojectmayexposeatmostoneglobalvariable.

Anotherexampleofacceptanceamongthedevelopercommunity,comesfromtheMozillaDeveloperNetwork.Itsguideforobject-orientedJavaScript(availableathttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Namespace)alsosuggestsusingNamespaces,towraptheimplementationofourapplicationunderasingleexposedvariable,usingsomethingassimpleasfollows:

//globalnamespace

varMYAPP=MYAPP||{};

Page 127: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 128: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheObjectLiteralPatternTheObjectLiteralPatternisprobablythesimplestwaytowrapalltherelatedpartsofanimplementationunderanumbrellaobjectthatworksasaModule.Thenameofthispatternaccuratelydescribesthewayitisused.ThedeveloperjustneedstodeclareavariableandassignanobjectwithalltherelatedpartsthatneedtobeencapsulatedintothisModule.

Let’sseehowwecancreateaModulethatprovidesuniqueintegerstoapage,inasimilarwayhowjquery.guiddoesit:

varsimpleguid={

guid:1,

init:function(){

this.guid=1;

},

increaseCounter:function(){

this.guid++;

//orsimpleguid.guid++;

},

getNext:function(){

varnextGuid=this.guid;

this.increaseCounter();

returnnextGuid;

}

};

Asseenabove,asimplerulethatyoucanfollowinordertoadoptthispatternistodefineallthevariablesandfunctionsthateachimplementationneedsaspropertiesofanobject.OurcodeisreusableanddoesnotpollutetheGlobalNamespace,otherthanjustdefiningasinglevariablenameforourModule,simpleguidinthiscase.

WecanaccesstheModulepropertiesinternally,eitherbyusingthethiskeyword,suchasthis.guid,orusingthefullnameoftheModulesuchassimpleguid.guid.InordertousetheaboveModuleinourcode,wejustneedtoaccessitspropertybyusingitsname.Forexample,callingthesimpleguid.getNext()methodwillreturntoourcodethenext-in-ordernumericguidandalsochangetheModule’sstatebyincreasingtheinternalcounter.

OneofthenegativesofthispatternisthatitdoesnotprovideanyprivacytotheinternalpartsoftheModule.AlltheinternalpartsoftheModulecanbeaccessedandbeoverriddenbyexternalcode,eventhoughweideallyprefertoonlyexposethesimpleguid.init()andsimpleguid.getNext()methods.Thereareseveralnamingconventionsthatdescribeprependingorappendinganunderscore(_)tothenamesofpropertiesthatareintendedonlyforinternaluse,butthistechnicallydoesn’tfixthisdisadvantage.

AnotherdisadvantageisthatwritingabigModuleusinganobjectliteralcaneasilygettiring.It’struethatJavaScriptdevelopersareusedtoendtheirvariablesandfunctiondefinitionswithsemicolons(;),andtryingtowriteabigModuleusingcommas(,)aftereachpropertycaneasilyleadtosyntacticerrors.

Page 129: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

EventhoughthispatternmakesiteasytodeclarenestedNamespacesforaModule,itcanalsoleadtobigcodestructureswithbadreadabilityincaseweneedseverallevelsofnesting.Forexample,let’stakealookatthefollowingskeletonofaTodoapplication:

varmyTodoApp={

todos:[],

addTodo:function(todo){this.todos.push(todo);},

getTodos:function(){returnthis.todos;},

updateTodo:function(todo){/*...*/},

imports:{

fromGDrive:function(){/*...*/},

fromUrl:function(){/*...*/},

fromText:function(){/*...*/}

},

exports:{

gDrivePublicKey:'#wnanqAASnsmkkw',

toGDrive:function(){/*...*/},

toFile:function(){/*...*/},

},

share:{

toTwitter:function(todo){/*...*/}

}

};

Fortunately,thiscanbeeasilyfixedbysplittingtheobjectliteraltomultipleassignmentsforeachsubmodule(andpreferablytodifferentfiles)asfollows:

varmyTodoApp={

todos:[],

addTodo:function(todo){this.todos.push(todo);},

getTodos:function(){returnthis.todos;},

updateTodo:function(todo){/*...*/},

};

/*…*/

myTodoApp.exports={

gDrivePublicKey:'#wnanqAASnsmkkw',

toGDrive:function(){/*...*/},

toFile:function(){/*...*/},

};

/*...*/

Page 130: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 131: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheModulePatternThekeyconceptofthebasicModulePatternistoprovideasimplefunction,class,orobjectthattherestoftheapplicationcanuse,throughawell-knownvariablename.ItenablesustoprovideaminimalAPIforaModule,byhidingthepartsoftheimplementationthatdonotneedtobeexposed.Thisway,wealsoavoidpollutingtheGlobalNamespacewithvariablesandutilityfunctionsthatareneededforinternalusebyourModule.

Page 132: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheIIFEbuildingblockInthissubsection,wewillgetasmallintroductiontotheIIFEDesignPatternsinceit’sanintegralpartforallthevariantsoftheModulePatternthatwewillseeinthischapter.TheImmediatelyInvokedFunctionExpression(IIFE)isaverycommonlyusedDesignPatternamongJavaScriptdevelopersbecauseofthecleanwayinwhichitisolatesblocksofcode.IntheModulePattern,anIIFEisusedtowrapalltheimplementationinordertoavoidpollutingtheGlobalNamespaceandprovideprivacytothedeclarationstotheModuleitself.

EachIIFEcreatesaClosurewiththevariablesandfunctionsdeclaredinsideit.TheClosurethatiscreatedenablestheexposedfunctionoftheIIFEtokeepreferencestotherestofthedeclarationsoftheirenvironmentandaccessthemnormallywhenexecutedfromotherpartsofanimplementation.Asaresult,thenon-exposeddeclarationsoftheIIFEdonotleakoutsideit,butarekeptprivateandareaccessibleonlybythefunctionsthatarepartofthecreatedClosure.

NoteFormoreinformationonIIFEsandClosures,youcanvisithttps://developer.mozilla.org/en-US/docs/Glossary/IIFEandhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

AnIIFEismostcommonlyusedasfollows:

(function(){

varx=7;

console.log(x);

//prints7

})();

Sincetheprecedingcodeconstructmightlookbizarreonfirstsight,let’sseethepiecesthatitiscomposedfrom.AnIIFEisalmostequivalenttodeclaringananonymousfunction,assigningittoavariable,andthenexecutingit,asshowninthefollowingcode:

vartmp=function(){

varx=7;

console.log(x);

};

tmp();

//or

(tmp)();

Intheprecedingcode,wedefineafunctionexpressionandexecuteitusingtmp().Since,inJavaScript,wecanuseparenthesesaroundanidentifierwithoutchangingitsmeaning,wecanalsoexecutethestoredfunctionwith(tmp)();.Thefinalstep,inordertoturntheprecedingcodeintoanIIFE,istoreplacethetmpvariablewiththeactualanonymousfunctiondeclaration.

Aswesawearlier,theonlydifferenceisthat,withanIIFE,wedoneedtodeclarea

Page 133: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

variablejusttoholdthefunctionitself.Weonlycreateananonymousfunctionandinvokeitimmediatelyrightafterdefiningit.

SincethecreationofanIIFEcanbeachievedinseveralways,whichmightlooklikeanexerciseofJavaScript’srules,thecommunityofJavaScriptdevelopershasconcludedtotheabovecodestructureasapointofreferenceforthispattern.ThiswayofcreatinganIIFEisconsideredtohavebetterreadabilityandisusedbylargelibrariesandasaresultofitsadoption,developerscaneasilyrecognizeitinsidelargeJavaScriptimplementations.

Anexampleoftheless-widely-usedwaystocreateanIIFEisthefollowingcodestructure:

(function(){

//code

}());

Page 134: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThesimpleIIFEModulePatternSincethereisnoactualnameforthispattern,itisrecognizedbythefactthatthedefinedModulereturnsasingleentity.Forreferenceonhowtocreateareusablelibraryusingthispattern,wewillrewritethesimpleguidModulethatwesawearlier.Theresultingimplementationwilllookasfollows:

varsimpleguid=(function(){

varsimpleguid={};

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

returnsimpleguid;

})();

ThispatternusesanIIFEtodefineanobjectthatactsastheModulecontainer,attachespropertiestoit,andlaterreturnsit.ThevariablesimpleguidinthefirstlineoftheprecedingcodeisusedastheNamespaceoftheModuleandisassignedwiththevaluethatisreturnedbytheIIFE.ThemethodsandpropertiesthataredefinedonthereturnedobjectaretheonlyexposedpartsoftheModulesandconstituteitspublicAPI.

Onceagain,thispatternallowsustousethethiskeyword,inordertoaccesstheexposedmethodsandpropertiesofourModule.Furthermore,italsoprovidestheflexibilitytoexecuteanyrequiredinitializationcodebeforecompletingtheModule’sdefinition.

UnliketheObjectLiteralPattern,theModulePatternenablesustocreateactualprivatemembersinourModules.VariablesdeclaredinsidetheIIFE,thatarenotattachedtothereturnvalue,suchastheguidvariable,actasprivatemembersandareonlyaccessibleinsidetheModulebyrestmembersofthecreatedClosure.

Lastly,incaseweneedtodefineanestedNamespace,allwehavetodoischangetheassignmentofthevaluereturnedbytheIIFE.Asanexampleofanapplicationstructuredwithsubmodules,let’sseehowwewilldefinetheexportingsubmodulefortheTodoapplicationskeletonthatwesawearlier:

varmyTodoApp=(function(){

varmyTodoApp={};

Page 135: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

vartodos=[];

myTodoApp.addTodo=function(todo){

todos.push(todo);

};

myTodoApp.getTodos=function(){

returntodos;

};

returnmyTodoApp;

})();

myTodoApp.exports=(function(){

varexports={};

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

returnexports;

})();

Giventhatourapplication’sNamespacemyTodoApphasalreadybeendefinedearlier,theexportssubmodulecanbedefinedasasimplepropertyonit.AgoodpracticetofollowwillbetocreateonefileforeachoneoftheaboveModules,usingtheIIFEsasthelandmarkstosplityourcode.Awidelyusednamingconvention,whichisalsosuggestedbyGoogle’sJavaScriptStyleGuide,istouselowercasenamingforyourfilesandadddashestoseparatesubmodules.Forexample,byfollowingthisnamingconvention,theprecedingcodeshouldbedefinedintwofilesnamedasmytodoapp.jsandmytodoapp-exports.jsforeachModule,respectively.

HowitisusedbyjQueryTheModulePatternisusedwithinjQueryitself,inordertoisolatethesourcecodeoftheCSSselectorengine(Sizzle),whichpowersthe$()function,fromtherestofthejQuerysource.Fromthebeginning,SizzlewasabigpartofthejQuerysource,whichiscurrentlycountingabout2135linesofcode;since2009,ithasbeensplitintoaseparateprojectnamedSizzle,soitcanbemoreeasilymaintained,bedevelopedindependently,andbereusablebyotherlibraries:

varSizzle=(function(window){

/*179linesofcode*/

functionSizzle(selector,context,results,seed){

/*131linesofcode*/

}

/*

Page 136: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

1804linesofcode,definingmethodslike:

Sizzle.attr

Sizzle.compile

Sizzle.contains

Sizzle.getText

Sizzle.matches

Sizzle.matchesSelector

Sizzle.select

*/

returnSizzle;

})(window);

jQuery.find=Sizzle;

SizzleisaddedtothejQuery’ssourceinsideanIIFE,whileitsmainfunctionisreturnedandassignedtojQuery.findforuse.

NoteFormoreinformationonSizzle,youcanvisithttps://github.com/jquery/sizzle.

Page 137: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheNamespaceParameterModulevariantInthisvariant,insteadofreturninganobjectfromourIIFEandthenassigningittothevariablethatactsastheNamespaceoftheModule,wecreatetheNamespaceandpassitasaparametertotheIIFEitself:

(function(simpleguid){

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

})(window.simpleguid=window.simpleguid||{});

ThelastlineoftheModuledefinitiontestswhethertheModuleisalreadydefined;incaseitisnot,itinitializesittoanemptyobjectliteralandassignsittotheglobalobject(window).Inanycase,thesimpleguidparameterinthefirstlineoftheIIFEwillholdtheModule’sNamespace.

NoteTheaboveexpressionisalmostequivalenttowriting:

window.simpleguid=window.simpleguid!==undefined?window.simpleguid:

{};

UsingthelogicalORoperator(||)makestheexpressionbothshorterandmorereadable.Moreover,thisisapatternthatmostwebdevelopershavelearnedtoeasilyrecognize,anditappearsinalotofdevelopmentpatternsandbestpractices.

Onceagain,thispatternallowsustousethethiskeywordtoaccesspublicmembersfromwithintheexportedmethodsoftheModule.Atthesametime,itallowsustokeepsomefunctionsandvariablesprivate,whichwillbeaccessibleonlybyotherfunctionsoftheModule.

Eventhoughit’sconsideredagoodpracticetodefineeachModuletoitsownJSfile,thisvariantalsoallowsustosplittheimplementationoflargeModulestomorethanonefile.ThisbenefitcomesasaresultofcheckingwhethertheModuleisalreadydefined,beforeinitializingittoanemptyobject.Thismightbeusefulinsomecases,withtheonlylimitationbeingthateachpartialfileofaModulecanaccesstheprivatemembersdefinedinitsownIIFE.

Page 138: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Moreover,inordertoavoidrepetition,wecanuseasimpleridentifierfortheparameteroftheIIFEandwriteourModuleasfollows:

(function(namespace){

/*…*/

namespace.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

namespace.init();

})(window.simpleguid=window.simpleguid||{});

WhenitcomestoapplicationswithnestedNamespaces,thispatternmightstartfeelingalittleuncomfortabletoread.ThelastlineoftheModuledefinitionwillstarttogetlongerforeveryextralevelofnestednamespacingthatwedefine.Forexample,let’sseehowtheexportssubmoduleofourTodoapplicationwouldlook:

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

})(myTodoApp.exports=myTodoApp.exports||{});

Asyoucansee,eachextralevelofthenestedNamespaceneedstobeaddedonbothsidesoftheassignmentthatispassedasaparametertotheIIFE.ForapplicationswithcomplexfeaturesthatleadtomultiplelevelsofnestedNamespaces,thiscouldleadtoModuledefinitionslookingsomethinglikethis:

(function(smallModule){

smallModule.method=function(){/*...*/};

returnsmallModule;

})(myApp.bigFeature.featurePart.smallModule=

myApp.bigFeature.featurePart.smallModule||{});

Moreover,ifwewanttoprovidethesamesafetyguaranties,asintheoriginalcodesample,thenwewouldneedtoaddsimilarsafechecksforeachNamespacelevel.Withthisinmind,theexportsModuleofourTodoapplicationthatwesawearlierwouldneedtohavethefollowingform:

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

Page 139: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

})((window.myTodoApp=window.myTodoApp||{},myTodoApp.exports=

myTodoApp.exports||{}));

Asseenintheprecedingcode,weusedthecommaoperator(,)toseparateeachnamespaceexistencecheckandwrappedthewholeexpressioninanextrapairofparenthesissothatthewholeexpressionisusedasthefirstparameteroftheIIFE.Usingthecommaoperator(,)tojoinexpressionswillleadthemtobeevaluatedinorderandpasstheresultofthelastevaluatedexpressionastheparameteroftheIIFE,andthatresultwillbeusedastheNamespaceoftheModule.Keepinmindthat,foreachextranestedNamespacelevel,weneedtoaddanextraexistencecheckexpressionusingthecommaoperator(,).

Adisadvantageofthispattern,especiallywhenusedfornestednamespacing,isthattheNamespacedefinitionoftheModuleisattheendofthefile.EventhoughitishighlyrecommendedtonameyourJSfilessothattheyproperlyrepresenttheModulesthattheycontain,forexample,mytodoapp.exports.js;nothavingtheNamespacenearthetopofthefilecansometimesbecounterproductiveormisleading.Aneasywork-aroundforthisproblemwouldbetodefinetheNamespacebeforetheIIFEandthenpassitasaparameter.Forexample,theprecedingcodeusingthistechniquewouldbetransformedtosomethingasfollows:

window.myTodoApp=window.myTodoApp||{};

myTodoApp.exports=myTodoApp.exports||{};

(function(exports){

vargDrivePublicKey='#wnanqAASnsmkkw';

exports.toGDrive=function(){/*...*/};

exports.toFile=function(){/*...*/};

})(myTodoApp.exports);

Page 140: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheIIFE-containedModulevariantLikeinthepreviousvariantsoftheModulePattern,thisvariantdoesnotactuallyhaveaspecificvariantname,butisrecognizedbythewaythecodeisstructured.ThekeyconceptofthisvariantistomovealltheModule’scodeinsidetheIIFE:

(function(){

window.simpleguid=window.simpleguid||{};

varguid;

simpleguid.init=function(){

guid=1;

};

simpleguid.increaseCounter=function(){

guid++;

};

simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

simpleguid.init();

})();

ThisvariantlooksverysimilartothepreviousoneandmainlydiffersinthewaythattheNamespaceiscreated.Firstofall,itkeepstheNamespacecheckandinitializationnearthetopoftheModule,likeaheading,makingourcodemorereadableregardlessofwhetherweuseaseparatefilefortheModuleornot.LikeothervariantsoftheModulePattern,itsupportsprivatemembersforourModulesandalsoallowsustousethethiskeywordtoaccesspublicmethodsandproperties,makingourcodelookmoreobject-oriented.

RegardingimplementationswithnestedNamespaces,thecodestructureoftheexportssubmoduleofourTodoapplicationskeletonwilllookasfollows:

(function(){

window.myTodoApp=window.myTodoApp||{};

myTodoApp.exports=myTodoApp.exports||{};

vargDrivePublicKey='#wnanqAASnsmkkw';

myTodoApp.exports.toGDrive=function(){/*...*/};

myTodoApp.exports.toFile=function(){/*...*/};

})();

Asseenintheprecedingcode,wealsoborrowedtheNamespacedefinitionchecksfromthepreviousvariantand,likewise,appliedittoeverylevelofnestednamespacing.Even

Page 141: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

thoughthisisnotabsolutelynecessary,itbringsthebenefitsthatwediscussedearliersuchasenablingustosplitaModuledefinitionintoseveralfilesandevenresultsinamoreerror-tolerantimplementationregardingtheimportorderoftheapplication’sModules.

Page 142: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 143: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheRevealingModulePatternTheRevealingModulePatternisavariantoftheModulePatternwithaknownandwidelyrecognizedname.WhatmakesthispatternspecialisthatitcombinesthebestpartsoftheObjectLiteralPatternandtheModulePattern.AllthemembersoftheModulearedeclaredinsideanIIFE,whichattheend,returnsanObjectLiteralcontainingonlythepublicmembersoftheModuleandisassignedtothevariablethatactsasourNamespace:

varsimpleguid=(function(){

varguid=1;

functioninit(){

guid=1;

}

functionincreaseCounter(){

guid++;

}

functiongetNext(){

varnextGuid=guid;

increaseCounter();

returnnextGuid;

}

return{

init:init,

getNext:getNext

};

})();

OneofthemainbenefitsofthispatternthatdifferentiatesitfromothervariantsisthatitallowsustowriteallthecodeofourModuleinsidetheIIFE,justlikewewouldiftheywouldbedeclaredontheGlobalNamespace.Moreover,thispatterndoesnotrequireanyvariationonthewaythatthepublicandprivatemembersaredeclared,makingthecodeoftheModulelookuniform.

SincethereturnedObjectLiteraldefinesthepubliclyavailablemembersoftheModule,itisalsoaconvenienteasywaytoinspectitspublicAPI,evenifitiswrittenbysomeoneelse.Moreover,incaseweneedtoexposeaprivatemethodonourModule’sAPI,allweneedtodoisaddanextrapropertytothereturnedObjectLiteralwithoutchanginganypartofitsdefinition.Additionally,theuseofanObjectLiteralenablesustochangetheexposedidentifiersfortheModule’sAPI,withoutchangingthenamesusedbytheModule’simplementationinternally.

Evenifthisisnotclearlyvisible,thethiskeywordcanbeusedforcallsbetweenthepublicmembersoftheModule.Unfortunately,usingthethiskeywordisdiscouragedforthispattern,sinceitbreakstheuniformityofthefunctiondeclarationsandcaneasilyleadtoerrors,especiallywhenchangingthevisibilityofapublicmethodtoprivate.

Page 144: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SincetheNamespacedefinitioniskeptoutsidethebodyoftheIIFE,thispatternclearlyseparatestheNamespacedefinitionfromtheactualimplementationoftheModule.UsingthispatterntodefineaModuleinanestedNamespacedoesnotaffecttheModule’simplementation,whichwillnotlookdifferentatanypointfromatop-levelNamespaceModule.RewritingtheexportssubmoduleofourTodoskeletonapplicationusingthispatternwillmakeitlooklikethis:

myTodoApp.exports=(function(){

vargDrivePublicKey='#wnanqAASnsmkkw';

functiontoGDrive(){/*...*/}

functiontoFile(){/*...*/}

return{

toGDrive:toGDrive,

toFile:toFile

};

})();

Asaresultofthisseparation,wehavelesscoderepetitionandwecaneasilychangetheNamespaceofaModulewithoutaffectingitsimplementationatall.

Page 145: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 146: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingES5StrictModeAsmallbutpreciousadditiontoalltheModulePatternsthatuseIIFEsastheirbasicbuildingblocks,istheuseofStrictModeforJavaScriptexecution.ThiswasstandardizedinthefiftheditionofJavaScript,andisanopt-inexecutionmodewithslightlydifferentsemantics,inordertopreventsomeofthecommonpitfallsofJavaScript,butalsohavingbackwardscompatibilityinmind.

Underthismode,theJavaScriptruntimeenginewillpreventyoufromaccidentallycreatingaglobalvariableandpollutingtheGlobalNamespace.Eveninnot-so-largeapplications,itisquitepossiblethatavardeclarationbeforetheinitialassignmentofavariablecanbemissing,automaticallypromotingthattoaglobalvariable.Topreventthiscase,strictmodethrowsanerrorincaseanassignmentisissuedtoanundeclaredvariable.ThefollowingimageshowtheerrorthatisthrownbyFirefoxandChromewhenaStrictModeviolationhappens.

Thismodecanbeenabledbyaddingthe"usestrict";or'usestrict';statementbeforeanyotherstatements.Eventhoughthiscanbeenabledontheglobalscope,itishighlyrecommendedthatyouenableitonlyinsidethescopeofafunction.Enablingitontheglobalscopemightmakethird-partylibrariesthatarenon-strict-modecompliantstopworkingormisbehave.Ontheotherhand,thebestplacetoenableStrictModeisinsidetheIIFEofaModule.TheStrictModewillberecursivelyappliedtoallnestedNamespaces,methods,andfunctionsofthatIIFE.

NoteFormoreinformationonJavaScript’sstrictexecutionmode,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode.

Page 147: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 148: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingES6ModulesEventhoughJavaScriptinitiallyhadnobuilt-inpackagingandnamespacingsupportlikeotherprogramminglanguages,webdevelopersfilledthegapsbydefiningandadoptingsomedesignpatternsforthispurpose.ThesesoftwaredevelopmentpracticesworkedaroundthemissingfeaturesofJavaScriptandallowedlargeandscalableimplementationsofcomplexapplicationsonaprogramminglanguagethatsomeyearsagowasmostlyusedforformvalidation.

Thiswasuntilthe6thversionofJavaScript,commonlyreferredtoasES6,wasreleasedasastandardonJune2015andintroducedtheconceptofModulesaspartofthelanguage.

NoteES6isanabbreviationofECMAScript6thedition,whichisalsoreferredtoasHarmonyorECMAScript2015,whereECMAScriptisthetermthatisusedforthestandardizationprocessofJavaScript.Thespecificationcanbefoundathttp://www.ecma-international.org/ecma-262/6.0/index.html#sec-modules.

AsanexampleofES6Modules,wewillseeoneofthemanywaysinwhichthesimpleguidModulecanbewritten:

vares6simpleguid={};

exportdefaultes6simpleguid;

varguid;

es6simpleguid.init=function(){

guid=1;

};

es6simpleguid.increaseCounter=function(){

guid++;

};

es6simpleguid.getNext=function(){

varnextGuid=guid;

this.increaseCounter();

returnnextGuid;

};

es6simpleguid.init();

Ifwesavethisasafilenamedes6simpleguid.js,thenwecanimportanduseitinadifferentfilebysimplywritingthefollowingcode:

importes6simpleguidfrom'es6simpleguid';

console.log(es6simpleguid.getNext());

SinceES6ModulesarebydefaultinStrictMode,writingyourModulestodayusingyourpreferredModulePatternvariantwithStrictModeenabledwillmakeyourtransitiontoES6Moduleseasier.Someoftheabovepatternsrequireveryfewchangestoachievethis.

Page 149: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Forexample,intheIIFE-containedModulePatternvariant,allthatisneededisremovetheIIFEandthe"usestrict";statement,replacethecreationoftheModule’sNamespacewithavariable,andusetheexportkeywordonit.

Unfortunately,atthetimeofwritingthisbook,nobrowserhas100%supportforES6Modules.Asaresult,specialloadersortoolsthattranspileES6toES5arerequiredsothatwecanstartwritingourcodeusingthenewfeaturesofES6.

NoteFormoreinformation,youcanvisitES6Moduleloader’sdocumentationpageathttps://github.com/ModuleLoader/es6-module-loader,andBabeltranspiler(earlierknownasES6toES5)athttp://babeljs.io/.

Page 150: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 151: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingModulesinjQueryapplicationsInordertodemonstratehowtheModulePatterncanleadtoabetterapplicationstructure,wewillreimplementthedashboardexamplethatwesawinthepreviouschapters.Wewillincludeallthefunctionalitiesthatwehaveseenuntilnow,includingthecounteroftheopeninformationboxes.TheHTMLandCSScodeusedisexactlythesameasinthepreviouschapterand,asaresult,ourdashboardlooksexactlythesameasbefore:

Forthisdemonstration,wewillrefactorourJavaScriptcodeintofoursmallModulesusingthesimpleIIFE-containedModulevariant.ThedashboardModulewillactasthemainentryofcodeexecutionandalsoasthecentralcoordinationpointofthedashboardapplication.Thecategoriessubmodulewillberesponsiblefortheimplementationoftheupper-toppartofourdashboard.Thisincludescategoryselection,thepresentationofappropriatebuttons,andthehandlingofbuttonclicks.TheinformationBoxsubmodulewillberesponsibleforthemainpartofourdashboard.Itwillprovidemethodstocreateandremoveinformationboxesfromthedashboard.Finally,thecountersubmodulewillberesponsibleforkeepingthefieldwiththenumberofthecurrentlyopeninformationboxesup-to-date,respondingtotheuseractions.

AsinglechangethatweneedtomaketotheHTMLofthepageinordertosupportthismultimodulearchitectureislimitedtothewayinwhichtheJavaScriptfilesareincluded:

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="dashboard.js"></script>

<scripttype="text/javascript"src="dashboard.categories.js"></script>

<scripttype="text/javascript"src="dashboard.informationbox.js">

</script>

<scripttype="text/javascript"src="dashboard.counter.js"></script>

TipEvenifthismultifilestructuremakesthedevelopmentanddebuggingprocessesaloteasier,itisrecommendedthatwecombineallthesefilesbeforemovingourapplicationtoaproductionenvironment.Severaltoolsspecializedforthisjobexist;forexample,theverysimpleandeffectivegrunt-contrib-concatprojectthatisavailableathttps://github.com/gruntjs/grunt-contrib-concat.

Page 152: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThemaindashboardmoduleTheresultingcodeforthedashboardmodulewilllookasfollows:

(function(){

'usestrict';

window.dashboard=window.dashboard||{};

dashboard.$container=null;

dashboard.init=function(){

dashboard.$container=$('.dashboardContainer');

dashboard.categories.init();

dashboard.informationBox.init();

dashboard.counter.init();

};

$(document).ready(dashboard.init);

})();

Aswealreadymentioned,thedashboardmodulewillbethecentralpointofourapplication.Sincethisisthestartingpointofexecutionforourapplication,itsmaindutyistodoalltherequiredinitializationsforitselfandeachsubmodule.Theinvocationoftheinit()methodiswrappedinsideacalltothe$(document).ready()methodsothatitsexecutionisdelayeduntiltheDOMtreeofthepageisfullyloaded.

Oneimportantthingtonoteisthat,duringtheinitialization,wedoaDOMtraversalinordertofindthecontainerelementofthedashboardandstoreittoapublicpropertyoftheModulenamed$container.ThiselementwillbeusedbyallthemethodsofthedashboardthatneedtoaccesstheDOMtree,inordertoscopetheircodeinsidethatcontainerelement,removingtheneedtoconstantlytraversethewholeDOMtreeusingcomplexselectors.KeepingreferencestokeyDOMelementsandreusingtheminthedifferentsubmodules,canmaketheapplicationsnappierandalsolessenthechanceofaccidentallyinterferingwiththerestofthepage;thus,leadingtolessbugsthatarealsoeasiertoresolve.

TipCacheelementsbutavoidmemoryleaks.

KeepinmindthatmaintainingreferencestoDOMelementsthatareconstantlyaddedandremovedfromthepageaddsextracomplexitytoourapplication.Thiscanevenleadtomemoryleaksincaseweareaccidentallykeepingareferencetoanelementthathasalreadybeenremovedfromthepage.Forsuchelements,suchastheinformationboxes,itmightbesaferandmoreeffectivetohavedelegatedhandlingfortheeventstriggeredonthemandtodoascopedDOMtraversalwhenneeded,inordertoretrieveajQueryobjectwithfreshreferencesoftheelements.

Page 153: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThecategoriesmoduleLet’sproceedwiththecategoriessubmodule:

(function(){

'usestrict';

dashboard.categories=dashboard.categories||{};

dashboard.categories.init=function(){

dashboard.$container.find('#categoriesSelector').change(function()

{

var$selector=$(this);

varcategoryIndex=+$selector.val();

dashboard.categories.selectCategory(categoryIndex);

});

dashboard.$container.find('.dashboardCategories').on('click',

'button',function(){

var$button=$(this);

varitemName=$button.text();

dashboard.informationBox.openNew(itemName);

});

};

dashboard.categories.selectCategory=function(categoryIndex){

var$dashboardCategories=

dashboard.$container.find('.dashboardCategory');

var$selectedItem=$dashboardCategories.eq(categoryIndex).show();

$dashboardCategories.not($selectedItem).hide();

};

})();

Thissubmodule’sinitializationmethodusesthereferencetothe$containerelementthatthemainModuleprovidesandaddstwoobserverstothepage.Thefirsthandlesthechangeeventonthe<select>categoryandcallstheselectCategory()methodwiththenumericvalueoftheselectedcategory.TheselectCategory()methodofthissubmodulewillthenhandlerevealingtheappropriatecategoryitems,decouplingitfromtheeventhandlingcodeandmakingitareusablefunctionalityavailabletotheentireapplication.

Rightafterthis,wecreateasingleDelegatedEventObserverthathandlestheclickeventonthe<button>categoryitem.Itextractsthetextofthe<button>pressedandcallstheopenNew()methodoftheinformationBoxsubmodulethatcontainsalltheimplementationrelatedtoinformationboxes.Inanon-demogradeapplication,aparametertosuchamethodwouldprobablybeanidentifierinsteadofatextvaluethatwouldbeusedtoretrievemoredetailsfromaremoteserver.

Page 154: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TheinformationBoxmoduleTheinformationBoxsubmodulethatcontainstheimplementationpartsrelatedtothemainareaofourdashboardhasthefollowingform:

(function(){

'usestrict';

dashboard.informationBox=dashboard.informationBox||{};

var$boxContainer=null;

dashboard.informationBox.init=function(){

$boxContainer=dashboard.$container.find('.boxContainer');

$boxContainer.on('click','.boxCloseButton',function(){

var$button=$(this);

dashboard.informationBox.close($button);

});

};

dashboard.informationBox.openNew=function(itemName){

varboxHtml='<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

itemName+

'<buttonclass="boxCloseButton">&#10006;'+

'</button>'+

'</header>'+

'Informationboxregarding'+itemName+

'</article></div>';

$boxContainer.append(boxHtml);

};

dashboard.informationBox.close=function($boxElement){

$boxElement.closest('.boxsizer').remove();

};

})();

Thefirstthingthatthissubmodule’sinitializationcodedoesisretrieveandstoreareferenceofthecontainerthatholdstheinformationboxestothe$boxContainervariable,usingthe$containerpropertyofthedashboardforscoping.

TheopenNew()methodisresponsibleforcreatingtheHTMLrequiredforanewinformationboxandaddingittothedashboardusingthe$boxContainervariable,whichactslikeaprivatememberoftheModule,andisusedforcachingthereferenceofthepreviouslyassignedDOMelement.Thisisagoodpracticethatcanimprovetheapplication’sperformance,sincethestoredelementisneverremovedfromthepageandisusedduringtheinitializationandtheopenNew()methodsoftheModule.Thisway,wenolongerneedtoexecuteslowDOMtraversalseverytimetheopenNew()methodiscalled.

Theclose()method,ontheotherhand,isresponsibleforremovinganexistinginformationboxfromthedashboard.ItreceivesajQuerycompositecollectionobjectasa

Page 155: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

parameterrelatedtothetargetinformationbox,whichisbasedonthewaythatthe$.fn.closest()methodworks,andcaneitherbetheboxelementcontaineroranyofitsdescendants.

TipImplementationsofmethodsthatprovideflexibilityregardingthewaythattheycanbecalledcanmakethemusablebymorepartsofalargeapplication.Thenextlogicalstepforthismethod,whichisleftasanexercisetothereader,wouldbetomakeitacceptasaparameter,theindex,oranidentifieroftheinformationboxthatneedstobeclosed.

Page 156: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThecountermoduleLastly,hereishowwerewrotethecounterimplementation,whichwesawinthepreviouschapter,asanindependentsubmodule:

(function(){

'usestrict';

dashboard.counter=dashboard.counter||{};

vardashboardItemCounter;

var$counter;

dashboard.counter.init=function(){

$counter=$('#dashboardItemCounter');

var$boxContainer=dashboard.$container.find('.boxContainer');

varinitialCount=$boxContainer.find('.boxsizer').length;

dashboard.counter.setValue(initialCount);

dashboard.$container.find('.dashboardCategories').on('click',

'button',function(){

dashboard.counter.setValue(dashboardItemCounter+1);

});

$boxContainer.on('click','.boxCloseButton',function(){

dashboard.counter.setValue(dashboardItemCounter-1);

});

};

dashboard.counter.setValue=function(value){

dashboardItemCounter=value;

$counter.text(dashboardItemCounter);

};

})();

Forthissubmodule,weareusingthe$countervariableasaprivatemembertocacheareferencetotheelementthatdisplaysthecount.AnotherprivatememberoftheModuleisthedashboardItemCountervariable,whichatanypointoftimewillholdthenumberofvisibleinformationboxesinthedashboard.KeepingsuchinformationonthemembersofourModulesreducesthetimesweneedtoreachtheDOMtreetoextractinformationonthestateoftheapplication,makingtheimplementationmoreefficient.

TipPreservingthestateoftheapplicationinthepropertiesofJavaScriptobjectsorModulesinsteadofreachingtheDOMtoextractthem,isaverygoodpracticethatmakestheapplication’sarchitecturemoreobject-oriented,andisalsoadoptedbymostofthemodernwebdevelopmentframeworks.

DuringtheinitializationoftheModule,wearegivinganinitialvaluetoourcountervariablesothatwearenolongerdependentontheinitialHTMLofthepageandhavea

Page 157: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

morerobustimplementation.Moreover,weareattachingtwoDelegatedEventObservers,oneforclicksthatwillleadtothecreationofnewinformationboxesandanotheroneforclicksthatwillclosethem.

Page 158: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

OverviewoftheimplementationWiththeabove,wecompletedtherewriteofthedashboardskeletonapplicationtoamodulararchitecture.Alltheavailableactionsareexposedaspublicmethodsofeachofoursubmodulesthatcanbeinvokedprogrammaticallyandthiswaytheyaredecoupledfromtheeventsthattriggerthem.

Agoodexerciseforthereaderwouldbetopromotethedecouplingevenfurther,byalsoadoptingthePublisher/SubscriberPatternintheaboveimplementation.ThefactthatthecodeisalreadystructuredintoModuleswillmakesuchchangealoteasiertoimplement.

Anotherpartthatcanbeimplementedinadifferentwayisthewayinwhichthesubmodulesareinitialized.InsteadofexplicitlyorchestratingtheinitializationofeachModuleinourmaindashboardModule,wecouldinsteadinitializeeachsubmoduleonitsownbywrappingtheinvocationoftheinit()methodina$(document).ready()callandissuingitsinitializationrightafteritsdeclaration.Ontheotherhand,nothavingacentralpointtocoordinatetheinitializationsandrelyingonpageeventscanfeellessdeterministic.AnotherwaytoimplementitwouldbelikethePublisher/SubscriberPattern,byexposingaregisterForInit()methodonourmainModule,whichwouldkeeptrackoftheModulesthathavebeenrequestedtobeinitializedusinganarray.

NoteFormorejQuerycodeorganizationtips,youcanvisithttp://learn.jquery.com/code-organization/concepts/.

Page 159: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 160: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedtheconceptsofModulesandNamespacesandalsothebenefitsthatcomefromtheiradoptioninlargeapplications.Wehadanin-depthanalysisofthemostwidelyadoptedpatternsandcomparedtheirbenefitsandlimitations.WelearnedbyexamplehowtodevelopModulesusingtheObjectLiteralPattern,thevariantsoftheModulePattern,andtheRevealingModulePattern.

WecontinuedwithasmallintroductiontoES5’sStrictModeandsawhowitcanbenefittoday’sModules.ThenweproceededbylearningsomedetailsaboutthestandardizedbutnotyetwidelysupportedES6Modules.Lastly,wesawhowthearchitectureofthedashboardapplicationcanchangedramaticallyafterusingtheModulePatterninitsimplementation.

NowthatwehavecompletedourintroductiononhowtouseModulesandNamespaces,wecanmoveontothenextchapterwherewewillbeintroducedtothefacadepattern.Inthenextchapter,wewilllearnaboutthephilosophyoffacadesandtheuniformwaythattheydefinehowcodeabstractionsshouldbecreatedsothattheyareeasilyunderstandableandreusablebyotherdevelopers.

Page 161: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 162: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter5.TheFacadePatternInthischapter,wewillshowcasetheFacadePattern,astructuraldesignpatternthattriestodefineauniformwayregardinghowdevelopersshouldcreateabstractionsintheircode.Initially,wewillusethispatterntowrapcomplexAPIsandexposesimpleronesthatfocusontheneedsofourapplication.WewillseehowjQueryembracestheconceptsofthispatterninitsimplementation,howitachievesencapsulatingcompleximplementationsthatareintegralpartsofthewebdeveloper’stool-beltintoeasy-to-useAPI’s,andhowthisplaysacriticalroleforitswideadoption.

Inthischapter,wewill:

IntroducetheFacadePatternDocumentitskeyconceptsandbenefitsSeehowjQueryusesitinitsimplementationWriteanexampleimplementationwhereFacadesareusedtocompletelyabstractanddecoupleathird-partylibrary

Page 163: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheFacadePatternTheFacadeisastructuralsoftwaredesignpatternthatdealswithhowabstractionsofthevariouspartsofanimplementationshouldbecreated.ThekeyconceptoftheFacadePatternistoabstractanexistingimplementationandprovideasimplifiedAPIthatbettermatchestheusecasesofthedevelopedapplication.AccordingtomostComputerSciencebibliographiesdescribingthispattern,aFacadeismostcommonlyimplementedasaspecializedclassthatisusedtosegmenttheimplementationofanapplicationintosmallerpiecesofcode,whileprovidinganinterfacethatcompletelyhidestheencapsulatedcomplexity.Inthewebdevelopmentworld,itisalsocommontouseplainobjectsorfunctionsfortheimplementationofaFacade,takingadvantageofthewayinwhichJavaScripttreatsfunctionsasobjects.

Inapplicationsthathaveamodularstructure,liketheexamplesofthepreviouschapter,itisalsocommontoimplementFacadesasseparatemoduleswiththeirownnamespace.Moreover,foralargerimplementationwithverycomplexparts,anapproachwithmultiplelevelsofFacadescanalsobefollowed.Onceagain,theFacadeswillbeimplementedasmodulesandsubmodules,havingthetop-levelFacadeorchestratingthemethodsofitssubmodules,whileprovidinganAPIthatcompletelyhidesthecomplexityoftheentiresubsystem.

Page 164: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 165: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThebenefitsofthispatternMostofthetime,theFacadePatternisadoptedforimplementationpartsthathavearelativelyhighdegreeofcomplexityandareusedinseveralplacesofanapplication,whereinlargepiecesofcodecanbereplacedwithasimplecalltothecreatedFacade,leadingnotonlytolesscoderepetition,butalsohelpingustoincreasethereadabilityoftheimplementation.SincetheFacademethodsareusuallynamedbythehigher-levelapplicationconceptsthattheyencapsulate,theresultingcodeisalsoeasiertounderstand.ThesimplifiedAPIthataFacadeprovidesthroughitsconvenientmethods,leadstoanimplementationthatiseasiertouse,understand,andalsowriteunittestsfor.

Moreover,havingFacadestoabstractcompleximplementationsprovesitsusefulnessincaseswherethereisaneedtointroduceachangetothebusinesslogicoftheimplementation.IncaseaFacadehasawell-designedAPIwithapredictionforfuturerequirements,suchchangescanoftenrequiremodificationsjusttotheFacade’scode,leavingtherestoftheapplication’simplementationuntouchedandfollowingtheSeparationofConcernsprinciple.

Inthesamemanner,usingFacadestoabstracttheAPIofathird-partylibrarytobettermatchtheneedsofeachapplication,providesadegreeofdecouplingbetweenourcodeandtheusedlibrary.Incasethethird-partylibrarychangesitsAPIorneedstobereplacedwithanotherone,thedifferentmodulesoftheapplicationwillnotneedtoberewritten,sincetheimplementationchangeswouldbelimitedtothewrapperFacade.Inthiscase,allthatisneededistoprovideanequivalentimplementationusingthenewlibraryAPIwhilekeepingtheFacade’sAPIintact.

Page 166: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Asanexampleoforchestratingmethodcallsandusingsensibledefaultsforspecificusecases,takealookatthefollowingsampleimplementation:

functiondo(x,y){

varz=y-x/2;

varyy=Math.pow(y,2);

varb=3*Math.random();//addsomerandomnesstotheresult

vari=0;//forthiscase

returnLibraryA.doingMethod(x,z,i,yy,b);

}

Page 167: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 168: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisadoptedbyjQueryAverylargepartofthejQueryimplementationisdedicatedtoprovidingsimpler,shorter,andmoreconvenient-to-usemethodsforthingsthatthedifferentJavaScriptAPIsalreadyallowustoachieve,butwithmorelinesofcodeandeffort.BytakingalookattheprovidedAPIsofjQuery,wecandistinguishsomegroupsofrelatedmethods.Thisgroupingcanalsobeseeninthewayinwhichthesourcecodeisstructured,placingmethodsforrelatedAPIsneartoeachother.

EvenifthewordFacadedoesnotappearinjQuery’ssourcecode,theuseofthispatterncanbewitnessedbythewayinwhichtherelatedmethodsaredefinedontheexposedjQueryobject.Mostofthetime,therelatedmethodsthatformagroupareimplementedanddefinedaspropertiesonanObjectLiteralandthenattachedtothejQueryobjectwithasinglecalltothe$.extend()orthe$.fn.extend()method.Asyoumightremember,fromthebeginningofthischapter,thismatchesalmostexactlywiththeimplementationthatComputerSciencecommonlyusestodescribehowaFacadeisimplemented,withtheexceptionthat,inJavaScript,wecancreateaplainobjectwithoutneedingtofirstdefineaclass.Asaresult,jQueryitselfcanbeseenasacollectionofFacades,whereeachoneindependentlyaddsgreatvaluetothelibrarywiththeAPIofconvenientmethodsthatitprovides.

NoteFormoreinformationon$.extend()and$.fn.extend(),youcanvisithttp://api.jquery.com/jQuery.extend/andhttp://api.jquery.com/jQuery.fn.extend/.

SomeoftheabstractedAPIgroupsthatarebigpartsofthejQueryimplementationandplayacriticalroletoitsadoptionareasfollows:

TheDOMTraversalAPITheAJAXAPITheDOMManipulationAPITheEffectsAPI

Also,agreatexampleofhowthispatterncanbeusedtoprovidesimplifiedAPIsisjQuery’sEventsAPI,whichprovidesavarietyofconvenientmethodsforthemostcommonusecasesthatareeasiertousethantherespectiveplainJavaScriptAPIs.

Page 169: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThejQueryDOMTraversalAPIAtthetimethatjQuerywasreleased,webdeveloperscouldlocatespecificDOMelementsofapageonlybyusingtheverylimitedgetElementById()andgetElementsByTagName()methods,sinceothermethods,suchasgetElementsByClassName(),werenotwidelysupportedbytheexistingbrowsers.ThejQueryteamrealizedhowthewebdevelopmentcouldbeleveragediftherewasasimpleAPIthatwouldeasesuchDOMtraversals,whichwouldworkthesamewayacrossallbrowsers,beaseffectiveasthefamiliarCSSSelectors,anddidtheirbesttomakesuchanimplementationareality.

TheresultofthiseffortisthenowfamousjQueryDOMTraversalAPIthatisexposedthroughthe$()function,whichplayedaseriousroleinthestandardizationofthequerySelectorAll()methodaspartoftheLevel2SelectorAPI.TheimplementationunderthehoodusesthemethodsprovidedbytheDOMAPIandcountsabout2,135linesofcodeinjQueryv2.2.0,whileitisevenbiggerinthev1.xversionsthatneededtosupportolderbrowsersaswell.Aswesawinthischapter,becauseofitscomplexitythisimplementationisnowpartofaseparatestand-aloneprojectthatisnamedSizzle.

NoteFormoreinformationonSizzleandthequerySelectorAll()method,youcanvisithttps://github.com/jquery/sizzleandhttps://developer.mozilla.org/en-US/docs/Web/API/document/querySelectorAll.

Regardlessofitscompleximplementation,theexposedAPIsarequiteeasytouse,mostlyusingsimpleCSSSelectorsasstringparameters,makingitanexcellentexampleofhowaFacadecanbeusedtocompletelyhidethecomplexityofitsinnerworkingsandexposeaconvenientAPI.SinceSizzle’sAPIisstillquitecomplex,thejQuerylibraryactuallywrapsitwithitsownAPIactingasanextraFacadelevel:

//Line733

functionSizzle(selector,context,results,seed){/*...*/}

//Line2678

jQuery.find=Sizzle;

ThejQuerylibraryfirstkeepsareferenceofSizzletotheinternaljQuery.find()methodandthenusesittoimplementallitsexposedDOMTraversalmethods,whichworkonCompositeObjectssuchas$.fn.find():

//Line2769

jQuery.fn.extend({

find:function(selector){

/*15linesofcode*/

for(i=0;i<len;i++){

jQuery.find(selector,self[i],ret);

}

/*3linesofcode*/

returnret;

}

Page 170: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

});

Finally,thefamous$()functioncanactuallybeinvokedinseveralways,butevenwhenitisinvokedwithaCSSSelectorasastringparameter,itactuallyhasanextralevelofhiddencomplexity:

//Line71

jQuery=function(selector,context){

returnnewjQuery.fn.init(selector,context);

};

//Line2825

rquickExpr=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

//Line2735

init=jQuery.fn.init=function(selector,context,root){

/*12linesofcode*/

if(typeofselector==="string"){

if(/*...*/){

/*3linesofcode*/

}else{

match=rquickExpr.exec(selector);

}

//Matchhtmlormakesurenocontextisspecifiedfor#id

if(match&&(match[1]||!context)){

if(match[1]){

/*27linesofcode*/

//HANDLE:$(#id)

}else{

elem=document.getElementById(match[2]);

//Support:Blackberry4.6

//gEBIDreturnsnodesnolongerinthedocument(#6963)

if(elem&&elem.parentNode){

//InjecttheelementdirectlyintothejQueryobject

this.length=1;

this[0]=elem;

}

this.context=document;

this.selector=selector;

returnthis;

}

//HANDLE:$(expr,$(...))

}elseif(!context||context.jquery){

return(context||root).find(selector);

//HANDLE:$(expr,context)

//(whichisjustequivalentto:$(context).find(expr)

}else{

returnthis.constructor(context).find(selector);

}

}/*else…21linesofcode*/

};

Page 171: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Asyoucansee,intheprecedingcode,the$()isactuallycreatinganewobjectwith$.fn.init().Insteadofbeingjustanentrypointto$.fn.find()orjQuery.find(),itisactuallyaFacadethathidesalevelofoptimization.Specifically,itmakesjQueryfasterbyavoidinginvoking$.fn.find()andSizzle,whensimpleIDselectorsareusedbydirectlyinvokingthegetElementById()method.

Page 172: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ThepropertyaccessandmanipulationAPIAnotherveryinterestingabstractionthatfollowstheprinciplesoftheFacadePatternandcanbefoundinjQuery’ssource,isthe$.fn.prop()method.Likethe$.fn.attr(),$.fn.val(),$.fn.text(),and$.fn.html(),itbelongstoafamilyofmethodsthatischaracterizedbythefactthateachmethodisbothagetterandasetteroftherelatedsubject.Thedistinctionofthemethod’sexecutionmodeisdonebyinspectingthenumberofparametersthatarepassedduringitsinvocation.ThisconvenientAPIallowsustohavetorememberlessmethodsignaturesandmakethesettersdifferonlybyoneextraparameter.Forexample,$('#myCheckBox').prop('checked')willreturntrueorfalse,basedonthestateoftheselectedcheckbox.Ontheotherhand,$('#myCheckBox').prop('checked',true);willprogrammaticallycheckthatcheckboxforus.Inthesameconcept,$('button').prop('disabled',true);willdisableallthe<button>elementsonapage.

The$.fn.prop()methoddoesthejQueryCompositeObjecthandling,buttheactualimplementationoftheFacadeistheinternaljQuery.prop()method.AnextraconcernthataddscomplexitytotheFacade’simplementationisthefactthattherearesomeHTMLattributesthathavedifferentidentifiersforthecorrespondingpropertiesontheDOMelements:

jQuery.extend({

prop:function(elem,name,value){

/*8liesofcode*/

if(nType!==1||!jQuery.isXMLDoc(elem)){

//Fixnameandattachhooks

name=jQuery.propFix[name]||name;

hooks=jQuery.propHooks[name];

}

if(value!==undefined){

if(hooks&&"set"inhooks&&

(ret=hooks.set(elem,value,name))!==undefined){

returnret;

}

return(elem[name]=value);

}

if(hooks&&"get"inhooks&&(ret=hooks.get(elem,name))!==

null){

returnret;

}

returnelem[name];

},

propHooks:{

tabIndex:{

get:function(elem){

vartabindex=jQuery.find.attr(elem,"tabindex");

returntabindex?parseInt(tabindex,10):/*...*/;

Page 173: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

}

}

},

propFix:{

"for":"htmlFor",

"class":"className"

}

});

ThefirsthighlightedcodeareaefficientlyresolvesthepropertytoattributeidentifiermismatchbyusingthepropFixandpropHooksobjectstodothematching.ThepropFixobjectactslikeasimpledictionarytomatchtheidentifiers,whilethepropHooksobjectholdsafunctionthatdoesthematchinginaless-hard-codedway,withprogrammatictesting.Thisisagenericimplementationthatcaneasilybeextendedbyaddingextrapropertiestothosetwoobjects.

Therestofthehighlightedareasareresponsibleforthegetter/settermodeofthemethod.Theoverallimplementationistoperformthefollowingtasks:

Checkwhetheravalueispassedasanargumentand,ifthepropertyfindsthattheassignmentissuccessful,dotheassignmentandreturnthevalue.Alternatively,iftherewasnovaluepassed,returnthevalueoftherequestedpropertyifitisretrievable.

Page 174: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 175: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingFacadesinourapplicationsInordertodemonstratehowfacadescanbeusedbothtoencapsulatecomplexity,helpingusenforcetheSeparationofConcernsprinciple,andalsoabstractthird-partylibraryAPIsintomoreconvenientmethodsthatareapplicationcentric,wearegoingtodemonstrateaverysimplelotteryapplication.Our“ElementLottery”applicationwillpopulateitscontainerwithsomeLotteryTicketelementsthatwillhaveauniqueIDandcontainarandomnumber.

Thewinningticketwillbepickedbyrandomlyselectingoneofthelotteryelements,basedonarandomindexamongthecreateduniqueIDs.Thewinningnumberwillthenbeannouncedtobethenumericcontentofthepickedelement.Let’sseethemodulesofourapplication:

(function(){

window.elementLottery=window.elementLottery||{};

varelementIDs;

var$lottery;

varticketCount=30;

elementLottery.init=function(){

elementIDs=[];

$lottery=$('#lottery').empty();

elementLottery.add(ticketCount);

$('#lotteryTicketButton').on('click',elementLottery.pick);

};

elementLottery.add=function(n){

for(vari=0;i<n;i++){

varid=this.uidProvider.get();

elementIDs.push(id);

$lottery.append(this.ticket.createHtml(id));

}

};

Page 176: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

elementLottery.pick=function(){

varindex=Math.floor(Math.random()*elementIDs.length);

varresult=$lottery.find('#'+elementIDs[index]).text();

alert(result);

returnresult;

};

$(document).ready(elementLottery.init);

})();

ThemainelementLotterymoduleofourapplicationinitializeditselfrightafterthepagewasfullyloaded.Theaddmethodisusedtopopulatethelotterycontainerelementwithtickets.ItusestheuidProvidersubmoduletogenerateuniqueidentifiersfortheticketelements,keepstrackofthemontheelementIDsarray,usestheticketsubmoduletoconstructtheappropriateHTMLcode,andfinallyappendstheelementtothelottery.Thepickmethodisusedtorandomlyselectthewinningticketbyrandomlyselectingoneofthegeneratedidentifiers,retrievingthepageelementwiththatID,anddisplayingitscontentinsideanalertboxasthewinningresult.ThepickmethodistriggeredbyclickingonthebuttonthatwehaveaddedanObserverduringtheinitializationphase:

(function(){

elementLottery.ticket=elementLottery.ticket||{};

elementLottery.ticket.createHtml=function(id){

varticketNumber=Math.floor(Math.random()*1000*10);

return'<divid="'+id+'"class="ticket">'+ticketNumber+

'</div>';

};

})();

(function(){

elementLottery.uidProvider=elementLottery.uidProvider||{};

elementLottery.uidProvider.get=function(){

return'Lot'+simpleguid.getNext();

};

})();

TheticketsubmobuleactsasaFacadewithasinglemethodthatisusedtoencapsulatethegenerationofarandomnumberandthecreationoftheHTMLcodethatwillbeusedastheticket.Ontheotherhand,theuidProvidesubmoduleisaFacadethatprovidesasinglegetmethodthatencapsulatesthewayweusethesimpleguidmodulethatwesawinthepreviouschapters.Asaresult,wecaneasilychangethelibrarythatisusedtogenerateuniqueidentifiersandtheonlyplacethatwewillhavetomodifytheexistingimplementationwillbetheuidProvidesubmodule.Forexample,let’sseehowitwilllookifwedecidedtousethegreatnode-uuidlibrarythatgenerates128-bituniqueidentifiersasstringsofhexadecimalcharacters:

(function(){

elementLottery.uidProvider=elementLottery.uidProvider||{};

Page 177: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

elementLottery.uidProvider.get=function(){

returnuuid.v4();

};

})();

NoteFormoreinformationonthenode-uuilibrary,youcanvisithttps://github.com/broofa/node-uuid.

Page 178: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 179: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedwhataFacadeactuallyis.Welearneditsphilosophyandtheuniformwayinwhichitdefineshowcodeabstractionsshouldbecreatedsothattheyareeasilyunderstandableandreusablebyotherdevelopers.

Startingfromthesimplestusecasesofthispattern,welearnedhowtowrapacomplexAPIwithaFacadeandexposeasimpleronethatisfocusedontheneedsofourapplicationandisabettermatchtoitsspecificusecases.WealsosawhowjQueryembracestheconceptsofthispatterninitsimplementationandhowprovidingsimpleAPIsformorebasicweb-developingtechniques,suchasDOMTraversals,playedacriticalroleforitswideadoption.

NowthatwehavecompletedourintroductiontohowtheFacadePatterncanbeusedtodecoupleandabstractpartsofanimplementation,wecanmoveontothenextchapterwherewewillbeintroducedtotheBuilderandFactoryPatterns.Inthenextchapter,wewilllearnhowtousethesetwoCreationalDesignPatternstoabstracttheprocessofgeneratingandinitializingnewobjectsforspecificusecasesandanalyzehowtheiradoptioncanbenefitourimplementations.

Page 180: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 181: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter6.TheBuilderandFactoryPatternsInthischapter,wewillshowcasetheBuilderandFactoryPatterns,twoofthemostcommonlyusedCreationalDesignPatterns.Thesetwodesignpatternshavesomesimilaritieswitheachother,sharesomecommongoals,andarededicatedtoeasingthecreationofcomplexresults.Wewillanalyzethebenefitsthattheiradoptioncanbringtoourimplementationsandalsothewaysinwhichtheydiffer.Finally,wewilllearnhowtousethemproperlyandchoosethemostappropriateoneforthedifferentusecasesofourimplementations.

Inthischapter,wewill:

IntroducetheFactoryPatternSeehowtheFactoryPatternisusedbyjQueryHaveanexampleoftheFactoryPatteninajQueryapplicationIntroducetheBuilderPatternComparetheBuilderandFactoryPatternsSeehowtheBuilderPatternisusedbyjQueryHaveanexampleoftheBuilderPatteninajQueryapplication

Page 182: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheFactoryPatternTheFactoryPatternispartofthegroupofCreationalPatternsandoverallitdescribesagenericwayforobjectcreationandinitialization.Itiscommonlyimplementedasanobjectorfunctionthatisusedtogenerateotherobjects.AccordingtothemajorityofComputerScienceresources,thereferenceimplementationoftheFactoryPatternisdescribedasaclassthatprovidesamethodthatreturnsnewlycreatedobjects.Thereturnedobjectsarecommonlytheinstancesofaspecificclassorsubclass,ortheyexposeasetofspecificcharacteristics.

ThekeyconceptoftheFactorypatternistoabstractthewayanobjectoragroupofrelatedobjectsarecreatedandinitializedforaspecificpurpose.Thepointofthisabstractionistoavoidcouplinganimplementationwithspecificclassesorthewaythateachobjectinstanceneedstobecreatedandconfigured.Theresultisanimplementationthatworksasanabstractwayforobjectcreationandinitialization,whichfollowstheconceptofSeparationofConcerns.

Theresultingimplementationsareonlybasedontheobjectmethodsandpropertiesthatarerequiredbytheiralgorithmorbusinesslogic.Suchanapproachcanbenefitthemodularityandextensibilityofanimplementation,byfollowingtheconceptofprogrammingoverObjectFeaturesandFunctionalityinsteadofObjectClasses.Thisgivesustheflexibilitytochangetheusedclasseswithanyotherobjectthatexposesthesamefunctionality.

Page 183: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisadoptedbyjQueryAswehavealreadynotedintheearlierchapters,oneoftheearlygoalsofjQuerywastoprovideasolutionthatworkedthesameacrossallbrowsers.The1.12.xversionseriesofjQueryarefocusedonprovidingsupportforbrowsersasoldasInternetExplorer6(IE6),whilemaintainingthesameAPIwiththenewerv2.2.xversionsthatonlyfocusonmodernbrowsers.

Inordertohaveasimilarstructureandmaximizethecommoncodebetweenthetwoversions,thejQueryteamtriedtoabstractmostcompatibilitymechanismsinadifferentimplementationlayer.Suchadevelopmentpracticegreatlyimprovesthereadabilityofthecodeandreducesthecomplexityofthemainimplementation,encapsulatingitintodifferentsmallerpieces.

AgreatexampleofthisistheimplementationoftheAJAX-relatedmethodsthatjQueryprovides.Specifically,inthefollowingcode,youcanfindapartofit,asfoundinversion1.12.0ofjQuery:

//Createtherequestobject

//(ThisisstillattachedtoajaxSettingsforbackwardcompatibility)

jQuery.ajaxSettings.xhr=window.ActiveXObject!==undefined?

//Support:IE6-IE8

function(){

//XHRcannotaccesslocalfiles,alwaysuseActiveXforthatcase

if(this.isLocal){

returncreateActiveXHR();

}

//Support:IE9-11

if(document.documentMode>8){

returncreateStandardXHR();

}

//Support:IE<9

return/^(get|post|head|put|delete|options)$/i.test(this.type)&&

createStandardXHR()||createActiveXHR();

}:

//Forallotherbrowsers,usethestandardXMLHttpRequestobject

createStandardXHR;

//Functionstocreatexhrs

functioncreateStandardXHR(){

try{

returnnewwindow.XMLHttpRequest();

}catch(e){}

}

functioncreateActiveXHR(){

try{

returnnewwindow.ActiveXObject("Microsoft.XMLHTTP");

}catch(e){}

}

Page 184: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

EverytimeanewAJAXrequestisissuedonjQuery,thejQuery.ajaxSettings.xhrmethodisusedasaFactorythatcreatesanewinstanceoftheappropriateXHRobjectbasedonthesupportofthecurrentbrowser.Lookinginmoredetail,wecanseethatthejQuery.ajaxSettings.xhrmethodorchestratestheuseoftwosmallerFactoryfunctions,witheachresponsibleforaspecificimplementationofAJAX.Moreover,wecanseethatitactuallytriestoavoidrunningthecompatibilitytestsoneverycallbydirectlywiringupitsreferencetothesmallercreateStandardXHRFactoryfunctionwhenappropriate.

Page 185: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingFactoriesinourapplicationsAsanexampleusecaseofFactories,wewillcreateadata-drivenformwhereouruserswillbeabletofillsomefieldsthataredynamicallycreatedandinsertedintothepage.Wewillassumetheexistenceofanarraycontainingobjectsthatdescribeeachformfieldthatneedstobepresented.OurFactorymethodwillencapsulatethewayinwhicheachformfieldneedstobeconstructed,andproperlyhandleeachspecificcase,basedonthecharacteristicsdefinedontherelatedobjects.

TheHTMLcodeforthispageisquitesimple:

<h1>DataDrivenForm</h1>

<form></form>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="datadrivenform.js"></script>

Itonlycontainsan<h1>elementwiththepageheadingandanempty<form>elementthatwillhostthegeneratedfields.AsfortheCSSused,weonlystylethe<button>elementsinthesamewayaswedidinthepreviouschapters.

AsfortheJavaScriptimplementationoftheapplication,wecreateamoduleanddeclare

Page 186: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

dataDrivenFormasthenamespaceofthisexample.Thismodulewillcontainthedatathatdescribesourform,theFactorymethodthatwillgeneratetheHTMLofeachformelementand,ofcourse,theinitializationcodethatwillcombinetheaforementionedpartstocreatetheresultingform:

(function(){

'usestrict';

window.dataDrivenForm=window.dataDrivenForm||{};

dataDrivenForm.formElementHTMLFactory=function(type,name,title){

if(!title||!title.length){

title=name;

}

vartopPart='<div><label><span>'+title+':</span><br/>';

varbottomPart='</label></div>';

if(type==='text'){

returntopPart+

'<inputtype="text"maxlength="200"name="'+name+'"/>'+

bottomPart;

}elseif(type==='email'){

returntopPart+

'<inputtype="email"requiredname="'+name+'"/>'+

bottomPart;

}elseif(type==='number'){

returntopPart+

'<inputtype="number"min="0"max="2147483647"'+'name="'+name+

'"/>'+

bottomPart;

}elseif(type==='date'){

returntopPart+

'<inputtype="date"min="1900-01-01"name="'+

name+'"/>'+

bottomPart;

}elseif(type==='textarea'){

returntopPart+

'<textareacols="30"rows="3"maxlength="800"name="'+name+'"

/>'+

bottomPart;

}elseif(type==='checkbox'){

return'<div><label><span>'+title+':</span>'+

'<inputtype="checkbox"name="'+name+'"/>'+

'</label></div>';

}elseif(type==='notice'){

return'<p>'+name+'</p>';

}elseif(type==='button'){

return'<buttonname="'+name+'">'+title+'!</button>';

}

};

})();

OurFactorymethodwillbeinvokedwiththreeparameters.Startingfromthemostimportantone,itacceptsthetypeandthenameoftheformfieldandalsothetitlethatwillbeusedasitsdescription.Sincemostformfieldssharesomecommoncharacteristics,

Page 187: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

liketheirtitle,theFactorymethodtriestoabstracttheminordertohavelesscoderepetition.Asyoucansee,theFactorymethodalsocontainssomesensibleextraconfigurationforeachfieldtype,likethemaxlengthattributeofthetextfields,thatisspecificforthisusecase.

TheobjectstructurethatwillbeusedtorepresenteachformelementwillbeaplainJavaScriptobjectthathasatype,name,andtitleproperty.ThecollectionofobjectsthatdescribetheformfieldswillbegroupedinanarrayandbeavailableonthedataDrivenForm.partspropertyofourmodule.Inareal-worldapplication,thesefieldswouldcommonlyeitherberetrievedwithanAJAXrequestorbeinjectedintosomepartoftheHTMLofthepage.Inthefollowingcodesnippet,wecanseethedatathatwillbeusedtodrivethecreationofourform:

dataDrivenForm.parts=[{

type:'text',

name:'firstname',

title:'FirstName'

},{

type:'text',

name:'lastname',

title:'LastName'

},{

type:'email',

name:'email',

title:'e-mailaddress'

},{

type:'date',

name:'birthdate',

title:'Dateofbirth'

},{

type:'number',

name:'experience',

title:'Yearsofexperience'

},{

type:'textarea',

name:'summary',

title:'Summary'

},{

type:'checkbox',

name:'receivenotifications',

title:'Receivenotificatione-mails'

},{

type:'notice',

name:'Byusingthisformyouacceptthetermsofuse'

},{

type:'button',

name:'save'

},{

type:'button',

name:'submit'

}];

Finally,wedefineandimmediatelyinvokeaninitmethodforourmodule:

Page 188: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

dataDrivenForm.init=function(){

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

varpart=dataDrivenForm.parts[i];

varelementHTML=dataDrivenForm.formElementHTMLFactory(part.type,

part.name,part.title);

//checkiftheresultisnull,undefinedoremptystring

if(elementHTML&&elementHTML.length){

$('form').append(elementHTML);

}

}

};

$(document).ready(dataDrivenForm.init);

TheinitializationcodewaitsuntiltheDOMofthepageisfullyloadedandthenusestheFactorymethodtocreatetheformelementsandattachthemtothe<form>elementofourpage.AnextraconcernoftheprecedingcodeistochecktheresultoftheFactorymethodinvocationbeforeactuallystartingtouseit.

MostFactories,wheninvokedwithparametersforacasetheycan’thandle,returnnulloremptyobjects.Asaresult,it’sagoodcommonpractice,whenusingFactories,tocheckwhethertheresultofeachinvocationisactuallyvalid.

Asyoucansee,havingFactoriesthatacceptonlysimpleparameters(forexample,stringsandnumbers),inmanycases,leadstoanincreasednumberofparameters.Eventhoughtheseparametersmayonlybeusedinspecificcases,theAPIofourFactorystartstobeawkwardlylongandneedsproperdocumentationforeachspecialcaseinordertobeusable.

Ideally,aFactorymethodshouldacceptasfewargumentsaspossible,otherwiseitwillstartlookinglikeaFacadethatonlyprovidesadifferentAPI.Since,insomecases,usingasinglestringornumericargumentdoesnotsuffice,inordertoavoidusingahugenumberofparameters,wecanfollowapracticewheretheFactoryisdesignedtoacceptasingleobjectasitsparameter.

Forexample,inourcase,wecanjustpassthewholeobjectthatdescribestheformfieldasaparametertotheFactorymethod:

dataDrivenForm.formElementHTMLFactory=function(formElementDefinition){

vartopPart='<div><label><span>'+formElementDefinition.title+':

</span><br/>';

varbottomPart='</label></div>';

if(formElementDefinition.type==='text'){

returntopPart+

'<inputtype="text"maxlength="200"name="'

+formElementDefinition.name+'"/>'+

bottomPart;

}/*...*/

};

Thispracticeissuggestedforthefollowingcases:

WhenwecreategenericFactoriesthatarenotfocusedonspecificusecasesandweneedtoconfiguretheirresultsdifferentlyforeachspecificusecase.

Page 189: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Whentheconstructedobjectshavemanyoptionalconfigurationparametersthatlargelydiffer.Inthiscase,addingthemasseparateparameterstotheFactorymethodwouldleadtoinvocationsthathaveanumberofnullarguments,dependingonwhichexactargumentweareinterestedindefining.

Anotherpractice,especiallyinJavaScriptprogramming,istocreateaFactorymethodthatacceptsasimplestringornumericvalueasitsfirstargumentandoptionallyprovideacomplementaryobjectasasecondparameter.ThisenablesustohaveasimplegenericAPIthatcanbeuse-case-specificandalsogivesussomeextrapointsoffreedomtoconfiguresomespecialcases.Thisapproachisusedbythe$.ajax(url[,settings])methodthatallowsustogeneratesimpleGETrequestsbyjustprovidingaURLandalsoacceptsanoptionalsettingsparameterthatallowsustoconfigureanyaspectoftherequest.Changingtheaboveimplementationtousethisvariationisleftasanexerciseforthereader,inordertoexperimentandgetfamiliarwiththeuseofFactorymethods.

Page 190: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 191: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheBuilderPatternTheBuilderPatternispartofthegroupofCreationalPatternsandprovidesusawaytocreateobjectsthatrequirealotofconfigurationbeforetheyreachthepointwheretheycanbeused.TheBuilderPatternisoftenusedforobjectsthatacceptmanyoptionalparametersinordertodefinetheiroperation.Anothermatchingcaseisforthecreationofobjectswheretheirconfigurationneedstobedoneinseveralstepsorinaspecificorder.

ThecommonparadigmfortheBuilderPatternaccordingtoComputerScienceisthatthereisaBuilderObjectthatprovidesoneormoresettermethods(setA(...),setB(...))andasinglegenerationmethodthatconstructsandreturnsthenewlycreatedresultobject(getResult()).

Thispatternhastwoimportantconcepts.ThefirstoneisthattheBuilderObjectexposesanumberofmethodsasawaytoconfigurethedifferentpartsoftheobjectthatisunderconstruction.Duringtheconfigurationphase,theBuilderObjectpreservesaninternalstatethatreflectstheeffectsoftheinvocationsoftheprovidedsettermethods.Thiscanbebeneficialwhenusedtocreateobjectsthatacceptalargenumberofconfigurationparameters,solvingtheproblemofTelescopicConstructors.

NoteTelescopicConstructorsisananti-patternofobject-orientedprogrammingthatdescribesthesituationwhereaclassprovidesseveralconstructorsthattendtodifferonthenumber,thetype,andthecombinationoftheargumentsthattheyrequire.Objectclasseswithseveralparametersthatcanbeusedinmanydifferentcombinationscanoftenleadtoimplementationsfallingintothisanti-pattern.

Thesecondimportantconceptisthatitalsoprovidesagenerationmethodthatreturnstheactualconstructedobjectbasedontheprecedingconfiguration.Mostofthetime,theinstantiationoftherequestedobjectisdonelazilyandactuallytakesplaceatthemomentthatthismethodisinvoked.Insomecases,theBuilderObjectallowsustoinvokethegenerationmethodmorethanonce,allowingustogenerateseveralobjectswiththesameconfiguration.

Page 192: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisadoptedbyjQuery’sAPITheBuilderPatterncanalsobefoundaspartoftheAPIthatjQueryexposes.Specifically,thejQuery$()functioncanalsobeusedtocreatenewDOMelementsbyinvokingitwithanHTMLstringasanargument.Asaresult,wecancreatenewDOMelementsandsettheirdifferentpartsasweneedthem,insteadofhavingtocreatetheexactHTMLstringthatisneededforthefinalresult:

var$input=$('<input/>');

$input.attr('type','number');

$input.attr('min','0');

$input.attr('max','100');

$input.prop('required',true);

$input.val(4);

$input.appendTo('form');

The$('<input/>')callreturnsaCompositeObjectcontaininganelementthatisnotattachedtotheDOMtreeofthepage.Thisunattachedelementisonlyanin-memoryobjectthatisneitherfullyconstructednorfullyfunctionaluntilweattachittothepage.Inthiscase,thisCompositeObjectactslikeaBuilderObjectInstancehavinganinternalstateofobjectsthatarenotyetfinalized.Rightafterthis,wedoaseriesofmanipulationsonitusingsomejQuerymethodsthatactlikethesettermethodsdescribedbytheBuilderPattern.

Finally,afterweapplyalltherequiredconfigurations,sothattheresultingobjectbehavesinthedesiredway,weinvokethe$.fn.appendTo()method.The$.fn.appendTo()methodworksasthegenerationmethodoftheBuilderPattern,byattachingthein-memoryelementofthe$inputvariabletotheDOMtreeofthepage,transformingitintoanactualattachedDOMelement.

Ofcourse,theaboveexamplecangetmorereadableandlessrepetitivebyutilizingtheFluentAPIthatjQueryprovidesforitsmethods,andalsocombinethe$.fn.attr()methodinvocations.Moreover,jQueryallowsustousealmostallitsmethodstodotraversalsandmanipulationsontheelementsthatareunderconstruction,justaswecanonnormalDOMelementCompositeObjects.Asaresult,theaboveexamplecangetalittlemorecompleteasfollows:

$('<input/>').attr({

'type':'number',

'min':'0',

'max':'100'

})

.prop('required',true)

.val(4)

.css('display','block')

.wrap('<label>')//wraptheinputwitha<label>

.parent()//traverseonelevelup,tothe<label>

.prepend('<span>Qty:#</span')

.appendTo('form');

Page 193: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Theresultwilllookasfollows:

Thecriteriathatallowustocategorizethisoverloadedwayofinvokingthe$()functionasanimplementationthatadoptstheBuilderPattern,isthefactthat:

Itreturnsanobjectwithaninternalstatecontainingpartiallyconstructedelements.Thecontainedelementsareonlyin-memoryobjectsthatarenotpartofthepage’sDOMtree.Itprovidesusmethodstomanipulateitsinternalstate.MostjQuerymethodscanbeusedforthispurpose.Itprovidesusmethod(s)togeneratethefinalresult.WecanusejQuerymethodssuchas$.fn.appendTo()and$.fn.insertAfter(),asawaytocompletetheconstructionoftheinternalelementsandmakethempartoftheDOMtreewithpropertiesthatreflecttheirearlierin-memoryrepresentation.

AswehavealreadyseeninChapter1,ARefresheronjQueryandtheCompositePattern,theprimarywaytousethe$()functionistoinvokeitwithaCSSselectorasastringparameterandinturnitwillretrievethematchingpageelementsandreturntheminaCompositeObject.Ontheotherhand,whenthe$()functiondetectsthatithasbeeninvokedwithastringparameterthatlookslikeapieceofHTML,itworksasaDOMelementBuilder.Thisoverloadedwayofinvokingthe$()functionbasesitsdetectionontheassumptionthattheprovidedHTMLcodestartsandendswiththeinequalitysymbols<and>:

init=jQuery.fn.init=function(selector,context){

/*11linesofcode*/

//HandleHTMLstrings

if(typeofselector==="string"){

if(selector[0]==="<"&&selector[selector.length-1]===">"

&&selector.length>=3){

//Assumethatstringsthatstartandendwith<>areHTML//and

skiptheregexcheck

match=[null,selector,null];

}/*...*/

//Matchhtmlormakesurenocontextisspecifiedfor#id

if(match&&(match[1]||!context)){

//HANDLE:$(html)->$(array)

Page 194: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

if(match[1]){

/*4linesofcode*/

jQuery.merge(this,jQuery.parseHTML(match[1],/*...*/));

/*16linesofcode*/

returnthis;

}/*...*/

}/*...*/

}/*...*/

};

Aswecanseeintheprecedingcode,thisoverloadusesthejQuery.parseHTML()helpermethodthatultimatelyleadstoacallofthecreateDocumentFragment()method.ThecreatedDocumentFragmentisthenusedasahostoftheunderconstructiontreestructureofelements.AfterjQueryfinishesconvertingtheHTMLintoelements,theDocumentFragmentisdiscardedandonlyit’shostedelementsarereturned:

jQuery.parseHTML=function(data,context,keepScripts){

/*17linesofcode*/

//Singletag

if(parsed){

return[context.createElement(parsed[1])];

}

parsed=buildFragment([data],context,scripts);

/*5linesofcode*/

returnjQuery.merge([],parsed.childNodes);

};

ThisresultsinthecreationofanewjQueryCompositeObjectcontaininganin-memorytreestructureofelements.EventhoughtheseelementsarenotattachedtotheactualDOMtreeofthepage,wecanstilldotraversalsandmanipulationsonthemlikeanyotherjQueryCompositeObject.

NoteFormoreinformationonDocumentFragments,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment.

Page 195: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowitisusedbyjQueryinternallyAnundoubtedlybigpartofjQueryisitsAJAX-relatedimplementation,whichaimstoprovideasimpleAPIforasynchronouscallsthatisalsoconfigurabletoalargedegree.UsingthejQuerySourceViewerandsearchingforjQuery.ajax,ordirectlysearchingjQuery’ssourcecodefor"ajax:",willbringustheaforementionedimplementation.Inordertomakeitsimplementationmorestraightforwardandalsoallowittobeconfigurable,jQueryinternallyusesaspecialobjectstructurethatactsasaBuilderObjectforthecreationandhandlingofeachAJAXrequest.Aswewillsee,thisisnotthemostcommonwayofusingaBuilderObject,butitisactuallyaspecialvariantwithsomemodificationsinordertofittherequirementsofthiscompleximplementation:

jqXHR={

readyState:0,

//Buildsheadershashtableifneeded

getResponseHeader:function(key){/*...*/},

//Rawstring

getAllResponseHeaders:function(){/*...*/},

//Cachestheheader

setRequestHeader:function(name,value){/*...*/},

//Overridesresponsecontent-typeheader

overrideMimeType:function(type){/*...*/},

//Status-dependentcallbacks

statusCode:function(map){/*...*/},

//Canceltherequest

abort:function(statusText){/*...*/}

};

ThemainmethodthatthejqXHRobjectexposestoconfigurethegeneratedasynchronousrequestisthesetRequestHeader()method.Theimplementationofthismethodisquitegeneric,enablingjQuerytosetallthedifferentHTTPheadersfortherequest,usingonlyonemethod.

Inordertoprovideanevengreaterdegreeofflexibilityandabstraction,jQueryinternallyusesaseparatetransportobjectasawrapperofthejqXHRobject.ThistransportobjecthandlesthepartofactuallysendingtheAJAXrequesttotheserver,workinglikeapartnerbuilderobjectthatcooperateswiththejqXHRobjectforthecreationofthefinalresult.Thisway,jQuerycanfetchScripts,XML,JSON,andJSONPresponsesfromthesameorcross-originservers,usingthesameAPIandoverallimplementation:

transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);

//Ifnotransport,weauto-abort

if(!transport){

done(-1,"NoTransport");

}else{

Page 196: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jqXHR.readyState=1;

/*12linesofcode*/

try{

state=1;

transport.send(requestHeaders,done);

}catch(e){/*7linesofcode*/}

}

AnotherspecialthingaboutthisimplementationoftheBuilderPatternisthatitshouldbeabletooperateinbothsynchronousandasynchronousmanner.Asaresult,thesend()methodofthetransportobjectthatactsastheresultgeneratormethodofthewrappedjqXHRobjectcan’tjustreturnaresultobject,butitisinsteadinvokedwithacallback.

Finally,aftertherequestiscomplete,jQueryusesthegetResponseHeader()methodtoretrievealltherequiredresponseheaders.Rightafterthis,theheadersareusedtoproperlyconvertthereceivedresponsethatisstoredintheresponseTextpropertyofthejqXHRobject.

Page 197: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowtouseitinourapplicationsAsanexampleusecaseoftheBuilderPatterninaclient-sideapplicationthatusesjQuery,wewillcreateasimpledata-drivenmultiple-choicequiz.ThemainreasonthattheBuilderPatternisabettermatchforthiscase,ascomparedtotheFactoryPatternexamplethatwesawearlier,isthattheresultismorecomplexandhasmoredegreesofconfiguration.Eachquestionwillbegeneratedbasedonamodelobjectthatwillrepresentitsdesiredproperties.

Onceagain,therequiredHTMLisverysimple,containingjustan<h1>elementwiththeheaderofthepage,anempty<form>tag,andsomereferencestoourCSSandJavaScriptresources:

<h1>DataDrivenQuiz</h1>

<form></form>

<scripttype="text/javascript"src="jquery.js"></script>

<scripttype="text/javascript"src="datadrivenquiz.js"></script>

Besidesthecommon,simplestylesthatwehaveseeninthepreviouschapters,theCSSof

Page 198: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

thisexampleadditionallydefines:

ul.unstyled>li{

margin:0;

padding:0;

list-style:none;

}

Fortheneedsofthisexample,wewillcreateamodulewithanewnamespacenameddataDrivenQuiz.Aswesawearlierinthischapter,wewillassumetheexistenceofanarraycontainingthemodelobjectsthatdescribeeachmultiple-choicequestionthatneedstobepresented.Eachofthesemodelobjectswillhave:

AtitlepropertythatwillholdthequestionAnoptionspropertythatwillbeanarraywiththeavailableanswerstochoosefromAnoptionalacceptsMultiplepropertytosignifywhetherweshoulduseradioorcheckboxes

ThearraywiththemodelobjectsthatdescribetheformquestionswillbeavailableatthedataDrivenQuiz.partspropertyofourmodule,whilekeepinginmindthatourimplementationcouldeasilybemodifiedtofetchthemodelswithanAJAXrequest:

dataDrivenQuiz.questions=[{

title:'WhichisthemostpreferredwaytowriteourJavaScriptcode?',

options:[

'inlinealongwithourHTML',

'flatinside*.jsfiles',

'insmallModules,oneper*.jsfile'

]

},{

title:'Whatdoesthe$()functionreturnswheninvokedwithaCSS

selector?',

options:[

'asingleelement',

'anarrayofelements',

'theHTMLoftheselectedelement',

'aCompositeObject'

]

},{

title:'WhichofthefollowingareDesignPatterns',

acceptsMultiple:true,

options:[

'GarbageCollector',

'Class',

'ObjectLiteral',

'Observer'

]

},{

title:'Howcangetaholdtothe<body>elementofapage?',

acceptsMultiple:true,

options:[

'document.body',

'document.getElementsByTagName(\'body\')[0]',

'$(\'body\')[0]',

Page 199: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

'document.querySelector(\'body\')'

]

}];

TipDefiningthedatastructuresthatarerequiredtodescribeaproblem,beforestartingtheactualimplementation,allowsustofocusontheneedsoftheapplicationandgetanestimateofitsoverallcomplexity.

Giventheprecedingsampledata,let’snowproceedtotheimplementationofourBuilder:

functionMultipleChoiceBuilder(){

this.title='Untitled';

this.options=[];

}

dataDrivenQuiz.MultipleChoiceBuilder=MultipleChoiceBuilder;

MultipleChoiceBuilder.prototype.setTitle=function(title){

this.title=title;

returnthis;

};

MultipleChoiceBuilder.prototype.setAcceptsMultiple=

function(acceptsMultiple){

this.acceptsMultiple=acceptsMultiple;

returnthis;

};

MultipleChoiceBuilder.prototype.addOption=function(title){

this.options.push(title);

returnthis;

};

MultipleChoiceBuilder.prototype.getResult=function(){

var$header=$('<header>').text(this.title||'Untitled');

varquestionGuid='quizQuestion'+(jQuery.guid++);

var$optionsList=$('<ulclass="unstyled">');

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

var$input=$('<input/>').attr({

'type':this.acceptsMultiple?'checkbox':'radio',

'value':i,

'name':questionGuid,

});

var$option=$('<li>');

$('<label>').append($input,$('<span>').text(this.options[i]))

.appendTo($option);

$optionsList.append($option);

}

return$('<article>').append($header,$optionsList);

};

UsingthePrototypicalObject-OrientedapproachofJavaScript,wefirstlydefinetheConstructorFunctionforourMultipleChoiceBuilderclass.WhentheConstructor

Page 200: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Functionisinvokedusingthenewoperator,itwillcreateanewinstanceoftheBuilderandinitializeitstitlepropertyto"Untitled"andtheoptionspropertytoanemptyarray.

Rightafterthis,wecompletethedefinitionoftheConstructorFunctionofourBuilder,weattachitasamemberofourmodule,andcontinuewiththedefinitionofitssettermethods.FollowingthePrototypicalClassparadigm,thesetTitle(),setAcceptsMultiple(),andaddOption()methodsaredefinedaspropertiesofourBuilder’sPrototypeandareusedtomodifytheinternalstateoftheunderconstructionelement.Additionally,inordertoenableustochainseveralinvocationsofthesemethods,whichresultsinamorereadableimplementation,allofthemendwiththereturnthis;statement.

WecompletetheimplementationoftheBuilderwiththegetResult()methodthathasthedutyofgatheringalltheparametersthatareappliedontheBuilderobjectinstanceandgeneratingtheresultingelementwrappedinsideajQueryCompositeObject.Initsfirstline,itcreatesaheaderofthequestion.Rightafterthis,itcreatesa<ul>elementwiththeunstyledCSSclasstoholdthepossibleanswerstothequestionandauniqueidentifierthatwillbeusedasthenameofthegenerated<input>ofthequestion.

Intheforloopthatfollows,wewill:

Createan<input/>elementforeachoptionofthequestionProperlysetitstypeasacheckboxoraradiobutton,basedonthevalueoftheacceptsMultiplepropertyUsetheforloop’siterationnumberasitsvalueSettheuniqueidentifierthatwegeneratedearlierforthequestionastheinput’snameinordertogrouptheanswersFinally,adda<label>withtheoption’stext,whichwrapsalloftheminsidean<li>,andappendittothequestion’s<ul>.

Lastly,theheaderandthelistofoptionsarewrappedinan<article>element,whichisthenreturnedasthefinalresultoftheBuilder.

Intheaboveimplementation,weusethe$.fn.text()methodtoassignthecontentofthequestion’sheaderanditsavailablechoicesinsteadofstringconcatenation,inordertoproperlyescapethe<and>charactersthatarefoundintheirdescriptions.Asanextranote,sincesomeoftheanswersalsocontainsinglequotes,weneedtoescapetheminthemodelobjectsusingabackslash(\').

Finally,inourmodule’simplementation,wedefineandimmediatelyinvoketheinitmethod:

dataDrivenQuiz.init=function(){

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

varquestion=dataDrivenQuiz.questions[i];

varbuilder=newdataDrivenQuiz.MultipleChoiceBuilder();

builder.setTitle(question.title)

.setAcceptsMultiple(question.acceptsMultiple);

for(varj=0;j<question.options.length;j++){

builder.addOption(question.options[j]);

Page 201: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

}

$('form').append(builder.getResult());

}

};

$(document).ready(dataDrivenQuiz.init);

TheexecutionoftheinitializationcodeisdelayeduntiltheDOMtreeofthepageisfullyloaded.Thentheinit()methoditeratesoverthemodelobjectsarrayandusestheBuildertocreateeachquestionandpopulatethe<form>elementofourpage.

Agoodexerciseforthereaderwouldbetoextendtheaboveimplementationinordertosupporttheclient-sideevaluationofthequiz.Firstly,thiswouldrequireyoutoextendthequestionobjectstocontaininformationaboutthevalidityofeachchoice.Then,itwouldbesuggestedthatyoucreateaBuilderthatwouldretrievetheanswersfromtheform,evaluatethem,andcreatearesultobjectwiththeuserchoicesandtheoverallsuccessonthequiz.

Page 202: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 203: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedtheconceptsoftheBuilderandFactoryPatterns,twoofthemostcommonlyusedCreationalDesignPatterns.Weanalyzedtheircommongoals,theirdifferentapproachesonabstractingtheprocessofgeneratingandinitializingnewobjectsforspecificusecases,andhowtheiradoptioncanbenefitourimplementations.Finally,welearnedhowtousethemproperlyandhowtochoosethemostappropriateoneforthedifferentusecasesofanygivenimplementations.

NowthatwehavecompletedourintroductiontothemostimportantCreationalDesignPatterns,wecanmoveontothenextchapterwherewewillbeintroducedtothedevelopmentpatternsthatareusedtoprogramasynchronousandconcurrentprocedures.Inmoredetail,wewilllearnhowtoorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother,byusingcallbacksandjQueryDeferredandPromisesAPIs.

Page 204: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 205: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter7.AsynchronousControlFlowPatternsThischapterisdedicatedtodevelopmentpatternsthatareusedtoeasetheprogrammingofasynchronousandconcurrentprocedures.

Atfirst,wewillhavearefresheronhowCallbacksareusedinJavaScriptprogrammingandhowtheyareanintegralpartofwebdevelopment.Wewillthenproceedandidentifytheirbenefitsandlimitationswhenusedinlargeandcompleximplementations.

Rightafterthis,wewillbeintroducedtotheconceptofPromises.WewilllearnhowjQuery’sDeferredandPromiseAPIsworkandhowtheydifferfromES6Promises.WewillseewhereandhowtheyareusedinternallybyjQuerytosimplifyitsimplementationandleadtomorereadablecode.Wewillanalyzetheirbenefits,classifythebestmatchingusecases,andcomparethemwiththeclassicCallbackPattern.

Bytheendofthischapter,wewillbeabletousejQueryDeferredandPromisestoefficientlyorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother.

Inthischapter,wewill:

HavearefresheronhowCallbacksareusedinJavaScriptprogrammingGetintroducedtotheconceptofPromisesLearnhowtousejQuery’sDeferredandPromiseAPIsComparejQueryPromiseswithES6PromisesLearnhowtoorchestrateasynchronoustasksusingPromises.

Page 206: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ProgrammingwithcallbacksACallbackcanbedefinedasafunctionthatispassedasaninvocationargumenttoanotherfunctionormethod(whichisreferredtoasaHigher-OrderFunction)andisexpectedtobeexecutedatsomelaterpointoftime.Inthisway,thepieceofcodethatwashandedourCallbackwilleventuallyinvokeit,propagatingtheresultsofanoperationoreventbacktothecontextthattheCallbackwasdefined.

Callbackscanbecharacterizedassynchronousorasynchronous,basedonthewaythattheinvokedmethodoperates.ACallbackischaracterizedassynchronouswhenitisexecutedbyablockingmethod.Ontheotherhand,JavaScriptdevelopersaremorefamiliarwithasynchronouscallbacks,alsocalleddeferredcallbacks,whicharesettobeexecutedafteranasynchronousprocedurefinishesorwhenaspecificeventoccurs(pageload,click,AJAXresponsearrival,andsoon).

CallbacksarewidelyusedinJavaScriptapplicationssincetheyareanintegralpartofmanycoreJavaScriptAPIssuchasAJAX.Moreover,JavaScriptimplementationsofthispatternarealmostwordforwordasdescribedbytheabovesimpledefinition.ThisisaresultofthewaythatJavaScripttreatsfunctionsasobjectsandallowsustostoreandpassmethodreferencesassimplevariables.

Page 207: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingsimplecallbacksinJavaScriptPerhapsoneofthesimplestexamplesofasynchronouscallbacksinJavaScriptisthesetTimeout()function.Thefollowingcodedemonstratesasimpleuseofit,whereweinvokesetTimeout()withthedoLater()functionasacallbackparameterand,after1000millisecondsofwaiting,thedoLater()callbackisinvoked:

varalertMessage='Onesecondpassed!';

functiondoLater(){

alert(alertMessage);

}

setTimeout(doLater,1000);

Asseeninthesimpleprecedingexample,thecallbackisexecutedinthecontextthatitwasdefined.Thecallbackstillhasaccesstothevariablesofthecontextthatitwasdefinedbycreatingaclosure.Eventhoughtheprecedingexampleusesanamedfunctiondefinedearlier,thesameappliesforanonymouscallbacks:

varalertMessage='Onesecondpassed!';

setTimeout(function(){

alert(alertMessage);

},1000);

Inmanycases,usinganonymouscallbacksisamoreconvenientwayofprogramming,sinceitresultsinshortercodeandalsoreducesthereadabilitynoise,whichisaresultofdefiningseveraldifferentnamedfunctionsthatareusedonlyonce.

Page 208: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SettingcallbacksasobjectpropertiesAsmallvariationoftheabovedefinitionalsoexists,wherethecallbackfunctionisassignedtoapropertyofanobjectinsteadofbeingpassedasanargumentofamethodinvocation.Thisiscommonlyusedincaseswherethereareseveraldifferentactionsthatneedtotakeplaceduringorafteramethodinvocationiscompleted:

varc=newCountdown();

c.onProgress=function(progressStatus){/*...*/};

c.onDone=function(result){/*...*/};

c.onError=function(error){/*...*/};

c.start();

Anotherusecaseoftheabovevariantistoaddhandlersonobjectsthathavealreadybeeninstantiatedandinitialized.Agoodexampleofthiscaseisthewaywesetuparesulthandlerforsimple(non-jQuery)AJAXcalls:

varr=newXMLHttpRequest();

r.open('GET','data.json',true);

r.onreadystatechange=function(){

if(r.readyState!=4||r.status!=200){

return;

}

alert(r.responseText);

};

r.send();

Intheprecedingcode,wesetananonymousfunctionontheonreadystatechangepropertyoftheXMLHttpRequestobject.Thisfunctionactsasacallbackandisinvokedeverytimethereisastatechangeontheongoingrequest.Insideourcallback,wecheckwhethertherequesthascompletedwithasuccessfulHTTPstatuscodeanddisplayanalertwiththeresponsebody.Likeinthisexample,whereweinitiatetheAJAXcallbyinvokingthesend()methodwithoutpassinganyarguments,itiscommonforAPIsthatusethisvarianttoleadtominimalwaysofinvokingtheirmethods.

Page 209: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingcallbacksinjQueryapplicationsPerhapsthemostcommonwayinwhichcallbacksareusedinjQueryapplicationsisforeventhandling.Thisislogicalsincethefirstthingthateveryinteractiveapplicationshoulddoishandleandrespondtouseractions.Aswesawinearlierchapters,oneofthemostconvenientwaystoattacheventhandlerstoelementsisbyusingjQuery’s$.fn.on()method.

AnothercommonplacewherecallbacksareusedinjQueryisforAJAXrequests,wherethe$.ajax()methodhasthecentralrole.Moreover,thejQuerylibraryalsoprovidesseveralotherconvenientmethodstomakeAJAXrequeststhatarefocusedonthemostcommonusecases.Sinceallthesemethodsareexecutedasynchronously,theyalsoacceptacallbackasaparameter,asawaytomaketheretrieveddataavailablebacktothecontextthatinitiatedtheAJAXrequest.Oneoftheseconvenientmethodsis$.getJSON(),whichisawrapperaround$.ajax(),andisusedasabettermatchingAPItoexecuteAJAXrequeststhatintendtoretrieveJSONresponses.

OtherwidelyusedjQueryAPIsacceptingcallbacksareasfollows:

Theeffects-relatedjQuerymethodssuchas$.animate()The$(document).ready()method

Let’snowcontinuebydemonstratingacodeexamplewherealltheabovemethodsareused.

$(document).ready(function(){

$('#fetchButton').on('click',function(){

$.getJSON('AjaxContent.json',function(json){

console.log('doneloadingnewcontent');

$('#newContent').css({'display':'none'})

.text(json.data)

.slideDown(function(){

console.log('donedisplayingnewcontent');

});

});

});

});

TheprecedingcodefirstlydelaysitsexecutionuntiltheDOMtreeofthepagehasbeenfullyloadedandthenaddsanObserverforclicksonthe<button>withIDfetchButtonbyusingthejQuery’s$.fn.on()method.Whenevertheclickeventisfired,theprovidedcallbackwillbeinvokedandinitiateanAJAXcalltofetchtheAjaxContent.jsonfile.Fortheneedsofthisexample,weareusingasimpleJSONfile,likethefollowing:

{"data":"I'mthetextcontentfetchedbyanAJAXcall!"}

WhentheresponseisreceivedandtheJSONisparsedsuccessfully,thecallbackisinvokedwiththeparsedobjectasaparameter.Finally,thecallbackitselflocatesthepageelementwiththeIDnewContentinthepage,hidesit,andthensetsthedatafieldoftheretrievedJSONasitstextcontent.Rightafterthis,weusethejQuery$.fn.slideDown()

Page 210: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

methodthatmakesthenewlysetpagecontentappear,byprogressivelyincreasingitsheight.Finally,aftertheanimationiscomplete,wewritealogmessagetothebrowserconsole.

NoteFurtherdocumentationregardingjQuery’s$.ajax(),$.getJSON(),and$.fn.slideDown()methodscanbefoundathttp://api.jquery.com/jQuery.ajax/,http://api.jquery.com/jQuery.getJSON/,andhttp://api.jquery.com/slideDown/.

Keepinmindthatthe$.getJSON()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butworksasintendedwhenservedusinganywebserversuchasApache,IIS,ornginx.

Page 211: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WritingmethodsthatacceptcallbacksWhenwritingafunctionthatutilizesoneormoreasynchronousAPIs,thatalsodictatesthattheresultingfunctionwillbeasynchronousbydefinition.Inthatcase,itisobviousthatsimplyreturningaresultvalueisnotanoption,sincetheresultwillprobablybeavailableafterthefunctioninvocationhasalreadyfinished.

Theeasiestsolutionforasynchronousimplementationsistouseacallbackasaparameterofyourfunction,which,aswediscussedearlier,ishassle-freeinJavaScript.Asanexample,wewillcreateanasynchronousfunctionthatgeneratesarandomnumberofaspecifiedrange:

functiongetRandomNumberAsync(max,callbackFn){

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

callbackFn(result);

},runFor);

}

ThegetRandomNumberAsync()functionacceptsitsmaxargumentasthenumericupperboundforthegeneratedrandomnumberandalsoacallbackfunctionthatitwillinvokewiththegeneratedresult.ItusessetTimeout()toemulateanasynchronouscalculationthatrangesfrom1000to2000milliseconds.Forthegenerationoftheresult,itusestheMath.random()method,multiplyingitwiththemaximumallowedvalue,andfinallyinvokestheprovidedcallbackwithit.Asimplewaytoinvokethisfunctionwilllookasfollows:

getRandomNumberAsync(10,function(number){

console.log(number);//returnsanumberbetween0and10

});

EventhoughtheaboveexampleusessetTimeout()toemulateasynchronousprocessing,theimplementationprinciplesremainthesameregardlessoftheasynchronousAPI(s)thatisused.Forexample,wecanrewritetheabovefunctiontoretrieveitsresultthroughanAJAXcall:

functiongetRandomNumberWS(max,callbackFn,errorFn){

$.ajax({

url:'https://qrng.anu.edu.au/API/jsonI.php?length=1&type=uint16',

dataType:'json',

success:function(json){

varresult=json.data[0]/65535*max;

callbackFn(result);

},

error:errorFn

});

}

Theprecedingimplementationusesthe$.ajax()methodthatisinvokedwithanobjectparameter,enclosingalltheoptionsoftherequest.ExceptfortheURLfortherequest,theobjectalsodefinestheexpecteddataTypeoftheresultandthesuccessanderror

Page 212: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

callbacks,whicharewiredwiththerespectiveparametersofourfunction.

Perhapstheonlyextraconcernthattheprecedingcodehastoresolveishowtohandleerrorsinsidethesuccesscallbacksothatthecallerofthefunctioncanbenotifiedincasesomethinggoeswrongduringthecreationoftheresult.Forexample,theAJAXrequestmightreturnanemptyobject.Addingproperhandlingforsuchcasesisleftasanexerciseforthereader,afterreadingtherestofthischapter.

NoteTheAustralianNationalUniversity(ANU)providesfree,trulyrandom,numberstothepublic,throughtheirRESTWebService.Formoreinformation,youcanvisithttp://qrng.anu.edu.au/API/api-demo.php.

Page 213: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

OrchestratingcallbacksWewillnowcontinuebyanalyzingsomepatternsthatarecommonlyusedtocontroltheexecutionflowwhendealingwithasynchronousmethodsthatacceptcallbacks.

QueuinginorderexecutionAsourfirstexample,wewillcreateafunctionthatdemonstrateshowwecanqueuetheexecutionofseveralasynchronoustasks:

functiongetThreeRandomNumbers(callbackFn,errorFn){

varresults=[];

getRandomNumberAsync(10,function(number){

results.push(number);

getRandomNumberAsync(10,function(number){

results.push(number);

getRandomNumberWS(10,function(number){

results.push(number);

callbackFn(results);

},function(error){

errorFn(error);

});

});

});

}

Intheprecedingimplementation,ourfunctioncreatesaqueueofthreerandomnumbergenerations.ThefirsttworandomnumbersaregeneratedfromoursamplesetTimeout()implementationandthethirdisretrievedfromtheaforementionedwebservicethoughanAJAXcall.Inthisexample,allthenumbersaregatheredintheresultarray,whichispassedasaninvocationparametertothecallbackFnafteralltheasynchronoustaskshavecompleted.

TheprecedingimplementationisquitestraightforwardandjustappliesthesimpleprinciplesoftheCallbackPatternrepeatedly.Foreveryextraorqueuedasynchronoustask,wejustneedtonestitsinvocationinsidethecallbackofthetaskthatitdependson.Keepinmindthat,indifferentusecases,wemightonlycaretoreturntheresultofthefinaltaskandhavetheresultsoftheintermediatestepsbepropagatedasargumentsforeachsubsequentasynchronouscall.

AvoidingtheCallbackHellanti-pattern

Eventhoughwritingcodeasshownintheaboveexampleiseasy,whenappliedtolargeandcompleximplementations,itcanleadtobadreadability.Thetriangularshapethatiscreatedbythewhite-spacesinfrontofourcodeandthestackingofseveral});nearitsend,arethetwosignsthatourcodemightleadtoananti-patternknownasCallbackHell.

NoteFormoreinformation,youcanvisithttp://callbackhell.com/.

Page 214: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Awaytoavoidthisanti-patternistounfoldthenestedcallbacks,bycreatingseparatenamedfunctionsatthesamelevelwiththeasynchronoustaskthattheyareused.Afterapplyingthissimpletiptotheaboveexample,theresultingcodelooksalotcleaner:

functiongetThreeRandomNumbers(callbackFn,errorFn){

varresults=[];

getRandomNumberAsync(10,function(number){//task1

results.push(number);

task2();

});

functiontask2(){

getRandomNumberAsync(10,function(number){

results.push(number);

task3();

});

}

functiontask3(){

getRandomNumberWS(10,function(number){

results.push(number);

callbackFn(results);

},errorFn);

}

}

Asyoucansee,theresultingcodesurelydoesnotremindusofthecharacteristicsoftheCallbackHellanti-pattern.Ontheotherhand,itnowneedsmorelinesofcodeforitsimplementation,mostlyusedfortheadditionalfunctiondeclarationsfunctiontaskX(){}thatarenowrequired.

TipAmiddlegroundsolutionbetweentheabovetwoapproachesistoorganizetherelatedpartsofsuchasynchronousexecutionqueuesinsmallandmanageablefunctions.

RunningconcurrentlyEventhoughJavaScriptinwebbrowsersissingle-threaded,makingindependentasynchronoustasksrunconcurrentlycanmakeourapplicationsworkfaster.Asanexample,wewillrewritetheprecedingimplementationtofetchallthreerandomnumbersinparallel,whichcanmaketheresulttoberetrievedalotfasterthanbefore:

functiongetRandomNumbersConcurent(callbackFn,errorFn){

varresults=[];

varresultCount=0;

varn=3;

functiongatherResult(resultPos){

returnfunction(result){

results[resultPos]=result;

resultCount++;

if(resultCount===n){

Page 215: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

callbackFn(results);

}

};

}

getRandomNumberAsync(10,gatherResult(0));

getRandomNumberAsync(10,gatherResult(1));

getRandomNumberWS(10,gatherResult(2),errorFn);

}

Intheprecedingcode,wedefinedthegatherResult()helperfunction,whichreturnsananonymousfunctionthatisusedasacallbackforourrandomnumbergenerators.ThereturnedcallbackfunctionusestheresultPosparameterastheindexofthearraywhereitwillstorethegeneratedorretrievedrandomnumber.Additionally,ittrackshowmanytimesithasbeeninvoked,asawaytoknowwhetherallthreeconcurrenttaskshaveended.Finally,rightafterthethirdandfinalinvocationofthecallback,thecallbackFnfunctionisinvokedwiththeresultsarrayasaparameter.

Anothergreatapplicationofthistechnique,otherthanAJAXcalls,istoaccessdatastoredinIndexedDB.Retrievingmanyvaluesfromthedatabaseconcurrentlycanleadtoperformancegains,sincethedataretrievalscanexecuteinparallelwithoutblockingeachother.

NoteFormoreinformationonIndexedDB,youcanvisithttps://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB.

Page 216: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 217: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheconceptofPromisesPromises,alsoknownasFutures,aredescribedbyComputerScienceasspecializedobjectsthatareusedforsynchronizationofasynchronous,concurrent,orparallelprocedures.Theyarealsousedasproxiestopropagatetheresultofataskwhenitsgenerationcompletes.Thisway,aPromiseobjectislikeacontractwhereanoperationwilleventuallycompleteitsexecution,andanyonehavingareferencetothiscontractcandeclaretheirinteresttobenotifiedabouttheresult.

SincetheywereintroducedtoJavaScriptdevelopers,aspartofseverallibraries,theyrevolutionizedthewayweuseasynchronousfunctionsandcomposetheminimplementationwithcomplexsynchronizationschemes.Thisway,webdeveloperscancreatemoreflexible,scalable,andreadableimplementations,makingmethodinvocationswithcallbackslooklikeaprimitivepatternandeffectivelyeliminatingtheCallbackHellsituations.

OneofthekeyconceptsofPromisesisthatasynchronousmethodsreturnanobjectthatrepresentstheireventualresult.EveryPromisehasaninternalstatethatinitiallystartsasPending.Thisinternalstatecanchangeonlyonce,fromPendingtoeitherResolvedorRejected,byusingoneoftheresolve()orreject()methodsthateveryimplementationprovides.ThesemethodscanbeinvokedonlytochangethestateofaPendingPromise;inmostcases,theyareintendedtobeusedonlybytheoriginalcreatorofthePromiseobjectandnotbeavailabletoitsconsumers.Theresolve()methodcanbeinvokedwiththe

Page 218: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

resultoftheoperationasasingleparameter,whilethereject()methodisusuallyinvokedwiththeErrorthatcausedthePromiseobjecttogetRejected.

AnotherkeyconceptofPromisesistheexistenceofathen()method,givingthemthecharacterizationofthe“thenable”,asageneraltermtodescribepromisesamongallthedifferentimplementations.EveryPromiseobjectexposesathen()methodthatisusedbyacallerinordertoprovidethefunction(s)thatwillbeinvokedwhenthePromiseissettled(ResolvedorRejected).Thethen()methodcanbeinvokedwithtwofunctionsasparameters,wherethefirstisinvokedincasethePromisegetsResolved,whilethesecondisinvokedwhenitisRejected.ThefirstargumentiscommonlyreferredtoastheonFulfilled()callback,whilethesecondisreferredtoastheonRejected().

EveryPromisepreservestwointernallistcontainingalltheonFulfilled()andonRejected()callbackfunctionsthatarepassedasargumentstothethen()method.Thethen()methodcanbeinvokedseveraltimesforeachPromise,addingnewentriestotheappropriateinternallist,asfarastherespectiveparameterisactuallyafunction.WhenaPromiseeventuallygetsResolvedorRejected,ititeratesovertheappropriatelistofcallbacksandinvokestheminorder.Moreover,fromthepointthataPromisegetssettledandafter,everyfurtherusageofthethen()methodhas,asaresult,theimmediateinvocationoftheappropriateprovidedcallback.

NoteBasedonitscharacteristics,aPromisecanbelikenedtoaBrokerfromthe

Page 219: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Publish/SubscribePatterntosomedegree.TheirkeydifferencesincludethefactsthatitcanonlybeusedforasinglePublishandthattheSubscribersgetnotifiedoftheresulteveniftheyexpressedtheirinterestafterthePublishtookplace.

Page 220: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingPromisesAswesaidearlier,theconceptofPromisesrevolutionizedprogrammingofasynchronoustasksinJavaScriptand,foralongtime,theywerethenewbigthingthateveryonewasenthusiasticabout.Atthattime,manyspecializedlibrariesappearedwhereeachoneprovidedanimplementationofPromiseswithslightdifferencestoeachother.Moreover,PromiseimplementationsbecameavailableaspartofutilitylibrariessuchasjQueryandwebframeworkssuchasAngularJSandEmberJS.Atthattime,the“CommonJSPromises/A”specificationmadeitsappearanceasareferencepointandwasthefirstattempttodefinehowPromisesshouldactuallyworkacrossallimplementations.

NoteFormoreinformationonthe“CommonJSPromises/A”specification,youcanvisithttp://wiki.commonjs.org/wiki/Promises/A.

UsingthejQueryPromiseAPIAPromise-basedAPIfirstappearedinthejQuerylibraryinv1.5,basedonthe“CommonJSPromises/A”design.ThisimplementationintroducedtheadditionalconceptoftheDeferredobject,whichworkslikeaPromiseFactory.TheDeferredobjectsexposeasupersetofthemethodsthatPromisesprovide,wheretheadditionalmethodscanbeusedtodomanipulationstothestateofitsinternalPromise.Additionally,theDeferredobjectexposesapromise()methodandreturnstheactualPromiseobject,whichdoesnotexposeanywaytomanipulateitsinternalstateandjustexposesobservationmethodssuchasthen().

Inotherwords:

OnlycodethathasareferencetoaDeferredobjectcanactuallychangetheinternalstateofitsPromise,byeitherresolvingorrejectingit.AnypieceofcodethathasareferencetoaPromiseobjectcan’tchangeitsstatebutjustobserveforitsstatetochange.

NoteFormoreinformationonjQuery’sDeferredobject,youcanvisithttp://api.jquery.com/jQuery.Deferred/.

AsasimpleexampleofjQuery’sDeferredobject,let’sseehowwecanrewritethegetRandomNumberAsync()functionthatwesawearlierinthischapter,tousePromisesinsteadofCallbacks:

functiongetRandomNumberAsync(max){

vard=$.Deferred();

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

d.resolve(result);

},runFor);

returnd.promise();

Page 221: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

}

getRandomNumberAsync(10).then(function(number){

console.log(number);//returnsanumberbetween0and10

});

OurtargetistomakeanasynchronousfunctionthatreturnsaPromisethatiseventuallyresolvedtotheresultingrandomnumber.Atfirst,anewDeferredobjectiscreatedandthentherespectivePromiseobjectisreturned,byusingthepromise()methodoftheDeferred.Whentheasynchronousgenerationoftheresultiscomplete,ourmethodusestheresolve()methodoftheDeferredobjecttosetthefinalstateofthePromisethatwasreturnedearlier.

Thecallerofourfunctionusesthethen()methodofthereturnedPromise,toattachacallbackthatwillbeinvokedwiththeresultasaparameterassoonasthePromisegetsResolved.Moreover,asecondcallbackcanalsobepassedinordertogetnotifiedincasethePromisegetsRejected.Animportantthingtonoticeisthat,byfollowingtheabovepatternwherefunctionsalwaysreturnPromisesandnevertheactualDeferredobjects,wecanbesurethatonlythecreatoroftheDeferredobjectcanchangethestateofthePromise.

UsingPromises/A+Aftersometimeofhands-onexperimentationwithCommonJSPromises/A,thecommunityidentifiedsomeoftheirlimitationsandalsorecommendedsomewaystoimprovethem.TheresultwasthecreationofthePromises/A+specification,asawaytoimprovetheexistingspecificationandalsoasasecondattempttounifythevariousavailableimplementations.ThemostimportantpartsofthenewspecificationfocusedonhowchainingPromisesshouldwork,makingthemevenmoreusefulandconvenienttoworkwith.

NoteFormoreinformationonthePromises/A+specification,youcanvisithttps://promisesaplus.com/.

Finally,thePromises/A+specificationwaspublishedaspartofthe6thversionofJavaScript,commonlyreferredasES6,thatwasreleasedasastandardonJune,2015.Asaresult,Promises/A+startedtobeimplementednativelyinbrowsers,removingtheneedtousecustomthird-partylibrariesandpushingmostoftheexistinglibrariestoupgradetheirsemantics.Asofwritingofthisbook,nativePromises/A+compliantimplementationshavebeenavailableinmostmodernbrowsers,exceptforIE11,makingthemavailableout-of-the-boxtomorethan65%ofwebusers.

NoteFormoreinformationontheadoptionofA+Promisesinbrowsers,youcanvisithttp://caniuse.com/#feat=promises.

ArewriteofthegetRandomNumberAsync()functionusingthenownativelyimplementedES6A+Promiseswilllookasfollows:

Page 222: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

functiongetRandomNumberAsync(max){

returnnewPromise(function(resolve,reject){

varrunFor=1000+Math.random()*1000;

setTimeout(function(){

varresult=Math.random()*max;

resolve(result);

},runFor);

});

}

getRandomNumberAsync(10).then(function(number){

console.log(number);//returnsanumberbetween0and10

});

Asyoucansee,ES6/A+PromisesarecreatedbyusingthePromiseconstructorfunctionwiththenewkeyword.Theconstructorisinvokedwithafunctionasaparameter,whichmakesaclosurethathasaccesstoboththevariablesofthecontextthatthePromiseiscreated,butalsogetsaccesstotheresolve()andreject()functionsasparameters,whichistheonlywaytochangethestateofthenewlycreatedPromise.AfterthesetTimeout()functionfiresitscallback,theresolve()functionisinvokedwiththegeneratedrandomnumberasaparameter,changingthestateofthePromiseobjecttoFulfilled.Finally,thecallerofourfunctionusesthethen()methodofthereturnedPromiseinexactlythesamewayaswesawintheearlierimplementationthatwasusingjQuery.

ComparingjQueryandA+PromisesWewillnowhaveanin-depthstep-by-stepanalysisofthecoreconceptsofthejQueryandA+PromiseAPIs,byalsodoingaside-by-sidecodecomparisonofthetwo.Thiscanbeagreatassettohave,sinceyouwillalsobeabletouseitasareferencewhiletheimplementationsofPromisesaregraduallyadaptingtotheES6A+specification.

Theneedtounderstandfromthebeginninghowthetwovariantsdifferseemsevengreater,sincethejQueryteamhasalreadyannouncedthatVersion3.0ofthelibrarywillhavePromises/A+compliantimplementation.Specifically,asofwritingthisbook,thefirstbetaversionisalreadyout,makingthetimethatthemigrationwillhappentoappearevencloser.

NoteFormoreinformationonjQueryv3.0A+Promisesimplementation,youcanvisithttp://blog.jquery.com/2016/01/14/jquery-3-0-beta-released/.

OneofthemostobviousdifferencesbetweenthetwoimplementationsisthewaythatnewPromisesarecreated.Aswesaw,jQueryusesthe$.Deferred()functionlikeafactoryofamorecomplexobjectthatprovidesdirectaccesstothestateofthePromiseandeventuallyextractstheactualPromiseusingaseparatemethod.Ontheotherhand,A+Promisesusethenewkeywordandafunctionasaparameter,whichwillbeinvokedbytheruntimewiththeresolve()andreject()functionsasparameters:

vard=$.Deferred();

Page 223: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

setTimeout(function(){

d.resolve(7);

},2000);

varp=d.promise();//jQueryPromise

varp=newPromise(function(resolve,reject){//Promises/A+

setTimeout(function(){

resolve(7);

},2000);

});

Moreover,jQueryalsoprovidesanotherwaytocreatePromisesthatlookmorelikethewaythatA+Promiseswork.Inthiscase,$.Deferred()canbeinvokedwithafunctionasanargumentthatreceivestheDeferredobjectasaparameter:

vard=$.Deferred(function(deferred){

setTimeout(function(){

deferred.resolve(7);

},2000);

});

varp=d.promise();

Aswediscussedearlier,thesecondpossibleoutcomeofaPromiseistobeRejected,afeaturethatnicelypairswiththeclassicalexceptionsofJavaScriptinsynchronousprogramming.RejectingaPromiseiscommonlyusedforcaseswhereanerroroccursduringtheprocessingoftheresult,orinsituationswheretheresultisnotvalid.WhileES6Promisesprovideareject()functionasanargumenttothefunctionpassedtoitsconstructor,injQuery’simplementationareject()methodissimplyexposedontheDeferredobjectitself.

varp=$.Deferred(function(deferred){

deferred.reject(newError('Somethinghappened!'));

}).promise();

varp=newPromise(function(resolve,reject){

reject(newError('Somethinghappened!'));

});

Inboththeimplementations,theresultofaPromisecanberetrievedusingthethen()method,whichcanbeinvokedwithtwofunctionsasarguments,onetohandlethecasethatthePromisegetsFulfilledandoneforthecasewhereitisRejected:

p.then(function(result){//worksthesameinjQuery&ES6

console.log(result);

},function(error){

console.error('Anerroroccurred:',error);

});

BothimplementationsalsoprovideconvenientmethodstohandlethecasewherethePromisegetsRejected,butwithdifferentmethodnames.Insteadofusingp.then(null,fn),ES6Promisesprovidethecatch()methodthatnicelypairswiththetry…catchJavaScriptexpression,whilejQuery’simplementationprovides,forthesamepurpose,thefail()method:

Page 224: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

p.fail(function(error){//jQuery

console.error(error);

});

p.catch(function(error){//ES6

console.error(error);

});

Moreover,asajQueryexclusivefeature,jQueryPromisesalsoexposeadone()andanalways()method.Thecallbacksprovidedtodone()areinvokedwhenthePromisegetsFulfilledandisequivalenttousingthethen()methodwithasingleparameter,whilethecallbacksofthealways()methodareinvokedwhenthepromisegetssettledinbothpossibleoutcomes.

NoteFormoreinformationondone()andalways(),youcanvisithttp://api.jquery.com/deferred.doneandhttp://api.jquery.com/deferred.always.

Finally,bothimplementationsprovideaneasywaytodirectlycreatePromisesthatarealreadyResolvedorRejected.Thiscanbeusefulasastartingvaluetoimplementcomplexsynchronizationschemesorasaneasywaytomakesynchronousfunctionstooperatelikeasynchronousones:

varpResolved=$.Deferred().resolve(7).promise();//jQuery

varpRejected=$.Deferred().reject(newError('Something

happened!')).promise();

varpResolved=Promise.resolve(7);//ES6

varpRejected=Promise.reject(newError('Somethinghappened!'));

Page 225: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AdvancedconceptsAnotherkeyconceptofPromisesthatmakesthemuniqueandgreatlyincreasestheirusefulnessistheabilitytoeasilycreatecompositionsofseveralPromisesthatinturnarePromisesthemselves.Compositionisavailableintwoforms,serialcompositionthatchainsPromisestogetherandparallelcompositionthatusesspecialmethodstojointheresolutionofconcurrentPromisesintoanewone.Aswesawearlierinthischapter,implementingsuchsynchronizationschemescanbehardtoimplementwiththetraditionalcallbackapproach.Promises,ontheotherhand,trytosolvethisprobleminamoreconvenientandreadableway.

Page 226: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 227: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ChainingPromisesEveryinvocationofthethen()methodreturnsanewPromise,whosebothfinalstatusandresultdependsonthePromisethatthethen()methodwascalledon,butisalsosubjecttothevaluereturnedbytheattachedcallbacks.Thisallowsustochaincallsofthethen()method,enablingustocomposePromisesbyseriallyjoiningthem.Thisway,wecaneasilyorchestratebothasynchronousandsynchronouscode,whereeachchainingsteppropagatesitsresulttothenextoneandallowsustoconstructthefinalresultinareadableanddeclarativeway.

Let’snowproceedtoanalyzingallthedifferentwaysthatchainingofcallstothethen()methodworks.SincewewillbefocusingontheconceptsofPromisecompositionbychaining,whichworksthesameasjQueryandES6Promises,let’ssupposethatthereisapvariablethatisholdingaPromiseobjectcreatedbyeitherofthefollowinglinesofcode:

varp=$.Deferred().resolve(7).promise();

//or

varp=Promise.resolve(7);

Thesimplestusecasethatdemonstratesthepowerofchainingiswhentheinvokedcallbackreturnsa(non-promise)value.ThenewlycreatedPromiseusesthereturnedvalueasitsresult,whilepreservingthesamestateasthePromisethatthethen()methodwascalledon:

p.then(function(x){//worksthesameinjQuery&ES6

console.log(x);//logs7

returnx*3;

}).then(function(x){

console.log(x);//logs21

});

Aspecialcasetohaveinmindisthatfunctionsthatdonotreturnanythingasaresultarehandledlikereturningundefined.ThisessentiallyremovestheresultvaluefromthenewlyreturnedPromise,whichnowonlypreservestheparentsettlementstatus:

p.then(function(x){//worksthesameinjQuery&ES6

console.log(x);//logs7

}).then(function(x){

console.log(x);//logsundefined

});

InthecasewheretheinvokedcallbackreturnsanotherPromise,itsstateandresultareusedforthePromisereturnedbythethen()method:

p.then(function(x){//forjQueryPromises

console.log(x);//logs7

vard2=$.Deferred();

setTimeout(function(){

d2.resolve(x*3);

},2000);

returnd2.promise();

}).then(function(x){

Page 228: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

console.log(x);//logs21

});

p.then(function(x){//fortheA+Promises

console.log(x);//logs7

returnnewPromise(function(resolve){

setTimeout(function(){

resolve(x*3);

},2000);

});

}).then(function(x){

console.log(x);//logs21

});

TheprecedingcodesamplesdemonstratetheimplementationsforboththejQueryandA+Promises,andbothhaveequivalentresults.Inbothcases,7isloggedintotheconsolefromthefirstthen()methodinvocationandanewPromiseisthenreturnedthatwillbeResolvedatalatertimeusingsetTimeout().After2000milliseconds,thatsetTimeout()willfireitscallback,thereturnedPromisewillbeResolvedwith21asavalueand,atthatpoint,21willalsobeloggedintotheconsole.

OneextrathingtonoteisthecasewheretheoriginalPromisegetssettledandthereisnoappropriatecallbackprovidedtothechainedthen()method.Inthiscase,thenewlycreatedPromisesettlestothesamestateandresult,asthePromisewherethethen()methodwascalledon:

p.then(null,function(error){//worksthesameinjQuery&ES6

console.error('Anerrorhappened!');//doesnotrun,sincethepromise

isresolved

}).then(function(x){

console.log(x);//logs7

});

Intheprecedingexample,thecallbackwiththeconsole.errorstatementthatispassedasthesecondargumentofthethen()method,doesnotgetinvokedsincethePromiseisresolvedwith7asitsvalue.Asaresult,thecallbackofthechaineventuallyreceivesanewPromise,whichisalsoresolvedwith7asitsvalueandlogsthatintheconsole.SomethingtohaveinmindinordertodeeplyunderstandhowchainingofPromisesworks,isthatp!=p.then()inallcases.

Page 229: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HandlingthrownerrorsThefinalconceptofchainingdefinesthecasewhereexceptionsarethrownduringtheinvocationofathen()callback.ThePromise/A+specificationdefinedthatthenewlycreatedPromiseisRejectedandthatitsresultistheErrorthatwasthrown.Moreover,theRejectionwillbubblethroughtheentirechainofPromises,enablingustobenotifiedaboutanyerrorinthechainonlydefiningtheerrorhandlingonce,neartotheendofthechain.

Unfortunately,thisisnotconsistentintheimplementationofthelateststableversionofjQuery,whichasofthewritingofthisbookisv2.2.0:

$.Deferred().resolve().promise().then(function(){

thrownewError('Somethinghappened!');

//theexecutionstopshere

}).then(null,function(x){

console.log(x);//nothinggetsprinted

});

$.Deferred().resolve().promise().then(function(){

try{//thisisaworkaround

thrownewError('Somethinghappened!');

}catch(e){

return$.Deferred().reject(e).promise();

}

}).then(function(){

console.log('Success');//notprinted

}).then(null,function(x){//almostequivalentto.fail()

console.log(x);//logs'Somethinghappened!''

});

Promise.resolve().then(function(){

thrownewError('Somethinghappened!');

}).then(function(){

console.log('Success');//notprinted

}).then(null,function(x){//equivalentto.catch()

console.log(x);//logs'Somethinghappened!''

});

Inthefirstcase,theexceptionthatisthrownstopstheexecutionofthePromisechain.Theonlywayarounditisprobablyexplicitlyaddingatry…catchstatementinsidethecallbackthatispassedtothethen()method,asshowninthesecondcasethatisdemonstrated.

Page 230: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

JoiningPromisesTheotherwayoforchestratingPromisesthatrunconcurrentlyisbycomposingthemtogether.Asanexample,let’ssupposetheexistenceoftwoPromises,p1andp2,thatgetresolvedwith7and11astheirvalues,after2000and3000milliseconds,respectively.SincethesetwoPromisesareexecutedconcurrently,thecomposedPromisewillonlyneed3000millisecondstogetResolved,asitisthegreaterofthetwodurations:

//jQuery

$.when(p1,p2).then(function(result1,result2){

console.log('p1',result1);//logs7

console.log('p2',result2);//logs11

//thiscanbeusedtomakeourcodelooklikeA+

varresults=arguments;

});

//A+

Promise.all([p1,p2]).then(function(results){

console.log('p1',results[0]);//logs7

console.log('p2',results[1]);//logs11

});

BothPromiseAPIsprovideaspecializedfunctionthatallowsustoeasilycreatePromisecompositionsandalsoretrievetheindividualresultsofthecomposition.AcomposedPromisegetsResolvedwhenallitspartsgetResolved,whileitgetsRejectedwhenanyoneofitspartsgetsRejected.Unfortunately,thetwoPromiseAPIsdiffer,notonlybythenameofthefunctions,butalsobythewaytheyareinvokedandthewaytheyprovidetheirresults.

ThejQueryimplementationprovidesthe$.when()methodthatcanbeinvokedwithanynumberofargumentsthatwewanttobecomposed.Byusingthethen()methodonacomposedjQueryPromise,wecangetnotifiedwhenthecompositiongetssettledasawholeandalsoaccesseachindividualresultasargumentsofourcallback.

Ontheotherhand,theA+PromisesspecificationprovidesusthePromise.all()methodthatisinvokedwithanarrayasitssingleparameterthatcontainsallthePromisesthatwewanttogetcomposed.ThereturnedcomposedPromisedoesnotdifferatallfromthePromisesthatwehaveseensofarandthecallbackofthethen()methodisinvokedwithanarrayasitsparameter,whichcontainsalltheresultsofthePromisesthatarepartofthecomposition.

Page 231: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HowjQueryusesPromisesAtthetimethatjQueryaddedanimplementationofPromisestoitsAPI,italsostartedtoexposeitthroughotherasynchronousmethodsofitsAPI.Perhapsthemostwell-knownexampleofthiskindisthemethodofthe$.ajax()familythatreturnsajqXHRobject,whichisaspecializedPromiseobjectthatalsoprovidessomeextramethodsrelatedtotheAJAXrequest.

NoteFormoreinformationonthejQuery’s$.ajax()methodandthejqXHRobject,youcanvisithttp://api.jquery.com/jQuery.ajax/#jqXHR.ThejQueryteamalsodecidedtochangetheimplementationofseveralinternalpartsofthelibrarytousePromises,inordertoimprovetheirimplementations.Firstofall,the$.ready()methodisimplementedusingPromisessothattheprovidedcallbacksfireevenifthepagehasalreadybeenloadedalongtimebeforeitsinvocation.Also,someofthecomplexanimationsthatjQueryprovidesusePromisesinternallyasthepreferredwaytosynchronizetheexecutionofthesequentialpartsoftheanimationqueue.

Page 232: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TransformingPromisestoothertypesDevelopingbyusingseveraldifferentJavaScriptlibrariesoftenmakesmanyPromiseimplementationsavailabletoourprojectsthatunfortunatelytendtohavedifferentlevelsofcompliancetothereferencePromisesspecification.ComposingPromisesreturnedbythemethodsofdifferentlibrariescanoftenleadtoproblemsthatarehardtotrackandresolve,asaresultoftheirimplementationinconsistencies.

Inordertoavoidconfusionsinsuchsituations,itisn’tconsideredagoodpracticetotransformallthePromisestoasingletypebeforeattemptingtocomposethem.ThesuggestedtypeforsuchsituationsisthePromises/A+specification,sincenotonlyisitwidelyacceptedbythecommunitybutitisalsopartofthenewlyreleasedversionofJavaScript(theES6languagespecification)thatisalreadynativelyimplementedinmanybrowsers.

TransformingtoPromises/A+Forexample,let’sseehowajQueryPromisecanbetransformedtoanA+Promisethatisavailableinmostrecentbrowsers:

varjqueryPromise=$.Deferred().resolve('IwillbeA+

compliant').promise();

varp=Promise.resolve(jqueryPromise);

p.then(function(result){

console.log(result);

});

Intheprecedingexample,thePromise.resolve()methoddetectsthatithasbeeninvokedwitha“thenable”andthatthenewlycreatedA+PromisethatisreturnedbindsitsstatusandresulttothoseoftheprovidedjQueryPromise.Thisisessentiallyequivalenttodoingsomethingasfollows:

varp=newPromise(function(resolve,reject){

jqueryPromise.then(resolve,reject);

});

Ofcourse,thisisnotlimitedtoPromisesthatarecreatedbydirectinvocationsofthe$.Deferred()method.TheabovetechniquecanalsobeusedtotransformPromisesthatarereturnedbyanyjQuerymethod.Forexample,thisishowitcanbeusedwiththe$.getJSON()method:

varaPlusAjaxPromise=Promise.resolve($.getJSON('AjaxContent.json'));

aPlusAjaxPromise.then(function(result){

console.log(result);

});

TransformingtojQueryPromisesEventhoughIwouldgenerallynotrecommendthis,itisalsopossibletotransformanyPromisetoajQueryvariant.ThenewlycreatedjQueryPromisereceivesalltheextrafunctionalitiesthatjQueryprovides,butthetransformationisnotasstraightforwardasthepreviousone:

Page 233: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

varaPromise=Promise.resolve('IwillbeajQueryPromise');

varp=$.Deferred(function(deferred){

aPromise.then(function(result){

returndeferred.resolve(result);

},function(error){

returndeferred.reject(error);

});

}).promise();

p.then(function(result){

console.log(result);

});

YoushouldonlyusetheprecedingtechniqueincaseswhereyouneedtoextendabigwebapplicationthatisalreadyimplementedusingjQueryPromises.Ontheotherhand,youshouldalsoconsiderupgradingsuchimplementations,sincethejQueryteamhasalreadyannouncedthatVersion3.0ofthelibrarywillhavePromises/A+compliantimplementation.

NoteFormoreinformationonjQueryv3.0A+Promisesimplementation,youcanvisithttp://blog.jquery.com/2016/01/14/jquery-3-0-beta-released/.

Page 234: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummarizingthebenefitsofPromisesOverall,thebenefitsofusingPromisesoverplainCallbacksinclude:

HavingaunifiedwaytohandletheresultofasynchronousinvocationsHavingpredictableinvocationparametersfortheusedcallbacksTheabilitytoattachmultiplehandlersforeachoutcomeofthePromiseTheguaranteethattheappropriateattachedhandlerswillexecuteevenifthePromisehasalreadybeenResolved(orRejected)Theabilitytochainasynchronousoperations,makingthemruninorderTheabilitytoeasilycreatecompositionsofasynchronousoperations,makingthemrunconcurrentlyTheconvenientwayofhandlingerrorsinPromisechains

UsingamethodthatreturnsaPromiseremovestheneedtodirectlypassfunctionsofonecontexttoanotherasaninvocationargumentandthequestionregardingwhichparametersareusedasthesuccessandtheerrorCallbacks.Moreover,wealreadyknowtosomedegreehowtoretrievetheresultofanyoperationthatreturnsaPromise,byusingthethen()method,evenbeforereadingthedocumentationaboutthemethod’sinvocationparameters.

Lessparametersoftenmeanslesscomplexity,smallerdocumentation,andlesssearchingeverytimewewanttodoamethodinvocation.Evenbetter,thereisagoodchancethattherewillonlybeasingleorafewparameters,makingtheinvocationmoresensibleandreadable.Theimplementationofasynchronousmethodsalsobecomeslesscomplex,sincethereisnolongertheneedtoacceptcallbackfunctionsasanextraargumentorhavingtoproperlyinvokethemwiththeresult.

Page 235: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 236: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,weanalyzedthedevelopmentpatternsthatareusedtoprogramasynchronousandconcurrentprocedures.Wealsolearnedhowtousethemtoefficientlyorchestratetheexecutionofasynchronousproceduresthatruneitherinorderorparalleltoeachother.

Atfirst,wehadarefresheronhowCallbacksareusedinJavaScriptprogrammingandhowtheyareanintegralpartofwebdevelopment.Weanalyzedtheirbenefitsandlimitationswhenusedinlargeandcompleximplementations.

Rightafterthis,wewereintroducedtotheconceptsofPromises.WelearnedhowjQuery’sDeferredandPromiseAPIsworkandhowtheydifferfromES6Promises.WealsosawwhereandhowtheyareusedinternallybyjQueryitself,asanexampleofhowtheycanleadtomorereadablecodeandsimplifysuchcompleximplementations.

Inthenextchapter,wewillproceedtolearninghowtodesign,create,anduseMockObjectsandMockServicesinourapplications.WewillanalyzethecharacteristicsthataproperMockObjectshouldhaveandunderstandhowtheycanbeusedasrepresentativeusecasesandevenastestcasesforourcode.

Page 237: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 238: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter8.MockObjectPatternInthischapterwewillshowcasetheMockObjectPattern,apatterntofacilitatethedevelopmentofapplicationswithoutactuallybeingpartofthefinalimplementation.Wewilllearnhowtodesign,createandusethisindustry-standarddesignpatterninordertocoordinateandcompletethedevelopmentofmulti-partjQueryapplicationsfaster.WewillanalyzethecharacteristicsthataproperMockObjectshouldhaveandunderstandhowtheycanbeusedasrepresentativeusecasesandevenastestcasesforourcode.

WewillseehowgoodapplicationarchitecturemakesiteasierforustouseMockObjects&Servicesbymatchingindividualpartsoftheapplication,andalsorealizethebenefitsofusingthemduringdevelopment.Bytheendofthischapter,wewillbeabletocreateMockObjects&Servicestoacceleratetheimplementationofourapplicationandalsotogetasenseoftheoverallfunctionalitylongbeforeallofitspartsarecompleted.

Inthischapter,weshall:

IntroducetheMockObjectandMockServicePatternsAnalyzethecharacteristicsthatMockObjects&ServicesshouldhaveUnderstandwhytheyfitbetterwithapplicationswithgoodarchitectureLearnhowtousetheminjQueryapplicationsasawaytodrivethedevelopmentandaccelerateit

Page 239: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingtheMockObjectPatternThekeyconceptoftheMockObjectPatternisincreatingandusingadummyobjectthatsimulatesthebehaviorofamorecomplexobjectthatis(orwillbe)partofanimplementation.TheMockObjectshouldhavethesameAPIastheactual(orreal)object,returnsimilarresultsusingthesamedatastructures,andalsooperateinasimilarmannerwithregardstohowitsmethodsalteritsexposedstate(theproperties).

MockObjectsareusuallycreatedduringtheearlydevelopmentphasesofanapplication.TheirprimaryusecaseistoenableustoproceedwiththedevelopmentofaModule,evenifitdependsonothersthathavenotyetbeenimplemented.MockObjectscanalsobedescribedasprototypesofthedataexchangedbetweenthedifferentpartsoftheimplementation,actinglikecontractsbetweenthedevelopersandeasingtheparalleldevelopmentofinterdependentmodules.

TipInthesamewaythattheprinciplesoftheModulePatterndecoupletheimplementationsofthedifferentpartsofanapplication,creatingandusingMockObjectsandMockServicesdecouplestheirdevelopment.

CreatingMockObjectsforeveryModulebeforestartingtheirimplementationclearlydefinesthedatastructuresandAPIsthatwillbeusedbytheapplication,removinganymisconceptionsandenablingustodetectinsufficienciesintheproposedAPIs.

TipDefiningthedatastructuresthatarerequiredtodescribeaproblembeforestartingtheactualimplementationallowsustofocusontheneedsoftheapplicationandgetanideaofitsoverallcomplexityandstructure.

YoucanalwaystestanypartofyourimplementationafteranycodechangebyusingtheMockObjectsthatwerecreatedfortheoriginalimplementation.YoucanbesurethattheoriginalusecasestillworksbyusingtheMockObjectsonthemodifiedmethods.Thisisveryusefulwhenthemodifiedimplementationisapartofausecaseinvolvingseveralstages.

MockObjectsareespeciallyusefulfortracingerrorsiftheimplementationofaModulehaschangedandcausedtherestoftheapplicationtomisbehave.ByusingtheexistingMockObjects,wecaneasilyidentifytheModulethatdivergedfromtheoriginalspecification.Moreover,thesameMockObjectscanbeusedasthebasisforhighqualitytestcasessincetheyoftencontainmorerealisticsampledata,somethingespeciallyusefulifyourteamisfollowingaTestDrivenDevelopment(TDD)paradigm.

NoteInTestDrivenDevelopment(TDD),thedeveloperfirstlydefinesatestcaseforausecaseoranewfeaturethatneedstobeaddedandthenproceedswithitsimplementationbytryingtosatisfythecreatedtestcase.Formoreinformation,youcanvisit:

Page 240: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

https://www.packtpub.com/books/content/overview-tdd.

TheMockObjectPatterniscommonlyusedamongfrontendwebdeveloperstodecoupletheclient-sidedevelopmentfromthewebservicesthatthebackendwillexpose.Thathasledtowittycommentssuchas:

“Thewebservicewillalwaysbelate&changesuddenly,souseaMockinstead.”

Summarizingallofthis,themainreasonstocreateMockObjectsandServicesinclude:

Theactualobjectorserviceisnotyetimplemented.Theactualobjectisdifficulttosetupforaspecificusecase.Weneedtoemulatearareornon-deterministicbehavior.Theactualobjectbehavesinawaythatishardtoreproduce,suchasnetworkerrorsorUIevents.

Page 241: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 242: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingMockObjectsinjQueryapplicationsInordertodemonstratehowtheMockObjectPatterncanbeusedduringthedevelopmentofamulti-partapplication,wewillextendthedashboardexample,aswesawinChapter4,DivideandConquerwiththeModulePattern,inordertopresentthumbnailsofYouTubevideosfromwebdevelopingconferences.Thevideoreferencesaregroupedintofourpredefinedcategoriesandtherelatedbuttonswillbedisplayedbasedonthecurrentcategoryselection,asillustratedbelow:

ThechangesthatneedtobeintroducedtotheHTMLandtheCSSareminimal.TheonlyextraCSSthatisneededfortheaboveimplementation,whencomparedtotheexistingimplementationfromChapter4,DivideandConquerwiththeModulePattern,isrelatedtothewidthofthethumbnails:

.boximg{

width:100%;

}

ThechangeintheHTMLisintendedtoorganizethe<button>elementsofeachcategory.ThischangewillmakeourimplementationmorestraightforwardsincethecategoriesandtheiritemsarenolongerstaticallydefinedintheHTMLbutareinsteadcreateddynamically,drivenbytheavailabledata.

<!--…-->

<sectionclass="dashboardCategories">

Page 243: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

<selectid="categoriesSelector"></select>

<divclass="dashboardCategoriesList"></div>

<divclass="clear"></div>

</section>

<!--…-->

IntheabovepieceofHTML,the<div>elementwiththedashboardCategoriesListCSSclass,willbeusedasacontainerforthegroupedbuttonsofthedifferentvideocategories.AftercoveringtheUIelements,let’snowmoveontotheanalysisoftheJavaScriptimplementation.

Page 244: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DefiningtheactualservicerequirementsThevideoreferencestobedisplayedinourdashboardcouldberetrievedfromvarioussources.Forexample,youcouldmakeadirectcalltoYouTube’sclient-sideAPIoranAJAXcalltoabackendwebservice.Inalloftheabovecases,itisconsideredagoodpracticetoabstractthisdataretrievalmechanismintoaseparatemodule,followingthecodestructuringrecommendationsofthepreviouschapters.

Forthisreason,weneedtoaddanextramoduletotheexistingimplementation.Thiswillbeaservice,responsibleforprovidingthemethodsthatwillallowustoretrievethemostrelevantvideosfromeachcategoryandloadinformationforeachvideoindividually.ThiswillbeachievedbyusingthesearchVideos()andgetVideo()methodsrespectively.

Aswehavealreadysaid,oneofthemostimportantphasesofeachimplementation,especiallyincaseofparalleldevelopment,istheanalysisanddefinitionofthedatastructurestobeused.SinceourdashboardwillbeusingtheYouTubeAPI,weneedtocreatesomesampledatawhichfollowitsdatastructurerules.AfterinspectingtheAPI,weendupwithasub-setofthefieldsthatarerequiredforourdashboard,andcanproceedtocreateaJSONobjectwithmockdatatodemonstratetheuseddatastructure:

{

"items":[{

"id":{"videoId":"UdQbBq3APAQ"},

"snippet":{

"title":"jQueryUIDevelopmentTutorial:jQueryUITooltip|

packtpub.com",

"thumbnails":{

"default":{"url":

"https://i.ytimg.com/vi/UdQbBq3APAQ/default.jpg"},

"medium":{"url":

"https://i.ytimg.com/vi/UdQbBq3APAQ/mqdefault.jpg"},

"high":{"url":"https://i.ytimg.com/vi/UdQbBq3APAQ/hqdefault.jpg"

}

}

}

}/*,...*/]

}

NoteFormoreinformationabouttheYouTubeAPI,youcanvisit:https://developers.google.com/youtube/v3/getting-started.

Ourserviceprovidestwocoremethods,oneforsearchingforvideosinaspecifiedcategoryandoneforretrievinginformationaboutaspecificvideo.Thestructureofthesampleobjectisusedforthesearchmethodtoretrieveasetofrelevantitems,whilethemethodforretrievinginformationforasinglevideousesthedatastructureofeachindividualitem.TheresultingimplementationforthevideoinformationretrievalisinaseparatemodulenamedvideoService,whichwillbeavailableonthedashboard.videoServicenamespace,andourHTMLwouldcontaina<script>referencelikethefollowing:

Page 245: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

<scripttype="text/javascript"src="dashboard.videoservice.js"></script>

Page 246: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImplementingaMockServiceChangingthe<script>referencesoftheserviceimplementationwiththeMockServiceandviceversashouldleaveuswithaworkingapplication,helpingusprogressandtesttherestoftheimplementationbeforetheactualimplementationofthevideoserviceisfinished.Asaresult,theMockServiceneedstousethesamedashboard.videoServicenamespace,butitsimplementationshouldbeinadifferentlynamedfilesuchasdashboard.videoservicemock.jsthatsimplyaddsthe“mock”suffix.

Aswehavealreadymentioned,itisagoodpracticetoplaceallourmockdataunderasinglevariable.Moreover,iftherearealotofMockedObjects,itiscommontoplacetheminadifferentfilealtogether,withanestednamespace.Inourcase,thefilewiththemockdataisnameddashboard.videoservicemock.mockdata.jsanditsnamespaceisdashboard.videoService.mockData,whileexposingthesearchesandvideospropertiesthatwillbeusedbythetwocoremethodsofourMockService.

EventhoughtheimplementationsofMockServicesshouldbesimple,theyhavetheirowncomplexitysincetheyneedtoprovidethesamemethodsasthetargetimplementations,acceptthesamearguments,andlookasiftheyareoperatingintheexactsameway.Forexample,inourcase,thevideoretrievalserviceneedstobeasynchronousanditsimplementationneedstoreturnPromises:

(function(){//dashboard.videoservicemock.js

'usestrict';

dashboard.videoService=dashboard.videoService||{};

dashboard.videoService.searchVideos=function(searchKeywords){

return$.Deferred(function(deferred){

varsearches=dashboard.videoService.mockData.searches;

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

if(searches[i].keywords===searchKeywords){

//returnthefirstmatchingsearchresults

deferred.resolve(searches[i].data);

return;

}

}

deferred.reject('Notfound!');

}).promise();

};

dashboard.videoService.getVideo=function(videoTitle){

return$.Deferred(function(deferred){

varvideos=dashboard.videoService.mockData.allVideos;

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

if(videos[i].snippet.title===videoTitle){

//returnthefirstmatchingitem

deferred.resolve(videos[i]);

return;

}

}

deferred.reject('Notfound!');

Page 247: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

}).promise();

};

varvideoBaseUrl='https://www.youtube.com/watch?v=';

dashboard.videoService.getVideoUrl=function(videoId){

returnvideoBaseUrl+videoId;

};

})();

AsshownintheMockServiceimplementationabove,thesearchVideos()andgetVideo()methods,areiteratingoverthearrayswiththemockdataandreturnaPromisethatiseitherResolvedwithanappropriateMockObjectorRejectedwhensuchanobjectisnotfound.Finally,youcanseebelowthecodeforthesub-modulecontainingtheMockObjects,followingthedatastructurethatwedescribedearlier.NotethatwestoretheMockObjectsofallcategoriesintheallVideospropertyinordertomakesearchingwiththemockgetVideo()methodsimpler.

(function(){//dashboard.videoservicemock.mockdata.js

'usestrict';

dashboard.videoService.mockData=dashboard.videoService.mockData||

{};

dashboard.videoService.mockData.searches=[{

keywords:'jQueryconference',

data:{

"items":[/*...*/]

}

}/*,...*/];

varallVideos=[];

varsearches=dashboard.videoService.mockData.searches;

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

allVideos=allVideos.concat(searches[i].data.items);

}

dashboard.videoService.mockData.allVideos=allVideos;

})();

ExperimentingwiththeimplementationofsomeMockServiceswillgetyoufamiliarwiththeircommonimplementationpatternsinaveryshortperiodoftime.Beyondthat,youwillbeabletoeasilycreateMockObjectsandServices,helpingyoudesigntheAPIsofyourapplications,trythemoutbyusingthemocksandfinallysettleonthebestmatchingmethodsanddatastructuresforeachusecase.

TipUsingthejQueryMockjaxlibrary

TheMockjaxjQueryPluginlibrary(availableathttps://github.com/jakerella/jquery-mockjax)focusesonprovidingasimplewayofmockingorsimulatingAJAXrequestsandresponses.ThisreducesthecodeneededtofullyimplementyourownMockServices,ifallthatyouneedistointerceptanAJAXrequesttoawebserviceandreturnaMock

Page 248: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Objectinstead.

Page 249: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingtheMockServiceInordertoaddthefunctionalitythatwedescribedearliertotheexistingdashboardimplementation,weneedtointroducesomechangestothecategoriesandtheinformationBoxmodules,addingthecodethatwillconsumethemethodsofourservice.AsarepresentativeexampleofusingthenewlycreatedMockService,let’stakealookattheimplementationoftheopenNew()method,intheinformationBoxmodule:

dashboard.informationBox.openNew=function(itemName){

var$box=$('<divclass="boxsizer"><articleclass="box">'+

'<headerclass="boxHeader">'+

'<buttonclass="boxCloseButton">&#10006;</button>'+

itemName+

'</header>'+

'<divclass="boxContent">Loading…</div>'+

'</article></div>');

$boxContainer.append($box);

dashboard.videoService.getVideo(itemName).then(function(result){

var$a=$('<a>').attr('href',

dashboard.videoService.getVideoUrl(result.id.videoId));

$a.append($('<img/>').attr('src',

result.snippet.thumbnails.medium.url));

$box.find('.boxContent').empty().append($a);

}).fail(function(){

$buttonContainer.html('Anerroroccurred!');

});

};

ThismethodinitiallyopensanewinformationboxwithaLoading…labelasitscontentandusesthedashboard.videoService.getVideo()methodtoretrievethedetailsoftherequestedvideoasynchronously.Finally,whenthereturnedPromisegetsresolved,itreplacestheLoading…labelwithananchorcontainingthethumbnailofthevideo.

Page 250: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 251: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedhowtodesign,createanduseMockObjectsandMockServicesinourapplications.WeanalyzedthecharacteristicsthatMockObjectsshouldhaveandunderstoodhowtheycanbeusedasrepresentativeusecases.WearenowabletouseMockObjects&Servicestoacceleratetheimplementationofourapplicationsandgetabettersenseofitsoverallfunctionality,longbeforeallofitsindividualpartsarecompleted.

Inthenextchapter,wewillbeintroducedtoclient-sidetemplatingandlearnhowtogeneratecomplexHTMLstructuresinthebrowserfromreadabletemplatesefficiently.WewillgetanintroductiontoUnderscore.jsandHandlebars.js,analyzetheirconventions,evaluatetheirfeaturesandfindwhichonebettersuitsourtaste.

Page 252: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 253: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter9.Client-sideTemplatingThischapterwilldemonstratesomeofthemostwidelyusedlibrariestocreatecomplexHTMLtemplatesfaster,whilemakingourimplementationeasiertoreadandunderstandwhencomparedtotraditionalstringconcatenationtechniques.WewilllearninmoredetailhowtousetheUnderscore.jsandHandlebars.jstemplatinglibraries,getatasteoftheirconventions,evaluatetheirfeaturesandfindtheonethatbestsuitsourtaste.

Bytheendofthischapter,wewillbeabletogeneratecomplexHTMLstructuresinthebrowserefficientlybyusingreadabletemplatesandutilizingtheuniquecharacteristicsofeachtemplatinglibrary.

Inthischapter,wewill:

DiscussthebenefitsofusingaspecializedtemplatinglibraryIntroducethecurrenttrendsinclient-sidetemplating,specificallythetoprepresentativeofthefamiliesthatuse<%%>and{{}}astheirplaceholdersIntroduceUnderscore.jsasanexampleofthefamilyoftemplatingenginesthatuse<%%>placeholdersIntroduceHandlebars.jsasanexampleofthefamilyoftemplatingenginesthatusecurlybraces{{}}placeholders

Page 254: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingUnderscore.jsUnderscore.jsisaJavaScriptlibrarythatprovidesacollectionofutilitymethodsthathelpwebdevelopersworkmoreefficientlyandfocusontheactualimplementationoftheirapplicationratherthanbotheringwithrepetitivealgorithmicproblems.Underscore.jsis,bydefault,accessiblethroughthe“_”identifieroftheglobalnamespaceandthat’sexactlywhereitsnamecomesfrom.

NoteAswiththe$identifierinjQuery,theunderscore“_”identifiercanalsobeusedasavariablenameinJavaScript.

Oneoftheutilityfunctionsthatitprovidesisthe_.template()method,whichprovidesuswithaconvenientwayofinterpolatingspecificvaluesintoexistingtemplatestringsthatfollowaspecificformat.The_.template()methodrecognizesthreespecialplaceholdernotationsinsidetemplates,whichareusedtoadddynamiccharacteristics:

The<%=%>notationisusedasthesimplestwaytointerpolateavalueofavariableoranexpressioninatemplate.The<%-%>notationperformsHTMLescapingonavariableorexpressionandtheninterpolatesitinatemplate.The<%%>notationisusedtoexecuteanyvalidJavaScriptstatementaspartofthetemplategeneration.

The_.template()methodacceptsatemplatestringthatfollowsthesecharacteristicsandreturnsaplainJavaScriptfunction,commonlyreferredtoasthetemplatefunction,whichcanbeinvokedwithanobjectcontainingthevaluesthataregoingtobeinterpolatedinthetemplate.Theresultoftheinvocationofthetemplatefunctionisastringvalue,whichistheresultoftheinterpolationoftheprovidedvaluesinsidethetemplate:

vartemplateFn=_.template('<h1><%=title%></h1>');

varresultHtml=templateFn({

title:'Underscore.jsexample'

});

Asanexample,theabovecodereturns<h1>Underscore.jsexample</h1>andisequivalenttothefollowingshorthandinvocation:

varresultHtml=_.template('<h1><%=title%></h1>')({

title:'Underscore.jsexample'

});

NoteFormoreinformationaboutthe_.templatemethod,youcanreadthedocumentationat:http://underscorejs.org/#template.

WhatmakesUnderscore.jstemplatesveryflexibleisthe<%%>notation,whichallowsustoperformanymethodinvocationandis,forexample,usedastherecommendedwaytocreateloopsinatemplate.Ontheotherhand,overusingthisfeaturemayaddtoomuch

Page 255: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

logictoyourtemplates,whichisaknownanti-patternfoundinmanyotherframeworks,violatingtheprincipleofSeparationofConcerns.

Page 256: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingUnderscore.jstemplatesinourapplicationsAsanexampleofusingUnderscore.jsfortemplating,wewillnowuseittorefactortheHTMLcodegenerationwhichtakesplaceinsomemodulesofthedashboardexample,aswesawinpreviouschapters.ThemodificationsrequiredtotheexistingimplementationarelimitedtothecategoriesandtheinformationBoxmodules,whichmanipulatetheDOMtreeofthepagebyaddingnewelements.

Thefirstplacethatsucharefactorcanbeappliedisintheinit()methodofthecategoriesmodule.Wecanmodifythecodethatcreatestheavailable<option>softhe<select>categorytolooklikethis:

varoptionTemplate=_.template('<optionvalue="<%=value%>"><%-title%>

</option>');

varoptionsHtmlArray=[];

for(vari=0;i<dashboard.categories.data.length;i++){

varcategoryInfo=dashboard.categories.data[i];

optionsHtmlArray.push(optionTemplate({

value:i,

title:categoryInfo.title

}));

}

$categoriesSelector.append(optionsHtmlArray.join(''));

Asyoucansee,weiterateoverthecategoriesofthedashboardinordertocreateandappendtheappropriate<option>elementstothe<select>categoryelement.Inourtemplate,weareusingthe<%=%>notationforthevalueattributeofthe<option>sinceweknowthatitwillholdanintegervaluethatdoesnotneedescaping.Ontheotherhand,weareusingthe<%-%>notationforthecontentpartofeach<option>inordertoescapethetitleofeachcategoryforthecaseitsvalueisnotanHTML-safestring.

Weareusingthe_.template()methodoutsidetheforloopinordertocreateasinglecompiledtemplatefunctionthatwillbereusedoneachiterationoftheforloop.Inthisway,thebrowsernotonlyexecutesthe_.template()methodjustonce,butalsooptimizesthegeneratedtemplatefunctionandmakesitrunfasteroneachsubsequentexecutioninsidetheforloop.Lastly,weareusingthejoin('')methodtocombinealltheHTMLstringsoftheoptionsHtmlArrayvariableandappend()theresulttotheDOMwithasingleoperation.

Analternativeandpossiblysimplerwaytoachievethesameresultisbycombiningthe<%%>notationandthe_.each()methodthatUnderscore.jsprovides,enablingustoimplementaloopinsidethetemplateitself.Inthisway,thetemplatewillberesponsiblefortheiterationovertheprovidedarrayofcategories,movingthecomplexityfromtheimplementationofthemoduleintothetemplate.

vartemplateSource=''.concat(

'<%_.each(categoryInfos,function(categoryInfo,i){%>',

'<optionvalue="<%=i%>"><%-categoryInfo.title%></option>',

'<%});%>');

varoptionsHtml=_.template(templateSource)({

categoryInfos:dashboard.categories.data

Page 257: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

});

$categoriesSelector.append(optionsHtml);

Asyoucanseeintheabovecode,ourJavaScriptimplementationnolongercontainsaforloop,reducingitscomplexityandtherequirednesting.Thereisonlyasinglecalltothe_.template()method,whichnicelyabstractstheimplementationtoanoperationthatgeneratestheHTMLandrendersthe<option>elementsforallthecategories.YoucanalsoseehownicelythistechniquefitsinwiththeCompositelogicthatjQueryitselffollows,inwhichthemethodsaredesignedtooperateovercollectionsofelementsinsteadofsingleitems.

SeparatingHTMLtemplatesfromJavaScriptcodeEvenafterintroducingalloftheaboveimprovements,itsoonstartstobecomeobviousthatwritingtemplatesinbetweenyourapplicationlogicmightnotbethebestapproachtofollow.Assoonasyourapplicationbecomescomplexenough,orwhenyouneedtousetemplatesthataremorethanafewlineslong,theimplementationstartstofeelfragmentedbythemixoftheapplication’slogicandtheHTMLtemplates.

AcleanerapproachtothisproblemistostoreyourtemplatesalongsidetherestoftheHTMLcodeofyourpage.ThisisagoodsteptowardsbetterSeparationofConcernssinceitproperlyisolatesthepresentationfromtheapplicationlogic.

InordertoincludeHTMLtemplatesaspartofwebpagesinaninactiveform,weneedtouseahosttagthatwillpreventthemfrombeingrendered,butalsoallowustoretrieveitscontentprogrammaticallywhenneeded.Forthispurpose,wecanuse<script>tagsinsidethe<head>orthe<body>ofourpageandspecifyanytypeotherthanthecommontext/javascriptthatwenormallyuseforourJavaScriptcode.Theoperationprinciplebehindthisisthatbrowsersdonottrytoparse,executeorrenderthecontentof<script>tags,incasetheirtypeattributeisn’trecognized.Aftersomeexperimentation,thecommunityofUnderscore.jsusershaslargelyadoptedthispracticeandagreedtospecifytext/templateasthepreferredtypeforthese<script>tags,inanattempttomaketheseimplementationsmoreuniformamongdevelopers.

TipEventhoughUnderscore.jsisneitheropinionatednorcontainsanyimplementationspecifictothewaythatthetemplatesbecomeavailable,usingtext/template<script>tagsand/orAJAXrequestshavebeenvaluabletechniquesthatarewidelyusedandareconsideredbestpractices.

Asanexampleofacomplextemplatethatwouldbebeneficialtomoveintoa<script>tag,wewillrefactortotheopenNew()methodoftheinformationBoxmodule.Asyoucanseeinthecodebelow,theresulting<script>tagiscleanlyformattedandwenolongerneedtousestringconcatenationforthedefinitionofthemulti-linetemplate:

<scriptid="box-template"type="text/template">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

Page 258: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

<buttonclass="boxCloseButton">&#10006;</button>

<%-itemName%>

</header>

<divclass="boxContent">Loading…</div>

</article>

</div>

</script>

AgoodpracticewhenmovingHTMLtemplatesoutofourcodeistowriteanabstractedmechanismtoberesponsibleforretrievingthemandprovidingthecompiledtemplatefunction.Thisapproachnotonlydecouplestherestoftheimplementationfromthetemplateretrievalmechanismbutalsomakesitlessrepetitiveandcreatesacentralizedmethoddesignedtoprovidetemplatesfortherestoftheapplication.Moreover,aswecanseebelow,thisapproachalsoallowsustooptimizethewaythattemplatesareretrieved,propagatingthebenefitstoalltheplacesthattheyareused.

vartemplateCache={};

functiongetEmbeddedTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(!compiledTemplate){

vartemplate=$('#'+templateName).html();

compiledTemplate=_.template(template);

templateCache[templateName]=compiledTemplate;

}

returncompiledTemplate;

}

dashboard.informationBox.openNew=function(itemName){

varboxCompiledTemplate=getEmbeddedTemplate('box-template');

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);

/*...*/

};

Asshownintheaboveimplementation,theopenNew()methodoftheinformationBoxmodulesimplyinvokesthegetEmbeddedTemplate()functionbypassingauniqueidentifierthatisassociatedwiththerequestedtemplateandusesthereturnedtemplatefunctiontogeneratethenewbox’sHTMLandfinallyappendittothepage.ThemostinterestingpartoftheimplementationisthegetEmbeddedTemplate()method,whichusesthetemplateCachevariableasadictionarytoholdallthepreviouslycompiledtemplatefunctions.

Thefirststepisalwaystocheckwhethertherequestedtemplateidentifierexistsinourtemplatecache.Ifnot,thentheDOMtreeofthepageissearchedforthe<script>tagwiththerelatedIDanditsHTMLcontentisusedtocreatethetemplatefunction,whichisthenstoredinthecacheandreturnedtothecaller.

KeepinmindthatitisagoodpracticetouseaspecificprefixorsuffixforalltheidentifiersofyourHTMLtemplatesinordertoavoidconflictswiththeIDsofotherpage

Page 259: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

elements.Forthispurpose,intheaboveexampleweusedthe-templateasasuffixoftheidentifierofourboxtemplate.

Ideally,theimplementationofthetemplateprovidermethodshouldbeinaseparatemodulethatwillbeusedbyallthepartsofanapplicationbut,sinceinourdashboardthisisusedinonlyoneplace,wemettheneedsofourdemonstrationbysimplyusingafunction.

Page 260: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 261: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingHandlebars.jsHandlebars.js,orsimplyHandlebars,isaspecializedclient-sidetemplatinglibrarythatenableswebdeveloperstocreatesemantictemplateseffectively.UsingHandlebarsfortemplatingleadstothecreationoflogic-freetemplateswhichensuresthattheviewandthecodeareisolated,helpingpreservetheSeparationofConcernsprinciple.ItislargelycompatiblewithMustachetemplates,whichareatemplatinglanguagespecificationthathaveproventheireffectivenessovertimeandhavemanyimplementationsforallthemajorprogramminglanguages.Additionally,HandlebarsprovidesasetofextensionsontopoftheMustachetemplatespecification,suchashelpermethodsandpartials,asameansofextendingthetemplatingengineandcreatingmoreeffectivetemplates.

NoteYoucanseeallthedocumentationforHandlebarsat:http://handlebarsjs.com/.YoucangetmoreinformationaboutMustacheinJavaScriptat:https://github.com/janl/mustache.js/.

ThemaintemplatenotationthatHandlebarsprovidesisthedoublecurlybracessyntax{{}}.AsHandlebarswasdesignedtobeusedforHTMLtemplatesfromthebeginning,thisnotationalsoappliesHTMLescapingbydefault,loweringthechancesthatanon-escapedvaluecouldreachthetemplatecausingpotentialsecurityproblems.Ifanon-escapedinterpolationisrequiredforaspecificpartofatemplate,wecanusethetriplecurlybracesnotation{{{}}}.

Moreover,sinceHandlebarspreventsusfrominvokingmethodsdirectlyfromwithinatemplate,itprovidesuswiththeabilitytodefineandusehelpermethodsandblockexpressionsasawaytocovermorecomplexusecaseswhilealsohelpingtomaintainourtemplatesascleanandreadableaspossible.Thesetofbuilt-inhelpersincludesthe{{#if}}and{{#each}}helperswhichallowustoperformiterationsoverarraysandchangetheoutcomesofatemplatebasedonconditionsveryeasily.

ThecentralmethodoftheHandlebarslibraryistheHandlebars.compile()method,whichacceptsatemplatestringasaparameterandreturnsafunctionthatcanbeusedtogeneratestringvaluesthatfollowtheformoftheprovidedtemplate.Thisfunctioncanthenbeinvoked(asinUnderscore.js)withanobjectasaparameter,thepropertiesofwhichwillbeusedasacontextfortheevaluationofalltheHandlebarsexpressions(thecurlybracesnotations)thatweredefinedintheoriginaltemplate:

vartemplateFn=Handlebars.compile('<h1>!!!{{title}}!!!</h1>');

varresultHtml=templateFn({

title:'>Handlebarsexample<'

});

Asanexample,theabovecodereturns"<h1>!!!&gt;Handlebarsexample&lt;!!!</h1>",turningtheinterpolatedtitleintoasafeHTMLstring,butonewhichwouldotherwiserenderproperlywhenattachedtotheDOMtreeofapage.Ofcourse,thesameresultcanbeachievedwiththefollowingshorthandinvocation,ifwedon’tneedtokeepareferencetothecompiledtemplatefunctionforfutureuse:

Page 262: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

varresultHtml=Handlebars.compile('<h1>!!!{{title}}!!!</h1>')({

title:'>Handlebarsexample<'

});

Page 263: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingHandlebars.jsinourapplicationsAsanexampleofusingHandlebars.jsfortemplatingandinordertodemonstrateitsdifferencesfromUnderscore.jstemplates,wewillnowuseittorefactorourdashboardexample,likewedidintheprevioussection.Likebefore,therefactoringislimitedtothecategoriesandtheinformationBoxmodules,whichmanipulatetheDOMtreeofthepagebyaddingnewelements.

Therefactoredimplementationoftheinit()methodofthecategoriesmoduleshouldlooklikethis:

varoptionTemplate=Handlebars.compile('<optionvalue="{{value}}">{{

title}}</option>');

varoptionsHtmlArray=[];

for(vari=0;i<dashboard.categories.data.length;i++){

varcategoryInfo=dashboard.categories.data[i];

optionsHtmlArray.push(optionTemplate({

value:i,

title:categoryInfo.title

}));

}

$categoriesSelector.append(optionsHtmlArray.join(''));

Firstofall,wehaveusedtheHandlebars.compile()methodwhichgeneratesandreturnsatemplatefunctionbasedontheprovidedtemplatestring.ThemaindifferencewiththeUnderscore.jsimplementationwesawintheprevioussection,isthatwenowusethedoublecurlybracesnotation{{}}tointerpolatevaluesinourtemplate.Apartfromthedifferentappearance,Handlebars.jsalsodoesHTMLstringescapingbydefaultinanattempttoeliminateHTMLinjectionsecurityholesbymakingescapingpartofitsprimaryusecase.

Aswedidearlierinthischapter,wewillcreatethetemplatefunctionoutsidetheforloopanduseittogeneratetheHTMLforeach<option>element.AllthegeneratedHTMLstringsaregatheredinanarrayandarefinallycombinedandattachedtotheDOMtreewithasingleoperation,usingthe$.append()method.

ThenextincrementalsteptoreducethecomplexityofourimplementationistoabstracttheiterationsawayfromourJavaScriptcodeusingtheloopingcapabilitiesofthetemplatingengineitself:

vartemplateSource=''.concat(

'{{#eachcategoryInfos}}',

'<optionvalue="{{@index}}">{{title}}</option>',

'{{/each}}');

varoptionsHtml=Handlebars.compile(templateSource)({

categoryInfos:dashboard.categories.data

});

$categoriesSelector.append(optionsHtml);

TheHandlebars.jslibraryallowsustoachievethatbyusingthespecial{{#each}}notation.Inbetweenthe{{#each}}and{{/each}},thecontextofthetemplateischangedtomatcheachindividualobjectoftheiteration,allowingtodirectlyaccessand

Page 264: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

interpolatethe{{title}}ofeachobjectinthecategoryInfosarray.Moreover,inordertoaccesstheloopcounter,Handlebarsprovidesuswiththespecial@indexvariableaspartofthecontextoftheloop.

NoteForafulllistofallthespecialnotationsthatHandlebarsprovides,youcanreadthedocumentationat:http://handlebarsjs.com/reference.html

SeparatingHTMLtemplatesfromJavaScriptcodeLikemosttemplatingengines,HandlebarsalsoleadsustoisolateourtemplatesfromtheJavaScriptimplementationofourapplicationanddeliverthemtothebrowserbyincludingthemin<script>tags,insidetheHTMLofourpages.Moreover,Handlebarsisopinionatedandprefersthespecialtext/x-handlebars-templateasthetypeattributeforall<script>tagsthatcontainHandlebarstemplates.Forexample,hereishowthetemplateforthedashboard’sboxesshouldbedefinedaccordingtothelibraryrecommendations:

<scriptid="box-template"type="text/x-handlebars-template">

<divclass="boxsizer">

<articleclass="box">

<headerclass="boxHeader">

<buttonclass="boxCloseButton">&#10006;</button>

{{itemName}}

</header>

<divclass="boxContent">Loading…</div>

</article>

</div>

</script>

TipEventhoughourimplementationwouldstillworkifadifferenttypewasspecifiedforthe<script>tag,followingthelibrary’sguidelinescanobviouslymakeimplementationsmoreuniformamongdevelopers.

Aswedidearlierinthischapter,wewillfollowthebestpracticeofcreatingaseparatefunctiontoberesponsibleforprovidingthetemplateswherevertheyareneededintheapplication:

vartemplateCache={};

functiongetEmbeddedTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(!compiledTemplate){

vartemplate=$('#'+templateName).html();

compiledTemplate=Handlebars.compile(template);

templateCache[templateName]=compiledTemplate;

}

returncompiledTemplate;

}

dashboard.informationBox.openNew=function(itemName){

Page 265: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

varboxCompiledTemplate=getEmbeddedTemplate('box-template');

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);

/*...*/

};

Asyoucansee,theimplementationismostlythesameastheUndescore.jsexamplethatwesawearlierinthischapter.TheonlydifferenceisthatwearenowusingtheHandlebars.compile()methodtogeneratethecompiledtemplatefunctionsfromtheretrievedtemplates.

Pre-compilingtemplatesAnextrafeatureoftheHandlebarslibraryisthesupportfortemplatepre-compilation.Thisallowsustopre-generateallthetemplatefunctionswithasimpleterminalcommandandthenhaveourserverdelivertothemtothebrowser,insteadoftheactualtemplates.Inthisway,thebrowserwillbeabletousethepre-compiledtemplatesdirectly,removingtheneedforthecompilationofeachindividualtemplateandmakingtheexecutionofthelibraryandourapplicationfaster.

Inordertopre-compileourtemplates,wefirstneedtoplacetheminseparatefiles.TheHandlebarsdocumentationsuggestsusingthe.handlebarsextensionforourfilesbutwecanstillusethe.htmlextensionifitispreferred.Afterinstallingthecompilationtoolonourdevelopmentmachine(withnpminstallhandlebars-g),wecanissuethefollowingcommandinourterminaltocompileatemplate:

handlebarsbox-template.handlebars-fbox-template.js

Thiswillgeneratethebox-template.jsfilethatisactuallyamini-moduledefinitionthataddsthetemplatetoHandlebars.templates.ThegeneratedfilecanthenbecombinedandminifiedlikeregularJavaScriptfilesand,whenloadedbyabrowser,thetemplatefunctionwillbecomeavailablethroughtheHandlebars.templates['box-template']property.

NoteKeepinmindthatifthe.htmlextensionisbeingusedforthetemplates,thenthepre-compiledtemplatefunctionwillbeavailablethroughtheHandlebars.templates['box-template.html']property.

Asyoucansee,usingatemplateproviderfunctionassistswiththemigrationofanexistingapplicationtopre-compiledtemplatessinceitallowsustoencapsulatethewaythatthetemplatesareretrieved.Movingtopre-compiledtemplatesonlyrequireschangingthegetEmbeddedTemplate()tosomethinglikethis:

functiongetEmbeddedTemplate(templateName){

returnHandlebars.templates[templateName];

}

Note

Page 266: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Formoreinformationabouttemplatepre-compilationinHandlebars,readthedocumentationat:http://handlebarsjs.com/precompilation.html.

Page 267: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 268: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

RetrievingHTMLtemplatesasynchronouslyThefinalsteptomasteringclient-sidetemplatingisadevelopmentpracticethatallowsustoloadtemplatesdynamicallyandusetheminawebpagethathasalreadybeenloaded.Thisapproachcanleadtomorescalableimplementationsthantheapproachofembeddingalltheavailabletemplatesas<script>tagsinsidetheHTMLsourceofeachpage.

Thekeyelementofthistechniqueistoloadeachtemplateonlywhenitisrequiredforthepresentationofawebpage,commonlyafterauseraction.Themainbenefitsofthisapproacharethat:

TheinitialpageloadtimeisreducedsincetheHTMLofthepageissmaller.Thegainsfromthereductionofthepagesizebecomeevengreaterifourapplicationhasalotoftemplatesthatareusedonlyundercertaincircumstances,forexample,afterspecificuserinteractions.Theuseronlydownloadsatemplateifitisactuallygoingtobeused.Inthisway,thesizeofthetotaldownloadedresourcesforeachpageloadcanbereduced.Subsequentrequestsforanalreadyloadedtemplatewillnotleadtoanextradownload,sincethebrowser’sHTTPcachingmechanismwillreturnthecachedresource.Additionally,sincethebrowsercacheisusedforallHTTPrequestsregardlessofthepagefromwhichtheyoriginate,usersonlyhavetodownloadtherequiredtemplateoncewhileusingourwebapplication.

Becauseofitsbenefitstouserexperienceanditsscalability,thistechniqueiswidelyusedbythemostpopularwebmailandsocialnetworkingwebsites,wherevariousHTMLtemplatesandJavaScriptmodulesareloadeddynamically,basedonuseractions.

NoteFormoreinformationonhowjQuerycanbeusedtoloadJavaScriptmodulesonapagedynamically,readthedocumentationforthe$.getScript()methodat:https://api.jquery.com/jQuery.getScript/.

Page 269: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AdoptingitinanexistingimplementationToillustratethistechnique,wewillchangetheUnderscore.jsandHandlebars.jsimplementationsoftheinformationBoxmodulesothatitfetchestheboxtemplateforourdashboardusinganAJAXrequest.

Let’sproceedbyanalyzingthenecessarychangesforourUnderscore.jsimplementation:

vartemplateCache={};

functiongetAjaxTemplate(templateName){

varcompiledTemplate=templateCache[templateName];

if(compiledTemplate){

return$.Deferred().resolve(compiledTemplate);

}

return$.ajax({

mimeType:'text/html',

url:templateName+'.html'

}).then(function(template){

templateCache[templateName]=_.template(template);

returntemplateCache[templateName];

});

}

Asyoucanseeintheabovecode,wehaveimplementedthegetAjaxTemplate()functionasawayofdecouplingthemechanismthatisresponsibleforfetchingthetemplatefromtheimplementationthatusesit.ThisimplementationhasalotincommonwiththegetEmbeddedTemplate()functionthatweusedearlier,themaindifferencebeingthatthegetAjaxTemplate()functionisasynchronousand,asaresult,returnsaPromise.

ThegetAjaxTemplate()functionfirstlycheckswhetherornottherequestedtemplatealreadyexistsinitscache,asanextraattempttoreduceHTTPrequeststotheserver.Ifthetemplateisfoundinthecache,thenitisreturnedaspartofaResolvedPromise,otherwiseweinitiateanAJAXrequestusingthe$.ajax()methodtoretrieveitfromtheserver.Likebefore,weneedtohaveaconventionregardingthenamingofthetemplateHTMLfilesandthepathusedtostorethemintheserver.Inourexample,wearelookinginthesamedirectoryasthewebpageitselfandjustappendingthe.htmlfileextension.Anextraconcerninsomecases,dependingonthewebserverused,isthedefinitionofthemimeTypeoftheresourceastext/html.

WhentheAJAXrequestcompletes,thethen()methodisexecutedwiththecontentofthetemplateasastringparameter,whichisusedtogeneratethecompiledtemplatefunction.OurimplementationfinallyreturnsthecompiledtemplatefunctionastheresultofthechainedPromise,rightafteraddingittoitscache.SincethegetAjaxTemplate()functionisasynchronous,wealsohadtochangetheimplementationoftheopenNew()methodandmoveallthecodeusingthereturnedtemplatefunctioninsideathen()callback.Apartfromthis,theimplementationhasremainedthesameandusesthetemplatefunctioninexactlythesamewayasbefore.

dashboard.informationBox.openNew=function(itemName){

vartemplatePromise=getAjaxTemplate('box-template');

Page 270: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

templatePromise.then(function(boxCompiledTemplate){

varboxHtml=boxCompiledTemplate({

itemName:itemName

});

var$box=$(boxHtml).appendTo($boxContainer);box);

/*...*/

});

};

Whenre-implementingthegetAjaxTemplate()functiontouseHandlebars.js,theresultingcodeismostlythesameasbefore.TheonlydifferenceisintheinvocationoftheHandlebars.compile()methodinsteadoftheUndescore.jsequivalent.Thisisanaddedbenefitasmanyclient-sidetemplatingenginesinfluencedeachotherandhaveconvergedintoaverysimilarAPIregardingthewaythattheirtemplatefunctionsareused,largelybecauseofthepositiveuserfeedbackontheexistingimplementations.

functiongetAjaxTemplate(templateName){

/*…sameasbefore…*/

return$.ajax({/*…sameasbefore…*/}).then(function(template){

templateCache[templateName]=Handlebars.compile(template);

returntemplateCache[templateName];

});

}

NoteKeepinmindthatthe$.ajax()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butworksasintendedwhenservedusingawebserverlikeApache,IIS,ornginx.

Page 271: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ModerationisbestinallthingsEventhoughthistechniquereducestheoveralldownloadfootprintofeachwebpage,italsoinevitablyincreasesthenumberofHTTPrequestsmade.Moreover,thepracticeofloadingeverytemplatelazilycansometimesincreasethetimethattheuserwillhavetowaitifthetemplatesarerequiredfortheinitialrenderingofthepage.

Balancingthewaythatweloadourtemplatesbetweenlazyloadingandembeddingthemin<script>tagsusuallybringsthebestofbothworlds.Thishybridapproachisconsideredabestpracticebytheindustrysinceitallowsustomicromanageandfinetuneeachimplementationbasedonitsneeds.Accordingtothispractice,thetemplatesthatarerequiredforthepresentationofthemaincontentofapageareembeddedinitsHTML,whiletherestofthemaredeliveredlazilywhenneeded,takingadvantageofbrowsercaching.

Theimplementationofsuchatemplateproviderfunctionisleftasanexerciseforthereader.Asahint,suchmethodshavetobeasynchronoussince,whentherequestedtemplateisnotfoundembeddedinthe<script>tagofthepage,itwillhavetoproceedandmakeanAJAXrequesttoretrieveitfromtheserver.

TipKeepinmindthatitisgenerallypreferabletogeneratethecompleteinitialHTMLcontentofthepageontheserversideinsteadofusingclient-sidetemplating.ThisnotonlyleadstoasmallerloadingtimeoftheinitialpagecontentbutitalsopreventssituationsinwhichtheuserispresentedwithanemptypagewhenJavaScriptisunavailableoranerrorhasoccurred.

Page 272: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 273: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedhowtousetwoofthemostcommonclient-sidetemplatinglibraries:Underscore.jsandHandlebars.js.WealsolearnedhowtheyallowustocreatecomplexHTMLtemplatesfasterwhilemakingourimplementationseasiertoreadandunderstand.Wethenwentontoanalyzetheirconventionsandevaluatetheirfeaturesandlearnedbyexamplehowtheycanbeeffectivelyandefficientlyusedinourimplementations.

Aftercompletingthischapter,wearenowabletogeneratecomplexHTMLstructuresinabrowserefficientlybyusingreadabletemplatesandutilizingtheuniquecharacteristicsofthetemplatinglibraries.

Inthenextchapter,wewilllearnhowtocreatejQueryPluginsasawaytoabstractpartsofourapplicationsintoreusableandextensibleimplementations.WewillintroducethemostwidelyusedpatternsfordevelopingjQueryPluginsandanalyzetheimplementationproblemsthateachofthemhelpstosolve.

Page 274: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 275: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter10.PluginandWidgetDevelopmentPatternsThischapterfocusesonthedesignpatternsandbestpracticesusedwhenimplementingjQueryPlugins.WewilllearnherehowtoabstractpartsofanapplicationintoseparatejQueryPlugins,promotingtheSeparationofConcernsprincipleandcodereusability.

WewillfirstlyanalyzethesimplestwaysthatajQueryPlugincanbeimplemented,learnthevariousconventionsofjQueryPlugindevelopmentandthebasiccharacteristicsthateverypluginshouldsatisfyinordertofollowjQueryprinciples.Wewillthenproceedwithanintroductiontothemostwidelyuseddesignpatternsandanalyzethecharacteristicsandbenefitsofeachofthem.Bytheendofthischapter,wewillbeabletoimplementextensiblejQueryPluginsusingthedevelopmentpatternthatbestsuitseachusecase.

Inthischapterwewill:

IntroducethejQueryPluginAPIanditsconventionsAnalyzethecharacteristicsthatmakeanexcellentpluginLearnhowtocreateapluginbyextendingthe$.fnobjectLearnhowtoimplementgenericpluginsthatareextensibleinordertomakethemreusableinmoreusecasesLearnhowtoprovideoptionsandmethodstoyourpluginsIntroducethemostcommondesignpatternsforjQueryplugindevelopmentandanalyzethecommonimplementationproblemsthateachofthemhelpstosolve

Page 276: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IntroducingjQueryPluginsThekeyconceptofjQuerypluginsliesinextendingthejQueryAPIbymakingtheirfunctionalityaccessibleasamethodonjQueryCompositeCollectionObjects.AjQuerypluginissimplyafunctionthatisdefinedasanewmethodonthe$.fnobject,whichisthePrototypeObjectthateveryjQueryCollectionObjectinheritsfrom.

$.fn.simplePlugin101=function(arg1,arg2/*,...*/){

//Plugin'simplementation…

};

Bydefiningamethodonthe$.fnobject,weareactuallyextendingthecorejQueryAPIitself,sincethismakesthemethodavailableonallcreatedjQueryCollectionObjectsfromthatpointonwards.Asaresult,afterapluginhasbeenloadedinawebpage,itsfunctionalityisavailableasamethodoneveryobjectreturnedbythe$()function:

$('h1').simplePlugin101('test',1);

ThemainconventionofthejQuerypluginAPIisthatthejQueryCollectionObjectthatthepluginwasinvokedonismadeavailabletotheplugin’smethodasitsexecutioncontext.Inotherwords,wecanusethethisidentifierinthepluginmethod,asshownbelow:

$.fn.simplePlugin101=function(){

this.slideToggle();

//"this"isajQueryobjectwhereall

//jQuerymethodsareavailable

};

Page 277: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

FollowingjQueryprinciplesOneofthegoalswhencreatingapluginistomakeitfeellikeapartofjQueryitself.Afterreadingthepreviouschapters,youshouldbefamiliarwithsomeoftheprinciplesthatalljQuerymethodsfollowandthecharacteristicsthatmakeitsapproachspecial.ImplementingapluginthatfollowstheseprinciplesmakesusersfeelmorecomfortablewithitsAPI,bemoreproductive,andmakefewerimplementationerrors,whichleadstoanincreaseintheplugin’spopularityandadoption.

TwoofthemostimportantcharacteristicsthatagreatjQuerypluginshouldhaveareasfollows:

ItshouldapplyonalltheelementsofthejQueryCollectionObjectitisinvokedonwheneverapplicableItshouldallowfurtherchainingofotherjQuerymethods

Let’snowmoveonandanalyzeeachoftheseprinciples.

WorkingonCompositeCollectionObjectsOneofthemostimportantfeaturesofjQuerymethodsisthattheyareappliedoneveryitemoftheCompositeCollectionObjectthattheyareinvokedon.Asanexample,the$.fn.addClass()methodaddsoneormoreCSSclassestoeveryitemofthecollectionafterindividuallycheckingwhethereachclasshasalreadybeendefinedoneachindividualelement.

Asaresult,ourjQuerypluginsshouldalsofollowthisprinciplebyoperatingoneveryelementofacollection,whensuchathingseemslogical.IfyouareusingonlyjQuerymethodsinyourplugin’simplementation,mostofthetime,yougetthisforfree.Ontheotherhand,animportantconsiderationtobearinmindisthatnotalljQuerymethodsoperateoneveryelementofacollectionobject.Methodslike$.fn.html(),$.fn.css()and$.fn.data()applyonalltheitemsofthecollectionwhenusedassettermethods,butoperateonlyonthefirstelementwhenusedasgetters.

Let’sseeanexampleimplementationofapluginthatuses$.fn.animate()tocreateashakeeffectonallitemsofajQueryobject:

$.fn.vibrate=function(){

this.each(function(i,element){

//specificallyhandleeveryelement

var$element=$(element);

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

});

this.animate({left:'+=3'},30)

.animate({left:'-=6'},60)

.animate({left:'+=6'},60)

.animate({left:'-=3'},30);

returnthis;//allowfurtherchaining

Page 278: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

};

Invokingthispluginwith$('button').vibrate();appliestheshakinganimationoneverymatchedelementofthepage.Toachievethat,thepluginchangestheleftCSSpropertyofallmatchedelementsusingthe$.fn.animate()method,whichconvenientlyoperatesoneveryelement.Ontheotherhand,sincethe$.fn.css()methodappliesonlyonthefirstelementofthecollectionwhenusedasagetter,wehadtoiterateoveralltheelementsusingthe$.fn.each()methodandensurethateachofthemwasnotstaticallypositioned,inwhichcasetheleftCSSpropertywouldnotaffectitsappearance.

Obviously,usingonlyjQuerymethodsisnotalwayssufficientfortheimplementationofaplugin.Inmostcases,anewpluginwillhavetouseatleastonenon-jQueryAPIforitsimplementation,requiringustoiterateovertheitemsofthecollectionandapplythelogicoftheplugintoeachofthemindividually.Thesameapproachshouldbeusedwheneachelementofthecollectionhastobehandledslightlydifferentlybasedonitsstate.

Asaresult,itisquitecommonforpluginstowrapalmostalloftheirimplementationsinsidea$.fn.each()invocation.Byrecognizingthecommonneedsthatarecoveredbyexplicititeration,thejQueryteamandmostjQuerypluginboilerplatesnowmakeitpartoftheirstandardpractice.

AllowingfurtherchainingIngeneral,whenyourplugin’scodedoesnotneedtoreturnanything,allthatyouhavetodotoenablefurtherchainingistoaddareturnthis;statementtoitslastline,aswesawinthepreviousexample.Makesurethatallthecodepathsreturnareferenceoftheinvocationcontext(this)oranotherrelevantjQuerycollectionobject,inthesamewaythat$.fn.parent()and$.fn.find()do.Alternatively,whenallyourcodeiswrappedinsideanotherjQuerymethod,suchas$.fn.each(),itiscommonpracticetosimplyreturntheresultofthatinvocation,asdemonstratedbelow:

$.fn.myLogPlugin=function(){

returnthis.each(function(i,element){

console.log($(element).text());

});

};

Keepinmindthat,ifyourcodemanipulatesthecollectionobjectthatitwasinvokedon,insteadofreturningthethisreference,youmightneedtoreturnthenewcollectionthatwastheresultofyourplugin’smanipulations.

NoteYoushouldavoidbasingyourplugin’simplementationonareturnvalueinordertoallowfurtherchaining.Insteadofdoingthat,itispreferabletoinitializethepluginonitsfirstinvocationandthenprovidesomeoverloadedwaystoinvokeit,asawayofreturningvalues.

Page 279: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Workingwith$.noConflict()Thefirststeptoimproveaplugin’simplementationistomakeitworkinenvironmentsthatdonothaveaccesstothe$identifier.AnexampleofthisiswhenawebpageusesthejQuery.noConflict()method,whichpreventsjQueryfromassigningitselftothe$globalidentifier(orwindow.$)andkeepsitavailableonlyonthejQuerynamespace(window.jQuery).

NoteThejQuery.noConflict()methodallowsustopreventjQueryfromconflictingwithotherlibrariesandimplementationsthatalsohappentousethe$variable.Formoreinformation,youcanvisitthejQuerydocumentationpageat:http://api.jquery.com/jQuery.noConflict/

Insuchcases,theplugindefinitionwouldthrowan$isnotdefinederrororevenworse;itmighttrytousethe$variablethatthedeveloperhasreservedtouseinanimplementation,leadingtoerrorsthatarehardtodebug.

Fortunately,thechangesrequiredtofixthisproblemareeasytoimplementanddonotaffectthefunctionalityoftheplugin.Allthatwehavetodoisrenamealloftheoccurrencesofthe$identifierinourpluginwithjQuery,asshownbelow:

jQuery.fn.simplePlugin101=function(arg1,arg2/*,...*/){

var$buttons=jQuery('button');

//...

};

Page 280: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WrappingwithanIIFEThenextbestpracticetofollowistowrapthedefinitionandimplementationofourpluginwithanIIFE.ThisnotonlymakesourpluginlookliketheModulePatternbutalsomakesourimplementationmorerobustbyaddingseveralotherbenefitstoit.

Firstofall,theIIFEpatternallowsustocreateanduseprivatevariablesandfunctionsinthecontextoftheplugin’sdefinition.Thesevariablesaresharedacrossalltheinstancesoftheplugininasimilarwaytohowstaticvariablesworkinotherprogramminglanguages,enablingustousethemassynchronizationpointsbetweentheplugininstances:

(function($){

varcallCounter=0;

functionutilityLogMethod(message){

if(window.console&&console.log){

console.log(message);

}

}

$.fn.simplePlugin101=function(arg1,arg2/*,...*/){

callCounter++;

utilityLogMethod(callCounter);

returnthis;

};

})(jQuery);

Otherwise,wewouldhavetousesomethinglike$.simplePlugin101._callCounteror$.simplePlugin101._utilityLogMethod()toemulateprivacy,whichisjustanamingconventionanddoesnotprovideanyactualprivacy.

Thesecondbenefit,asdemonstratedintheaboveexample,isthatitallowsustousethe$identifieragaintoaccessjQuerywithnoconcernsaboutconflicts.Inordertoachievethis,wearepassingthejQuerynamespacevariableasaninvocationparametertoourIIFEandusethe$identifiertonametherespectiveparameter.Inthisway,weeffectivelyaliasthejQuerynamespaceto$inthecontextcreatedbytheIIFE,enablingustousetheminimal$identifierinourimplementationtokeepourcodeslimandreadable,evenifjQuery.noConflict()isused.

Additionally,addingtheusestrict;statementonthetopofourIIFEhelpsustoeliminateanyleakingofvariablesintotheglobalnamespace.Forexample,thefollowingcodewouldthrowaReferenceError:assignmenttoundeclaredvariablexerrorduringtheinvocationoftheplugin’smethod,enablingustocatchthoseerrorsduringthedevelopmentphaseofthepluginhelpingproduceamorerobustfinalimplementation:

(function($){

'usestrict';

$.fn.leakingPlugin=function(){

x=0;//thereisno"varx"declaration,

//soanerroristhrownwhenexecuted

};

Page 281: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

})(jQuery);

$('div').leakingPlugin();

NoteFormoreinformationaboutJavaScript’sstrictexecutionmode,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

Finally,thispattern,aswithallthenamespacealiasingpracticesthatuseIIFEs,canalsohelpincreasethegainswhenminifyingyourplugin’ssourcecode,whencomparedtoanimplementationthatreferencesthejQuerynamespacevariabledirectly.Inanattempttomaximizethebenefitsofthistechnique,it’salsocommontoaliasalltheglobalnamespacevariablesthatourpluginaccesses,asdemonstratedbelow:

(function($,window,document,undefined){

//Plugin'simplementation…

})(jQuery,window,document);

Page 282: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 283: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

CreatingreusablepluginsAfteranalyzingthemostimportantaspectsofthedevelopmentofjQueryplugins,wearenowreadytoanalyzeanimplementationthatisusedforsomethingmorethanasimpledemonstration.Inordertocreateareallyusefulandreusableplugin,itmustbedesignedsuchthatitsoperationsarenotrestrictedbythedemandsofitsoriginalusecase.

Themostpopularplugins,likethemostusefuljQuerymethods,arethosethatprovideahighdegreeofconfigurationoftheirfunctionality.Creatingapluginthatisconfigurableaddsadegreeofflexibilitytoitsimplementation,whichenablesustomatchtheneedsofseveralotherusecasesthataregovernedbythesameoperationprinciples.

Aswesaidearlier,ajQuerypluginisjustafunctionattachedtothe$.fnobjectand,asaresult,wecanmakeitsimplementationmoreabstractandgenericinthesamewayaswithplainfunctionsofourmodules.Asinsimplefunctions,theeasiestwaytodifferentiatetheoperationofajQuerypluginisbyusinginvocationparameters.Apluginthatexposesalotofconfigurationparametershasgreatpotentialofbeingabletobematchtherequirementsofseveraldifferentusecases.

Page 284: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AcceptingconfigurationparametersIncontrasttohowweimplementfunctionsthatusuallyacceptuptofiveargumentsandstillhaveamanageableandrelativelycleanAPI,thispracticedoesnotworksowellwithjQueryplugins.InordertoexposeaclearAPIandmaintainahighlevelofusability,regardlessofthevariousconfigurationoptionsthatareexposed,mostjQuerypluginsprovideaminimalAPIthatacceptsuptothreeinvocationarguments.Thisisachievedbyusingdedicatedsettingobjectswithaspecificformat,asawayofencapsulatingmultipleoptionsandpassingthemasasingleargument.AnotherapproachistoexposeanAPIwithtwoparameters,wherethefirstoneisaregularvaluethatdefinestheoperationofthepluginandthesecondoneisusedtowrapthelessimportantconfigurationoptions.

Agreatexampleofbothofthesepracticesisthe$.ajax(settings)method,whichisinvokedwithasinglesettingsobjectasaparametertodefinehowitshouldoperate,butalsoexposesanotheroverloadedwaytobeinvokedwithtwoarguments.Thetwoargumentoverloadisinvokedwith$.ajax(url,settings),wherethefirstisthetargetURLfortheHTTPrequestandthesecondisanobjectwiththerestconfigurationoptions.Whatappliestobothofthemisthatthemethoditselfcontainsasetofsensibledefaultsthatareusedinsteadofanyconfigurationparameterthattheuserhasnotdefined.Moreover,thesecondoverloadalsodefinesthesecondparameterasoptionaland,ifthatwasnotprovidedduringitsinvocation,itbasesitsoperationonthedefaultsettings.

Adoptingthesettingsobjectpracticeinourpluginsnotonlybringsalltheaforementionedbenefits,butalsoallowsustoextendtheimplementationinamorescalableway,sincetheadditionofanextraconfigurationparameterhaslittleeffectontherestofitsAPI.Asanexampleofthis,wewillreimplementthe$.fn.vibratepluginthatwesawearlierinthischapterinamoregenericway,sothatasettingobjectwithdefaultvaluesisusedforitsconfiguration:

(function($){

$.fn.vibrate=function(options){

varopts=$.extend({},$.fn.vibrate.defaultOptions,options);

this.each(function(i,element){

var$element=$(element);

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

});

for(vari=0,len=opts.loops*4;i<len;i++){

varanimationProperties={};

varmovement=(i%2)?'+=':'-=';

movement+=(i===0||i===len-1)?

opts.amplitude/2:

opts.amplitude;

vart=(i===0||i===len-1)?

Page 285: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

opts.period/4:

opts.period/2;

animationProperties[opts.direction]=movement;

this.animate(animationProperties,t);

}

returnthis;

};

$.fn.vibrate.defaultOptions={

loops:2,

amplitude:8,

period:100,

direction:'left'

};

})(jQuery);

Incontrasttotheoriginalfixedimplementation,thisoneacceptsasingleobjectasaninvocationparameterwhichwrapsfourdifferentoptionsthatcanbeusedtodiversifytheoperationoftheplugin.Theoptionsobjectallowsustodiversifytheoperationofthepluginbyexposingfourcustomizationpoints:

ThenumberofloopsthattheshakeeffectshouldrunTheamplitudeoftheanimation,asameansofcontrollinghowmuchanelementshouldmoveawayfromitsoriginalpositionTheperiodofeachloop,asameansofcontrollinghowfastthemovementwillbeThedirectionoftheanimation,whichishorizontalwhenleftisusedorverticalwhentopisused

Byfollowingawidelyacceptedbestpractice,wehavedefinedallthedefaultvaluesfortheconfigurationoptionsasaseparateobject.Thispatternnotonlyallowsustogatheralltherelatedvaluesunderasingleobject,butalsoenablesustousethe$.extend()methodasaneffectivewayofcomposingallthedefinedoptionswiththedefaultvaluesoftheundefinedones.Wecanthusavoidcheckingexplicitlyfortheexistenceofeachindividualproperty,reducingthecomplexityandthesizeofourcode.

Inbrief,the$.extend()methodreturnstheobjectpassedasitsfirstargumentaftermergingthepropertiesofthesubsequentobjectstogetherintothefirstobject.Asaresult,thereturnedobjectwillcontainallthedefaultvaluesexceptthosethatweredefinedintheoptionsobjectthatwaspassedasaninvocationparameter.

NoteFormoreinformationaboutthe$.extend()helpermethod,youcanvisitthedocumentationpageat:http://api.jquery.com/jQuery.extend/

Moreover,insteadofusingasimplevariable,weareexposingthedefaultoptionsobjectasapropertyoftheplugin’sfunction,enablinguserstochangethemtobettersuittheirneeds.Asanexample,consideracaseinwhichasmoothanimationisrequiredfortheneedsofaspecificapplication.Bysetting$.fn.vibrate.defaultOptions.period=250,thedeveloperwouldcompletelyremovetheneedtospecifytheperiodoptionin

Page 286: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

everyinvocationoftheplugin,whichwouldleadtoanimplementationwithlessrepetitivecode.

NoteThejQuerylibraryitselfadoptsthispracticefordefiningthedefaultconfigurationparametersofthe$.ajax()method.Becauseoftheincreasedcomplexityofthismethod,jQueryprovidesuswiththejQuery.ajaxSetup()methodasawayofsettingupthedefaultparametersforeveryAJAXrequest.

Finally,inordertocreateagenericvariantoftheoriginalimplementationandutilizetheaforementionedconfigurationoptions,wereplacedthefourfixedinvocationsofthe$.fn.animate()methodoftheoriginalimplementationwithaforloopthatutilizedtheloopsoption.Insidetheforloopitself,weconstructtheparametersforeachcallofthe$.fn.animate()methodandbrieflyalternatethedirectionoftheanimatedmovementoneachsubsequentexecutionoftheloop,andalsoensurethatthefirstandlastmovementshavehalfofthetimedurationandhalfoftheshiftofalloftheothersteps.

Thefinalimplementationcanbeconfiguredtoproducedifferentanimations,basedontheneedsofeachspecificusecase,rangingfromshorthorizontalanimationsthatareidealfornotifyingauseraboutaninvalidaction,toverticallonganimationsthatlooklikealevitationeffect.Theplugincanbeinvokedwithanycombinationoftheaforementionedoptions,usethedefaultvaluesformissingoptionsandevenoperatewithnoinvocationargument,asshownbelow:

//dothedefaultintenseanimationonabutton

//thatappearsdisabled,todesignateaninvalidaction

$('button.disabled').on('click',function(){

$(this).vibrate();

});

//doasmothershakeanimationtocatchtheuser's

//attentiononanimportantpartofthepage

$('.save-button').vibrate({loops:3,period:250});

//startalongrunninglevitationeffectontheheaderofthepage

$('h1').vibrate({direction:'top',loops:1000,period:5000});

Page 287: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WritingstatefuljQuerypluginsThepluginimplementationsthatwehavelookedatsofarwerestatelesssince,aftercompletingtheirexecution,theyreverttheirmanipulationsontheDOM’sstateanddon’tleaveallocatedobjectsinthebrowser’smemory.Asaresult,subsequentinvocationsofstatelesspluginsalwaysproducethesameresults.

Asyoucanprobablyguess,suchpluginshavelimitedapplicationssincetheycan’tbeusedtocreateaseriesofcomplexinteractionswiththeuserofthewebpage.Inordertoorchestratecomplexuserinteractions,apluginneedstopreserveaninternalstatewiththeactionstakenuptothatpointinordertochangeitsoperationmodeappropriatelyandhandlesubsequentinteractions.Comparingthecharacteristicofstatefulandstatelesspluginscouldbedefinedastheequivalenttocomparingplain(static)functionswithmethodsthatarepartofanobjectandcanoperateonitsstate.

Anotherpopularcategoryofplugins,inwhichhavinganinternalstateisessential,isthefamilyofpluginsthatmanipulatetheDOMtree.Thesepluginsusuallycreatecomplexelementstructuressuchasarichtexteditors,datepickersandcalendars,commonlybybuildingonauser-definedempty<div>element.

Page 288: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImplementingastatefuljQueryPluginAsanexampleofthepatternsusedfortheimplementationofpluginsofthisfamily,wewillwriteagenericElementMutationObserverplugin.ThispluginwillprovideuswithaconvenientwayofaddingeventlistenersforchangestotheDOMtreethatoriginatefromanyoftheelementsthatthispluginwasinvokedon.Asawayofachievingthat,thefollowingimplementationusestheMutationObserverAPI,which,atthetimeofwriting,isimplementedbyallmodernbrowsersandisavailabletomorethan86%ofwebusers.

NoteFormoreinformationontheMutationObserver,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

Let’snowproceedwiththeimplementationandanalyzethepracticesthatwereused:

(function($){

$.fn.mutationObserver=function(action){

returnthis.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

if(!instance){

varobserver=newMutationObserver(function(mutations){

mutations.forEach(function(mutation){

instance.callbacks.forEach(function(callbackFn){

callbackFn(mutation);

});

});

});

observer.observe(element,{

attributes:true,

childList:true,

characterData:true

});

instance={

observer:observer,

callbacks:[]

};

$element.data('plugin_mutationObserver',instance);

}

if(typeofaction==='function'){

instance.callbacks.push(action);

}

});

};

})(jQuery);

Firstly,wedefineourplugininsideanIIFE,asrecommendedearlierinthischapter.Rightafterthedeclarationofthepluginonthe$.fnobject,weusethe$.fn.each()methodasa

Page 289: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

directapproachtoensurethatthefunctionalityofourpluginisappliedtoeveryitemofthejQueryCollectionObjectthatitwasinvokedon.

Twoofthemainissuesthatstatefulpluginimplementationshaveisthelackofamechanismtopreservetheinternalstateofeachinstantiationofthepluginandawayofavoidingbeinginitializedmanytimesonthesamepageelement.Inordertosolvebothoftheseproblems,weneedtousesomethinglikeahashtableinwhichthekeyistheelementitselfandthevalueisanobjectwiththestateoftheplugin’sinstance.

Fortunately,thisismoreorlesshowthe$.fn.data()methodworksbyassociatingDOMelementsandJavaScriptobjectvaluesusingspecificstringkeys.Byusingthe$.fn.data()methodandtheplugin’snameasanassociationkey,weareabletostoreandretrievethestateobjectofourpluginveryeasily.

TipUsingthe$.fn.data()methodforthisusecaseisconsideredabestpracticeandisusedbymoststatefulpluginimplementationsandboilerplatessinceitisarobustpartofjQuerythatenablesustoreducethesizeofourplugin’simplementation.

Ifanexistingstateobjectisnotfoundthenwecanassumethatthepluginisnotyetinitializedonthatspecificelementandstartitsinitializationrightaway.ThestateobjectofthispluginwillcontaintheinstanceoftheactiveMutationObserverresponsiblefortrackingthechangesthathappenontheobservedDOMelement,andanarraywithallthecallbacksthathavesubscribedtoittogetnotificationsaboutchanges.

AftercreatinganewMutationObserverinstance,weconfigureittolookforthreespecifictypesofDOMchangesandinstructittoinvokeallthecallbacksoftheplugin’sstateobjectwheneversuchDOMchangesoccur.Finally,wecreatethestateobjectitselftoholdtheobserverandtheassociatedcallbacksandusethe$.fn.data()methodasasetterandassociateitwiththepageelement.

Afterensuringthatthepluginisinstantiatedandinitializedontheprovidedelement,wecheckwhetherthepluginisinvokedwithafunctionasaparameterand,ifso,weaddittothelistoftheplugin’scallbacks.

TipKeepinmindthatusingasingleMutationObserverinstanceperelementandhavingitnotifyaboutDOMchangesbyiteratingoveranarrayofcallbacksgreatlyreducesthememoryrequirementsoftheimplementation,justlikewhenweareusingasingledelegateobserver.

AnexampleofusingournewlyimplementedplugintoobserveforchangesofaspecificDOMelementwouldlooklikethis:

$('.container').mutationObserver(function(mutation){

console.log('SomethingchangedontheDOMtree!');

});

Page 290: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DestroyingaplugininstanceAnextraconsiderationthatastatefulpluginhastotakeintoaccountisofferingthedeveloperawaytoreversethechangesthatitintroducedtothestateofthepage.ThemostcommonandsimpleAPIforachievingthisistoinvokethepluginwiththedestroyliteralasitsfirstparameter.Let’sproceedwiththerequiredimplementationchanges:

(function($){

$.fn.mutationObserver=function(action){

returnthis.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

if(action==='destroy'&&instance){

instance.observer.disconnect();

instance.observer=null;

$element.removeData('plugin_mutationObserver');

return;

}

if(!instance){

/*...*/

}

});

};

})(jQuery);

Inordertoadaptourimplementationtotheaboverequirement,allwehadtodowastocheckwhetherthepluginwasinvokedwiththedestroystringvalueasitsfirstparameter,rightafterretrievingtheplugin’sstateobject.Ifwefindthatthepluginhasalreadybeeninstantiatedonthespecifiedelementandthatthedestroystringvaluehasbeenused,wecanproceedtostoptheMutationObserveritselfandcleartheassociationthat$.fn.data()createdbyusingthe$.fn.removeData()method.Finally,attheendoftheifstatementweaddedareturnstatementsince,aftercompletingthedestructionoftheplugininstance,wenolongerneedtoexecuteanyothercode.Anexampleofdestroyingaplugininstancewiththisimplementationwouldlooklikethis:

$('.container').mutationObserver('destroy');

Page 291: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImplementinggetterandsettermethodsByusingthesametechniquethatwedemonstratedearlierfortheimplementationofthedestroymethodofourplugin,wecanprovideseveralotheroverloadedwaystoinvokeourpluginthatworklikenormalmethods.ThispatternisnotonlyusedbyplainjQueryplugins,butisalsoadoptedbymorecomplexpluginarchitectures,aswithjQuery-UI.

Ontheotherhand,wemightendupwithapluginimplementationthatresultsinalargenumberofinvocationoverloads,whichissomethingthatwouldmakeitdifficulttouseanddocument.AwaytoworkaroundthisistocombinethegetterandsettermethodsofyourAPIintomulti-purposemethods.ThisnotonlyreducestheAPIsurfaceofyourpluginsothatadeveloperhastorememberfewermethodnamesbutitalsoincreasestheproductivitysincethesamepatternisusedinmanyjQuerymethodslike$.fn.html(),$.fn.css(),$.fn.prop(),$.fn.val(),and$.fn.data().

Asademonstrationofthis,let’sseehowwecanaddanewmethodtoourMutationObserverpluginthatworksbothasagetterandasetterfortheregisteredcallbacks:

(function($){

$.fn.mutationObserver=function(action,callbackFn){

varresult=this;

this.each(function(i,element){

var$element=$(element);

varinstance=$element.data('plugin_mutationObserver');

/*...*/

if(typeofaction==='function'){

instance.callbacks.push(action);

}elseif(action==='callbacks'){

if(callbackFn&&callbackFn.length>=0){

//usedasasetter

instance.callbacks=callbackFn;

}else{

//usedasagetterforthefirstelement

result=instance.callbacks;

returnfalse;//breakthe$.fn.each()iteration

}

}

});

returnresult;

};

})(jQuery);

Asshownintheabovecode,wehavecreatedanoverloadedinvocationmethodwhichusesthecallbacksstringvalueasthefirstargumentoftheplugininvocation.ThisgetterandsettermethodallowsustoretrieveoroverwriteallofthecallbacksthatareregisteredontheMutationObserverandworksinadditiontothepre-existingmethodsforinvokingtheplugin,byusingafunctionparameterandthedestroymethod.

Page 292: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Thegetterandsetterimplementationisbasedontheassumptionthat,whentryingtousethecallbacksmethodasagetter,youdon’tneedtopassanyextraparametersand,whentryingtouseitasasetter,youwillpassanextraarrayasaninvocationparameter.Inordertosupportthegettervariant,whichpreventsfurtherchainingandonlyoperatesonthefirstelementofthecompositecollection,wehadtodeclareandusetheresultvariablewhichisinitializedtothevalueofthethisidentifier.Ifthecallbacksgetterisused,weassignthecallbacksofthefirstelementofthecollectiontotheresultvariableandbreakoutofthe$.fn.each()iterationbyreturningfalsetofinishtheexecutionoftheplugin’smethod.

Hereisanexampleusecaseforournewlyimplementedgetterandsettermethod:

//retrievethecallbacks

varoldCallbacks=$('.container').mutationObserver('callbacks');

//clearthem

$('.container').mutationObserver('callbacks',[]);

//addanewone

$('.container').mutationObserver(function(){

console.log('Printedonlyonce');

//restoretheoldcallbacks

$('.container').mutationObserver('callbacks',oldCallbacks);

});

TipKeepinmindthatinvocationoverloadsthatpreventfurtherchainingbyreturningnon-jQueryobjectresultsshouldbewelldocumentedsincethistechniqueconflictswiththechainingprinciplethateveryoneexpectstowork.

Page 293: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingourplugininourDashboardapplicationAftercompletingourmutationObserverplugin,letsnowseehowwecanuseitfortheimplementationofthecountersub-modulethatweusedinourDashboard’simplementationinpreviouschapters:

(function(){

'usestrict';

dashboard.counter=dashboard.counter||{};

var$counter;

dashboard.counter.init=function(){

$counter=$('#dashboardItemCounter');

var$boxContainer=dashboard.$container

.find('.boxContainer');

$boxContainer.mutationObserver(function(mutation){

dashboard.counter.setValue($boxContainer.children().length);

});

};

dashboard.counter.setValue=function(value){

$counter.text(value);

};

})();

Asyoucanseeintheaboveimplementation,ourpluginabstractsnicelyandreplacestheoldimplementationbyprovidingageneric,flexibleandreusableAPI.Insteadoflisteningforclickeventsonthedifferentbuttonsofthepage,theimplementationisnowusingthemutationObserverpluginandobservestheboxContainerelementfortheadditionsorremovalsofchildelements.Moreover,thisimplementationchangedoesnotaffectthefunctionalityofthecountermodulewhichappearstoworkinthesamewaysinceallthechangesareencapsulatedinthemodule.

Page 294: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 295: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingthejQueryPluginBoilerplateThejQueryBoilerplateproject,whichisavailableathttps://github.com/jquery-boilerplate/jquery-patterns,offersseveraltemplatesthatcanbeusedasstartingpointsfortheimplementationofrobustandextensibleplugins.Thesetemplatesincorporatealotofbestpracticesanddesignpatternssuchasthoseanalyzedearlierinthischapter.Eachofthetemplatespacksanumberofbestpracticesthatworkwelltogether,inanattempttoprovidegoodstartingpointsthatbettermatchthevarioususecases.

Perhapsthemostwidelyusedtemplateisjquery.basic.plugin-boilerplatefromAdamSontagandAddyOsmani,whicheventhoughitischaracterizedasagenerictemplateforbeginnersandabove,successfullycoversmostaspectsofjQueryplugindevelopment.WhatmakesthistemplateuniqueistheObject-Orientedapproachthatitfollowswhichispresentedinsuchawaythatithelpsyouwritebetterstructuredcode,withoutmakingithardertointroducecustomizationsontheimplementation.Let’sproceedandanalyzeitssourcecode:

/*!

*jQuerylightweightpluginboilerplate

*Originalauthor:@ajpiano

*Furtherchanges,comments:@addyosmani

*LicensedundertheMITlicense

*/

;(function($,window,document,undefined){

varpluginName="defaultPluginName",

defaults={

propertyName:"value"

};

functionPlugin(element,options){

this.element=element;

this.options=$.extend({},defaults,options);

this._defaults=defaults;

this._name=pluginName;

this.init();

}

Plugin.prototype={

init:function(){/*Placeinitializationlogichere*/},

yourOtherFunction:function(options){/*somelogic*/}

};

//Areallylightweightpluginwrapperaroundtheconstructor,

//preventingagainstmultipleinstantiations

$.fn[pluginName]=function(options){

returnthis.each(function(){

if(!$.data(this,"plugin_"+pluginName)){

$.data(this,"plugin_"+pluginName,

newPlugin(this,options));

}

});

};

})(jQuery,window,document);

Page 296: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Thesemi-colonrightbeforetheIIFEistheretoavoiderrorsincaseofunfortunatescriptconcatenation(andpossiblyminification)withafilethatmightbemissinganendingsemi-colon.Rightbelow,theboilerplateusesthepluginNamevariableasaDRYwayofnamingourpluginandusingitsnameforanyothercase.Asanaddedbenefit,allthatwehavetodoifweneedtorenameourpluginischangethevalueofthisvariableandrenamethe.jsfileofourpluginaccordingly.

Followingthebestpracticesthatwesawearlier,avariableisusedtoholdthedefaultoptionsofthepluginand,aswecanseeafewlineslater,itismergedwiththeuser-providedoptionsusingthe$.extend()method.Keepinmindthat,ifwewanttoexposethedefaultoptions,allthatwehavetodoisdefineitaspartoftheplugin’snamespace:$.fn[pluginName].defaultOptions=defaults;

Theactualplugindefinitioncanbefoundneartheendofthisboilerplatecode.Followingthealreadydiscussedbestpractices,ititeratesovertheitemsofthecollectionusing$.fn.each()andreturnsitsresult,whichisequivalenttoreturningthis.Itthenensuresthatapluginstateinstanceexistsforeachitemofthecollectionbyusingthe$.data()methodandtheprefixedpluginnameasanassociationkey.

ThePluginconstructorfunctionisusedforthecreationoftheplugin’sstateobjectwhich,afterstoringtheDOMelementandthefinalpluginoptionsaspropertiesoftheobject,invokestheinit()methodofitsprototype.Theinit()methodisthesuggestedplacetodefineourinitializationcode,forexample,itcouldinstantiateanewMutationObserveraswedidearlierinthischapter.

Page 297: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

AddingmethodstoyourpluginBydefault,everymethodthatisdefinedaspartoftheprototypeisonlyavailableforinternaluse.Ontheotherhand,wecaneasilyextendtheaboveimplementationtomakeamethodavailabletoallourusers,asshownbelow:

$.fn[pluginName]=function(options,extraParam){

returnthis.each(function(){

varinstance=$.data(this,"plugin_"+pluginName);

if(!instance){

instance=newPlugin(this,options);

$.data(this,"plugin_"+pluginName,instance);

}elseif(options==='yourOtherFunction'){

instance.yourOtherFunction(this,extraParam);

}

});

};

OneguidelinetofollowwhenworkingwiththisboilerplateistoextendyourpluginbyaddingextramethodstothePlugin‘sprototype.Additionally,trytokeepanymodificationstotheplugin’sdefinitionassmallaspossible,ideallysinglelinemethodinvocations.

Inordertomaketheimplementationmorescalable,withregardstohowthepluginmethodsareinvokedandifwewanttoaddanabstractapproachformethodsthatareintendedforinternalorprivateusebytheplugin,wecanintroducethefollowingchanges:

$.fn[pluginName]=function(options){

varrestArgs=Array.prototype.slice.call(arguments,1);

returnthis.each(function(){

varinstance=$.data(this,"plugin_"+pluginName);

if(!instance){

instance=newPlugin(this,options);

$.data(this,"plugin_"+pluginName,instance);

}elseif(typeofoptions==='string'&&//methodname

options[0]!=='_'&&//protectprivatemethods

typeofinstance[options]==='function'){

instance[options].apply(instance,restArgs);

}

});

};

Intheaboveimplementation,weusedthefirstargumenttoidentifythemethodthatneedstobeinvokedandtheninvokeditwiththerestarguments.Wealsoaddedachecktopreventtheinvocationofmethodsthatstartwithanunderscorewhich,accordingtocommonconventions,areintendedtobeforinternalorprivateuse.Asaresult,inordertoaddanextramethodtoyourplugin’spublicAPI,wejustneedtodeclareitinthePlugin.prototypethatwesawearlier.

NoteAnothergreatwaytoimplementyourpluginwhenyouarealreadyusingjQuery-UIinyourapplicationistousethe$.widget()methodwhichisalsoknownasjQuery-UI

Page 298: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WidgetFactory.Itsimplementationabstractsseveralpartsoftheboilerplatecodethatwesawinthischapterandhelpscreatecomplexandrobustplugins.Formoreinformation,youcanreadthedocumentationat:http://api.jqueryui.com/jQuery.widget/

Page 299: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 300: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ChoosinganameLastly,afterlearningthebestpracticesthatweneedtocreateajQueryplugin,let’ssaysomethingaboutthenamingconventionsandwheretopublishyournewandshinyplugin.

Asyouhaveprobablyalreadyseen,mostjQuerypluginsusethefollowingnamingconvention:jQuery-myPluginNamefortheirprojectsitesandrepositoriesandstoretheirimplementationsinafilenamedjquery.mypluginname.js.Aftersettlingonsomeprospectivenamesforyourplugin,takeamomentandsearchthewebtoverifythatthereisnooneelsewiththesameprojectname.ThejQuerydocumentationsuggestssearchingforpluginsonNPMandrefiningyourresultsbyusingthejquery-pluginkeyword.Thisisobviouslythebestwaytopublishyourpluginsothatitcanbeeasilyfoundbyothers.

NoteFormoreinformationaboutNPM,youcanvisit:https://www.npmjs.com/

AnotherpopularplaceforsearchingandhostingJavaScriptlibrariesisGitHub.Youcanfinditsrepositorysearchpageathttps://github.com/search?l=JavaScript,whereitfiltersthesearchresultstoincludeonlyJavaScriptprojectsandsearchesforexistingpluginsandalreadyusedprojectnames.SinceinourcasewearefocusingonjQueryplugins,youwillgetbetterresultsbysearchingforprojectnamesthatfollowtheaforementionednamingconvention,jQuery-myPluginName.

NoteUntilrecently,developerscouldsearchforexistingpluginsandregisteranewoneattheofficialjQueryPluginRegistry(http://plugins.jquery.com/).Unfortunately,ithasbeendiscontinuedandnowonlyallowssearchingforolderpluginswithnonewsubmissions.

Page 301: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 302: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapterwelearnedhowjQuerycanbeextendedbyimplementingandusingplugins.WefirstsawanexampleofthesimplestwaythatajQueryplugincanbeimplementedandanalyzedthecharacteristicsthatmakeagreatplugin,andonewhichfollowstheprinciplesofthejQuerylibrary.

WewerethenintroducedtothemostcommondevelopmentpatternsinthedevelopercommunityforcreatingjQueryPlugins.Weanalyzedtheimplementationproblemsthateachofthemsolvesandtheusecasesthatareabettermatchforthem.

Aftercompletingthischapter,wearenowabletoabstractpartsofourapplicationsintoreusableandextensiblejQuerypluginsthatarestructuredusingthedevelopmentpatternthatbestmatcheseachusecase.

Inthenextchapter,wewillpresentseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofourjQueryapplications,especiallywhentheybecomelargeandcomplex.WewilldiscusssimplepracticessuchasusingCDNstoloadthird-partylibrariesandcontinuewithmoreadvancedsubjectssuchaslazyloadingthemodulesofanimplementation.

Page 303: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 304: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Chapter11.OptimizationPatternsThischapterpresentsseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofjQueryapplications,especiallywhentheybecomelargeandcomplex.

WewillstartwithsimplepracticeslikebundlingandminifyingourJavaScriptfilesanddiscussthebenefitsofusingCDNstoloadthird-partylibraries.WewillthenmoveontoanalyzesomesimplepatternsforwritingefficientJavaScriptcodeandlearnhowtowriteefficientCSSselectorsinordertoimprovethepage’srenderingspeedandDOMtraversalsusingjQuery.

WewillthenstudyjQuery-specificpracticessuchasthecachingofjQueryCompositeCollectionObjects,howtominimizeDOMmanipulations,andhaveareminderoftheDelegateObserverPatternasagoodexampleoftheFlyweightPattern.Lastly,wewillgetanintroductiontotheadvancedtechniqueofLazyLoadingandhaveademonstrationofhowtoloadthedifferentmodulesofanimplementationprogressively,basedonuseractions.

Bytheendofthischapter,wewillbeabletoapplythemostcommonoptimizationpatternstoourimplementationsandusethischapterasachecklistofbestpracticesandperformancetipsbeforemovingtheapplicationtoaproductionenvironment.

Inthischapter,weshall:

LearnthebenefitsofbundlingandminifyingourJavaScriptfilesLearnhowtoloadthird-partylibrariesthroughtheCDNserverLearnsomesimpleJavaScriptperformancetipsLearnhowtooptimizeourjQuerycodeIntroducetheFlyweightpatternandshowcasesomeexamplesofitLearnhowtolazyloadpartsofourapplicationwhenrequiredbyauseraction

Page 305: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

PlacingscriptsneartheendofthepageThefirsttipformakingyourpage’sinitialrenderingfasteristogatheralltherequiredJavaScriptfilesandplacetheir<script>tagsneartheendofthepage,preferablyjustbeforetheclosing</body>tag.Thischangewillhaveagreatimpactonthetimeneededfortheinitialrenderingofthepage,especiallyforuserswithlowspeedconnectionssuchasmobileusers.Ifyouarealreadyusingthe$(document).ready()methodforallinitializationpurposesthatrelatetotheDOM,movingthe<script>tagsaroundshouldnotaffectthefunctionalityofyourimplementationatall.

Themainreasonforthisisthat,eventhoughbrowsersdownloadthepage’sHTMLandotherresources(CSS,images,andsoon)inparallel,whena<script>tagisencountered,thebrowserpauseseverythingelseuntilitisdownloadedandexecuted.Inordertoworkaroundthislimitationofthespecification,attributeslikedeferandasyncfromHTLM5havebeenintroducedaspartsofthe<script>tagspecificationbutunfortunatelyhaveonlystartedtobeadoptedbysomebrowsersrecently.Asaresult,thispracticeisstillwidelyusedtoobtaingoodpageloadingspeedsevenonolderbrowsers.

NoteFormoreinformationaboutthe<script>tagyoucanvisit:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

Page 306: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 307: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

BundlingandminifyingresourcesThefirstplacetolookwhentryingtomakeapageloadfasterisforwaystoreducethenumberandtotalsizeofHTTPrequests.Thebenefitscomefromthefactthatthebrowserdownloadsthecontentinlargerchunksinsteadofspendingtimewaitingforalotofsmallround-tripstotheservertocomplete.Thisisespeciallybeneficialforuserswithlowspeedconnectionssuchasmobileusers.

Resourceconcatenationisasimpleconceptthatdoesnotneedanyintroduction.Thiscanbedonemanuallybutitispreferabletoautomatethistaskwithabundlingscriptorintroduceabuildstepforyourproject.Dependingonyourdevelopmentenvironment,therearedifferentbundlingsolutionstochoosefrom.Ifyouareusinggruntorgulpaspartofyourdevelopmentstack,youcanusesolutionslikegrunt-contrib-concat(https://github.com/gruntjs/grunt-contrib-concat)andgulp-concat(https://github.com/contra/gulp-concat)respectively.

MinifyingJavaScriptfilesisamorecomplexprocedurewhichincludesaseriesofcodetransformationsthatareappliedtothetargetsourcecode,rangingfromsomethingassimpleaswhitespaceremovaltomorecomplextaskslikevariablerenaming.PopularsolutionsforminifyingJavaScriptinclude:

YUICompressoravailableathttp://yui.github.io/yuicompressor/Google’sClosureCompileravailableathttps://developers.google.com/closure/compiler/UglifyJSavailableathttps://github.com/mishoo/UglifyJS2

Onceagain,varioussolutionsexistthatintegratetheabovelibrariesnicelywithyourpreferreddevelopmentenvironmentandmakeminificationasimpletask.Examplesofintegrationsforgruntandgulpincludegrunt-contrib-uglify(https://github.com/gruntjs/grunt-contrib-uglify)andgulp-uglify(https://github.com/terinjokes/gulp-uglify)respectively.

Asafinalword,keepinmindthatyourcodeshouldbeasreadableandaslogicallystructuredaspossible.BundlingandminifyingyourJavaScriptandCSSfilesismosteffectivelydoneasabuildstepofyourdevelopmentanddeploymentprocedures.

Page 308: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingIIFEparametersApartfromhelpingtoavoidpollutingtheglobalnamespace,usingIIFEstowrapyourimplementationcanalsobebeneficialforthesizeofyourminifiedJavaScriptfiles.Let’stakealookatthefollowingcodeinwhichthejQuery,thewindow,andthedocumentvariablesarepassedasinvocationparameterstothemodule’sIIFE.

(function($,window,document,undefined){

if(window.myModule===undefined){

window.myModule={};

}

myModule.init=function(){/*...*/};

$(document).ready(myModule.init);

})(jQuery,window,document);

Wesawasimilarpatterninthepreviouschapter,aspartofthesuggestedtemplateforcreatingjQueryplugins.Eventhoughthevariablealiasingdoesnotaffectthefunctionalityoftheimplementation,itallowsthecodeminifierstoapplyvariablerenaminginmoreplacesthanbefore,resultingincodelikethefollowing:

(function(b,a,c,d){

a.myModule===d&&(a.myModule={});

myModule.init=function(){/*...*/};

b(c).ready(myModule.init);

})(jQuery,window,document);

Asyoucanseeintheabovecode,alltheinvocationparametersoftheIIFEwererenamedbytheminifiertosingleletteridentifiers,whichincreasesthegainsoftheminificationespeciallyiftheoriginalidentifiersareusedinseveralplaces.

TipAsanaddedbenefit,aliasingalsoprotectsourmodulesfromthecasethattheoriginalvariablesgetaccidentallyassignedadifferentvalue.Forexample,whenIIFEparametersarenotused,anassignmentlike$={}orundefined=7fromwithinadifferentmodulewouldbreakalltheimplementation.

Page 309: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 310: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingCDNsInsteadofservingalloftheJavaScriptandCSSfilesofthethird-partylibrariesfromyourwebserver,youshouldconsiderusingaContentDeliveryNetwork(CDN).UsingaCDNtoservethestaticfilesofthelibrariesthatareusedbyyourwebsitecanmakeitloadfastersince:

CDNshavehighspeedconnectionsandseveralcachinglevels.CDNshavemanygeographicallydistributedserversthatcandelivertherequestedfilesfastersincetheyareclosertotheenduser.CDNshelpparallelizeresourcerequests,sincemostbrowserscanonlydownloaduptofourresourcesconcurrentlyfromanyspecificdomain.

Moreover,ifauserhasstaticresourcescachedfromapreviousvisittoanotherwebsitethatusesthesameCDN,heorshewillnothavetodownloadthemagain,reducingthetimethatyoursiteneedstoload.

BelowisalistwiththemostwidelyusedCDNsforJavaScriptlibrarieswhichyoucanuseinyourimplementations:

https://code.jquery.com/https://developers.google.com/speed/libraries/https://cdnjs.com/http://www.jsdelivr.com/

Page 311: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingJSDelivrAPIAnewcomertotheCDNworldisJSDelivr,whichisgainingpopularitybecauseofitsuniquefeatures.Beyondsimplyservingexistingstaticfiles,JSDelivrprovidesanAPI(https://github.com/jsdelivr/api)thatallowsustocreateandusecustombundleswiththeresourcesthatweneedtoload,helpingustominimizetheHTTPrequeststhatoursiteneeds.Moreover,itsAPIallowsustotargetlibrarieswithdifferentlevelsofspecificity(major,minor,orbugfixreleases)andevenallowsustoloadonlyspecificpartsofalibrary.

Asanexample,takealookatthefollowingURL,whichallowsustoloadthemostrecentbugfixreleasesofjQueryv1.11.xwithasinglerequestaswellassomepartsofjQuery-UIv1.10.xandBootstrapv3.3.x:http://cdn.jsdelivr.net/g/[email protected],[email protected](jquery.ui.core.min.js+jquery.ui.widget.min.js+jquery.ui.mouse.min.js+jquery.ui.sortable.min.js),[email protected]

Page 312: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 313: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

OptimizingcommonJavaScriptcodeInthissection,wewillanalyzesomeperformancetipsthatarenotjQuery-specificandcanbeappliedtomostJavaScriptimplementations.

Page 314: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WritingbetterforloopsWheniteratingovertheitemsofanarrayoranarray-likecollectionwithaforloop,asimplewaytoimprovetheperformanceoftheiterationistoavoidaccessingthelengthpropertyoneveryloop.Thiscaneasilybedonebystoringtheiterationlengthtoaseparatevariable,declaredjustbeforethelooporevenalongwithit,asshownbelow:

for(vari=0,len=myArray.length;i<len;i++){

varitem=myArray[i];

/*...*/

}

Moreover,ifweneedtoiterateovertheitemsofanarraythatdoesnotcontainfalsyvalues,wecanuseanevenbetterpatternwhichiscommonlyappliedforiteratingoverarraysthatcontainobjects:

varobjects=[{},{},{}];

for(vari=0,item;item=objects[i];i++){

console.log(item);

}

Inthiscase,insteadofrelyingonthelengthpropertyofthearray,weexploitthefactthataccesstoanout-of-boundspositionofthearrayreturnsundefinedwhichisfalsyandstopstheiteration.AnothersamplecasethatthistrickcanbeusediniswheniteratingoverNodeListsorjQueryCompositeCollectionObjectsasshownbelow:

varanchors=$('a');//ordocument.getElementsByTagName('a');

for(vari=0,anchor;anchor=anchors[i];i++){

console.log(anchor.href);

}

NoteFormoreinformationaboutthetruthyandfalsyJavaScriptvalues,visit:https://developer.mozilla.org/en-US/docs/Glossary/Truthyandhttps://developer.mozilla.org/en-US/docs/Glossary/Falsy

Page 315: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 316: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WritingperformantCSSselectorsEventhoughSizzle(jQuery’sselectorengine)hidesthecomplexityofDOMtraversalsbasedoncomplexCSSselectors,weshouldhaveanideaofhowourselectorsareperforming.UnderstandinghowCSSselectorsarematchedagainsttheelementsoftheDOMhelpsuswritemoreefficientselectorswhichperformbetterwhenusedwithjQuery.

ThekeycharacteristicofefficientCSSselectorsisspecificity.Accordingtothis,IDandClassselectorsarealwaysmoreefficientthanselectorswithmanyresultslikedivand*.WhenwritingcomplexCSSselectors,keepinmindthattheyareevaluatedfromtherighttotheleftandthataselectorgetsrejectedafterrecursivelytestingitagainsteveryparentelementuntiltherootoftheDOM.

Asaresult,trytobeasspecificaspossiblewiththerightmostselectorinordertocutdownthematchedelementsasquicklyaspossibleduringtheexecutionoftheselector.

//initiallymatchesalltheanchorsofthepage

//andthenremovesthosethatarenotchildrenofthecontainer

$('.containera');

//performsbetter,sinceitmatchesfewerelements

//inthefirststepoftheselector'sevaluation

$('.container.mySpecialLinks');

TheotherperformancetipisusingtheChildSelector(“parent>child”)whereverapplicable,inanefforttoeliminatetherecursionoverallthehierarchyoftheDOMtree.Agreatexamplewherethiscanbeappliedisincaseswherethetargetelementscanbefoundataspecificdescendantlevelofacommonancestorelement:

//initiallymatchesallthediv'softhepage,whichisbad

$('.containerdiv');

//alotfasterthanthepreviousone,

//sinceitavoidstherecursiveclasschecks

//untilreachingtherootoftheDOMtree

$('.container>div');

//bestofall,butcan'tbeusedalways

$('.container>.specialDivs');

TipThesametipscanalsobeappliedtoCSSselectorsthatareusedforstylingpages.EventhoughbrowsershavebeentryingtooptimizeanygivenCSSselector,thetipsdescribedabovecangreatlyreducethetimethatisrequiredtorenderawebpage.

NoteFormoreinformationonjQueryCSSselectorperformance,youcanvisit:http://learn.jquery.com/performance/optimize-selectors/

Page 317: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 318: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

WritingefficientjQuerycodeLet’snowproceedandanalyzethemostimportantjQuery-specificperformancetips.Formoreinformationaboutthemostup-to-dateperformancetipsonjQuery,keepaneyeontherelevantpageforjQuery’sLearningCenter:http://learn.jquery.com/performance

Page 319: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

MinimizingDOMtraversalsSincejQuerymadeDOMtraversalssosimple,manywebdevelopersoverusedthe$()functioneverywhere,eveninsubsequentlinesofcode,makingtheirimplementationsslowerbyexecutingunnecessarycode.OneofthemainreasonsthatthecomplexityoftheoperationissooftenoverlookedistheelegantandminimalisticsyntaxthatjQueryuses.DespitethefactthatJavaScriptbrowserenginesbecamemanytimesfasterinthelastfewyears,withperformancecomparabletomanycompiledlanguages,theDOMAPIisstilloneoftheirslowestcomponentsand,asaresult,developershavetominimizetheirinteractionswithit.

CachingjQueryobjectsStoringtheresultofthe$()functiontoalocalvariableandsubsequentlyusingittooperateontheretrievedelementsisthesimplestwayofeliminatingunnecessaryexecutionsofthesameDOMtraversals.

var$element=$('.boxHeader');

if($element.css('position')==='static'){

$element.css({position:'relative'});

}

$element.height('40px');

$element.wrapInner('<b>');

Inthepreviouschapters,weevensuggestedstoringCompositeCollectionObjectsofimportantpageelementsaspropertiesofourmodulesandreusingthemeverywhereinourapplication:

dashboard.$container=null;

dashboard.init=function(){

dashboard.$container=$('.dashboardContainer');

};

TipCachingretrievedelementsonmodulesisaverygoodpracticewhentheelementsarenotgoingtoberemovedfromthepage.Keepinmindthat,whendealingwithelementswithshorterlifespans,inordertoavoidmemoryleaks,youhavetoeitherensurethatyouclearalltheirreferenceswhentheyareremovedfromthepageorhaveafreshreferenceretrievedwhenrequiredandcacheitonlyinsideyourfunctions.

ScopingelementtraversalsInsteadofwritingcomplexCSSselectorsforyourtraversalslike:

$('.dashboardContainer.dashboardCategories');

YoucaninsteadhavethesameresultinamoreefficientwaybyusinganalreadyretriedancestorelementtoscopetheDOMtraversal.Thisway,youarenotonlyusingsimplerCSSselectorsthatarefastertomatchagainstpageelements,butyouarealsoreducingthenumberofelementsthathavetobechecked.Moreover,theresultingimplementationshavelesscoderepetitions(areDRYer)andtheCSSselectorsusedaresimpleandasa

Page 320: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

resultmorereadable.

var$container=$('.dashboardContainer');

$container.find('.dashboardCategories');

Additionally,thispracticeworksevenbetterwithmodule-widecachedelementslikethoseweusedinthepreviouschapters:

$boxContainer=dashboard.$container.find('.boxContainer');

ChainingjQuerymethodsOneofthecharacteristicsofalljQueryAPIsisthattheyareFluentinterfaceimplementationsthatenableustochainseveralmethodinvocationsonasingleCompositeCollectionObject.

$('.boxContent').html('')

.append('<ahref="#">')

.height('40px')

.wrapInner('<b>');

Aswediscussedinpreviouschapters,chainingallowsustoreducethenumberofusedvariablesandleadstomorereadableimplementationswithfewercoderepetitions.

Page 321: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Don’toverdoitKeepinmindthatjQueryalsoprovidesthe$.fn.end()method(http://api.jquery.com/end/)asawayofmovingbackfromachainedtraversal.

$('.box')

.filter(':even')

.find('.boxHeader')

.css('background-color','#0F0')

.end()

.end()//undothefilterandfindtraversals

.filter(':odd')//appliedontheinitial.boxresults

.find('.boxHeader')

.css('background-color','#F00');

Eventhoughthisisahandymethodinmanycases,youshouldavoidoverusingitsinceitcandamagethereadabilityandperformanceofyourcode.Inmanycases,usingcachedelementcollectionsinsteadof$.fn.end()resultsinfasterandmorereadableimplementations.

Page 322: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ImprovingDOMmanipulationsAswesaidearlier,theextensiveuseoftheDOMAPIisoneofthemostcommonthingsthatmakesanapplicationslower,especiallywhenusedtomanipulatethestateoftheDOMtree.Inthissection,wewillshowcasesometipstoimproveperformancewhenmanipulatingtheDOMtree.

CreatingDOMelementsThemostefficientwaytocreateDOMelementsistoconstructaHTMLstringandappendittotheDOMtreeusingthe$.fn.html()method.Additionally,sincethisistoolimitinginsomeusecases,youcanalsousethe$.fn.append()and$.fn.prepend()methods,whichareslightlyslowerbutmaybeabettermatchforyourimplementation.Ideally,ifmultipleelementsneedtobecreated,youshouldtrytominimizetheinvocationofthesemethodsbycreatingaHTMLstringthatdefinesalltheelementsandtheninsertingitintotheDOMtree,asshownbelow:

varfinalHtml='';

for(vari=0,len=questions.length;i<len;i++){

varquestion=questions[i];

finalHtml+='<div><label><span>'+question.title+':</span>'+

'<inputtype="checkbox"name="'+question.name+'"/>'+

'</label></div>';

}

$('form').html(finalHtml);

Anotherwaytoachievethesameresult,isbyusinganarraytostoretheHTMLforeachintermediateelementandthenjointhemrightbeforetheinsertiontotheDOMtree:

varparts=[];

for(vari=0,len=questions.length;i<len;i++){

varquestion=questions[i];

parts.push('<div><label><span>'+question.title+':</span>'+

'<inputtype="checkbox"name="'+question.name+'"/>'+

'</label></div>');

}

$('form').html(parts.join(''));

NoteThisisacommonlyusedpatternsince,untilrecently,itperformedbetterthanconcatenatingtheintermediateresultswith“+=”.

StylingandanimatingWheneverpossible,useCSSclassesforyourstylingmanipulationsbyutilizingthe$.fn.addClass()and$.fn.removeClass()methodsinsteadofmanuallymanipulatingthestyleoftheelementswiththe$.fn.css()method.That’sespeciallyusefulwhenyouneedtostylealargenumberofelementssincethisisthemainpurposeofCSSclassesandbrowsershavealreadyspentyearsoptimizingit.

Tip

Page 323: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Asanextraoptimizationsteptominimizethenumberofmanipulatedelements,youcanapplyCSSclassesonasinglecommonancestorelementanduseadescendantCSSselectortoapplyyourstyling,asdemonstratedhere:https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_selectors

Whenyoustillneedtousethe$.fn.css()method,forexample,whenyourimplementationneedstobeimperative,usetheinvocationoverloadthatacceptsobjectparameters:http://api.jquery.com/css/#css-properties.Inthisway,therequiredmethodinvocationsareminimizedwhenapplyingmultiplestylesonelementsandyourcodeisbetterorganized.

Moreover,avoidmixingmethodsthatmanipulatetheDOMwithmethodsthatreadfromtheDOMsincethiswillforceareflowofthepagesothatthebrowsercancalculatethenewpositionsofthepageelements.

Insteadofdoingsomethinglikethis:

$('h1').css('padding-left','2%');

$('h1').css('padding-right','2%');

$('h1').append('<b>!!</b>');

varh1OuterWidth=$('h1').outerWidth();

$('h1').css('margin-top','5%');

$('body').prepend('<b>--!!--</b>');

varh1Offset=$('h1').offset();

Prefergroupingthenon-conflictingmanipulationstogetherlikethis:

$('h1').css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$('body').prepend('<b>--!!--</b>');

varh1OuterWidth=$('h1').outerWidth();

varh1Offset=$('h1').offset();

Thebrowsercanthusskipsomere-renderingsofthepage,resultinginfewerpausesoftheexecutionofyourcode.

NoteFormoreinformationaboutreflows,visitthefollowingpage:https://developers.google.com/speed/articles/reflow

Lastly,notethatalljQuery-generatedanimationsinv1.xandv2.xareimplementedusingthesetTimeout()function.Thisisgoingtochangeinv3.xofjQuerywhichplanstousetherequestAnimationFrame()function,whichisabettermatchforcreatingimperativeanimations.Untilthen,youcanusethejQuery-requestAnimationFrameplugin(https://github.com/gnarf/jquery-requestAnimationFrame)whichmonkey-patchesjQuerytousetherequestAnimationFrame()functionforitsanimationswhenitisavailable.

Page 324: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

ManipulatingdetachedelementsAnotherwaytoavoidunnecessaryrepaintsofthepagewhilemanipulatingDOMelementsistodetachtheelementfromthepageandre-attachitaftercompletingyourmanipulations.Workingwithadetachedin-memoryelementismuchfasteranddoesnotcausereflowsonthepage.

Inordertoachievethat,weusethe$.fn.detach()methodwhich,incontrastto$.fn.remove(),preservesalleventhandlersandjQuerydataonthedetachedelement.

var$h1=$('#pageHeader');

var$h1Cont=$h1.parent();

$h1.detach();

$h1.css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$h1Cont.append($h1);

Additionally,tobeabletoplacethemanipulatedelementbackintoitsoriginalposition,wecancreateandinsertahiddenplaceholderelementintotheDOM.Thisemptyandhiddenelementdoesnotaffecttherenderingofthepageandisremovedaftertheoriginalitemisplacedbackintoitsoriginalposition.

var$h1PlaceHolder=$('<divstyle="display:none;"></div>');

var$h1=$('#pageHeader');

$h1PlaceHolder.insertAfter($h1);

$h1.detach();

$h1.css({

'padding-left':'2%',

'padding-right':'2%',

'margin-top':'5%'

}).append('<b>!!</b>');

$h1.insertAfter($h1PlaceHolder);

$h1PlaceHolder.remove();

$h1PlaceHolder=null;

NoteFormoreinformationaboutthe$.fn.detach()method,youcanreadthedocumentationat:http://api.jquery.com/detach/

IntroducingtheFlyweightPatternAccordingtoComputerScience,aFlyweightisanobjectthatisusedasameansofreducingthememoryconsumptionofanimplementationbyprovidingfunctionalityand/ordatathataresharedwithotherobjectinstances.ThePrototypesofJavaScriptconstructorfunctionscanbecharacterizedasFlyweightssinceeveryobjectinstancecanuseallofthe

Page 325: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

methodsandpropertiesthataredefinedinitsprototypeuntilitoverwritesthem.Ontheotherhand,classicalFlyweightsareseparateobjectsfromtheobjectfamilythattheyareusedwithandoftenholdtheshareddataandfunctionalityinspecialdatastructures.

Page 326: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UsingDelegateObserversAgreatexampleofFlyweightsinjQueryapplicationsisDelegateObserverswhich,aswesawintheDashboardexampleinChapter2,TheObserverPattern,cangreatlyreducethememorydemandsofanimplementationbyworkingasacentralizedeventhandlerforalargegroupofelements.Inthisway,wecanavoidthecostofsettingupseparateobserversandeventhandlersforeveryelementandusethebrowser’seventbubblingmechanismtoobserveforthemonasinglecommonancestorelementandfiltertheirorigin.

$boxContainer.on('click','.boxCloseButton',function(){

var$button=$(this);

dashboard.informationBox.close($button);

});

NoteTheactualFlyweightobjectistheeventhandleralongwiththecallbackthatisattachedtotheancestorelement.

Page 327: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Using$.noop()ThejQuerylibraryoffersthe$.noop()methodwhichisactuallyanemptyfunctionthatcanbesharedamongimplementations.Usingemptyfunctionsasdefaultcallbackvaluessimplifiesandimprovesthereadabilityofanimplementationbyreducingthenumberofifstatements.ThisishandyforjQuerypluginsthatalreadyencapsulatecomplexfunctionality.

functiondoLater(callbackFn){

setTimeout(function(){

if(callbackFn){

callbackFn();

}

},500);

}

//with$.noop()

functiondoLater(callbackFn){

callbackFn=callbackFn||$.noop();

setTimeout(function(){

callbackFn();

},500);

}

Insuchsituations,wheretheimplementationrequirementsorthepersonaltasteofthedeveloperhasledtousingemptyfunctions,the$.noop()methodisusefulasawaytolowermemoryconsumptionbysharingasingleemptyfunctioninstanceamongallthedifferentpartsofanimplementation.Anaddedbenefitofusingthe$.noop()methodforeverypartofanimplementationisthatwecanalsocheckwhetherapassedfunctionreferenceistheemptyfunctionbysimplycheckingcallbackFn===$.noop().

NoteFormoreinformation,youcanfindthedocumentationat:http://api.jquery.com/jQuery.noop/

Page 328: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Usingthe$.singlepluginAnothersimpleexampleoftheFlyweightpatterninjQueryapplicationsisthejQuery.singlepluginasdescribedbyJamesPadolseyinhisarticle,76bytesforfasterjQuery,whichtriestoeliminatethecreationofnewjQueryobjectswheneverweneedtoapplyjQuerymethodsonasinglepageelement.TheimplementationisquitesmallandcreatesasinglejQuerycompositecollectionobjectthatisreturnedoneveryinvocationofthejQuery.single()method,containingthepageelementthatwasusedasanargument.

jQuery.single=(function(){

varcollection=jQuery([1]);

//Fillwith1item,tomakesurelength===1

returnfunction(element){

collection[0]=element;//Givecollectiontheelement:

returncollection;//Returnthecollection:

};

}());

ThejQuery.singlepluginisusefulwhenusedinobserverslike$.fn.on()anditerationswithmethodslike$.each().

$boxContainer.on('click','.boxCloseButton',function(){

//var$button=$(this);

var$button=$.single(this);

//thisisnotcreatinganynewobject

dashboard.informationBox.close($button);

});

ThebenefitsofusingthejQuery.singleplugincomefromthefactthatwearecreatingfewerobjectsand,asaresult,thebrowser’sGarbageCollectorwillalsohavelessworktodowhenfreeingupthememoryofshortlivedobjects.

Asasidenote,keepinmindthesideeffectsofhavingasinglejQueryobjectreturnedbyeveryinvocationofthe$.single()methodandthefactthatthelastinvocationargumentwillbestoreduntilthenextinvocationofthemethod:

varbuttons=document.getElementsByTagName('button');

var$btn0=$.single(buttons[0]);

var$btn1=$.single(buttons[1]);

$btn0===$btn1//thisistrue

Additionally,incasethatyouusesomethinglike$btn1.remove()thentheelementwillnotbefreeduntilthenextinvocationofthe$.single()methodwhichwillremoveitfromtheplugin’sinternalcollectionobject.

AnothersimilarbutmoreextensivepluginisthejQuery.flypluginwhichcanbeinvokedwitharraysandjQueryobjectsasparameters.

NoteFormoreinformationaboutjQuery.singleandjQuery.fly,youcanvisitthefollowingURLs:http://james.padolsey.com/javascript/76-bytes-for-faster-jquery/andhttps://github.com/matjaz/jquery.fly.

Page 329: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Ontheotherhand,thejQueryimplementationthathandlestheinvocationofthe$()methodwithasinglepageelementisnotcomplexatallandonlycreatesasinglesimpleobject.

jQuery=function(selector,context){

returnnewjQuery.fn.init(selector,context);

};

/*...*/init=jQuery.fn.init=function(selector,context,root){

/*...else*/

if(selector.nodeType){

this.context=this[0]=selector;

this.length=1;

returnthis;

}/*...*/

};

Moreover,theJavaScriptenginesofmodernbrowsershavealreadybecomequiteefficientwhendealingwithshort-livedobjectssincesuchobjectsarecommonlypassedaroundanapplicationasmethodinvocationparameters.

Page 330: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 331: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

LazyLoadingModulesFinally,wewillgetanintroductiontotheadvancedtechniqueofLazyLoadingModules.Thekeyconceptofthispracticeisthat,duringthepageload,thebrowserwillonlydownloadandexecutethosemodulesthatarerequiredfortheinitialrenderingofthepagewhiletherestoftheapplicationmodulesarerequestedafterthepageisfullyloadedandisrequiredtorespondtoauseraction.RequireJS(http://requirejs.org/)isapopularJavaScriptlibrarythatisusedasamoduleloaderbut,forsimplecases,wecanachievethesameresultwithjQuery.

Asanexampleofthis,wewilluseittolazyloadtheinformationBoxmoduleoftheDashboardexamplethatwesawinpreviouschapters,afterthefirstclickoftheuserontheDashboard’s<button>.WewillabstracttheimplementationthatisresponsiblefordownloadingandexecutingJavaScriptfilesintoagenericandreusablemodulenamedmoduleUtils:

(function(){

'usestrict';

dashboard.moduleUtils=dashboard.moduleUtils||{};

dashboard.moduleUtils.getModule=function(namespaceString){

varparts=namespaceString.split('.');

varresult=parts.reduce(function(crnt,next){

returncrnt&&crnt[next];

},window);

returnresult;

};

varongoingModuleRequests={};

dashboard.moduleUtils.ensureLoaded=function(namespaceString){

varexistingNamespace=this.getModule(namespaceString);

if(existingNamespace){

return$.Deferred().resolve(existingNamespace);

}

if(ongoingModuleRequests[namespaceString]){

returnongoingModuleRequests[namespaceString];

}

varmodulePromise=$.getScript(namespaceString.toLowerCase()+

'.js')

.always(function(){

ongoingModuleRequests[namespaceString]=null;

}).then(function(){

returndashboard.moduleUtils.getModule(namespaceString);

});

ongoingModuleRequests[namespaceString]=modulePromise;

returnmodulePromise;

};

Page 332: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

})();

ThegetModule()methodacceptsthemodule’snamespaceasastringparameterandreturnseithertheModule’sSingletonObjectitselforafalsyvalueifthemoduleisnotalreadyloaded.ThisisdonewiththeArray.reduce()methodwhichisusedtoiterateoverthedifferentpartsofthenamespacestring,usingthedot(.)asadelimiterandevaluatingeachpartonthepreviousobjectcontext,startingwithwindow.

NoteFormoreinformationabouttheArray.reduce()method,youcanvisit:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

ensureLoaded()istheprimarymethodofthemoduleUtilsmoduleandisresponsibleforretrievingandexecutingmodulesthatarenotalreadyloaded.ItfirstusesthegetModule()methodtocheckwhethertherequestedmodulehasalreadybeenloadedand,ifso,returnsitsnamespaceobjectasaResolvedPromise.

Thenextstep,ifamodulehasnotyetbeenloaded,istochecktheongoingModuleRequestsobjecttoverifywhethertherequestedmoduleisnotalreadybeingdownloaded.Inordertodothat,theongoingModuleRequestsobjectusesthemodule’snamespacestringasapropertyandstoresthePromisesoftheAJAXrequeststhatareusedtoretrievethe.jsfilesfromtheserver.IfaPromiseobjectisavailablethenwecaninferthattheAJAXrequestisstillongoingand,insteadofstartinganewone,wereturntheexistingPromise.

Finally,whennoneoftheabovereturnsaresult,weusethelowercasemodulefilenamingconventionthatwediscussedinpreviouschaptersandusejQuery’s$.getScript()methodtoinitiateanAJAXrequesttoretrievetherequestedmodulefile.ThePromisecreatedfortheAJAXrequestisassignedastotheappropriatepropertyoftheongoingModuleRequestsobjectandisthenreturnedtothecallerofthemethod.When,atalaterpointintime,thePromiseisFulfilled,were-evaluatethemoduleandreturnitasthefinalresultofthereturnedPromise.Moreover,regardlessoftheresultoftheAJAXrequest,thePromiseisalsoremovedfromtheongoingModuleRequestsobjectinordertokeeptheimplementationreusableincaseofanetworkfailureandalsofreeupthememorythatwasallocatedfortherequest.

NoteKeepinmindthatthe$.getScript()methodmightnotworkinsomebrowserswhenthepageisloadedthroughthefilesystem,butdoesworkasintendedwhenservedusingawebserverlikeApache,IISornginx.Formoreinformationabout$.getScript(),youcanvisit:http://api.jquery.com/jQuery.getScript/

TheonlychangethatweintroducedtotheexistingimplementationoftheinformationBoxmoduleforthisdemonstrationwastomakeitself-initializableinanattempttoreducethecomplexityoftheensureLoaded()method.

(function(){

Page 333: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

'usestrict';

dashboard.informationBox=dashboard.informationBox||{};

var$boxContainer=null;

dashboard.informationBox.init=function(){/*…*/};

$(document).ready(dashboard.informationBox.init);

/*...*/

})();

Finally,wealsohadtochangetheimplementationofthecategoriesmodulesothatitwouldusetheensureLoaded()methodbeforeusingtheinformationBoxmodule.Asyoucanseebelow,wehadtorefactorthecodehandlingtheclickeventonthedashboard’s<button>sincetheensureLoaded()methodreturnsaPromiseasaresult:

//indashboard.categories.init

dashboard.$container.find('.dashboardCategories').on('click','button',

function(){

var$button=$(this);

varitemName=$button.text();

varp=dashboard.moduleUtils.ensureLoaded('dashboard.informationBox');

p.then(function(){

dashboard.informationBox.openNew(itemName);

});

});

Page 334: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount
Page 335: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

SummaryInthischapter,welearnedseveraloptimizationtechniquesthatcanbeusedtoimprovetheperformanceofjQueryapplications,especiallywhentheybecomelargeandcomplex.

WestartedwithsimplepracticeslikebundlingandminifyingourJavaScriptfilesanddiscussedthebenefitsofusingCDNstoloadthird-partylibraries.WethenwentontoanalyzesomesimplepatternstowritingefficientJavaScriptcodeandlearnedhowtowriteefficientCSSselectorstoimprovethepage’srenderingspeedandDOMtraversalsusingjQuery.

WecontinuedwithjQuery-specificpracticessuchascachingofjQueryCompositeCollectionObjects,howtominimizeDOMmanipulations,andhadareminderoftheDelegateObserverpattern,asagoodexampleoftheFlyweightPattern.Lastly,wegotanintroductiontotheadvancedtechniqueofLazyLoadingandsawademonstrationofhowtoloadthevariousmodulesofanimplementationprogressively,basedonuseractions.

Aftercompletingthischapter,wearenowabletoapplythemostcommonoptimizationpatternstoourimplementationsandusethischapterasachecklistofbestpracticesandperformancetipsbeforemovinganapplicationtoaproductionenvironment.

Page 336: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IndexA

$.ajax()method/AcceptingconfigurationparametersaddEventListener()methods

URL/IntroducingtheObserverPatternapplications

developing,withCompositePattern/UsingtheCompositePatterntodevelopapplicationsUnderscore.jstemplates,using/UsingUnderscore.jstemplatesinourapplicationsHandlebars.jstemplates,using/UsingHandlebars.jsinourapplications

Array.reduce()methodreference/LazyLoadingModules

attachEvent()methodURL/IntroducingtheObserverPattern

AustralianNationalUniversity(ANU)/Writingmethodsthatacceptcallbacks

Page 337: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

BBabeltranspiler

URL/IntroducingES6Modulesbroker/IntroducingthePublish/SubscribePatternBuilderPattern

about/IntroducingtheBuilderPatternadopting,byjQuery/HowitisadoptedbyjQuery’sAPIusing,byjQueryinternally/HowitisusedbyjQueryinternallyusing,inapplications/Howtouseitinourapplications

Page 338: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

CCallbackHell

URL/AvoidingtheCallbackHellanti-patterncallbacks

about/Programmingwithcallbacksprogrammingwith/Programmingwithcallbackssimplecallbacks,usinginJavaScript/UsingsimplecallbacksinJavaScriptsetting,asobjectproperties/Settingcallbacksasobjectpropertiesusing,injQueryapplications/UsingcallbacksinjQueryapplicationsmethods,writing/Writingmethodsthatacceptcallbacks

callbacks,orchestratingabout/Orchestratingcallbacksqueuing,inorderexecution/QueuinginorderexecutionCallbackHellanti-pattern,avoiding/AvoidingtheCallbackHellanti-patternrunningconcurrently/Runningconcurrently

categoriesmodule/ThecategoriesmoduleCDNs

about/UsingCDNsusing/UsingCDNsJSDelivrAPI,using/UsingJSDelivrAPI

closureabout/IntroducingtheObserverPatternURL/IntroducingtheObserverPattern

ClosureCompilerreference/Bundlingandminifyingresources

closuresURL/TheIIFEbuildingblock

commonJavaScriptcodeoptimizing/OptimizingcommonJavaScriptcodeforloops,writingfor/Writingbetterforloops

CompositePatternabout/TheCompositePatternusing,byjQuery/HowtheCompositePatternisusedbyjQuerycomparing,withplainDOMAPIbenefits/ComparingthebenefitsovertheplainDOMAPIused,fordevelopingapplications/UsingtheCompositePatterntodevelopapplicationssampleusecase/AsampleusecaseCollectionImplementation/TheCompositeCollectionImplementationexampleexecution/Anexampleexecutionalternativeimplementations/Alternativeimplementationspairing,withIteratorPattern/HowitpairswiththeCompositePattern

configurationparameters

Page 339: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

accepting/AcceptingconfigurationparametersContentDeliveryNetwork(CDN)/UsingCDNscountermodule/ThecountermoduleCSSSelectors/ThejQueryDOMTraversalAPIcustomeventnamespacing

using/UsingcustomeventnamespacingURL/Usingcustomeventnamespacing

customeventsinjQuery/CustomeventsinjQueryused,forimplementingPublish/SubscribePattern/ImplementingaPub/Subschemeusingcustomevents

Page 340: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

DDashboardapplication

reusableplugins,using/UsingourplugininourDashboardapplicationdashboardexample

Publish/SubscribePattern,using/UsingPub/Subonthedashboardexampledashboardmodule/Themaindashboardmoduledeferredobserver/Thecategoriesmoduledeferredobservers/ThecountermoduleDelegatedEventObserverPattern

about/IntroducingtheDelegatedEventObserverPatternused,forsimplifyingcode/Howitsimplifiesourcodememoryusagebenefits,comparing/Comparethememoryusagebenefits

DelegateObserversusing/UsingDelegateObservers

descendantCSSselectorreference/Stylingandanimating

DocumentFragmentabout/HowitisadoptedbyjQuery’sAPI

DocumentFragmentsreference/HowitisadoptedbyjQuery’sAPI

DocumentObjectMode(DOM)URL/jQueryandDOMscriptingmanipulating,withjQuery/ManipulatingtheDOMusingjQuery

DOMAPI/ThejQueryDOMTraversalAPIDOMLevel2Eventspecification

URL/HowitiscomparedwitheventattributesDOMmanipulations,improving

about/ImprovingDOMmanipulationsDOMelements,creating/CreatingDOMelementsanimating/Stylingandanimatingstyling/Stylingandanimatingdetachedelements,manipulating/ManipulatingdetachedelementsFlyweightPattern/IntroducingtheFlyweightPattern

DOMscriptingandjQuery/jQueryandDOMscripting

DOMtraversals,minimizingabout/MinimizingDOMtraversalsjQueryobjects,caching/CachingjQueryobjectselementtraversals,scoping/ScopingelementtraversalsjQuerymethods,chaining/ChainingjQuerymethods

Page 341: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

E$.extend()helpermethod

URL/AcceptingconfigurationparametersefficientjQuerycode

writing/WritingefficientjQuerycodeDOMtraversals,minimizing/MinimizingDOMtraversalsoveruse,avoiding/Don’toverdoitDOMmanipulations,improving/ImprovingDOMmanipulationsDelegateObservers,using/UsingDelegateObservers$.noop(),using/Using$.noop()$.singleplugin,using/Usingthe$.singleplugin

EncapsulationURL/Encapsulatinginternalpartsofanimplementation

ES5StrictModeusing/UsingES5StrictMode

ES6modulesabout/IntroducingES6ModulesURL/IntroducingES6Modules

eventattributesURL/Howitiscomparedwitheventattributes

eventlistenersremoving,URL/Avoidmemoryleaks

eventobjectURL/Extendingtheimplementation

Page 342: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

F$.fn.addClass()method/WorkingonCompositeCollectionObjects$.fn.closest()method

URL/Demonstrateasampleusecase$.fn.data()method/ImplementingastatefuljQueryPlugin$.fn.end()method

reference/Don’toverdoit$.fn.ready()method/Thedocument-readyobserver

URL/Thedocument-readyobserverFacadePattern

about/IntroducingtheFacadePatternbenefits/Thebenefitsofthispatternadopting,byjQuery/HowitisadoptedbyjQuery

Facadesusing,inapplications/UsingFacadesinourapplications

Factoriesusing,inapplications/UsingFactoriesinourapplications

FactoryPatternabout/IntroducingtheFactoryPatternkeyconcept/IntroducingtheFactoryPatternadopting,byjQuery/HowitisadoptedbyjQuery

falsyJavaScriptvaluereference/Writingbetterforloops

FlyweightPatternabout/IntroducingtheFlyweightPattern

functionData()URL/ThejQueryonmethod

Page 343: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

G$.getScript()method

URL/RetrievingHTMLtemplatesasynchronouslyreference/LazyLoadingModules

genericiteratorfunction/HowtheIteratorPatternisusedbyjQuerygettermethod

implementing/ImplementinggetterandsettermethodsgetValuesmethod/TheCompositeCollectionImplementationglobalnamespace/AvoidingglobalvariableswithNamespaces,TheRevealingModulePatternGoogle’sJavaScriptStyleGuide

URL/Thewideacceptancegrunt-contrib-concatproject

URL/UsingModulesinjQueryapplications

Page 344: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

HHandlebars.js

about/IntroducingHandlebars.jsURL/IntroducingHandlebars.js,UsingHandlebars.jsinourapplications,Pre-compilingtemplatesusing,inapplications/UsingHandlebars.jsinourapplicationstemplatepre-compilation,URL/Pre-compilingtemplates

HTMLtemplatesseparating,fromJavaScriptcode/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcoderetrievingasynchronously/RetrievingHTMLtemplatesasynchronouslyadopting,inexistingimplementation/Adoptingitinanexistingimplementationmoderation/Moderationisbestinallthings

Page 345: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

IIIFE

used,forwrappingjQueryPlugin/WrappingwithanIIFEabout/WrappingwithanIIFE

IIFE-containedmodulevariant/TheIIFE-containedModulevariantIIFEparameters

using/UsingIIFEparametersImmediatelyInvokedFunctionExpression(IIFE)/Thedocument-readyobserver

about/TheIIFEbuildingblockURL/TheIIFEbuildingblock

incrementmethod/TheCompositeCollectionImplementationIndexedDB

URL/RunningconcurrentlyinformationBoxmodule/TheinformationBoxmoduleIteratorPattern

about/TheIteratorPatternusing,byjQuery/HowtheIteratorPatternisusedbyjQuerypairing,withCompositePattern/HowitpairswiththeCompositePatternusing/Wherecanitbeused

Page 346: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

JJavaScript

Prototype-basedprogrammingmodel,URL/TheCompositeCollectionImplementation

JavaScriptcodeHTMLtemplates,separating/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcode

JavaScriptlibrariesURL/Choosinganame

jQueryandDOMscripting/jQueryandDOMscriptingURL/jQueryandDOMscripting,ManipulatingtheDOMusingjQuery,HowtheIteratorPatternisusedbyjQueryused,formanipulatingDOM/ManipulatingtheDOMusingjQueryMethodChaining/MethodChainingandFluentInterfacesFluentInterfaces/MethodChainingandFluentInterfacesCompositePattern,using/HowtheCompositePatternisusedbyjQueryGitHubpage,URL/HowtheCompositePatternisusedbyjQueryIteratorPattern,using/HowtheIteratorPatternisusedbyjQueryObserverPattern,using/HowitisusedbyjQueryPublish/SubscribePattern/HowitisadoptedbyjQuerycustomevents/CustomeventsinjQuerycodeorganization,URL/Overviewoftheimplementation

jQuery-requestAnimationFramepluginreference/Stylingandanimating

jQuery-UIWidgetFactoryURL/Addingmethodstoyourplugin

jQuery.ajaxSetup()method/AcceptingconfigurationparametersjQuery.guid/ThejQueryonmethodjQuery.noConflict()method

URL/Workingwith$.noConflict()jQueryapplications

modules,using/UsingModulesinjQueryapplicationsMockObjectPattern,using/UsingMockObjectsinjQueryapplications

jQueryequivalentmethodURL/Avoidmemoryleaks

jQueryimplementationabout/HowitisadoptedbyjQueryjQueryDOMTraversalAPI/ThejQueryDOMTraversalAPIpropertyaccessandmanipulationAPI/ThepropertyaccessandmanipulationAPI

jQueryJavaScriptStyleGuideURL/Thewideacceptance

Page 347: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

jQueryonmethod/ThejQueryonmethodjQueryPlugin

about/IntroducingjQueryPluginsprinciples,following/FollowingjQueryprinciplescharacteristics/FollowingjQueryprinciples$.noConflict(),workingwith/Workingwith$.noConflict()wrapping,withIIFE/WrappingwithanIIFEnamingconventions/Choosinganame

jQueryPluginBoilerplateURL/UsingthejQueryPluginBoilerplateusing/UsingthejQueryPluginBoilerplatemethods,adding/Addingmethodstoyourplugin

jQueryPluginRegistryURL/Choosinganame

jQueryprinciplesfollowing/FollowingjQueryprinciplesCompositeCollectionObjects,workingon/WorkingonCompositeCollectionObjectsfurtherchaining/Allowingfurtherchaining

jQueryPromisestransforming,to/TransformingtojQueryPromises

jQuerysourceviewerURL/ThejQueryonmethod

jQuerySourceViewerURL/HowtheCompositePatternisusedbyjQuery

jQueryv3.0A+Promisesimplementationreference/ComparingjQueryandA+Promises

JSDelivrAPIusing/UsingJSDelivrAPIreference/UsingJSDelivrAPI

Page 348: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

LLazyLoadingModules

about/LazyLoadingModulesLevel2SelectorAPI/ThejQueryDOMTraversalAPI

Page 349: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Mmemoryusagebenefits

comparing/ComparethememoryusagebenefitsMethodChaining/MethodChainingandFluentInterfacesMockjaxjQueryPluginlibrary

reference/ImplementingaMockServiceusing/ImplementingaMockService

MockObjectPatternabout/IntroducingtheMockObjectPatternusing,injQueryapplications/UsingMockObjectsinjQueryapplicationsactualservicerequirements,defining/DefiningtheactualservicerequirementsMockService,implementing/ImplementingaMockServiceMockService,using/UsingtheMockService

ModulePatternabout/TheModulePatternImmediatelyInvokedFunctionExpression(IIFE)buildingblock/TheIIFEbuildingblocksimpleIIFEModulePattern/ThesimpleIIFEModulePatternusing,injQuery/HowitisusedbyjQuerynamespaceparametermodulevariant/TheNamespaceParameterModulevariantIIFE-containedmodulevariant/TheIIFE-containedModulevariant

modulesabout/ModulesandNamespaces,Encapsulatinginternalpartsofanimplementationinternalpartimplementation,encapsulating/Encapsulatinginternalpartsofanimplementationacceptance/Thewideacceptanceusing,injQueryapplications/UsingModulesinjQueryapplications

modules,jQueryapplicationsusing/UsingModulesinjQueryapplicationsdashboardmodule/Themaindashboardmodulecategoriesmodule/ThecategoriesmoduleinformationBoxmodule/TheinformationBoxmodulecountermodule/Thecountermoduleimplementation,overview/Overviewoftheimplementation

MustacheURL/IntroducingHandlebars.js

MutationObserverURL/ImplementingastatefuljQueryPlugin

Page 350: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

N$.noConflict()

working/Workingwith$.noConflict()$.noop()

using/Using$.noop()reference/Using$.noop()

namespacedeventsURL/Usingcustomeventnamespacing

namespaceparametermodulevariant/TheNamespaceParameterModulevariantnamespaces

about/ModulesandNamespaces,AvoidingglobalvariableswithNamespacesinternalpartimplementation,encapsulating/Encapsulatinginternalpartsofanimplementationglobalvariables,avoiding/AvoidingglobalvariableswithNamespacesbenefits/Thebenefitsofthesepatternsacceptance/Thewideacceptance

namespacing/AvoidingglobalvariableswithNamespacesnamingconventions,jQueryPlugin

selecting/ChoosinganameNPM

URL/Choosinganame

Page 351: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Oobject-orientedJavaScript

URL/ThewideacceptanceObjectLiteral/HowitisadoptedbyjQueryObjectLiteralPattern/TheObjectLiteralPattern,ThesimpleIIFEModulePattern,TheRevealingModulePatternObserverPattern

about/IntroducingtheObserverPatternURL/IntroducingtheObserverPatternusing,injQuery/HowitisusedbyjQueryjQuery.fn.on()method/ThejQueryonmethoddocument-readyobserver/Thedocument-readyobserversampleusecase,demonstrating/Demonstrateasampleusecasecomparing,witheventattributes/Howitiscomparedwitheventattributeseventattributes,comparingwith/Howitiscomparedwitheventattributesmemoryleaks,avoiding/AvoidmemoryleaksandPublish/SubscribePattern,differentiatingbetween/HowitdiffersfromtheObserverPattern

Page 352: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Ppatterns

benefits/ThebenefitsofthesepatternsperformancetipsonjQuery

reference/WritingefficientjQuerycodeperformantCSSselectors

writing/WritingperformantCSSselectorsplaceholdernotations,_.tempate()method

<%=%>notation/IntroducingUnderscore.js<%-%>/IntroducingUnderscore.js<%%>notation/IntroducingUnderscore.js

Promisesabout/IntroducingtheconceptofPromisesusing/UsingPromisesjQueryPromiseAPI,using/UsingthejQueryPromiseAPIadvancedconcepts/Advancedconceptsjoining/JoiningPromisesusing,byjQuery/HowjQueryusesPromisestransforming,toothertypes/TransformingPromisestoothertypesbenefits/SummarizingthebenefitsofPromises

Promises,chainingabout/ChainingPromisesthrownerrors,handling/Handlingthrownerrors

Promises/A+using/UsingPromises/A+reference/UsingPromises/A+comparing,withjQuery/ComparingjQueryandA+Promisestransforming,to/TransformingtoPromises/A+

Publish/SubscribePatternabout/IntroducingthePublish/SubscribePatternandObserverPattern,differentiatingbetween/HowitdiffersfromtheObserverPatternusing,byjQuery/HowitisadoptedbyjQueryimplementing,withcustomevents/ImplementingaPub/Subschemeusingcustomeventssampleusecase/Demonstratingasampleusecaseusing,ondashboardexample/UsingPub/Subonthedashboardexampleimplementation,extending/Extendingtheimplementation

publishers/IntroducingthePublish/SubscribePattern

Page 353: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

RRequireJS

URL/LazyLoadingModulesresources

bundling/Bundlingandminifyingresourcesminifying/Bundlingandminifyingresources

reusablepluginscreating/Creatingreusablepluginsconfigurationparameters,accepting/AcceptingconfigurationparametersstatefuljQueryPlugins,writing/WritingstatefuljQuerypluginsstatefuljQueryPlugin,implementing/ImplementingastatefuljQueryPlugininstance,destroying/Destroyingaplugininstancegettermethod,implementing/Implementinggetterandsettermethodssettermethods,implementing/Implementinggetterandsettermethodsusing,inDashboardapplication/UsingourplugininourDashboardapplication

RevealingModulePatternabout/TheRevealingModulePattern

Page 354: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

S$.singleplugin

using/Usingthe$.singleplugin<script>tag/Placingscriptsneartheendofthepagesampleusecase,ObserverPattern

demonstrating/Demonstrateasampleusecasesampleusecase,Publish/SubscribePattern

demonstrating/Demonstratingasampleusecaseobject,usingasbroker/Usinganyobjectasabroker

scriptsplacing,nearendofpage/Placingscriptsneartheendofthepage

SeparationofConcernsabout/EncapsulatinginternalpartsofanimplementationURL/Encapsulatinginternalpartsofanimplementation

SeparationofConcernsprinciple/Thebenefitsofthispatternsettermethod

implementing/Implementinggetterandsettermethodssimplecallback

defining/IntroducingtheObserverPatternsimpleIIFEModulePattern

about/ThesimpleIIFEModulePatternSingleResponsibilityprinciple

URL/TheIteratorPatternSizzle/ThejQueryDOMTraversalAPI,WritingperformantCSSselectors

URL/HowitisusedbyjQueryreference/ThejQueryDOMTraversalAPI

specifiedNodeTypesURL/HowtheCompositePatternisusedbyjQuery

statefuljQueryPluginswriting/WritingstatefuljQuerypluginsimplementing/ImplementingastatefuljQueryPlugininstance,destroying/Destroyingaplugininstance

strictexecutionmodeURL/WrappingwithanIIFE

strictmode,JavaScriptURL/UsingES5StrictMode

subscribers/IntroducingthePublish/SubscribePattern

Page 355: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

TTiny

URL/ImplementingaPub/SubschemeusingcustomeventstruthyJavaScriptvalue

reference/Writingbetterforloops

Page 356: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

UUglifyJS

reference/BundlingandminifyingresourcesUnderscore.js

about/IntroducingUnderscore.jsusing,inapplications/UsingUnderscore.jstemplatesinourapplicationsHTMLtemplates,separatingfromJavaScriptcode/SeparatingHTMLtemplatesfromJavaScriptcode,SeparatingHTMLtemplatesfromJavaScriptcodetemplates,pre-compiling/Pre-compilingtemplates

Page 357: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

Vvariable

namingconventions/ManipulatingtheDOMusingjQuery

Page 358: dl.ebooksworld.irdl.ebooksworld.ir/motoman/Packt.jQuery.Design.Patterns.pdf · Table of Contents jQuery Design Patterns Credits About the Author About the Reviewer eBooks, discount

YYUICompressor

reference/Bundlingandminifyingresources