a-software-engineer-learns-html5-javascript-and-jquery-dane-cameron().pdf

703

Upload: bertderat

Post on 08-Jul-2016

27 views

Category:

Documents


4 download

TRANSCRIPT

A Software Engineer LearnsHTML5, JavaScript and jQuery By Dane Cameron

© 2013 Dane Cameron All rights reserved. No part of thispublication may be reproduced,distributed, or transmitted in any formor by any means, includingphotocopying, recording, or otherelectronic or mechanical methods,without the prior written permission ofthe publisher, except in the case ofbrief quotations embodied in criticalreviews and certain other non-commercial uses permitted bycopyright law. For permissionrequests, write to the publisher,addressed “Attention: PermissionsCoordinator,” at the address below.Original and modified cover art byKarunakar Rayker and

Table of ContentsIntroduction

About this book

A Brief Overview of Web Applications

HTML5 Markup Language

Javascript Fundamentals

jQuery

Debugging

Moving to a Web Server

Building the Web Application

Managing Client-side Data

Tidying up the Web Application

Offline Web Applications

Working with Files

Web Workers

AJAX

Server Sent Events and Web Sockets

Error Handling

Conclusion

Appendix A: Cascading Style Sheets

Appendix B: Recommended Libraries

PrefaceJavaScript (and its frameworks such asjQuery) and HTML (along with itsstyle sheet language CSS) havebecome a ubiquitous presence insoftware development. Due to theirmonopoly position in web browsers,and the fact web browsers have spreadfrom PCs to phones, tablets and TVs;this pervasiveness will continue togrow and grow.Despite their success, many softwareengineers are apprehensive aboutJavaScript and HTML. Thisapprehensiveness is not completelyunfounded; both JavaScript and HTMLwere rushed in their early years, anddriven by commercial rather thanengineering interests. As a result, manydubious features crept into theselanguages. Due to backwardscompatibility concerns, most of thesefeatures still remain.

In addition, many software engineershave used these languages without everlearning them. JavaScript and HTMLhave low barriers to entry, and this,along with their similarity to otherlanguages, led many softwareengineers to conclude that there reallywas nothing much to learn.If you have not used JavaScript andHTML for a number of years you maybe surprised at what they now offer.Browser based web applications arenow capable of matching or exceedingthe sophistication and scale oftraditional desktop applications. Inorder to create complex webapplications however, it is essential tolearn these languages.This book takes the point of view thatonce you have a strong grasp of thefundamentals, the details will take careof themselves. It will not present youwith long lists of APIs, or intricate

details of every attribute, these can befound in reference manuals. It willfocus on the details of each languagethat are fundamental to understandinghow they work.I hope this book helps you discover theelegance and beauty of JavaScript andHTML, and makes you think differentlyabout what can be achieved with theselanguages. October, 2013

IntroductionI’m not going to second guess yourmotivations for reading this book – butI would like to tell you how I arrivedat writing it.I was a software engineer with 15years’ experience writing large-scale,enterprise Java applications. Typicallythese applications performed systemintegration functions, rather than end-user functionality.I then joined a team writing a complexweb application from scratch. Thisweb application had a number ofrequirements I had not encounteredbefore:• It had to run inside the latest versionof all major browsers.• It had to be capable of runningwithout network connectivity forperiods of time, and therefore neededto store reasonably large amounts of

data on the client.• It had to be capable of reading filesselected by the user while offline.• It needed to be highly dynamic, andallow complex interactions withoutpage refreshes.•It needed to perform as well or betterthan a desktop application.• It needed to be standards based, andnot utilize browser plugins.I had written simple HTML pages andsimple JavaScript over the years butwas often frustrated by it. JavaScriptwas particularly frustrating: itresembled Java (which I knew well),but it seemed to have got many thingswrong. The more I tried to apply myJava thinking to JavaScript, the worsethings seemed to get.I did at least realize that I had not takenthe time to learn JavaScript. I hadmade many assumptions about what

JavaScript was, and how it worked,but I had never taken the time to verifythese assumptions.Before starting my new project Idecided to start from scratch and learnthe best approached for building a webapplication with the languagesavailable. I had used enough webapplications over recent years to knowthe potential browser-basedtechnologies offered, but I didn’t knowthe best way to unlock this potential.The more I learned about the platformmodern browsers offered softwareengineers the more surprised I became.The standards loosely grouped togetheras HTML5 offer a wide-ranging set offeatures from data storage to offlineresource storage to file management.In addition, the more I learned aboutJavaScript the more impressed Ibecame. JavaScript may bear asuperficial similarity to Java, but in

actuality it has more in common withfunctional languages such as LISP andScheme. The features that had initiallytroubled me about JavaScript turnedout to be enormous strengths in thelanguage.Finally, I came across the jQuerylibrary. jQuery does not allow asoftware engineer to do anything thatcould not be done with nativeJavaScript APIs, but it provides suchan elegant abstraction on top ofJavaScript that it became an essentialcomponent in my toolbox. It removedmy final hesitation with browser-basedtechnologies: the cumbersome DOMAPI.This book is the book I wanted to readat the beginning of my journey. It startsfrom the assumption that you havesome training as a software engineer orcomputer programmer, and presents theessentials you need to understand,

without attempting to cover all aspectsof each language. Once thesefundamentals are understood, theprocess of expanding your knowledgewith these languages is comparativelytrivial.Before beginning, it is worthreviewing the rise of HTML andJavaScript over the last few years in-particular, and the reasons this hashappened.

Browser Wars Part 2The original browser wars took placein the late 1990s between Netscapeand Microsoft. Microsoft won. As aresult, browser technology stagnated:from 2001-2006 the user experiencebarely progressed at all.The second browser war startedaround 2005, first with Firefox, andthen with the rise of Chrome. Thisbrowser war became an arms race asall major browser vendors added newand interesting features to theirbrowsers. Many of these features wereeventually standardized as part of theHTML5 standardization process, andadopted by other browser vendors.One of the main consequences of thesecond browser war was a dramaticimprovement in the performance ofJavaScript.JavaScript is an interpreted language.As such it tends to have worse

performance than a compiled languagesuch as C or C++. This is because anintermediary (the interpreter) isresponsible for taking instructions, andconverting them to machine specificinstructions in real time as the programexecutes. The performance ofJavaScript was so poor in InternetExplorer it was really only appropriatefor simple tasks such as formvalidation.Google in particular recognised thatthe performance of JavaScript was amajor hindrance to the development ofweb applications. In order to improvethe performance of JavaScript, Googledeveloped the V8 JavaScript engine in2008.The V8 JavaScript engine producedmassive increases in JavaScriptperformance by compiling JavaScriptinto machine language on a Just-In-Time (JIT) basis rather than

interpreting it as it was executed.Since the release of V8, all majorbrowser vendors have implementedJIT compilation in their JavaScriptengines. Browser vendors also beganto actively compete amongst oneanother to create the fastest JavaScriptengine, and a variety of benchmarkshave been created to compare theirrelative performance. Microsoft finallyentered the race with IE9, andcontinued to build on theirperformance with IE10.JavaScript has now reached the stagewhere performance is seldom a majorissue, and the performance of largescale web applications can equal orsurpass that of desktop applications.All major browsers have highlyoptimised JavaScript engines, and theperformance has reached the pointwhere JavaScript has begun to be usedoutside the browser: Node.js

successfully uses JavaScript as aserver side technology (using the V8JavaScript engine).

Rise of the Web ApplicationAs a result of the improvements inbrowser technologies, it has becomepossible to create complex webapplications that run entirely withinbrowsers.In the early days of the World WideWeb, pages were largely static in theircontent. Web sites quickly evolved toallow dynamic interaction with users,and this led to the possibility ofcommerce web sites such as Amazon.The set of technologies adopted toallow the dynamic manipulation ofweb sites was referred to as DHTML(Dynamic HTML), and is really theprecursor to the HTML5 technologiesexplored in this book.DHTML allowed web pages to bemanipulated in real time after theywere loaded, but it was still difficult tocreate large-scale web applicationsthat did not rely on page refreshes to

perform most of their actions, largelydue to the performance issues withJavaScript, and the lack of browserAPIs for relatively simple features,such as data-storage.The first major game changer wasGmail, which was released to thegeneral public in 2007. Not only didGmail accelerate the trend towardscloud computing by offering users anunprecedented 1GB of storage, itpopularised the use of AJAX.AJAX allows a web page to interactwith a web server after the page isloaded, and without requiring a refreshof the web page. This meant a webapplication could consist of a singleweb page that would redraw itself asthe user interacted with it, and as itreceived additional data from theserver.Google didn’t invent the technologiesbehind AJAX (in fact Microsoft did),

and they weren’t the first to use AJAXto develop a web application, but theybrought AJAX into the limelight, andshowed programmers what could beachieved.AJAX has become such a dominanttechnology in the last 5 years it is hardto conceive of a time when it did notexist.Once people realized what could beachieved inside the browser, therecame a push from both IT departmentsand end-users to use browser basedweb applications for a variety of tasksthat had once been the domain ofdesktop applications. Browser basedweb applications provide manybenefits to their users:• There is no need to install theapplication on each machine.• New versions of software can bereleased on a regular basis withoutneeding users to follow an upgrade

process. In fact some web applicationshave daily releases of software.• Web applications can be hosted oncloud based infrastructure, leading tohigher availability, and lower costs.• The same web application can beused on multiple devices, includinghandheld devices such as phones andtablets.• Users can access the application fromanywhere in the world at any time ofthe day or night.Web browsers have now become akinto operating systems in the features andlibraries they offer software engineers.It now makes sense to think of thebrowser as a mature platform forsoftware development, just as you maythink of OSX, Android or Windows asa platform.

The Networked WorldThe other major change that hasoccurred in the last 5 years is theubiquitous availability of high-speednetworks. Many people now havenear-permanent access to high-speednetworks, either wired or wireless.The availability of networks has led tothe rise of cloud computing. Cloudcomputing is an umbrella term for anumber of technologies, but at heart itmeans that software engineers do notneed to think about hardware,hardware is provided as a service.For users, cloud computing means theirapplications and data are available atany time, and from any location.Cloud computing is one of the fastestgrowing trends in IT, and is only set togrow further and faster as more andmore devices become networkenabled. It is estimated in 2013 thathalf of Americans own 3 or more

network enabled devices.Although it is possible to write cloudbased applications that do not runinside browsers, browsers are theperfect platform for cloud basedapplications, because the one constantall devices have in common is a webbrowser, therefore a single version ofthe application can be written that runson all platforms.

ConclusionThe conclusion you can draw from thischapter is that HTML5 and JavaScriptare perfectly placed to be the drivingforce powering the applications mostusers interact with on a daily basis.

About This BookWhat you needThis book assumes you have someexperience developing software, andpreferably have at least a basicunderstanding of HTML.This book will not offer step-by-steptutorials on the basics of either HTMLor JavaScript. Even with no priorexperience with these languageshowever, the process of writing a webapplication will introduce you to allthe essential aspects of theselanguages, just not necessarily in thesame order a traditional tutorialwould.If you have not encountered JavaScriptand/or HTML previously it may beadvisable to gain an understanding ofthe basic syntax of these languages(loops, conditional expressions etc.)before beginning. Websites such as

http://www.w3schools.com/ providebasic introductions to both HTML andJavaScript.The exercises in this book can beperformed on any computer withaccess to the following:1. A text editor for writing code.Notepad++ (http://notepad-plus-plus.org) is a good option forWindows, Text Wrangler(http://www.barebones.com/products/textwrangler)is a good choice for Macs, and EMacsis a good choice for Linux. You mayalso choose to use an IntegratedDevelopment Environment (IDE) suchas Eclipse.2. Chrome or Firefox web browser. Ifyou choose to use Firefox, you willneed to install the Firebug plugin togain access to a full suite ofdevelopment tools. The examples andscreenshots in this book will useChrome, but there is nothing presented

in this book that does not work withFirefox, IE10 or Safari. I believe thedeveloper tools in Chrome are nowsuperior to those offered by otherbrowsers, therefore if you are startingfrom scratch I strongly recommendChrome.3. A Web Server. This will only berequired later in the book, and there isa chapter explaining how to install anduse the Mongoose web server. Youmay choose to use any other webserver you like, but the instructionswill only be provided for Mongoose.All the examples in this book areaccessible from the following website:www.cisdal.com/publishing.htmlA zip file is provided for each chapterof the book (where appropriate)containing the resources for the webapplication as they stand at the end ofthe chapter.

As mentioned above, this book willguide you through the process ofdeveloping a web application.Throughout the first half of this bookthe web application can be serveddirectly from your local file-systemrather than a web server.All web browsers can display HTMLfiles directly from the file-system: youcan simply drag and drop the HTMLfile into the web browser, or use theFile -> Open File option from thebrowser menu bar.Unfortunately, browsers will oftencache resources such as JavaScript andCSS files when a web page is loadeddirectly from the file-system. In orderto circumvent this in Chrome you canopt to open a new window in Incognitomode:

Any resources loaded by the browserin this mode will not be cached.If this proves too painful, you canchoose to serve pages from a localweb server from the start of this book.Chapter 8 provides detailedinstructions for installing theMongoose web server on yourcomputer. Pages served through a webserver can still be cached by the webbrowser, but using “force refresh” willreliably ensure the resources arerefreshed:• Command+Shirt+r on OSX

• Ctrl+F5 on WindowsMany of the examples in this book,particularly in the early chapters, canbe run directly using a JavaScriptinterpreter. All major browsers nowprovide development tools offeringdirect access to a JavaScriptinterpreter.In order to access the Chromeinterpreter, simply open Chrome, andtype:• Command+Option+i on OSX• F12 or Ctrl+Shift+I on WindowsAlternatively, you can right clickanywhere on any web page and choose“Inspect Element”:

Once the Developer Tools are open,click the “Console” tab.In order to prove that this is a genuineJavaScript interpreter, simply type 1+1at the command prompt:

One aspect of browsers that haveadvanced tremendously over the lastfew years are the tools offered todevelopers. Browser vendors haverealised that there is a direct benefit tothem when developers use their

browsers, and therefore actively woodevelopers with the tools they offer.This book will introduce you to manyof the features offered by the Chromedeveloper tools, but it is worthinvestigating the various capabilitieson your own.

ConventionsOne unfortunate aspect of eBooks isthat it is difficult to format computercode effectively on all devices, sincethe width of the screen can changefrom device to device. Ideally codewill be presented in a distinct, fixed-width font; however this is notpossible on all eBook readers. Wheresupported, all code in this book willutilize the following font:This is code

When code is executed inside theJavaScript interpreter, the input will beprefixed with a “>” character: whenentering these commands yourself thisshould be omitted. In addition an emptyline will separate input from output:> 1+1

2

If two commands are shown

simultaneously, these will be separatedby an additional empty line betweenthe result of the first command and theinput of the second command:>1+1

2

>2+2

4

If the output is irrelevant to the pointbeing made, it may be omitted.

FeedbackI would love to hear your feedback(positive and negative) on this book.Please email me [email protected].

A Brief Overview of WebApplicationsThis book is designed to teach youhow to write rich web applicationsutilizing the tools and technologiesavailable natively in web browsers (asopposed to plugins). This book willfocus solely on the languages andlibraries available in the latestversions of the following webbrowsers:• Chrome• Firefox• IE• Safari• OperaMany of the examples in this book willnot work in older browsers, and inmany cases there are no workarounds.When writing a web application theobvious first question to ask is “What

browsers, and which versions of thosebrowsers do I need or want tosupport?”There is an obvious trade-offinvolved:• The more browser and browserversions you support, the more userscan use your web application.Remember, some users, particularly incorporate environments, do not chooseeither their browser or their browserversion.• The more browser and browserversions you support, the morerestrictions you will encounter in termsof availability and compatibility ofAPIs. Later in this book we willencounter an approach called polyfillsthat allow you to “upgrade” thefeatures offered by a user’s browser,but this approach will not alwayswork.All major browsers now support auto

updates. Although this feature can beturned off, it does mean that it is nolonger a wild assumption to assumethat most users will have the latestversion of their favourite browser, atleast outside corporate environments.The main exception to this is InternetExplorer. Internet Explorer 10 is notavailable on older versions ofWindows; therefore many users willhave older versions of InternetExplorer. In general, most of theexamples in this book will work inInternet Explorer 9, some will work inInternet Explorer 8, but supportingInternet Explorer 6 and 7 becomes amore daunting proposition.The web site http://caniuse.com/ is aninvaluable resource for understandingthe features offered by variousbrowsers and browser versions.

What is a web application?A reasonable question to ask is “Whatis a web application, and how is itdifferent from a web site?” Even theopening section of the HTML5specification states that it is designedto address “…the vague subjectreferred to as web applications”.There is no definitive answer to thisquestion, but the web applicationdeveloped in this book exhibits thefollowing characteristics:• It uses a web browser for its userinterface.• It allows users to perform actions andmanipulate data without performingscreen refreshes.• It is interactive, and respondspromptly to user actions.• It stores data on behalf of a user,either on the client or the server.• If it needs to access a web server, it

does so using asynchronous AJAXcalls.• It favours asynchronous APIs oversynchronous APIs.• It may be available even when theuser is not connected to the Internet.

// It will be importantthroughout this book that youunderstand the differencebetween an asynchronous anda synchronous API. Althoughthis book will offer manyexamples, the basicdifference between the twois:• A synchronous API waitsfor a response, and blockseverything else fromhappening in the application

until that response isreceived.• An asynchronous API doesnot wait for a response, butinstead asks to be notifiedwhen a response is available.As a result it does not blockother functionality in theapplication from progressing.

The HTML5 specification suggests thatweb applications will also exhibit thefollowing features:• They are used on an occasional basis,or on a regular basis but from differentlocations.• They have low CPU requirements.There is some truth to these statements.For instance, a web applicationversion of a word processor will notgenerally exhibit the same usability

and features as a native wordprocessor, but has considerableadvantages if documents need to beedited by many different people indifferent locations.This chapter will briefly introduce youto the languages that we will use todevelop the web applicationthroughout this book.

HTML5HTML5 can be a confusing term.HTML5 includes a specification of amarkup language for creatingdocuments that can be rendered in webbrowsers. As a markup language,HTML5 both extends and rationalisesearlier versions of HTML andXHTML.As part of its extension of HTML,HTML5 offers a new set of tags to website developers. Many of these tags aredesigned to provide greaterdescriptive power to HTML. Forinstance, HTML5 contains header andfooter tags. These tags do not allowpages to do or look any different thanthey did previously, and are one of theless interesting aspects of HTML5; wewill examine a subset of these newtags in this book.HTML5 also contains new tags tosupport audio and video, and a canvas

for rendering 2D shapes and bitmaps.It is these features of HTML5 that havedrawn a lot of attention, particularlythe way these features positionHTML5 as a direct competitor toAdobe Flash. Apple refuses to allowAdobe Flash on certain devices,arguing that websites should useHTML5 equivalents, since they arestandards compliant, and do notrequire plugins. This book will largelyignore the multi-media aspects ofHTML5, since they are usually notrelevant for web applications, but it isimportant to know they are there.As part of its rationalisation ofXHTML in particular, HTML5acknowledges that the strictnessenforced by earlier versions of theHTML standards was both unnecessary(browsers still rendered pages thatbroke the rules), and counter-productive (since there was nostandard for how browsers should

handle pages that were invalid in someway, it was left up to each vendor).The HTML5 specification containsdetailed rules for how browservendors should create a consistentDocument Object Model from the inputprovided. A large part of the HTML5specification deals directly with theserules, and again, is beyond the scope ofthis book.

// Don’t worry if you are notfamiliar with the DocumentObject Model (it will beexplained below) or XHTML(it is largely obsolete).

HTML5 also enhances the formcomponents available in HTML. Inaddition to providing new types ofinput fields (such as date pickers and

color pickers), HTML5 providesadditional attributes on existing inputfields. HTML5 also provides nativevalidation of form components.In addition to providing a markuplanguage and a set of form components,HTML5 is a set of standards for APIsthat web browsers can implement.These APIs are wide ranging andvaried, and range from offline storageof data and content, reading files,background processes, server-sentevents and much more. It is thesefeatures of HTML5 that are trulyturning the web browser into aplatform for application development.This book will use many of the newAPIs when developing the exampleweb application.The HTML5 standards process isinteresting in its own right. Many of thestandards are actually reverseengineered from features already

present in web browsers. For instance,the technology behind AJAX (theXMLHttpRequest object) was firstdeveloped as a proprietary feature ofInternet Explorer. Other browsers thenreverse engineered this feature, andfinally, once the major browserssupported it, it was standardised byW3C (in fact, it is still a workingdraft).

// The World Wide WebConsortium (W3C) is themain standards organisationfor the World Wide Web.Their web site can be foundhere: http://www.w3.orgwhile the HTML5specification can be foundherehttp://www.w3.org/TR/html5The HTML5 specification is

actually produced by twoseparate bodies: W3C andWHATWG. Both bodies offerthe standards under their ownlicenses. WHATWG actuallydeserve far more credit thanW3C for HTML5, W3Cinitially voted not to beinvolved with HTML5, but tocontinue pushing XML basedstandards. W3C finallyacknowledged they hadbacked the wrong horse andbecame actively involvedwith HTML5.It is also worth mentioningthat the W3C and WHATWGversions of the specificationsare not identical. From asoftware engineers point ofview this is largelyirrelevant. Web designershave a saying “code alwayswins”. This is also true of

HTML5: the specification islargely irrelevant; it is thebrowser implementations thatmatter.

In some cases, one particular browservendor drives a standard. Thisoccasionally leads to an impasse, ashas occurred with the Web SQL API. Inother cases a speciation is progressedthat is not widely supported (such asthe File Writer and File System API),and therefore has an uncertain future. Inthe best cases however, all majorbrowser support the API according tothe standard agreed.The other important aspect of HTML5is that it is a living standard. As youwill see in the following chapters, theHTML5 document type does notspecify a version: it is just HTML, andit will change as the standardsprogress, and as browsers adopt those

standards.

JavaScriptJavaScript is the only languagenatively supported in virtually all webbrowsers in existence. JavaScript firstappeared in 1995 in an early versionof the Netscape Navigator browser,and quickly migrated to InternetExplorer. JavaScript is essential foradding dynamic and interactivefeatures to a web application.

// Although Microsoft continuesto support VBScript, this hasnot been implemented in otherbrowsers meaning it is not aviable option when creatingWeb Applications.

It is worth clearing up a small pointregarding terminology first. JavaScripthas been formalized in the

ECMAScript language specification.When this book refers to JavaScript,technically it is referring toECMAScript version 5.JavaScript was named after theprogramming language Java, but thiswas primarily to allow JavaScript topiggyback off the name recognition ofJava rather than any intrinsic similaritybetween the languages.JavaScript is in fact a very differentlanguage from Java, specifically:• JavaScript supports dynamic typingas opposed to Java, which supportsstatic typing. This means you candeclare a variable in JavaScriptwithout declaring its type, which willonly be derived at run-time.• JavaScript has first class functions. Itis possible to assign a function to avariable or pass it to another functionas a parameter. This may sound like asmall feature, but it leads to an

enormous number of possibilities, andallows software engineers to writesoftware using functional programmingtechniques. These techniques will bediscussed in detail in later chapters.• Although JavaScript supportsclasses, its implementation of classesis somewhat confusing. This book willrecommend that you avoid classes asfar as possible and utilize prototypingtechniques to create objects.This book is not a tutorial on allfeatures of the JavaScript language.Instead, this book will outline a set offundamental approaches that softwareengineers can adopt with JavaScript.If you have never taken the time tolearn JavaScript before, and especiallyif you have only used statically typedlanguages, you will likely beimpressed with the elegance andflexibility JavaScript syntax lends toits users.

JQueryjQuery is a JavaScript library designedto simplify the process of writingJavaScript applications within webbrowsers.Due to the document-centric nature ofweb pages, JavaScript is routinelyresponsible for selecting elementswithin the document (the internalrepresentation of a document inside thebrowser is referred to as the DocumentObject Model), manipulating theseelements, or reacting to eventstriggered by these elements. JavaScriptnatively supports this functionalitythrough the Document Object ModelAPI, which is also included in theHTML5 specification. jQueryessentially provides an elegantwrapper around the Document ObjectModel API.The heart of jQuery is a selectorengine. jQuery accepts selection

criteria based on CSS style selectors,and returns a set of elements from thedocument that meet these criteria. Oncea set of elements has been selected,jQuery provides a wide array offunctions to perform operations onthese elements, or to attach eventlisteners to them.Although jQuery cannot do anythingJavaScript could not do with the nativeDOM API, it has become enormouslypopular for several reasons:• It removes the pain of dealing withquirks between different browsers.• It provides a rich and succinct syntaxthat is seen by most as a vastimprovement over the DocumentObject Model API.• It is simple to write custom pluginsfor jQuery, and therefore it can beextended to meet specific needs.• There are a wide range of open

source plugins available for jQuery,including a popular UI toolkit calledjQuery UI.There are a number of competitors tojQuery such as Dojo and Prototype, butjQuery has obtained a critical mass inthe market place and is almost a de-facto standard for web applications.

Cascading Style SheetsCascading Style Sheets provides astyle sheet language for HTML. Themajority of presentational features thatremained in HTML from the pre-CSSdays have now been removed inHTML5, and all presentation shouldnow be performed entirely with CSS.CSS provides a separation ofconcerns, and allows the styling of apage to change independently of itscontent, and vice versa. HTML isresponsible for conveying the meaningof the web page, while CSS conveysits presentation.This also means that the same contentcan be repurposed for differentdevices (such as mobile phones) bysimply providing a new style sheet.CSS provides a set of properties thatdescribe how elements in the documentshould be styled when then matchcertain rules, and how they should

interact with one another. The stylesthat can be applied to elements ismind-boggling, and has beensignificantly extended in CSS3, whichis a specification largely running inparallel with HTML5.It is usually not important for asoftware engineer to have an intimateknowledge of all CSS features,however it is important to understandthe fundamentals, otherwise a hugeamount of frustration and agony canensue. As with all the languagesaddressed in this book, CSS is not assimple as it may appear, and a stronggrasp of its fundamentals is importantfor anyone involved in thedevelopment of web applications.We will largely ignore CSS during thedevelopment of the sample webapplication in this book. HoweverAppendix A: Cascading Style Sheetsprovides an in-depth introduction to

CSS, and you can skip to that sectionany time you need.

HTML5 Markup LanguageIn this chapter we are going to look atthe changes to the HTML markuplanguage that have been included in theHTML5 specifications. The sampleweb application will use many, but byno means all of the new HTML5 tags,and a number of the attributes that havebeen added.As mentioned above, the term HTML5refers to both a markup language (anew version of HTML), and a set ofAPIs. HTML5 APIs will be covered inlater chapters of this book.

Page structureIt is often good to start with thesimplest possible example, forHTML5 that would be:<!DOCTYPE html>

hello world!!!

Open your favourite text editor, enterthe code above, save it as “hello.html”and open it in your favourite HTML5compliant browser.This may not look like an HTML page.For instance, there is no html tag andno body tag? Despite this, the browserknows what to do with the minimalcontent provided. If we analyse theDocument Object Model generated forthis page in the Chrome browser (openthe Chrome Developer Tools and clickthe “Elements” tab) we will see thefollowing:

The browser has derived the intent ofthe HTML page and generated acompliant internal Document ObjectModel.The HTML5 specification is veryrelaxed compared to earlier iterationsof the specifications. Over the yearsthere has been a move to stricterdefinitions of HTML, most noticeablyHTML 4.01 Strict (published in 2000),and XHTML. These standardsemphasised strict markup rules, suchas always closing tags, and alwaysplacing quotes around attribute values.This drive for strictness was driven bya number of reasons:• Earlier versions of HTML andXHTML were based on other markup

languages (SGML and XMLrespectively), and this imposedrestrictions on HTML.• It is easier for browsers to derive theintent from documents written withstrict rules, and this would helpcompatibility across browsers.• It is easier for other tools to processdocuments if they comply with strictrules.Despite the increasing strictness of theHTML and XHTML specifications,browsers never really enforced theserules. Browser vendors had long agocome to the realisation that it was intheir best interests to make the best ofany markup they were given,regardless of its validity againstrelevant standards. From a browservendor point of view the rationale isobvious: users will lose patience witha browser that refuses to render pagesdue to technicalities, and choose a

browser that will.A large discord had developedbetween browser vendors on the onehand, and the teams developingtechnical specifications on the other.This made no sense, since the technicalspecifications only had value if theywere adopted by browser vendors.HTML5 has radically reversed thissituation with a heavy dose ofpragmatism.As mentioned above, a large part of theHTML5 specification details howbrowsers should handle markup thatwould previously have beenconsidered invalid. This is whyChrome could generate a DocumentObject Model from the “hello world”example. It is also why Firefox wouldgenerate exactly the same DocumentObject Model.Despite the fact that the example aboveworks, the following is probably the

most appropriate skeleton to use whendeveloping HTML5 compliantdocuments:<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

</head>

<body>

</body>

</html>

I will explain the meaning of eachsection below, but before that we willadd some content to the tasks.htmldocument to make a start with thesample web application.Throughout this book we are going todevelop a task list application. Thetask list will include the followingfunctionality:• Users can create new tasks: thisincludes due dates and task categories.

• Users can edit tasks.• Users can delete tasks.• Users can view their task list.• Overdue tasks are highlighted tousers.• Users can set tasks to complete.Although this may seem a relativelysimple web application, it containsenough complexity to show theimportant features of each language,but not so much complexity that thebook becomes repetitive or focused onrequirements.We will begin by writing the markupthat will form the basis of the task listscreen. In this chapter all content willbe static: in later chapters we willmake this dynamic through the use ofJavaScript and jQuery.To begin the sample project, create anew folder anywhere on your file-system and add a file to it called

tasks.html. This should contain thefollowing content:

// Remember these examplescan be downloaded from thebook’s website atcisdal.com/publishing.htm.Each chapter has a zip filewith all the examples.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css" media="screen" />

</head>

<body>

<header>

<span>Task list</span>

</header>

<main>

<section>

<form>

<div>

<label>Task</label> <input type="text"required="required"

name="task" class="large"placeholder="Breakfast at Tiffanys" />

</div>

<div>

<label>Required by</label> <inputtype="date" required="required"

name="requiredBy" />

</div>

<div>

<label>Category</label> <selectname="category">

<optionvalue="Personal">Personal</option>

<option value="Work">Work

</option>

</select>

</div>

<nav>

<a href="#">Save task</a> <ahref="#">Clear task</a>

</nav>

</form>

</section>

<section>

<table id="tblTasks">

<colgroup>

<col width="50%">

<col width="25%">

<col width="25%">

</colgroup>

<thead>

<tr>

<th>Name</th>

<th>Due</th>

<th>Category</th>

</tr>

</thead>

<tbody>

<tr>

<td>Return library books</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Personal</td>

</tr>

<tr class="even">

<td>Perform project demo tostakeholders</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Work</td>

</tr>

<tr>

<td>Meet friends for dinner</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Personal</td>

</tr>

</tbody>

</table>

<nav>

<a href="#">Add task</a>

</nav>

</section>

</main>

<footer>You have 3 tasks</footer>

</body>

</html>

As mentioned in the head section, thisfile has an accompanying CSS file.This should be placed in a sub-foldercalled “styles”, and called “tasks.css”:@CHARSET "UTF-8";

body, h1, h2, h3, h4, h5, h6, p, ul, dl, ol, form, fieldset,input, label, table, tbody, tfoot, th, tr, td, textarea,select {

font-family: "helvetica neue", helvetica, "lucindasans unicode", "sans serif";

font-weight: normal;

color: #333;

padding: 0;

border: 0;

margin: 0;

font-size: 12px;

}

header {

width:100%;

height:80px;

background:#d1e0e1;

color: #333;

font-weight: bold;

font-size: 20px;

text-align:center;

line-height: 80px;

}

footer {

width:100%;

height:60px;

background:#d1e0e1;

font-size: 12px;

text-align:center;

line-height: 80px;

margin-top:30px;

}

table, th, td

{

border: 1px solid #888;

}

section {

margin:20px 0 0 20px;

}

table {

width:90%;

border-collapse:collapse;

}

thead {

line-height: 30px;

}

thead th {

background: #53777a;

color: #fff;

font-size: 12px;

font-weight: bold;

text-align:center;

}

td {

font-size: 11px;

line-height: 25px;

padding-left: 10px;

}

.even {

background-color: #f8f8f8;

}

nav {

margin:15px 0 10px 0;

}

nav a {

background: #53777a;

color: #fff;

width: 80px;

text-decoration: none;

border: 1px solid #5b5b5b;

font-size: 13px;

text-align: center;

padding:5px 10px;

}

label {

display: block;

padding: 8px 0 8px 0;

color: #333;

}

input {

border-radius: 3px;

height: 24px;

border: 1px solid #AAA;

padding: 0 7px;

}

input.large {

width: 400px;

}

select {

border: 1px solid #AAA;

overflow: hidden;

margin-right: 15px;

width: 200px;

}

.required {

color: red;

}

.not {

display:none;

}

.rowHighlight {

font-weight:bold;

}

label.error {

color: red;

font-weight:bold;

}

.overdue {

background: #F7DCE5;

}

.warning {

background: #F7F7DC;

}

.taskCompleted {

text-decoration: line-through;

}

When opened in a web browser, theHTML document will look as follows:

There are a number of features that weshould stop to discuss here.Firstly, at the very top of the webpage,the DOCTYPE is simply:<!DOCTYPE html>

// The DOCTYPE is animportant signal to browsersand allows them to interpretthe content of the document inthe context of the rules

associated with the documenttype. If this is omitted thebrowser will revert to itstraditional rule set, and thismay produce very differentresults.

You will also notice that there is noversion number attached to html in theDOCTYPE. HTML should now beconsidered a living standard ratherthan a versioned standard with officialreleases, and this is reflected in theDOCTYPE. For this reason manypeople object to the term HTML5entirely: it is just HTML.The other thing you may notice aboutthe DOCTYPE declaration is that itdoes not contain a reference to aDocument Type Definition (DTD)document defining the rules of themarkup language. This is a pleasant

change for developers who may beaccustomed to copy and pastingDOCTYPE declarations such as:<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">

or<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

The reason for this has already beentouched upon: HTML5 is not based onSGML like earlier versions of HTML:in fact it is not based on anything.

// Standard Generalized MarkupLanguage (SGML) is atechnology for defining therules of markup languagessuch as XML or HTML.

Although HTML5 is not based on anyother standards, it is possible to writeHTML5 in XML serialisation mode.The following would be the skeletonfor an HTML5 page that serializes toXML (this is the equivalent ofXHTML):<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> </head> <body> </body></html>

In addition, HTML5 documents thatutilize “XML mode” should have adocument type ofapplication/xhtml+xml (rather thantext/html).We will not utilize XML mode in thisbook. In reality there are no realadvantages to using an XML compliant

version of HTML unless you need toprocess pages with an XML parser, butit is useful to know that this modeexists.On the next line in the example aboveyou will also notice that the html tag(which is optional) contains thelanguage:<html lang="en">

The specification does not dictate whatthe language attribute will be used for,but obviously browsers can use thelanguage for a variety of reasons,including offering translations to otherlanguages.Other than this, the only other featureyou should add to every page is thefollowing line in the head section tospecify the character encoding:<meta charset="utf-8">

Unless you have a good reason, it isadvisable to choose UTF-8 as the

encoding. It is also important that youadd this otherwise you may open yourweb application to a cross sitescripting attack using UTF-7.

// With Internet Explorer it maybe useful to also set thefollowing meta value:<meta http-equiv="X-UA-Compatible"content="IE=edge" />

Internet Explorer lets usersspecify the compatibilitymode for a document (since itsupports backwardscompatibility). This willguarantee that IE will use thelatest mode for HTML5.

TagsSince the advent of CSS, webdesigners have been relying on the divand span tags to layout content. Thesetags have no visual meaning; ratherthey act as containers for otherelements. These containers can then bepositioned anywhere on the screenusing CSS.The only difference between a spanand a div is that spans are inlineelements (they can be placed verticallyadjacent to other elements) whereasdivs are block elements, and thereforeare positioned on their own line in thedocument.

// If this does not make sense,you may want to jump toAppendix A: Cascading StyleSheets to understand CSS alittle better.

Although div and span elements aresufficient for laying out complexwebsites (with the help of CSS), theylack semantic meaning. For instance,documents naturally contain headersand footers, but historically these havehad to be represented with divelements.The lack of semantic meaning inherentin div and span elements has been thesubject of much criticism in the past.There is an argument that if a browserrealises that a section is a header or afooter it may choose to modify the waythe document is presented, orrepurpose the content, particularly onnon-traditional devices such as mobilephones. As more and more devicessupport HTML based browsers, theneed to repurpose content is likely togrow.

In addition, the lack of semanticmeaning of div and span tags can makeit difficult for a software engineer tomodify an existing document. Not onlycan it be difficult to match up heavilynested div tags (and therefore it is easyto miss one), it may not be obviouswhat the purpose of each section in thedocument is.HTML5 therefore provides anassortment of new tags that addsemantic meaning to HTML documents.It is not intended that the browser willnecessarily provide any visualimplementation of these tags; forinstance there is nothing to stop aheader appearing at the bottom of thepage and a footer appearing at the topof the page. In reality these tags are thevisual equivalents of div and span tags– either inline or block containers withno other visual properties.The following are the primary new

semantic tags that have been added(ordered roughly according tousefulness):• section: represents a genericdocument or section in an application.Using section correctly is part art, partscience. A section should be self-contained, and capable of existingindependently of other sections in thedocument. Examples can be seen intasks.html.• header: represents the introductorysection of an HTML document orsection of a document: there can bemore than one header in a document.Examples can be seen in tasks.html.• footer: represents information thatshould appear at the bottom of anHTML document or section. Again,there can be more than one footer inthe document. Examples can be seen intasks.html.

• aside: this is used for content that isloosely associated with other contentaround it, but which could beconsidered separate. An aside willoften be visually separated from thecontent around it with a border or font.• article: this should be used toseparate content that can be distributedindependently from other content in thedocument. An example may be a blogpost, or a review. This is similar tosection, but article should only beused for separating content, not genericsections of the document.• details: contains additional detailsthat a user can choose to show or hide.• summary: contains a summary of thecontents that appear in the details tag.The idea behind this is that thesummary can be shown to the userwhen the document loads, and they canselect to view the details if they wishto.

• main: this should be used to surroundthe main section of a document,stripped of all headers, footers,asides and menus. Unlike other tags,this should only be used once per page.This tag should surround the contentthat forms the central functionality orcontent of the document. Examples canbe seen in tasks.html.• nav: contains a set of navigation linkssuch as those that commonly appear inthe header section of a web page.• dialog: used for dialog boxes andwindows. This element supports anattribute called open that indicates ifthe dialog is active to the user.• wbr: this is used as a hint to thebrowser that it could add a line break.This can be useful if a browser isadding line breaks in the wrong placedue to a long word.• mark: this can be used to indicate

that a piece of text is highlighted.Browsers will add a background colorto the text, which can be overridden inCSS.• figure: this element can be used tosurround self-contained content such asphotos and illustrations. This elementuses the block display type rather thanthe inline-block display type (as usedfor images)• figcaption: this is used for providinga legend for a figure.• address: defines a section describingcontact information.It is important not to overuse these newtags. The new tags have specificmeaning, and if you need to separatecontent for other purposes, includingstylistic purposes (via CSS), there isnothing wrong with using div and spantags.In addition, don’t expect these tags to

radically change your life. In realitythey are one of the most uninterestingfeatures of HTML5. Even the oftenquoted benefit of these tags,“repurposing”, is probably more hypethat reality.As an example of repurposing,consider Safari’s “Reader” mode. Thiscuts out all the superfluous contentfrom a page containing an article, andtherefore makes the article easier toread. It may have been easier forApple to implement this if everyoneused the article tag: but Apple stillmanaged to implement this featurewithout it. In addition, it is unlikelyApple would simply trust the semantictags presented by a page, sincewebsites would quickly learn thebenefits of placing advertising materialinside an article element, even thoughthe specification implies they shouldbe outside it.

There are a number of other new tagsthat are directly related to functionalaspects of pages (such as video andaudio): these will be addressedseparately.

MicroformatsIf you look at the time tags in thedocument you will see the following:<time datetime="2013-10-14">2013-10-14</time>

This could also have been written:<time datetime="2013-10-14">14th October</time>

Or<time datetime="2013-10-14">October 2014</time>

The important aspect of this tag is thatit contains the same information twice.The first version of the date ispresented in an attribute, and conformsto the ISO standards for dates (andtimes if required). The second versionappears between the tags, and is theversion that will be displayed to theuser.The purpose of this feature is toprovide a machine and human readableversion of the same information.Features such as this are referred to as“microformats”, and are widely used

on the Internet to provide semanticmeaning to search engines and otherautomated clients, while providinghuman friendly versions of the samedata to humans.Microformats have not been officiallyincluded in the HTML5 specification,although the time tag is an example ofa microformat. There are severalstandards for additional microformats,and it is likely that HTML5 will beexpanded in time to support these.

HTML5 FormsThere are a number of additions inHTML5 to forms, and the input fieldsthey contain. Form elements such asinput fields and select boxes had notreally changed since the early versionsof HTML. Not only does HTML5introduce a new set of input types, itincludes a large set of attributes forcustomising form inputs, along withnative validation of form fields.

New Input TypesIf you look at the input type of the fieldnamed “requiredBy” you will noticethat its type is set to date:<input type="date"required="required"name="requiredBy"/>

// It is also valid, and possiblypreferable, to write this as<input type="date" required

name="requiredBy"/>

HTML5 does not require allattributes to have values.These attributes are referredto as Boolean attributes, sincetheir presence indicates true,and their absence indicatesfalse.It is arguably preferable toomit the value because itavoids the possibility ofbelieving the following isvalid:required="false"

It is the expectation of the HTML5specification that the browser willprovide the user some way to choose adate when they click on such a field,although the exact mechanism is left upto browser vendors.Some browsers do not currently

support the date input type, and inthose cases it acts just like a text inputtype.When browsers choose to implementone of the new input types they candecide on the best way to implement itbased on the specifics of the devicethey are running on. For instance, thedate input type on the iPad displaysthe following calendar:

This looks very different to the dateinput type presented by Chrome on thedesktop:

In addition to the date input type,HTML5 has several other new inputtypes. Many of these such as:• email• url• tel (telephone)• numberoffer the most advantage to devices

that use software based keyboards. Inthese cases the device can present theuser with a set of keys best suited tothe input type. For instance, if the typewas email the keyboard may presentthe user with the alphabetic characters,the “@” symbol, the “.” and maybe aspecial “.com” key.Mobile devices in particular offerinteresting possibilities for input typessuch as tel and email, since thebrowser could potentiallyautocomplete these based on details inthe mobile phone’s phonebook.HTML5 validation (which will beintroduced below) can also validatethat these fields contain valid valuesfor their specified type.In addition, HTML5 offers thefollowing input types which, like thedate input type, are expected topresent the user with a widget tosimplify the choice of a value:

• color• datedatetime• datetime-local• month• range• search• time• weekIn reality most of these types cannot berelied on in most browsers. This is afamiliar problem for developers ofweb applications, so it is worthstopping to discuss the concept of“polyfills”, which are a commonsolution to this problem.A polyfill is an elegant solution to theproblem that some features aresupported by a subset of browsers. If afeature is natively supported in aparticular browser, the polyfill doesnothing. If the feature is not supported,

the polyfill provides animplementation, usually via aJavaScript library.In order to utilize polyfills, thefollowing two features are required:1. The ability to detect whether abrowser supports a particular feature.2. The ability to provide animplementation for this featuredynamically using JavaScript. Evenwhere it is possible to detect a featureis missing, it may not be possible toprovide an implementation.Although it is often trivial to provideboth of these features in your owncode, it is always preferable to usewell tested existing libraries wherepossible. The most popular library fordetecting supported features isModernizr, and can be found athttp://modernizr.com/.With Modernizr in place, feature

detection is as simple as this:if (Modernizr.canvas) {

// do nothing

} else {

// provide implementation

}

In addition to feature detection,Modernizr also contains a large list ofpolyfill implementations that can beutilized, or you can write your own.HTML5 also offers native support fortwo entirely new form elements:• Progress: this provides a nativeimplementation of a progress bar thatcan be updated through changes to theprogress bar attributes.• Meter: this provides a scalarmeasurement within a defined range.These new elements will proveenormously useful when fullyimplemented, until then however it islikely you will need to rely on

alternatives offered by libraries suchas jQuery UI.

New Attributes on Input typesIn addition to the new input types, alarge number of new attributes aresupported on input types. Attributes areused to control how an element works.Many of these attributes are providedto support native HTML validation,these include:• required: this indicates that a valueis mandatory for the field in order tosubmit the form.• maxlength: this is used on textbased input fields to specify themaximum length of the input.• min and max: these are used onnumber, date and range based inputfields to specify minimum andmaximum values.• pattern: these are used whenever

input must conform to a regularexpression pattern. Most browsersprovide default implementations fortypes such as email.• formnovalidate: This can be appliedto a submit button in order to disablevalidation. In addition, the novalidateattribute can be applied to the form toachieve the same result.The validation of form elements willbe introduced in later chapters.A number of other attributes have beenadded to provide commonly requestedfunctionality:• placeholder: This provides a greyedout placeholder in an input field. Thiscan be used to provide context to auser, and act as a hint to the purpose ofa field.• autocomplete: When autocomplete isadded, the browser will suggest valuesto the user as they type.

• autofocus: This can be used toautomatically give a particular fieldfocus when the document loads.Previously this could only be achievedthrough JavaScript.• form: it is possible to denote an inputfield as part of a form even when it isnot nested inside the form. This alsoallows an input field to be included inmultiple forms.• formaction: It is possible to providea formaction attribute on a submitbutton to override the action set on theform itself. This is particularly usefulwhen there are multiple submit buttonsin the same form. The attributeformenctype can be used inconjunction with this to override thecontent type (enctype) set on the formitself, and formmethod can be used tooverride the form’s default method(e.g. POST).• step: This can be used on number,

date or range input fields. Theintention is that the input field willprovide up and down arrows, andpressing this will increment ordecrement the current value by the stepamount.

Other new featuresThe HTML5 markup language containsmany other new features that areoutside the scope of this book. Thissection will provide a very briefintroduction to these features so youknow they exist, without going intodetail about how they work.HTML5 provides a canvas elementthat allows for 2D drawing andanimation. This is one of the featuresof HTML5 that is intended to providean alternative to Adobe Flash. Thereare many interesting demos availableon the Internet showing the power ofthis feature. The canvas element covers some of thesame scope as Scalable VectorGraphics (SVG), which is nottechnically part of HTML5, but is stilla relatively new, and useful feature ofweb browsers.

WebGL provides similar capabilitiesto Canvas, but allows for 3Drendering. The main draw back forWebGL is that not as many browserssupport it as the Canvas, which hasuniversal support amongst the mainbrowser vendors. Where it issupported, the support is often partial.Another feature of HTML5 that drew alot of attention are the audio and videotags. Currently Adobe Flash is the de-facto standard for video in particular,largely because of its ubiquity and thefact YouTube used it. The audio andvideo elements are intended to allowweb site developers to embed audioand video in web sites without theneed for plugins.Ever since the early days of web sitedevelopment back buttons have causedissues. This has become even moreapparent with modern webapplications that often do not rely on

page refreshes, even when users thinkthey have changed pages. By default,this means the back button tends not todo what users expect in a large numberof scenarios. The Session HistoryManagement API allows thedeveloper finer-grained control overthe history of a tab, and thereforeallows for more intuitive behaviourfrom the Back and Forward buttons.

JavaScript FundamentalsThis section will provide an in-depthoverview of JavaScript, including itsstrengths and weaknesses. Theintention of this chapter is to provideyou a strong understanding ofJavaScript fundamentals, and to focuson how the language should be used,rather than how it can be used.JavaScript is a particularly flexiblelanguage, and does not enforce muchdiscipline or structure on its users. Inaddition, JavaScript contains a numberof features than can only truly beregarded as bugs. These remain in thelanguage principally due to backwardscompatibility concerns.In order to write large-scale webapplications it is necessary to harnessthe strengths of JavaScript, while at thesame time avoiding the pitfalls that caneasily confront software engineers andprogrammers who do not understand

the language fundamentals, and do notstructure their applications in a mannercompatible with the growth of the codebase.As mentioned in the introduction, thischapter will not act as a tutorial on thesyntax of JavaScript (such as loops andbranching), although anyone familiarwith languages utilizing similar syntax(C, C++, Java etc.), will quickly pickup those details from the examplesbelow. In order to follow the examples in thisbook, simply open the Chrome orFirefox console, and enter thecommands directly (as demonstratedearlier in the book).

TypesAny understanding of JavaScriptbegins with an understanding of itsdata types, and how these types areused.JavaScript has the following datatypes:• String• Number• Boolean• Null• Undefined• ObjectEach of these will be outlined in thesections below.

StringsStrings are series of charactersenclosed in either single or doublequotes:> "hello world"

"hello world"

> 'hello world'

"hello world"

The examples above are referred to asstring literals. We can also assign astring to a variable:> s = 'Hello world'

"Hello world"

// When using the console,variables will not bedeclared with the varkeyword. As you will seebelow, it is critical that this isused in most situations whenwriting actual JavaScriptcode.

We can then inspect the type of thisvariable using the typeof operator:> typeof s

"string”

Although strings are their own datatype, it is possible to invoke methodson them just as we will see it ispossible to invoke methods on objectsbelow.> s.charAt(1)

"e"

> s.substr(6)

"world"

> s.toUpperCase()

"HELLO WORLD"

In addition, strings have properties thatcan be accessed, just as we will see onobjects in the examples below:> s.length

11

JavaScript strings are largelyequivalent to strings in Java. Oneconsequence of this is that strings areimmutable.

// An immutable object is anobject that cannot be changedafter it is first created. Evenwhen these appear to change,as in the examples below, inreality a new object is beingcreated.

In order to see immutability in action,declare a new variable called t, andassign it the value of s:> t = s

"Hello world"

We can now print out the value of t,and also confirm that t and s are equal:> t

"Hello world"

> s == t

true

What should happen if we now modifythe string held against the variable s?We can append to the string value usingthe += operator:> s += 'test'

"Hello worldtest"

If you now print out the value of s youwill see that the string’s value appearsto have changed: > s

"Hello worldtest"

Despite this, if you print out the valueof t it has retained its old value:> t

"Hello world"

When we appended “test” to the stringheld against the variable s, theunderlying string was not modified;instead a new string was created andassigned to the variable s. Since t stillrefers to the original string, it is notimpacted by the modification.

NumbersThe number type is used to representboth integer and floating-point values;in fact all numbers are 64 bit floating-point numbers in JavaScript:> n = 6.827

6.827

> typeof n

"number"

> n2 = 6

6

> typeof n2

"number"

Due to the fact that all numbers arefloating-point, operations between twointegers can return floating-pointresults (unlike in Java).> 1/3

0.3333333333333333

In addition to real numbers, JavaScriptalso supports a number of specialvalues.“Not a number” is used in cases wherean arithmetic operation produces aresult that is not a number. Confusingly,this type is still a number.> a = 9/undefined

NaN

> typeof a

"number"

It would have potentially been moreuseful for JavaScript to generate anerror in this scenario.Negative and positive infinity are alsosupported, and are most oftengenerated when dividing by 0:> b = 6/0

Infinity

> b == Number.POSITIVE_INFINITY

true

> c = -6/0

-Infinity

> c == Number.NEGATIVE_INFINITY

true

Again, most programming languageswould generate errors in thesescenarios if confronted with the integervalue of 0, but since all numbers arefloating point in JavaScript, it followsthe IEEE convention for floating pointnumbers and returns infinity.JavaScript also natively supports aMath library modelled almostidentically on the Java equivalent.Most common maths functions areavailable in this library.> Math.pow(3, 2)

9

> Math.round(3.22)

3

Booleans

JavaScript supports a boolean type thatcontains the literal values true andfalse:> t = true

true

> typeof t

"boolean"

> f = false

false

Equality operators in JavaScript (>, <,==, !=, >=, <=) also return booleans astheir result:> f != t

true

NullNull is a data type that has a singlevalue: null. > n = null

null

Confusingly, null is considered to be oftype object:> typeof n

"object"

This is another bug in the JavaScriptlanguage that has been maintained forbackwards compatibility. Despite this,null is genuinely a unique data type inJavaScript.It is possible to set a variable to nullafter it has been assigned a value,therefore removing the reference to its

current value (and changing its datatype):> q = 2

2

> typeof q

"number"

> q = null

null

> typeof q

"object"

UndefinedThe undefined data type is returnedwhen you access a property on an

object that does not exist, or use avariable before it is declared, orbefore it is assigned a value. > typeof g

"undefined"

ObjectsOther than the types outlined above, alldata types in JavaScript are objects:this includes arrays, functions, datesand user defined objects. Objects willbe discussed at length in the sectionsbelow.

Truthy and Falsey ValuesNow that you have an understanding ofthe JavaScript data types, the next thingto understand is that some values forthese types evaluate to true, and someevaluate to false. For instance, the

following are all considered false inJavaScript:• false• 0 (zero)• "" (empty string)• null• undefined• NaNIn order to see this in action, simplyask if they are equal to false in theconsole:> 0 == false

true

All other values represent true values.As a consequence of this, it is possibleto utilize a shortcut when evaluatingthe value of variables in conditionalstatements. Instead of writing thefollowing:

> if (a == undefined || a == null) {

a = 1;

}

It is possible to simply write:> if (!a) {

a = 10

}

Likewise, if you only want to use avariable if it has a value you can writethe following:> if (s) {

console.log(s)

}

This shortcut is enormously useful, andextensively used in JavaScript code.The final thing that should beunderstood is which values are equalto one another; the following may comeas a surprise:> null == undefined

true

> 5 == "5"

true

> "true" == true

false

> "1" == true

true

> "2" == true

false

There are numerous inconsistencies inthe examples above, and again, theseare often bugs rather than features. Null

should not be considered equal toundefined, despite the fact they areboth falsey values they represent verydifferent data-types and meanings.Fortunately, JavaScript contains analternative pair of equality operators:===

!==

These compare variables based onboth their value and their data type,and therefore provide more expectedresults:> null === undefined

false

> 5 === "5"

false

> "true" === true

false

> "1" === true

false

It is best practice to always use theseequality operators unless youconsciously want to compare twovalues you know have different datatypes.

// If you want to know whetherany value is true or false in aBoolean sense, you can printit out by prepending !! to it. Asingle ! will negate a Booleanvalue, while !! provides adouble negative, andtherefore prints out the

Boolean value of any value:!!""

false

!!"hello"

true

Dynamic TypingFinally, it is worth reiterating thatJavaScript is a dynamically typedlanguage.Languages such as Java and C++ arestatically typed languages. In staticallytyped languages, all variables areassigned a type at compile time, andthis type cannot be changed.

// The terms strong and weaktyping are sometimes used torefer to statically typed anddynamically typed languagesrespectively.

In a statically typed language, thecompiler can perform type checking: ifa variable is defined to store aninteger, the compiler can check that itis not assigned a string. This catchesmany causes of bugs before they canbecome an issue at run-time.As we have seen, JavaScript variablesderive their types based on the valuesthey are assigned at run-time, andvariables can change their type if theyare assigned a new value. As a result itis not possible to perform static typechecking in JavaScript, e.g. to ensure astring is not provided where a numberis expected.

Consider the following function thatadds two numbers together:function add(v1, v2) {

return v1+v2;

}

If you invoke this function with twonumbers, the result is as expected:> add(1,1)

2

If you accidentally pass a string as oneof the parameters however, the result isvery different:> add(1,"1")

"11"

Instead of adding the numbers,JavaScript has performed stringconcatenation between the number andthe string. It is unlikely that this is theresult expected. This is one reason

why the typeof operator is soimportant in JavaScript, it allows thefunction above to be rewritten asfollows:function add(v1, v2) {

if (typeof v1 === "number"

&& typeof v2 === "number") {

return v1+v2;

} else {

throw "both arguments must be numbers";

}

}

This at least ensures data type issueswill be identified at run-time, even if itdoes not highlight these issues to theprogrammer who wrote the codeallowing the function to be calledincorrectly.

// Using the “+” operator ondifferent data types produces

a variety of random results inJavaScript:{} + [] = 0[] + {} = ObjectEven using the “+” operatoron the same data types canproduce meaningless results:[] + [] = empty string{} + {} = NaNIt is hard to make sense of anyof these results.In addition, the “-“ operatorshould only be used onnumbers:“a” + 1 = “a1”“a” – 1 = NaN

There are many arguments for andagainst dynamically typed languages.This book will not address these

arguments, but it is safe to concludethat dynamic typing has advantages, butthose come at the risks of run-timebugs.

ObjectsJavaScript also supports objects; infact, most values in JavaScriptapplications will be objects.JavaScript also supports syntax fordefining classes that objects can beinstantiated from. This may lead you tothink JavaScript is a conventionalobject orientated language – this wouldbe a mistake.In classical object orientated languagessuch as Java and C#, classes must bedefined before objects can beinstantiated from them. It is neverpossible to have an object that is not atype of a specific class.Classes are static templates thatcontain definitions of the propertiesand methods that objects will contain.During program execution, instances ofthese classes are created: these arecalled objects. All objects instantiatedfrom the same class have the same

properties and methods, although thevalues assigned to properties willdiffer from instance to instance.When designing applications with aclassical object orientated languageyou may find cases where you wouldlike some objects to contain additionalproperties or methods, even thoughthey are similar in other respects thosecreated by an existing class. Forinstance you may have started with aclass called “Vehicle” which containedthe following properties:1. Registration number2. Initial year of registration3. Make of vehicle4. Model of vehicleObjects can be instantiated from thisclass, and will contain four propertiesto which values can be assigned.

// This book will use the term“property” to refer to the stateof an object. Other languagesmay call these fields orattributes.

You may subsequently decide that youwould like to capture more informationabout trucks, for instance:1. Number of axles2. Towing capacityYou cannot simply add these newproperties to objects that have beencreated from the Vehicle class; youmust first create a new class (calledTruck), and extend the Vehicle class.Only when the class structure is inplace can you begin creating instancesof Trucks.A further feature of classes is that they

must be defined when the applicationis compiled; they cannot be defined onthe fly at run-time. It is not possible todecide midway through programexecution that you would like to startcapturing an additional property onsome objects.JavaScript has a far more flexibleattitude to classes and objects, in factclasses are not essential to JavaScriptprogramming at all.The simplest way you can create a newobject in JavaScript is as follows: > obj = {}

The typeof operator confirms that theobj variable is indeed an object:> typeof obj

"object"

If you are familiar with classicalobject orientated languages you may

wonder what type obj is? This objectis not of any type; it is just an object.It may sound difficult to write codewithout knowing the type. For instance,if a function is passed an objectwithout knowing its type, how does itknow what to do with it?JavaScript uses an approachcolloquially known as “duck typing”.There is an old saying, “if it walks likea duck, and swims like a duck, andquacks like a duck, it probably is aduck”. Likewise, in JavaScript wemight say “If it has a registrationnumber property, and has a year ofregistration property, it probably is avehicle”.An empty object with no properties ormethods is not very useful. WithJavaScript however, it is possible todynamically add properties andmethods:> obj.firstName = 'John';

> obj.lastName = 'Smith';

> obj.age = 32;

> obj.increaseAge = function() {

this.age++;

}

// Functions inside objects arereferred to as methods. Theyare exactly the same asfunctions, except in the waythey treat an importantvariable called this. You mayhave also noticed the use ofthis in the method above: thiswill be explained in fullbelow.

If you now look at the object in theJavaScript console you will see that ithas a set of properties with valuesassigned:> obj

Object {firstName: "John", lastName: "Smith", age:32, increaseAge: function}

The reason this is possible is becauseobjects in JavaScript are really justassociative arrays (also known as hashmaps in other languages). Associativearrays are supported natively in mostprogramming languages, and comprisea collection of name/value pairs.In order to access a property on aJavaScript object, simply use thefollowing notation:> obj.firstName

"John"

JavaScript supports an alternative

syntax for accessing and settingproperties that is even more evocativeof associative arrays in otherlanguages.> obj['firstName']

"John"

// These two approaches are notexactly equivalent. Thesecond approach will workwhen property names are notvalid variables names. Thedot notation on the other handwill not work if:• The property starts with anumber.• The property contains aspace or other specialcharacter except theunderscore or $ sign.

• The property name is one ofthe language keywords.If you are writing code thatneeds to handle any propertyname, including ones you hadno say in defining, the squarebrackets notation should bepreferred.

In addition to properties, the exampleabove provides an example of amethod being added to an object. Themethod increaseAge increments theage property by 1: it can be invoked asfollows:> obj.increaseAge()

> obj.age

33

I alluded to the use of the this variable

inside the method:obj.increaseAge = function() {

this .age++;

}

This is the only thing that separates afunction from a method: in a methodthe special variable this refers to theobject itself, and therefore:this.age

is a way of accessing the age propertyon the object. As we will see in futuresections, this takes on several differentmeanings depending on context.Understanding the meaning of this inthese different contexts is one of thekeys to understanding JavaScript.Although it is possible to constructobjects without any reliance onclasses, it is probably obvious that weare also missing out on the benefits thatclasses bring.If you want to create a new object to

refer to a different person, you need toadd these properties and methods allover again. This is not a majorproblem for the properties of anobject, since you would need toprovide values for those propertiesanyway, but it is a majorinconvenience for methods. Forinstance, you would need to write thefollowing:> obj2 = {}

> obj2.firstName = 'Albert'

> obj2.lastName = 'Jones'

> obj2.age = 28

> obj2.increaseAge = function() {

this.age++;

}

// An alternative approach is toinclude the properties andmethods inside the {}separating properties/methodswith commas, andproperties/methods from theirvalues with colons:obj2 = {

firstName: 'Albert',

lastName: 'Jones',

age: 28,

increaseAge: function() {

this.age++;

}

}

This is going to become a majorinconvenience, especially if you have a

large number of methods on yourobject.There is a solution to this problem thatdoes not rely on reverting to classes:you could simply clone an existingobject, and change its properties asrequired. The object being cloned canbe referred to as a prototype for otherobjects.We will see in later chapters thatjQuery contains a helper for cloningobjects, but for now we will write ourown clone implementation. Thisfunction will perform a deep clone onan object: if a property on an objectcontains a value that is an object, thatobject will also be cloned.function clone(obj) {

if (obj == null || typeof obj != 'object') {

return obj;

}

var newObj = {}

for (var key in obj) {

newObj[key] = clone(obj[key]);

}

return newObj;

}

This function uses the for (var key inobj) loop to iterate through all theproperties on an object. This is aspecial kind of JavaScript loopspecifically provided to iterate throughproperties in an object. If the value ofthe property is an object, it isrecursively passed to the clonefunction. If it is a simple type (such asa number or string) it is returnedimmediately so it can be set directly onthe new instance of the object. Youwill remember from earlier sectionsthat strings and numbers areimmutable; therefore they do not needto be cloned.This implementation should reinforceto you how simple JavaScript objectsare.

// There are potential problemswith this implementation thathave been ignored forsimplicity. Thisimplementation should not beused in real applications: useversions provided in thejQuery or Underscorelibraries.

You can now use this function toconstruct a new object for storinginformation about people:> obj3 = clone(obj2)

> obj3.firstName = 'Jim'

"Jim"

> obj3.firstName = 'Duffey'

"Duffey"

> obj3.age = 42

> obj3.increaseAge()

43

As you can see we have retained themethod already defined on itsprototype.This section is not intended to implyclasses have no value in JavaScript,instead it is intended to demonstratewhat objects truly are in JavaScript,and to suggest that there are viableways of writing JavaScript that doesnot utilize classes.There are potential pitfalls in thisimplementation. For instance, if youforget to set a property on the newly

cloned object, it will retain the valuefrom the object it was cloned from:this may or may not be correct, andcould become a source of bugs.Although we will examine moreadvanced approaches to objectcreation below, the approach toobjects examined in this section has alot to recommend it.

JavaScript Object NotationThe previous section demonstratedhow simple JavaScript objects are. Atheart, JavaScript objects are simpleassociative arrays. Each property inthe object can have a value that is asimple type (such as a number or astring), a function, an array, or anothertype of object.When writing web-based applicationsit is often necessary to send data fromthe client to the server, or the server tothe client. In order to transfer dataacross a network it must be encoded ina data format agreed by both the senderand the receiver.There are many data formats that canbe used to send and receive data; ofthese XML is probably the mostcommon. An example XML documentfor representing people might look asfollows:<person>

<firstName>John</firstName>

<lastName>Smith</lastName>

<age>32</age>

<address>

<city>Los Angeles</city>

<postCode>90245</postCode>

</address>

</person>

XML is a widely used data format,particularly in enterprise applications.It has many benefits, including a widearray of libraries that support it andwidespread acceptance in ITdepartments. XML is a particularlyverbose data format however, in theexample above far more than 75% ofthe text is made up of tags rather thancontent.Before gaining an understanding ofJSON, first consider what a JavaScriptobject may look like that contained thissame data:> person = {};

> person.firstName = 'John';

> person.lastName = 'Smith';

> person.age = 32;

> person.address = {};

> person.address.city = 'Los Angeles';

> person.address.postCode = 90245;

The example above consists of twoobjects. The first object is a person;this then contains a second object thatcaptures the address information.It would not be difficult to create anobject from the XML structure. Thereis however a data format that is farmore closely aligned with JavaScriptcalled the JavaScript Object Notation

(JSON) that makes this process trivial.You can transform this object into aJSON encoded string as follows:> JSON.stringify(person)

"{"firstName":"John","lastName":"Smith","age":32,"address":{"city":"Los Angeles","postCode":90245}}"

The output of this function call is astring, and could be assigned to avariable:> s = JSON.stringify(person)

A string can then be transformed backinto an object as follows:> person2 = JSON.parse(s)

The process of converting between astring and an object is calledserializing and de-serializing: thestring is a serialized form of the object.

// This process is only

applicable for properties:methods are not retainedwhen an object is serialized.

JSON is a remarkably simple dataformat. The entire data format iscontained in a couple of paragraphs atthe following web site:http://www.json.org/There are 3 types of value in JSON:1. Objects, denoted with the nowfamiliar curly brackets2. Arrays, which are denoted by []brackets, and contain comma separatedvalues just like JavaScript arrays.3. Literal values (strings, numbers,Booleans)An object or an array can in turncontain any of these 3 types. Forinstance, an array may contain anobject, an object may contain an array,

an object may contain another object,etc.JavaScript makes it possible to convertfrom a stringified version to an objectrepresentation purely because thelanguage does not rely on classes. Thestringified version of the object doesnot contain information on what type itis: it is simply a set of propertiesformatted according to the JSONspecification. Likewise though,JavaScript does not need to know whattype of object needs to be createdwhen de-serializing: it can simply addthe appropriate properties to anotherwise empty object.JSON has become a widely used dataformat even for applications that do notuse JavaScript. For instance, Javacontains libraries for converting to andfrom JSON. The only difference inlanguages such as Java is that you musttell the library what type of class the

textual string represents.

// Java can in fact de-serialize astring into an object withoutknowing the type, but it needsto use hash maps rather thanprogrammer defined types.

One reason for the widespreadadoption of JSON (beyond itssimplicity) is the fact it is far lessverbose than XML – the exampleabove is roughly half the size of theXML version. Although the size is farsmaller, it is still easy for a human toread and understand a JSON encodedmessage (which was a traditionalstrength XML had over other dataformats, particularly binary dataformats).As we go through the book we will

explore several cases where thisability to convert simply and easilyfrom an object to a textual string isenormously useful.

PrototypesWe will return now to our discussionof objects in JavaScript.The clone function that we wroteabove was our first attempt at codereuse. It allowed us to reuse or extendan object that we had already written.One problem discussed with the clonefunction was that it took all theproperties from the object it wascloning, including properties that werespecific to the cloned instance, such asfirstName and lastName.JavaScript provides a more elegantmechanism for extending objectscalled prototypes. In fact, JavaScriptitself is considered a prototype-basedlanguage.If you declare an empty object, youmay think that it contains no propertiesat all:> obj = {}

You can however execute thefollowing method on the object:> obj.toString()

"[object Object]"

Where did the toString method comefrom?All JavaScript objects have aprototype object (this can be null inrare instances, but this scenario canlargely be ignored). A prototype objectis an object in its own right, and canencapsulate properties and methods. Ifwe access a property or method on anobject, JavaScript will first try toaccess that property or method on theobject itself. If the object has noproperty or method with that name itwill look for it on the prototype object.In fact, there can be a whole chain ofobjects due to the fact that the objectthat is our prototype may itself have a

prototype. If no objects in theprototype chain have a propertymatching the name specified thenJavaScript returns a special typecalled undefined.The prototype of our empty object wasprovided by Object.prototype. Thisis the only object that does not have aprototype of its own, and therefore isthe end of the chain.In order to see the prototype chain inaction, we can define our owntoString implementation on the emptyobject.> obj.toString = function() {

return "I am an object"

};

If we now execute toString on thisobject, the newly defined version willbe used:> obj.toString()

"I am an object"

In this case you have not modified theimplementation of toString on theprototype; it has been overridden onthis specific instance. In order to provethis, you can create a new emptyobject, and execute the toStringmethod on it:> obj2 = {}

> obj2.toString()

"[object Object]"

The properties on a prototype areimmutable, just like strings areimmutable. Although all objects withthe same prototype share the propertieson the prototype, they cannot changethe prototype; they simply overridethese properties on themselves.The specific prototype assigned toobjects created with the object literal

notation is the Object.prototype.Different objects can however havedifferent prototypes. For instance, ifwe create an array using the arrayliteral notation, the variable is still anobject:> a = [1,2,3,4,5];

> typeof a

"object"

Because this is an object, it willcontain the Object prototypesomewhere in its hierarchy, andtherefore we can invoke the toStringmethod. You will notice that thetoString implementation has beenspecially tailored for arrays:> a.toString()

"1,2,3,4,5"

The array instance also has access to a

whole set of other properties that werenot available to our object createdwith the object literal notation:> a.reverse()

[5, 4, 3, 2, 1]

> a.pop()

1

> a.push(6)

5

These methods are derived from theprototype object for arrays calledArray.prototype (which in turn hasObject.prototype as its prototype).Due to the fact that all arrays are basedon the same prototype, if we addmethods to this prototype, they

immediately become available to allarrays. Remember, prototypes are justobjects themselves; therefore they canbe modified just like any other object.For instance, arrays do not have a“contains” method. It might be useful toimplement a method that accepts asingle parameter, and then returns trueif the array contains that value. Thiscan be written as follows:> Array.prototype.contains = function (val) {

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

if (this[i] === val) {

return true;

}

}

return false;

}

We can now execute the following: > [1,2,3,4,5].contains(3)

true

> a.contains(6)

false

Adding functionality to prototypes is avery effective code reuse pattern. Assoon as the functionality is added tothat prototype, it is immediatelyavailable to all objects that contain thatprototype in their prototype chain:even if they were created before thefunctionality was added to theprototype.

// If you are wondering howobjects can be given aspecific prototype, this willbe explained in more detailbelow.

Prototypes provide a mechanism totidy up the code reuse pattern that weused earlier. The new implementationof clone (which we will rename toextends) still accepts an object, butnow returns a new empty object withthat object set as its prototype.We will first write the object that willact as the prototype. This is going tocontain two methods, the increase agemethod we saw earlier, and a newmethod that returns the full name of theperson as the concatenation of the firstand last name. In addition, thisimplementation is going to combineobject creation, and the addition ofmethods to the object, into a singlestep:> person = {

getFullName: function() {

return this.firstName+" "+this.lastName;

},

increaseAge: function() {

this.age++;

}

}

Notice that this object is referring toproperties that are undefined. It doesnot include lastName, firstName orage properties, therefore calling thesemethods will not produce very usefulresults:> person.getFullName()

"undefined undefined"

We will now write an extends functionthat accepts this object as a parameter,and returns a new object with thisobject set as its prototype:function extend(obj) {

function E(){};

E.prototype = obj;

return new E();

}

This code may look unfamiliar ormysterious. That is because thisfunction is taking advantage of aspecial type of function we have notseen before called a constructorfunction.The first line of this function declares afunction called E:function E(){};

By convention constructor functionsalways start with a capital letter. Thisis because there is nothing differentbetween a regular function, a method,and a constructor function except (youguessed it) the meaning of the specialthis variable, and the fact that aconstructor function implicitly returnsa new object.On the next line, we set the prototypefor the E constructor function:E.prototype = obj;

This means that anytime we use the Econstructor function to create a newobject, it will implicitly set the passedin object to be its prototype, andtherefore it will have access to all thefunctionality defined in that prototype.Constructor functions are the closestJavaScript has to classes. They mustbe called with the new keyword, andas a result will construct an object thatis implicitly returned when theconstructor finishes. Before finishingour look at the extends function, it isworth learning a little more aboutconstructor functions.Within a constructor function you canuse the special this variable to setproperties on the implicitly createdobject. For instance, if we had writtenthe following constructor function:> function Person(firstName, lastName) {

this.firstName = firstName;

this.lastName = lastName;

}

you could then construct a person asfollows:> p = new Person('John', 'Smith');

The constructor implicitly returns thenewly created object even though it hasno return statement. This p variablewill therefore contain a reference to anobject with the appropriate nameproperties set.If you omit the new keyword whencalling a constructor function, it willact like any other function. This is whyconstructor functions start with acapital letter by default: to remind youto add the new keyword.Omitting the new keyword is actuallyfar worse than it may look. Inside theconstructor function you have access toa this variable that refers to the newlyconstructed object. If you omit the newkeyword this will refer to what it does

in normal functions: the windowobject.

// The window object is aglobal object within thebrowser that containsinformation about thedocument. When JavaScript isused outside the browser analternative global object isprovided in place of window.

This is a huge source of bugs becausethe code appears to work, but allinstances of the class will overwritethe same variables in the globalnamespace.> p = Person('John', 'Smith');

The value of p is now undefined, sincethe function does not have a returnvalue, but the window object has had

two new properties added to it:> window.firstName

John

> window.lastName

Smith

This is one of the reasons I recommendagainst constructor functions except incontrolled environments such as theextends function.

// Programmers who haveexperience with other objectorientated languages arealways initially drawn toconstructor functions. Theyprovide a certain familiarity,and appear to provide a classbased typing system.

Programmers are theninvariably annoyed whenthese classes do not providethe same features they areused to with classes in otherlanguages.

Finally, we can look at the final line ofthe extends function:return new E();

This is simply returning a new objectcreated by the E constructor. Since weonly need to write the extends functiononce however, we will not forget thenew keyword.You can now use the extends functionto create some objects: > p1 = extend(person)

> p1.firstName = 'John'

> p1.lastName = 'Smith'

> p1.age = 34

// As the examples aboveillustrate, semi colons areactually optional inJavaScript. It is highlyrecommended that allstatements are terminatedwith semi-colons however,since JavaScript willautomatically add them whenthey are missing, and in somecases they will not be addedwhere they are expected. Thisis another common source ofhard to find bugs, forinstance, the followingfunction returns undefined:

function a() {

return

{a:1};

}

Once the instance is populated with theappropriate properties, you can use themethods defined on the prototype:> p1.getFullName()

"John Smith"

Notice that the references to this insidethe prototype now refer to the objectitself and the full name of the person isreturned.JavaScript is a type of objectorientated language called a“prototype-based language”. Prototypelanguages use existing objects as thebasis for new objects, which are thenmodified to meet their specific needs.

The fact that JavaScript also supportssyntax for creating Class-likestructures sometimes obscures thisfact.Prototype-based languages lookunfamiliar to most people who haveused other classical object orientatedlanguages such as C++ or Java. Theapproach is very powerful however,and the examples in this book willfavour prototypes to classes as thebasic approach to code reuse.Prototype-based object orientatedlanguages are relatively rare, which iswhy they are so unfamiliar. Other thanlanguages based on JavaScript, it isunlikely most software engineers willever encounter another prototype-based language. In order to succeedwith JavaScript it is important to beaware of its fundamental naturehowever, and embrace it rather thanfight it.

Functional ProgrammingUnderstanding JavaScript begins withthe realisation that it is a prototype-based object orientated language. Thenext phase in understanding JavaScriptcomes from realising that it is also afunctional-orientated programminglanguage.

// There is no standarddefinition for what makes aprogramming language a“functional programminglanguage”. This section willhighlight the aspects ofJavaScript that make it afunctional programminglanguage without addressingarguments against consideringit a functional language.

JavaScript has first class functions.This means variables can containreferences to functions, and functionscan be passed as arguments to otherfunctions. The following is an example ofassigning a function to a variable:> f = function() {

console.log('Hello World');

}

The variable f now contains areference to a function. If we execute:> typeof f

The result will be“function”

Strictly speaking this is incorrect:functions are objects, and havemethods just like other objects. As wesaw earlier, functions are notconsidered a distinct data type.

// Following this precedence,you may expect that thetypeof an array would bearray: it is not, it will returnobject.

Once you have a reference to afunction, you can execute it byappending () to its name:> f()

Hello World

First class functions are a powerfulconcept. As another example, considerthis as a stand-alone function assignedto a variable:> f2 = function(i) {

return i % 2 == 0;

}

This function accepts a number, and

returns true if the number is even, andfalse if it is odd:> f2(9)

false

> f2(10)

true

Now, create an array of all thenumbers between 1 and 10, and assignthat to variable a: a = [1,2,3,4,5,6,7,8,9,10]

As mentioned earlier, JavaScriptarrays are objects, and therefore theycontain methods. One of the methodssupported by arrays is filter. Thismethod accepts a function as aparameter; the filter method will thenpass each member of the array in turn

to the function provided, and at the endreturn a new array containing eachvalue that evaluated to true in thatfunction. This means we can create anew array with all the even numbers asfollows:> a.filter(f2)

[2, 4, 6, 8, 10]

// The filter, map and reducemethods referred to in theseexamples were only added toJavaScript in ECMAScriptversion 5. As such they arenot natively supported inolder browsers, includingIE8. They can however easilybe added as polyfills.

Of course, we did not need to declare

the function first, we could havewritten the same functionality asfollows:> a.filter(function(i) {return i % 2 == 0})

[2, 4, 6, 8, 10]

The function passed to the filtermethod in this case is an anonymousfunction (i.e. a function without aname). This function only exists for theduration of the filter call, and cannotbe reused.Let’s now imagine a more complexexample. Suppose we want to take anarray, multiply each element by itself,and then return the result if it is even.JavaScript arrays also have a methodcalled map. Like filter, map passeseach member of the array to a function,and then returns a new array with theresult of these function calls.

// It is important to note thatthese methods are not alteringthe original array; they arecreating a new array with theappropriate entries. This is animportant paradigm, since itmeans the method call willnot impact any other code thathas a reference to the originalarray.

In order to multiply each member byitself, we could execute:> a.map(function(i) {return i*i})

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

In order to return the even numbersamongst these, we could thereforeperform the filter method on the arrayreturned by the map call:

a.map(function(i) {return i*i}).filter(function(i){return i % 2 == 0})

[4, 16, 36, 64, 100]

Finally, let’s imagine that we want tosum the values in the final array.Arrays.prototype supports a reducemethod for this. This method is slightlymore complex than map and filter,since the method must keep track of thecurrent count. This method will passthe following to our function for eachmember in the array:1. The current result.2. The value of the current member ofthe array.3. The index that member has in thearray (starting at 0).4. The array itself.

// The methods filter, map and reducedata sets in many languages, and were popularised by Google’s map/reduce algorithm http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//archive/mapreduce-osdi04.pdf

In order to see this working, executethe following:[1,2,3,4,5].reduce(function(total, currentValue, index,array) {

console.log('Current value is ' +currentValue);

console.log('Total is ' + total);

return total += currentValue;

});

This will print the following:Current value is 2

Total is 1

Current value is 3

Total is 3

Current value is 4

Total is 6

Current value is 5

Total is 10

15

The total value is initially set to thevalue of the first element in the array.Each member is then passed to thefunction, and we add this to the total.At the end, the total is 15, which isreturned from the reduce method.We can now write our final version ofthe code with map, filter and reduce

chained together, each using the resultof its predecessor as its input:> a.map(function(i) {return i*i})

.filter(function(i) {return i % 2 == 0})

.reduce(function(total, currentValue, index, array){ return total += currentValue; })

220

Functions that accept other functionsallow software engineers to writeextremely concise code. In manystrongly typed Object Orientatedlanguages, such as Java, functions arenot first class language constructs. Inorder to write a function (or method),you first must construct a class tocontain it, and then an object from thatclass. Although Java allowsanonymous classes, the syntax forperforming the examples above wouldbe nowhere near as concise.

Function ArgumentsJavaScript does not check that thearguments passed to a function matchthe signature of the function. Forinstance:• You can pass more arguments to afunction than it expects; in this case theextra arguments will be ignored.• You can pass fewer arguments to afunction than it expects; in this case thearguments are assigned the value ofundefined.

// A side effect of this is that itis not possible to overloadfunctions or methods inJavaScript. In many languagesit is possible to definemultiple versions of the samefunction, but with different

parameter lists (orsignatures). The compilerthen determines the correctversion to invoke based onthe parameters provided.In order to achieve this inJavaScript the functions mustbe given different names,otherwise JavaScript cannotdetermine the correct versionto invoke.

There are legitimate reasons to passfewer arguments to a function than itexpects. You may be happy for thesearguments to be undefined.There are also legitimate reasons topass more arguments to a function thanits signature specifies. For instance,consider a function that accepts anarbitrary number of arguments, andadds them all together.

Any time a function is invoked avariable called arguments isavailable inside the function. This is anarray containing all the variablespassed to the function. This means wecan defined an add function as afunction that accepts no parameters, butinstead uses the arguments array:> function add() {

var result = 0;

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

result += arguments[i];

}

return result;

}

This function uses a standard for-loopto iterate through all the arguments, andsimply adds them to a result variablethat is returned at the end.This can then be invoked as follows:> add(6,2,9,20)

37

Naturally, it is especially important toadd comments to functions that acceptvariable numbers of parameters;otherwise it can be difficult to workout how to invoke them.

ClosuresClosures are another of the mostimportant features of JavaScript. Whenwe continue the development of thesample web application we will makeextensive use of closures.Closures can be a difficult concept toexplain, so it is useful to learn aboutthem through examples.Consider the following code:> function f() {

var i = 0;

return ++i;

}

// This example uses ++i ratherthan i++. This means that thevalue is incremented (has 1added to it with the ++operator) before it isreturned. If this had used i++,

the value would be returnedand then incremented by 1 –which is not the same thing.

This code defines a function f. Insidethis function a private variable isdeclared and initialised to 0. Thisvariable is then incremented by 1 andreturned.If we perform repeated calls to thisfunction, it is not surprising that it willalways return 1:> f()

1

> f()

1

> f()

1

Each time this function is executed itdeclares a new variable, which isscoped to the function. The keywordvar is used to indicate that the variableis function scoped rather than globalscoped. The newly created variablehas 1 added to it, and the value isreturned. When the function ends thevariable is destroyed.If we try to access the variable ioutside the function an error will begenerated:> i

ReferenceError: i is not defined

The error is not because the variable isbeing accessed outside the function; itis because it does not exist anymore.Function variables are placed on astack when the function begins

execution, and when the functioncompletes they are popped off thestack and destroyed.Programming languages use thisapproach for good reason. Thisensures the space allocated tovariables inside functions isautomatically reclaimed when thefunction completes. This ensuresagainst out of memory errors.On the face of it this all seems to makesense. There are however goodreasons why we may wish to accessfunction scoped variables even afterfunctions complete. We do nothowever want to make these variablesglobal variables (as we could do byomitting the var keyword on thevariable declaration). This can beachieved via closures.Consider the following code:> function f2() {

var i = 0;

return function() {

return ++i;

};

}

This function does the following:1. Declares a function scoped variablecalled i initialised to the value 0.2. Returns a function that willincrement this variable when invoked.We can therefore call this function andassign the result (which is a function)to a variable:> incrementer = f2()

Based on our explanation of thefunction scoped variables above, youwould expect that the variabledeclared inside f2 would be destroyedwhen the function call f2 completed.Therefore, when we invoke thefunction that was returned from f2,there would be no i variable for it toaccess (since it has been destroyed).

This is not the case:> incrementer()

1

> incrementer()

2

> incrementer()

3

When the anonymous function wasdefined inside function f2 it “closed”over its environment as it existed atthat point of time, and kept a copy ofthat environment. Since the variable iwas accessible when the function wasdeclared, it is still available when thefunction is invoked. JavaScript hasrealised that the anonymous function

refers to the variable i, and that thisfunction has not been destroyed, andtherefore it has not destroyed the ivariable it depends on.If we construct another function usingthe same mechanism:> incrementer2 = f2()

This will also have access to avariable called i as it existed when thefunction was created, but it will be anew version of that variable:> incrementer2()

1

> incrementer2()

2

> incrementer2()

3

This may look like a simple quirk ofthe language, but it is an incrediblypowerful feature.JavaScript by default is not very goodat hiding data. It is not possible todeclare properties as private inside anobject. For instance, consider thefollowing object that provides thesame basic “incrementer”functionality:> obj1 = {i: 0,

increment: function() {

return ++this.i;

}

}

This appears to work correctly:> obj1.increment()

1

> obj1.increment()

2

> obj1.increment()

3

There is a potential problem herethough. Anyone with a reference to thisobject can change the current value ofi:> obj1.i = 20

Once this is done, the next call toincrement will cause the number tojump to 21:> obj1.increment()

21

This may be a big problem; it may bean even bigger problem if thefollowing occurs:> obj1.i = "hello world"

Now the next call will return thefollowing:> obj1.increment()

NaN

The closure-based implementationsolves this problem. There is no wayto modify the value of i, or impact thevalue returned by the function. If a callto the function returns 5, the next call tothe function is guaranteed to return 6.Data hiding (or encapsulation) is anenormously important concept whenwriting large applications. It allows usto write code modules with well-defined public interfaces (or APIs),while hiding (or encapsulating) theinternal logic and state from the caller.This reduces bugs, since code cannotaccidentally corrupt the state of themodule.The approach used to implement the

closure-based incrementer is arepresentation of a design pattern. Adesign pattern is a commonly used,reusable approach to solving acommon problem. This approach isreferred to as the module designpattern.The module design pattern is alsocommonly implemented by returning anobject rather than a function. Thisallows the object to use privatevariables for its private properties andfunctions, while still exposing a seriesof public properties and methods. Thefunctionality above can be rewritten asfollows:> function createIncrementer() {

var i = 0;

return {

increment: function() {

return ++i;

}

};

}

We can now create an incremeterobject:> obj2 = createIncrementer();

Once created, we now call theincrement method, and consistentlyreceive a value incremented by 1:> obj2.increment()

1

> obj2.increment()

2

> obj2.increment()

3

We can attempt to change the internalstate of the object by calling thefollowing:

> obj2.i = 10

but all this will do is create a newproperty on the object:> obj2.i

10

This is not the same property that isbeing used as the incrementing state ofthe object:> obj2.increment()

4

> obj2.increment()

5

> obj2.increment()

6

Scope and “this”In order to fully understand a language,you must understand its approach toscoping variables. Understandingscope tells us when various variablesare available within the program, andwhich variable is used if there aremultiple variables available with thesame name.Let’s start with a simple example:> function getNumber() {

num = 10;

return num;

}

This is a function that always returnsthe same number: 10.> getNumber()

10

> getNumber()

10

When this function finishes execution,it may seem that the variable numwould no longer be available based onour discussion of function scopedvariables earlier in this chapter. Thisis not the case:> num

10

This is because we forgot to use varwhen declaring the variable. If we haddone the following, the variable wouldnot have existed after the functioncompleted:> function getNumber() {

var num = 10;

return num;

}

Due to the fact var was omitted; thenum variable was added as a property

to the object represented by a specialvariable called this. Within a function,this refers to a special object calledwindow. You can see this by typingthis in the console:> this

Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

// Strictly speaking this is nottrue: it is only true offunctions executed in abrowser environment.JavaScript written in serverside applications will use adifferent object than windowfor the global scope.

In fact, this function could have been

written as follows:> function getNumber() {

this.num = 10;

return this.num;

}

The window object is a global objectthat contains information about thebrowser environment, but is also theobject that properties are added to bydefault within functions. The windowobject is available to any code in theweb page (including externallibraries), and therefore it is referredto as global scope.Adding properties to the windowobject is dangerous in any moderatelysized application. Since the globalproperties can be read and written byany piece of code, there is a significantpossibility that other code willaccidentally overwrite your variables.

// If you do need to createglobal variables (and thesample application willcreate a couple), it is often agood idea to create a singleobject in the window to holdall the variables for yourapplication:> window.THEAPP = {};

> window.THEAPP.myproperty ='myvalue ';

As mentioned earlier, the this variabletakes on a different meaning inside anobject’s method:> obj = { num: 10,

add: function(num2) {

this.num += num2;

return this.num;

}

}

This is a very simple object thatcontains a num property initialized to10. It also exposes an add method thatadds the parameter passed in to thisproperty and returns the result:> obj.add(10)

20

> obj.add(10)

30

You will notice that this inside anobject method refers not to the globalwindow object, but to the object itself.Let’s take this one step further:> obj = { num: 10,

add: function(num2) {

helper = function(num2) {

this.num += num2;

return this.num;

}

return helper(num2);

}

}

In this example we are declaring afunction inside the object’s method.Although this is a contrived example,the approach used here is common(especially for event listeners).Intuitively it looks like this codeshould work: the helper function isusing this.num to access the numproperty on the object. Unfortunatelythis code does not work as expected:> obj.add(20)

NaN

The problem can be seen if we addsome logging to the code:> obj = { nums: 10,

add: function(num2) {

console.log('Outer this ' + this)

helper = function(num2) {

console.log('Inner this ' + this)

this.num += num2;

return this.num;

}

return helper(num2);

}

}

If you execute this now, you will seethe following output:> obj.add(20)

Outer this [object Object]

Inner this [object Window]

NaN

Surprisingly the this inside the innerfunction has reverted from being theobject to being the window. This isconsidered by most as a bug in thelanguage, but it is a bug that will not berectified since it would break legacy

code.The common way to avoid this issue isas follows:> obj = { num: 10,

add: function(num2) {

var that = this;

helper = function(num2) {

that.num += num2;

return that.num;

}

return helper(num2);

}

}

Before entering the inner function wedeclare a variable called that, and setit to refer to the this object (the objectitself). Inside the inner function wethen access the that variable ratherthan the this variable.So far we have seen two differentdefinitions of the this variable. In both

these cases this was implicitly definedby the programming environment. It isalso possible to explicitly specify theobject that should be used to representthis. In order to see this in action wewill define a new object that adds twoproperties together:> adder = {

num1: 10,

num2: 20,

add: function() {

return this.num1+this.num2;

}

}

If we call the add method, the twoproperties will be added together andreturned:> adder.add()

30

As mentioned earlier, functions andmethods are actually objects in

JavaScript, and therefore they supporttheir own methods. These are definedon Function.prototype, (so naturallyyou can also add your own methods tofunctions). One of the methodsFunction.prototype supports is apply,which allows an alternativeenvironment to be provided for the thisvariable:> adder.add.apply({num1:30,num2:40})

70

The parameter passed to apply is anobject containing the appropriateproperties required by the function.This approach can be used to replacethe value of this in standalonefunctions and object methods.Another method provided toFunction.prototype is bind. Ratherthan executing the function using theobject passed in as the environment,

bind returns a new function thatpermanently binds the object passed inas the this variable for the function:> add2 = adder.add.bind({num1:30,num2:40})

It is now possible to execute thefunction as follows:> add2()

70

We can use this method to solve theproblem we encountered with innerfunctions in this example:> obj = { nums: 10,

add: function(num2) {

console.log('Outer this ' + this)

helper = function(num2) {

console.log('Inner this ' + this)

this.num += num2;

return this.num;

}

return helper(num2);

}

}

This can be rewritten as follows:> obj = { num: 10,

add: function(num2) {

console.log('Outer this ' + this)

helper = function(num2) {

console.log('Inner this ' + this)

this.num += num2;

return this.num;

}.bind(this);

return helper(num2);

}

}

Executing this now provides thecorrect result:> obj.add(20)

Outer this [object Object]

Inner this [object Object]

30

Earlier in this book I mentioned afourth way this could be defined:inside constructor functions. Within aconstructor function this refers to theimplicitly created object, provided thefunction was invoked with the newmodifier. Without the new modifier,this becomes the global object again.It is worth mentioning one morelimitation of JavaScript beforecompleting this section. JavaScriptdoes not support block level scope.This can be seen in the followingexample:function test() {

var a = [1,2,3,4];

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

var a = i;

console.log(a);

}

console.log(a);

}

The inner block here uses the samevariable name a as is used in the outerblock. In most programing languagesthe two variables named a would bedifferent, because they are defined indifferent blocks of code. JavaScriptdoes not support block level scoping:it only supports function level scoping,therefore the line:var a = i;

overwrites the variable defined here:var a = [1,2,3,4];

In addition to being limited tofunctional scoping, JavaScript employsanother technique for all the variablesdefined within a function called“hoisting”. Before we explain“hoisting”, try to work out why onlyone of these two functions produces anerror when executed:> function testLocal() {

console.log(j);

var j = 10;

}

> function testGlobal() {

console.log(j);

j = 10;

}

Intuitively it looks like both of thesefunctions will fail because they areattempting to access a variable beforeit is declared. In fact, when JavaScriptfunctions are executed they first lookfor all function scoped variables thatwill be declared anywhere in thefunction. These are then “hoisted” tothe top of the function.These function variables remainundefined until explicitly assigned avalue, but they do exist as undefinedvariables. Globally defined variablesare not hoisted, and therefore the twofunctions produce different results:> testLocal()

undefined

> testGlobal()

ReferenceError: j is not defined

For this reason it is always bestpractice to declare function scopedvariables at the top of the function,since this is what the language willautomatically do anyway.

Exception HandlingWe will discuss approaches toimplementing application wideexception handling later in this book.For now, it is worth emphasising thatJavaScript does support “Java-style”exception handling, but without thebenefits provided by static typing.Any code can throw an exceptionwithout declaring that it will throw thatexception. Any data type can be thrownas an exception, although it is commonpractice to throw an object with a codeand a message. This function throws anexception if it is passed an evennumber:> function dontLikeEven(num) {

if (num % 2 == 0) {

throw {code: 'even_number',

message: 'This function cannot be called witheven numbers'

};

}

}

It is also possible to catch anexception, and provide logic to handlethe failure scenario:> function passNumber(num) {

try {

dontLikeEven(num);

} catch(e) {

console.log(e.code+':'+e.message);

console.log('Retying with ' + (num+1));

dontLikeEven(num+1);

}

}

In order to catch exceptions, a tryblock must be declared in the code.Only errors that occur in this blockwill be caught. A catch block must beprovided at the end of the try block,and this will be passed any exceptionthat occurs in the block.The function above produces thefollowing output if it is invoked with

an even number:> passNumber(2)

even_number:This function cannot be called witheven numbers

Retying with 3

Unlike Java, only a single catch blockcan be provided, and this block mustthen determine the cause of theexception. If required the catch blockcan throw another exception.Try/catch blocks should be provided tocatch application logic exceptions, notto hide coding bugs. We will explorethis topic further later in the book.

ThreadingUnlike most languages, JavaScriptdoes not offer programmers anapproach for utilizing multiple threads.Within the browser environment, allJavaScript code executes on a singlethread, and this is also the thread thatthe browser utilizes to update thewindow. This means that if you makechanges to the DOM, and then continueto utilize the thread to perform anycomputation, your DOM changes willnot be applied until you finish thisprocessing.Browsers do allow documents indifferent tabs to utilize differentthreads: this is possible because thetabs do not interact with one another.The browser manages the single threadwith an event queue. Each time anevent occurs, be it a browser initiatedevent such as resizing the window, auser initiated even such as clicking a

button, or a JavaScript initiated eventsuch as a timer executing a function,the event is added to a queue. Thebrowser then processes these eventssequentially and does not beginprocessing a new event until all theevents ahead of it have finishedprocessing.This threading model can cause issues,since it does not prioritize theprocessing of events based on theirsource. In real-world applications it isoften more important to respond to userbased events quickly, even if thatmeans temporarily interrupting acomputational process currentlyexecuting.HTML5 has addressed this issue to adegree with an API called WebWorkers. These will be introducedlater in the book, but they are not ageneral purpose solution to threadingissues, since they contain numerous

limitations.JavaScript does provide a mechanismto alleviate some of the issues inherentin the single thread model with thesetTimeout function defined in thelanguage. The setTimeout functionallows code to execute at a delayedinterval.In order to see setTimeout in action,we will first define a function that wewish to execute at a delayed interval:> writer = function() {

for (var i = 0; i < 10; i++) {

console.log('Row '+i);

}

}Next we will ask the browser thread toexecute this with a delay of 5000milliseconds:> setTimeout(writer, 5000)

If you execute this you should see theexecution begin after approximately 5

seconds. JavaScript executes this byencapsulated the function call in anevent and adding that event to the eventqueue after 5 seconds. It will onlyexecute when it gets to the front of theevent queue.Before performing a long runningcalculation, it is sometimes useful toyield control back to the browser toensure any other events that are waitingcan be processed (particularly userdriven events) first, and therefore stopsthe application from appearing to“lock-up”.Your processing can be encapsulatedin a call to setTimeout with a verysmall delay (10 milliseconds forinstance). This will guarantee that yougo to the back of the event queue (andany pending events will occur), butstill will not result in any unnecessarydelay if there are no other eventswaiting to run.

The setTimeout function can also beused to yield control back to thebrowser during a long running task. Ifyou were to perform a computation thattook 10 seconds, by default you wouldnot be interrupted during this period,so all other events would queue upbehind you. Instead, if there is a way ofbreaking the computation up, you canchoose a point where you wish toyield, and ask the next portion of thealgorithm to run by calling setTimeoutwith a delay of 10 milliseconds.If this was done every 100milliseconds, it is unlikely the userwould notice that there was a longrunning computational processexecuting on the same thread.The main challenge in achieving this ispausing and resuming the computation.It will typically be necessary to storethe current state of the algorithm, andpass this to the function that will

continue the processing.setTimeout has a companion functioncalled setInterval. Unlike setTimeoutwhich causes a function to be executedonce, setInterval causes a function tobe executed indefinitely with a givendelay between executions. Thefollowing is a simple example:> setInterval(function() {

console.log('hello world');

}, 1000)

This will cause “hello world” to beprinted to the console every secondindefinitely. setInterval is very usefulfor implementing background jobs thatneed to perform operationsperiodically.As with setTimeout, setIntervalgenerates events that are placed on theevent queue. Therefore they can onlyrun once they get to the front of theevent queue.

Although setTimeout and setIntervalare rudimentary compared to thethreading libraries common in mostprogramming languages, it is importantto have a strong grasp of what they do,and when you should use them. Theydo allow many of the issues associatedwith the single thread model(particularly unresponsive GUIs, andslow reactions to user events) to bealleviated.

ConclusionJavaScript is best described as amulti-paradigm language: it supportsthe following programming paradigms:• Functional programming• Imperative programming• Classical object orientatedprogramming• Prototype-based programmingDue to its multi-paradigm nature,JavaScript is enormously flexible. Thedanger with JavaScript’s multi-paradigm nature is that it allowsprogrammers to see in it what theywant, without taking into accountwhich of these paradigms areJavaScript’s true strengths.This chapter has presented the casethat JavaScript should be best thoughtof as a prototype-based, functionalprogramming language.

JavaScript’s approach to functions is aparticular strength. First classfunctions are a powerful concept, andallow for concise, reusable code.JavaScript’s approach to prototyping isperhaps its least understood feature,and while unusual as a design choicein the language, is another key strengthof the language.Finally, JavaScript has more than itsfair share of quirks and design bugs.The key to circumventing these is tounderstand they exist. These quirks canbe easily worked around by those whounderstand them, but can causeannoying bugs for those who don’t.

jQueryUnderstanding jQuery begins with anunderstanding of JavaScript.Sometimes jQuery is treated as anindependent language that can be usedinstead of JavaScript. Although jQuerycontains many features associated withprogramming languages, it is bestthought of as a library that enhancesJavaScript in specific situations. Forthis reason, JavaScript has beenintroduced before jQuery.Before understanding jQuery however,it is worth taking a brief look at theDocument Object Model (DOM), sincejQuery is primarily a library fordealing with the DOM in a browserindependent manner.

Document Object ModelHTML (including XML and XHTML)documents are modelled in memoryusing a tree structure called theDocument Object Model.Each document has a single parentnode, and this node can have children.These nodes in turn can be parents ofother children. Each node in the tree(except the head node) has one, andonly one parent. All nodes in the treecan have zero or more children.DOM trees contain several kinds ofnodes, the most common of which areelement nodes (which represent tags)and text nodes (which represent thecontent inside tags).In order to see the inherent treestructure of a document, open thetasks.html document from chapter 4,and view it in the “Elements” tab ofChrome's developer tools. Any parentthat has children has an arrow beside it

that can be expanded. The overallparent of the whole document is thehtml tag at the start of the document.This has two children: head and body,and each of these have children. Evenin this relatively simple document,there are some elements that are eightgenerations removed from the htmlelement:

The Document Object Model is atechnology and language independentAPI for interacting with HTMLdocuments. The API allowsdevelopers to access nodes in the

document, traverse the document, andmanipulate elements in the document.Each element in the DOM tree isrepresented by an object. Theseobjects support an API that allowsthem to be manipulated. As you willsee when we start using jQuery;sometimes we will still encounternative DOM objects, but usually theywill be wrapped inside jQueryspecific versions of the objects, andexpose additional functionality.All web browsers that supportJavaScript support a JavaScriptimplementation of the DOM API. Thespecific version of the API theysupport will depend on the browserhowever, and this, along withinconsistencies in theirimplementations, can lead to issues forJavaScript programmers.In order to see the DOM API in action,open the Chrome console and type the

following:> document

This will return the DOMrepresentation of the HTML document,which is the exact same representationwe saw from the Elements tab of thedeveloper tools above. This may differfrom the literal document: for instanceif the HTML document was not wellformed (e.g. it was missing closingtags), the browser will attempt toconstruct a well-formed representationof the document (according to the rulesspecified in the HTML5 specification).The DOM API allows us to accesselements based on their characteristics;for instance, we can access the tableelements with:> document.getElementsByTagName('table')

In addition to querying, traversing andmanipulating the document, the DOMAPI also allows event listeners to beadded to the nodes in the document.

These can be used to detect usersclicking buttons, or text being typedinto input fields, along with many othertypes of event.jQuery does not allow you to doanything with the DOM that could notbe done using the native JavaScriptAPI, in fact, jQuery is implementedusing the native DOM API, and istherefore essentially an abstraction orwrapper of the DOM API.Since jQuery does not do anything thatcannot be done with the native DOMAPI you may wonder what is the use oflearning jQuery. For one thing, jQueryprovides a genuine cross browserimplementation of the DOM API, andalleviates the quirks that are found inmany browser implementations.Rather than providing a full set ofreasons for using jQuery, I encourageyou to work through the examplesbelow. They highlight the elegance and

conciseness of the jQuery API, andonce you begin using jQuery it is veryhard to go back to the native DOMAPI.

Starting with jQueryIn order to use jQuery you must includethe jQuery library in the HTML page.This can be achieved by serving yourown copy of the jQuery library, or byutilizing a hosted version from acontent delivery network (CDN), mostnotably Google.

// As a general rule, forproduction deployment youshould favour CDN hostedoptions. These tend toprovide superior performancefor users than hosting yourown copy. For development Igenerally prefer to downloadmy own copy, since thisremoved the need for anetwork connection to run theapplication.

If you wish to use the Google hostedversion of jQuery, simply include it inthe head of the HTML file:<scriptsrc="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

In order to serve your own copy,download the latest version of jQueryfrom here:http://jquery.com/download/The examples in this book are using2.0.3, but any recent version will becompatible.jQuery consists of a single JavaScriptfile that can be downloaded in eitherminimised or non-minimalized form.The non-minimalized form is useful fordebugging, but either version will beappropriate. Once downloaded, savethe file in a subdirectory of the mainfolder (the one containing the HTMLfile) called scripts.Your directory structure should now

look like this:

Now add the following to the headsection of the HTML file:<script src="scripts/jquery-2.0.3.js"></script>

SelectionThe first thing we are going to do withjQuery is select elements from thedocument.Selecting elements obviously has nointrinsic value in its own right; we areeventually going to do something withthese elements. A jQuery selection willreturn zero or more elements from thedocument. More specifically, theselection will return zero or morejQuery wrapped DOM elements fromthe document. This distinction will beimportant in later sections.In order to perform a selection, simplyinclude the selection criteria inside thefollowing construct:$('<selection criteria>')

The $ is an alias for the function calledjQuery, so we could also use thefollowing construct:jQuery('<selection criteria>')

The $ alias tends to produce betterreadability, so we will use thatconvention in the sections below. Theonly time to avoid this alias is if youare using any other libraries that usethe $ global variable: jQuery doessupport a no-conflicts mode in thiscase, and allows you to create a newalias.The selection criteria utilized byjQuery is in fact essentially the sameselection criteria utilized by CSS. Thisis enormously helpful, since it meansyou only need to learn the selectionlanguage once in order to use CSS andjQuery.There are five core ways to selectelements:• Element type.• Element attribute.• Element class.• Element ID.

• Pseudo classes.All five approaches will be brieflyoutlined below.The first way to select an element is byits type. For instance, if we want toselect all the table elements in thedocument, we can use the followingsyntax:> $('table')

This, and all other commands in thischapter, can be run directly in theconsole after first loading thetasks.html page. This command willreturn an array of one element, and thatelement will be the table holding thetasks.If we want to select all the td elementsin a document, we can use thefollowing:> $('td')

This will return an array of 9 elements.The second core way we can select

elements is based on one of theirattributes. If we wish to select all theelements with a placeholder attribute,the following selection can be used:> $('[placeholder]')

Notice the use of [] brackets around theattribute name. This will find allelements with a placeholder attribute,regardless of its value.Additionally, we may wish to specifythat the element has an attribute with aspecific value, in which case thefollowing syntax can be used:> $'[datetime="2013-10-14"]')

In this case we are mixing single anddouble quotes, since we wish toexpress the value as a string inside thestring that is the selection criteria.Selecting elements based on attributesbecomes even more useful due to thefact it is possible to add your owncustom attributes to HTML elements.

Adding custom attributes to elementsallows you to associate data with anelement, and then use this data in anyway we need.For instance, we may want to denotethat a cell in a table represents thename of a task; therefore we could addthe following attribute to the element:<td data-name-field="true">

In order to quickly find all name fieldnodes, we could then execute thefollowing selection:> $('[data-name-field]')

Alternatively, we may wish toassociate a priority with tasks, so eachtr element could include the following:<tr data-priority="high">

or<tr data-priority="medium">

We can then select all the high priorityrows in the table with the followingselection:

> $('[data-priority="high"]')

We will see below that the prefixadded to this attribute (“data-“) ismore than a convention, and allows forother possibilities. Binding datadirectly to elements turns out to be anenormously powerful concept. Itprovides a way to add context toelements in a manner that can be easilyunderstood and processed by code, andtherefore allows the same element tohave user facing and a computer facingmeaning.

// Data attributes should bespecified in lower casecharacters only, and wordsshould be separated with ahyphen.This is a good general rulewith HTML, since all

attributes are converted tolower case in the DOManyway.As we will see below, theseattributes can be returnedfrom elements as an objectvia the data() method onDOM elements. This willconvert the attribute names asfollows:data-this-is-long=”true”

is converted to the followingproperty on the data object:thisIsLong=true

The next way we can select elementsin a document is by class. Elementscan be given one or more classes withthe class attribute. All HTML elementssupport the class attribute (therestrictions from HTML4 applying tosome elements have been removed).

Inside tasks.html you will see thefollowing examples:<input type="text" required="required" name="task"class="large">

<tr class="even">

A class is just an arbitrary name: it is away of grouping together otherwiseunrelated elements to denote they sharesome characteristic. The characteristicthey usually have in common is thatthey should have the same stylesapplied via CSS, and therefore theclass attribute is usually associatedpurely with CSS.In reality classes can be used to groupelements for any reason. When usingjQuery it is common to assign classesto elements purely to allow jQueryselections to efficiently find relatedelements.For instance, in tasks.html everysecond row in the table is given theclass of even. All even rows can be

selected using the following selectioncriteria:> $('.even')

(Note the “.” at the start of theselection criteria)

// It is possible to applyspecific styles to everysecond row purely throughCSS:tr:nth-child(even) {

background-color: #f8f8f8;

}

Using classes for reasons other thanCSS matching does not go against thespirit of the HTML5 specification. Thespecification states that classes are oneway that elements can be extended,thereby effectively creating a new typeof element.

The fourth basic way to selectelements is based on their ID. Anyelement can be given an ID using the idattribute.ID names are arbitrary, just as classnames are, but ID names must beunique within a document.

// HTML5 has relaxed the ruleson the values that can be usedfor IDs. The only rules noware that they must be unique ina document, and cannot be anempty string or containspaces. The rules for classnames are identical.

An element can be given an ID asfollows:<table id='tblTasks'>

Once an element has been given an ID

it can be selected with the followingcriteria:> $('#tblTasks')

(Note the “#” sign at the start of theselection criteria.)The last way of selecting elements isvia jQuery filters. If you are familiarwith CSS, these may look the same asCSS pseudo-classes, and theyessentially serve the same purpose.Suppose we want to find the first rowin a table. We could add a class to therow, but if the table was re-ordered wewould need to make sure this wasupdated. We could also select all rowsfrom the table into an array and choosethe first element, but this is inefficient.With filters we can use the followingselection criteria:> $('tr:first')

(Filters are always prepended with acolon; this is therefore combining two

selectors, one to select tr elements,and then another limiting the selectionto tr elements that are in the firstposition amongst their siblings.)Filters can also accept parameters;therefore we can find any arbitraryrow in the table using the followingfilter:> $('tr:eq(1)')

This will find the second row in thetable (counting starts at 0).Alternatively we may wish to find anyrow except the first row, so we coulduse the following filter:> $('tr:gt(0)')

This is selecting all rows with aposition greater than 0.Other useful filters are as follows:• :even finds all even numberedelements in a selection.• :odd finds all odd numbered elements

in a selection.• :not(selection) finds all elementsthat do not match the selection.• :checked finds radio buttons orcheck boxes that are checked.• :selected finds options in selectboxes that are selected.• :contains(text) finds elements thatcontain a given piece of text.• :empty finds all elements that haveno children.•:focus finds the element that currentlyhas focus.• :last finds the last element in a set.In addition, filters can simplify theprocess of selecting input elements.Since most input fields use the elementtype of input, it is necessary to alsoquery on the attribute type. jQuerycontains the following filters forfinding specific types of input field:

• :hidden• :text• :checkbox• :password• :radio• :checkbox• :file• :buttonfor instance, this selects all text inputfields:> $(':text')One of the nice features about jQueryfilters is that you can actually writeyour own. For instance, jQuery doesnot provide a filter for finding all thedate input types. We can therefore adda custom filter to our code-base asfollows:> jQuery.expr[':'].date = function(elem) {

return jQuery(elem).is( "input" ) && $( elem

).attr( "type" ) === "date";

}

(Don’t worry if this code looksunfamiliar, it will look familiar by theend of the chapter.)When executed, this will be passed allelements in the document (or thespecified sub-tree of the document),and returns true or false depending onwhether the specified element meetsthe selection criteria. The result to thecaller is all the elements that evaluatedto true.

// This function takes advantageof the jQuery is function. Theis function is slightly unusualin that it returns true or falserather than a set of elements.

Once this has been added to the code-

base, the following pseudo class canbe used:> $(':date')

Now that we have investigated the fivemain selection mechanisms, the nextstep is to understand how thesemechanisms can be combined. We havealready been briefly introduced to thisconcept with pseudo-classes.The simplest way of combining filtersis in cases where elements need tomeet two or more selection criteria.For instance, if the :text filter did notexist, it could be written through thecombination of two selection criteria.In the first instance, we would need tomake sure the element was of typeinput:> $('input')

Additionally, the element must have anattribute called type set to the valuetext:

> $('[type="text"]')

In order to join these two criteria, asingle selection criterion can bewritten as follows:> $('input[type="text"]')

Notice that there is no space betweenone criteria and the next – if a spacewas placed here this would meansomething different, as we will seebelow.We can use the same approach to matchon both element type and class:> $('input.large')

This will return all elements of type“input” that have a class of “large”.It should never be necessary tocombine selectors based on ID withother types of selector, since IDs areunique within a document.In addition to combining selectors forcriterion relating to a single element, itis often necessary to select all

elements that match selection criteriawithin a particular sub-tree of thedocument.Consider a case where we havemultiple tables in the same document,but we want to return the first row in aspecific table (for instance, the tablewith the ID tblTasks). In order toachieve this we first need to find thetable called tblTasks, and then find thefirst row within its sub-tree.jQuery supports several ways of doingthis. The most common approach is asfollows:> $('#tblTasks tr:first')

The space denotes the fact that theseare two different selections. jQueryperforms this be selecting the elementsthat match the first selection:$('#tblTasks')

and then executing the second selectionagainst the sub-trees of these elements:

$('tr:first')

In fact, jQuery supports an alternativemechanism for doing this moreexplicitly:> $('#tblTasks').find('tr:first')

Yet another approach to performingthis same selection is to use theoptional second parameter to thejQuery selector:> $('tr:first', '#tblTasks')

The second parameter is used tospecify the root of the sub-tree that theselection should occur within. This canbe a useful approach when you knowyou are dealing with a sub-tree of thedocument, since you can assign thecontext to a variable, and then use thatin all selections:> documentContext = $('#tblTasks');

> $('tr:first()', documentContext);

It is possible to specify more than twolevels of selection within a single

selection criterion. For instance, wemay want to find all the td elements inthe last row of all the tables in thesecond section of the document. Thiscan be performed as follows:> $('section:eq(1) table tr:last td')

Sometimes we may want to be moreprecise about the relationship betweenelements. For instance, we may want toselect elements that are direct children(rather than just decedents) of anotherelement. This can be accomplishedthrough the use of the “>” sign, forinstance:> $('select[name="category"] > option')

This will find all the option elementswithin a particular select element, butonly because they are direct childrenof the select box. For instance, thiswill not return any results:> $('form > option')

TraversalSelecting a set of elements from theDOM is an important step, but is onlythe first step in the process. Once a setof elements has been identified acommon second step is to traversefrom these elements to another set ofelements.A traversal function always starts withthe results of a selection, and thenperforms a traversal operation on theseelements to return a new set ofelements.A common traversal requirement is totraverse from an element, or set ofelements, to their siblings. Forinstance, in tasks.html input fields andtheir labels are siblings because theyshare the same parent.Sibling-based queries can beperformed through the siblingsfunction. If we want to find all siblingsfor the select box with the name of

category, we can perform thefollowing query:> $('select[name="category"]').siblings()

If we want to limit the siblings toelements of type label we can add aselector to the siblings function:> $('select[name="category"]').siblings('label')

Two other similar functions are nextand prev. These return the next andprevious sibling element of theselected element. For instance, thefollowing returns the next sibling of alllabels in the document:> $('label').next()

while this returns the previous siblingsof all the input fields in the document:> $('input').prev()

Again, these functions also acceptselection criteria if necessary.Another common traversal requirementis to find specific parents of a givenelement or set of elements. For

instance, we may wish to find theparent of all input fields. This can beachieved with the parent function:> $('input').parent()

We may also wish to limit this to inputfields that have div elements as theirparents:> $('input').parent('div')

A slight variant on this function is theparents function. Instead of returningimmediate parents, this returns allancestors that meet the selectioncriteria. For instance, the followingreturns the section element that is theancestor of each input field:> $('input').parents('section')

Yet another variant on the same themeis the closest function. This allows usto find the closest ancestor thatmatches a given selection criteria,starting with a specific set of nodes inthe initial selection. This first

examines the selected node against thecriteria, then works its way up theDOM tree until it finds a match. Forinstance, if we want to find the closestdiv to each label, we could use thefollowing selection:> $('label').closest('div')

Another example of a traversalfunction is returning the last element.As we have seen, a pseudo-class onthe selection itself also supports this.For instance, this returns the last rowin the tasks table:> $('#tblTasks tr').last()

As with all traversal functions, the lastfunction also supports a parameterrepresenting selection criteriaallowing you to find the last elementthat meets specific criteria.The traversal functions we haveexamined up until this point all return anew set of elements that typically donot include any of the elements from

the original selection. In some cases itis useful to retain the original selectionwhile including additional elementsfound during the traversal. Forinstance, suppose we had returned aset of input fields, and now wish toalso include all the labels in the resultset. This can be achieved with thefollowing:> $('input').add('label')

A similar mechanism for achieving thisis to augment any of the traversalfunctions above with a request to alsoadd the original elements. For instance,the following call will return all labelsand their closest div elements:> $('label').closest('div').andSelf()

This particular line of code is a goodtime to introduce another importanttopic: chaining. Due to the fact thatmost jQuery function calls return anarray of elements, and most jQueryfunction calls can be invoked on an

array of elements, it is very easy tochain a set of function calls together,each acting on the elements returned bythe call that preceded it. This processcan continue almost indefinitely, forinstance:> $('input').parents('div').last().siblings().children()

If we trace this through, it is doing thefollowing:1. Find all input elements.2. Find any div elements that areparents of these elements.3. Limit the result set to the last divelement.4. Find its siblings.5. Find their children.Chaining allows for very concise code,but it also runs the risk of becomingdense and unreadable.

// This is similar to UNIXpipelining. Pipelining allowsmultiple applications to bechained together with theresult of one forming the inputof the other. In UNIX, the keydesign decision that allowsthis is the fact thatapplications return text onstandard output, and accepttext on standard input. InjQuery the key designdecision that allows this isthat functions can be called onarrays of elements, and thesefunctions return arrays ofelements.

ManipulationThe previous two sections on selectionand traversal have shown you how aset of elements can be selected fromthe document. This section is going tointroduce you to the ways you canmanipulate documents once you have aset of elements to work with.If you look at the tasks.html documentyou will see that the second row in thetable has a class called even assignedto it. The basic idea is that everysecond row in the table will be giventhe even class, and this will change thebackground colour of the row to makethe table easier to read.As mentioned previously, a real worldapplication would be better offperforming this functionality with CSS,but performing this with jQueryprovides a nice introduction to DOMmanipulation.Before beginning this section, remove

the even class from the second row inthe table. After this, refresh thetasks.html page in the browser andensure all the rows have a whitebackground.In order to manipulate elements wemust first select them. The selectioncriteria should be fairly standard bynow. We first find all the even rows inthe body of the table (this ensures wedo not change the background of theheader row):> $('tbody tr:even')

This will actually return two rows,since jQuery is counting from 0 thefirst row in the table and the third rowin the table are returned. This still suitsour needs, since our only real concernis that every second row is shaded.We can then manipulate these rows asfollowing:> $('tbody tr:even').addClass('even')

As soon as you execute this code youwill see the DOM update, and therelevant rows of the table will beshaded with a new background color.In addition to adding classes, we canalso remove classes withremoveClass and toggle classes withtoggleClass. Toggling is a particularlyuseful technique since it removes theclass if the element already has it, oradds the class if the element does notalready have the class. This will beused in examples later in this book.Another requirement we may wish toimplement is to add a red * next to thelabel for all mandatory fields. Weknow how to find all the mandatoryfields; they are the ones with arequired attribute (regardless of thevalue assigned to this attribute):> $('[required]')

and we can also find their labels asfollows:

> $('[required="required"]').prev('label')

The file tasks.css also contains a classcalled required that is defined asfollows:.required {

color: red;

}

In order to append the * to the label,we will include the * inside a span,and include that span within the label.This ensures it is separated from thelabel itself. We can dynamicallyappend the span to the label asfollows:> $('[required="required"]').prev('label').append('<span>*</span>')

If you execute this you will notice a *appear at the end of two of the labelson screen.This is not quite the finished result, westill need to add the appropriate classto the new spans; so refresh the screen

to remove these changes.You may have noticed that the result ofthe call above was the labels that hadbeen modified (rather than the spansthat were appended to them). Wetherefore need to select the child spansto these elements, and add the requiredclass to them:> $('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required')

Again, we have managed to achievethe entire operation in a single linethrough the use of chaining.An important aspect to understand isthat these changes have updated theDocument Object Model in real time.In order to see this, highlight one of thered *, and choose “Inspect Element”from the right click menu (this is ashortcut to finding a specific element inthe “Elements” tab of the developertools). You will see the following:

Many of jQuery’s manipulationfunctions can be utilized to insert newcontent either before or after existingcontent. Append is used to insertcontent inside a specific element, butother examples include:• after: this adds content after eachelement, making the new content thenext sibling of the original element. Ifwe had used this in the example above,the span would occur after the closinglabel tag.• before: this is similar to after,except the new element will appearbefore the original element. If we hadused this in the example above, thespan would have appearedimmediately before the label element.

• prepend: this creates a new childelement at the start of the element (asopposed to append which created thechild at the end of the element). If wehad used this in the example above, the* would have appeared to the left ofthe label text, but the span would stillbe a child of the label.• remove: this completely removes anelement from the document. You canuse this to remove the newly addedspan elements.• replaceWith: this replaces anelement or set of elements with a newelement or set of elements.In the examples above we have beenadding content to existing elements.Instead of adding content to elements,it is also possible to create content andadd it to elements. For instance, thefollowing is a valid jQuery call:> $('<span>*</span>')

This returns the element specified bythe HTML, although obviously thatelement is not part of the DOM at thispoint. It is then possible to callmanipulation functions to add thiselement to the document:> $('<span>*</span>').appendTo('label')

This will append a * as a child elementto each label in the document. Thisapproach can also used with thefollowing functions:• insertBefore: this function includesthe new elements as siblings of thespecified element or elements, butplaces them before them in the DOM.• insertAfter: this function includesthe new elements as siblings of thespecified element or elements, butplaces them after them in the DOM.• prependTo: this function includes thenew elements as children of thespecified element or elements, but

places them at the start of the element,making them the first children.The element inserted in this mannercan be any HTML element or set ofelements, including elements selectedfrom the document.In addition to adding new content to theDOM, some manipulation functionsoperate on characteristics of individualelements to either return informationabout them, or to manipulate thisinformation. For instance, to find thevalue of the select element in thedocument we can execute:> $('select').val()

The same function can be passed avalue if we want to change the currentvalue. If you execute the following thevalue of the select field willimmediately change:> $('select').val('Work')

// An important note regardingthis call is that if any eventlisteners are registered todetect changes to this element,they will not be notified withthis call.In order to notify any listenersof a change to the element, thefollowing call could be used: $('select').val('Work').change()

Event listeners will becovered in detail later in thischapter.

Other similar functions are:• html: this returns or manipulates thehtml of an element.• text: this returns the text (or content)of an element. The text is the contentbetween the elements tags.

• attr: this returns or manipulates thevalue of an attribute on an element.These functions are also a littledifferent from some of the others wehave examined in that they only operateon a single element. For instance, ifyou execute the following:> $('div').html()

Only the HTML for the first element inthe set of matched elements will bereturned, rather than the HTML of allelements. Some jQuery functions areinherently limited in this way. In orderto execute these functions on multipleelements, it is necessary to loopthrough those elements. This will beshown later in this chapter.

EventsThe next aspect of jQuery tounderstand is events. When writingweb applications, the application willneed to respond to events initiated bythe user.These events may be any of thefollowing:• Clicking a link or button.• Double clicking a button or link.• Changing the value in a text field.• Pressing a particular key inside aninput field.• Selecting an option in a select list.• Focusing on an input field.• Hovering the mouse over an element.In addition to these user-initiatedevents, the application may wish torespond to browser-initiated eventssuch as:

• The document has finished loading.• The web browser window is resized.• An error occurring.This section will first explain the waysevent listeners can be registered, andwill then look at some of these eventsin detail.Before beginning, we will add theexamples above permanently to thetasks.html page. In order to do this, addthe following block immediatelybefore the closing </html> tag:<script>

$('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required');

$('tbody tr:even').addClass('even');

</script>

This is a block of inline JavaScript.We will eventually provide morestructure to the web application, andremove code such as this from the

HTML page, but for now this is asimple way of including JavaScriptcode in the web page.We will now begin by adding a simpleevent to the sample web applicationwe have been working on. We willstart by defining the task creationsection of the screen (inside the firstsection element), to be hidden whenwe first come into the screen.We will also provide it an id so wecan easily refer to it:<section id="taskCreation" class="not">

The not class is defined in tasks.css,and provides a simple mechanism forhiding an element. It is defined asfollows:.not {

display:none;

}

Next, we will modify the link with thetext “Add Task” to have an id. This

will allow us to select it moreconveniently with jQuery:<a href="#" id="btnAddTask">Add task</a>

Finally, we will add the followingcode to the script section of tasks.html:$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

This code will be explained in detailbelow.The entire page should now look likethis (changes are highlighted in bold):<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css"

media="screen" />

<script src="scripts/jquery-2.0.3.js"></script>

</head>

<body>

<header>

<span>Task list</span>

</header>

<main>

<section id="taskCreation"class="not"> <form>

<div>

<label>Task</label> <input type="text"required="required"

name="task" class="large"placeholder="Breakfast at Tiffanys" />

</div>

<div>

<label>Required by</label> <inputtype="date" required="required"

name="requiredBy" />

</div>

<div>

<label>Category</label> <select

name="category">

<optionvalue="Personal">Personal</option>

<optionvalue="Work">Work</option>

</select>

</div>

<nav>

<a href="#">Save task</a> <ahref="#">Clear task</a>

</nav>

</form>

</section>

<section>

<table id="tblTasks">

<colgroup>

<col width="50%">

<col width="25%">

<col width="25%">

</colgroup>

<thead>

<tr>

<th>Name</th>

<th>Due</th>

<th>Category</th>

</tr>

</thead>

<tbody>

<tr>

<td>Return library books</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Personal</td>

</tr>

<tr>

<td>Perform project demo tostakeholders</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Work</td>

</tr>

<tr>

<td>Meet friends for dinner</td>

<td><time datetime="2013-10-14">2013-10-14</time></td>

<td>Personal</td>

</tr>

</tbody>

</table>

<nav>

<a href="#" id="btnAddTask">Addtask</a>

</nav>

</section>

</main>

<footer>You have 3 tasks</footer>

</body>

<script>

$('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required');

$('tbody tr:even').addClass('even');

$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

</script>

</html>

If you reload the page, you should seethat the task creation section (with allthe input fields) is not displayed whenthe page initially loads. If you click the“Add task” button however, thissection will immediately appear.If you look at the event handler codeyou will see some familiar features.First, we select the element we wish toadd an event listener to using standardjQuery selection criteria:> $('#btnAddTask')

Next we call the appropriate jQueryfunction on this element to add a clicklistener; this function is called clickand it accepts a JavaScript function asits parameter. In this example, theJavaScript function passed to the clickfunction is created on the fly as ananonymous function. This could alsohave been written as follows:

function btnAddClicked(evt) {

$(evt.target).preventDefault();

$('#taskCreation').removeClass('not');

}

$('#btnAddTask').click(btnAddClicked);

The technical term for the function wehave passed to the click function is acallback. This is because the functionis not executed immediately; it isexecuted when a specific event occurs(the user clicks the button). jQuery,like many other JavaScript libraries,makes extensive uses of callbacks, andwe will see many other examples inthe sections below.You will also see that our functionaccepts a parameter called evt. WhenjQuery invokes the function we passedto it, it will provide an object as aparameter representing the event thathas occurred.

The most useful feature that can beobtained from the event object is theelement that caused the event. Thesame event listener may be added tomany elements, therefore we will oftenneed to find out which of theseelements had the event invoked on it.This can be extracted from the eventobject as follows:evt.target

It may not be immediately obvious, butthe object returned as the target is aplain DOM object rather than a jQuerywrapped DOM object. This may soundlike a minor point, but it means that itis not possible to invoke jQueryfunctions on this element. For instance,if we attempt to call the html functionon this element, the following errorwill occur:

Whenever you are presented with a

native DOM object, it is easy toconvert it to jQuery wrapped object byselecting it:$(evt.target)

The result of this will expose all thestandard jQuery functionality:

You will also notice the following linein the click handler:evt.preventDefault();

A single element can have multipleevent listeners attached to it. Some ofthese will be added explicitly by theapplication, but the browser may addits own action implicitly. Theseimplicit event listeners are called thedefault action of the element; forinstance, a hyperlink has a defaultaction that invokes its specified URLwhen it is clicked.In this web application we do not wanthyperlinks to exhibit this default

behaviour, otherwise the page wouldbe refreshed every time the userclicked a button. Therefore we callpreventDefault on the event to signalthat the element’s default action shouldbe supressed.

// Using hyperlinks instead ofbutton elements is a personalpreference. Many designershave historically preferredthem, since they tend to beeasier to style, and moreflexible to use. There ishowever a strong argument infavour of using the buttonelements in these cases.

The final aspect of this event handler isthe removal of the class that wascausing this element to be hidden,

which should be familiar code by now:$('#taskCreation').removeClass('not');

It is possible to add click listeners toany HTML element. For instance, wecan add a feature to the table so thatwhen the user clicks a row it willhighlight in bold. If they then click therow again it will return to normal.The tasks.css file already contains aclass that can set the text of an elementto bold:.rowHighlight {

font-weight:bold;

}

As a first attempt at this code, we willtry adding the following to the scriptblock of tasks.html:$('tbody tr').click(function(evt) {

$(evt.target).toggleClass('rowHighlight');

});

This is adding a click listener to allrows in the table body. When invoked,

this will add the rowHighlighted classto the element that was clicked.If you debug this you will notice thatthe value of evt.target is in fact theelement that has been clicked on (thetd element) rather than the tr element,therefore only a single cell highlightsin bold.

// The next chapter will addressdebugging JavaScript code. Ifyou are unfamiliar with theChrome debugger, and wouldlike to see this for yourself,you may want to jump aheadto that chapter.

As a second attempt, we could try tofind the tr element that is the parent ofthe element that was clicked, and addthe class to this element. This also will

not work, since td elements have beendefined with normal font-styles intasks.css, therefore they will not inheritfont-style from their parents.What we want to do is add this class toall the td elements in the row that isselected. We could attempt this asfollows:$('tbody tr').click(function(evt) {

$(evt.target).siblings( ).toggleClass('rowHighlight');

});

There are two problems remainingwith this. The siblings function returnsa set of all the siblings, but leaves outthe element that has been clicked, soall cells except the one clicked willhighlight, we can solve this with thefollowing:$('tbody tr').click(function(evt) {

$(evt.target).siblings() .andSelf( ).toggleClass('rowHighlight');

});

The next problem is the td element thatcontains the time element. If the timeelement is clicked, the list of siblingswill be empty, since the time elementdoes not have any siblings. Beforefinding the siblings we therefore needto first find the closest td element tothe one clicked.As mentioned earlier, the closestfunction begins by examining theselected element, and only ascends thetree if that does not match therequirements. Therefore, the closest tdto a td is itself, but the closest td to atime element is its parent.The following code therefore meetsour requirements:$('tbody tr').click(function(evt) {

$(evt.target).closest( 'td').siblings( ).andSelf().toggleClass( 'rowHighlight');

});

Finally, note that we are using the

toggleClass function. Rather thanchecking whether the elements have theclass rowHighlight, and adding it ifthey don’t, and removing it if they do,we can let jQuery do the work for us.In the examples above we are addingevent listeners to elements in thedocument when the page is loaded. Acomplication with event listeners isthat we might want to add them toelements that are not in the documentyet. Due to the fact we can dynamicallyadd elements to the DOM, we maywant event listeners automaticallyadded to these elements when theymeet specified selection criteria.If we consider the case of the eventlistener that highlights selected rows inthe table, we may want this to workeven if rows are dynamically added tothe table after the page has loaded.Fortunately jQuery has an elegantsolution to this problem using the on

function. The first part of the solutioninvolves specifying the portion of thedocument that will contain any newelements, in our case that may be:$('#tblTasks tbody')

We could alternatively say we want toadd the event listener to any newelements anywhere in the documentwith:$(document)

Next we specify the type of eventlistener we want to attach, the type ofelement we want the event listeneradded against, and the callback wewant executed.In order to demonstrate this, we willadd a click listener to be able to deleteeach row in the table.Before beginning, we need to addnavigation buttons to each row in thetable body. Add the following to eachrow in the tbody immediately before

the </tr> (there are 3 of them):<td>

<nav>

<a href="#" class="editRow">Edit</a>

<a href="#" class="completeRow">Complete</a>

<a href="#" class="deleteRow" >Delete</a>

</nav>

</td>

In addition, add a new header cellinside the table header immediatelybefore the </tr>:<th>Actions</th>

Finally, to make sure the columns aresized correctly, change the columngroups for the table as follows:<colgroup>

<col width="40%">

<col width="15%">

<col width="15%">

<col width="30%">

</colgroup>

In order to verify the changes,executing the following should returnthree elements:$('.deleteRow')

We can now add an event listener asfollows:$('#tblTasks tbody').on('click', '.deleteRow', function(evt) {

evt.preventDefault();

$(evt.target).parents('tr').remove();

});

When an element with the classdeleteRow is clicked, this eventlistener will find the tr element that isa parent of this element:$(evt.target).parents('tr')

It will then remove this element fromthe document using the removefunction.Naturally this works for the three rowsthat were in the table when the pageloaded. If you want to prove that this

approach works for rows addeddirectly to the DOM, you can add anew row to the table with thefollowing code:$('#tblTasks tbody tr:first').clone().insertAfter('#tblTasks tbody tr:last')

This code will select the first rowfrom the table, clone it, to create a newrow, and then insert it after the last rowin the table. You will be able to thendelete this row from the table using itsdelete button, without having to add anevent listener explicitly to the button.

// Earlier versions of jQueryused a function called live toadd dynamic event listeners.This function has beendeprecated and should not beused.

So far we have concentrated on clickevents. There are many other eventsthat can be listened for with jQuery.The following are the other commonevents, all of which work in the samebasic way:• dblclick: is invoked when an elementis clicked twice in quick succession.• hover: is invoked when the mousehovers over the element.• mousedown: is invoked when themouse button is pressed, and before thebutton is release.• mouseup: is invoked when the mousebutton is released.• keypress: is invoked each time theuser types a key into an element, suchas a text field.• keydown: is invoked when the userpresses a key, but before the output isreflected on screen. This allows you toveto the action with preventDefault.

• blur: is invoked when the focusleaves a form field. This is usefulwhen you wish to validate content afterthe user has finished typing.• change: is invoked when the value ofa form field changes.• focus: is invoked when the form fieldreceives focus.For a complete list of events, see thejQuery documentation.Before finishing this section, we willmake a minor change to ensure that ourevent handlers are not added before theDOM has been fully constructed.Ideally we want to start processingscripts after the DOM has beenconstructed, even if all resources (suchas images) have not been loaded. Dueto the way JavaScript works, it ispossible that it will begin processingbefore the DOM has loaded, in whichcase elements will not be availablewhen selected:

// Technically in our case we donot need to worry about this,since our script is declared atthe bottom of the page. It ishowever a good habit to usethe approach suggestedbelow, even in this case.

In order to detect that the DOM hasfully loaded we can listen for theready event:$(document).ready()

As with all event listeners, this acceptsa callback function, therefore we willchange the code as follows:$(document).ready(function() {

$('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required');

$('tbody tr:even').addClass('even');

$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

$('tbody tr').click(function(evt) {

$(evt.target).closest('td').siblings( ).andSelf().toggleClass( 'rowHighlight');

});

$('#tblTasks tbody').on('click', '.deleteRow',function(evt) {

evt.preventDefault();

$(evt.target).parents('tr').remove();

});

});

If you need to delay code executionuntil all resources have loaded, theload event can be used instead:$(document).load()

Writing jQuery PluginsOne of the reasons jQuery has becomeso popular is that it is trivial to writeplugins that integrate with jQuery. Thishas led to a huge number of pluginsfreely available under the MIT license,and also allows you to write your owncustom plugins.A jQuery plugin usually works byperforming an operation on an element,or set of elements returned from ajQuery selection. Just like standardjQuery functions, depending on howthe plugin is written it may be capableof acting on a whole set of elements, orjust a single element.In this section we are going to write aplugin that can be executed on a formelement that has been selected usingjQuery. This plugin will then return anobject where the property names on theobject are the form field names, andthe values are the values of that field.

Effectively this plugin is going toserialize the values on a form into anobject. We will also allow this pluginto operate in the opposite direction: tode-serialize an object onto a form.This plugin will take advantage ofprogramming by convention. We willassume that the object names and theform field names should always match,even though there will be nothing in thecode that insists on this.Programming by convention does havedisadvantages. For instance, if anyonechanged the name of a field this willresult in changes to the property on theobjects serialized from that form, andthat may in turn break other code thathad expectations about what thoseproperties would be. Programming byconvention can significantly reduce theamount of code required to implementfunctionality however.Plugins work in jQuery by passing the

jQuery function to the plugin function,which will then extend the jQueryfunction by creating an object with aset of new functions in it.It is not particularly important that youunderstand this process, but theboilerplate code for adding newfunctions to jQuery looks like this:(function($) {

$.fn.extend({

action: function() {}

});

})(jQuery);

In this case we are adding a single newjQuery function called action. Thiscould then be invoked as follows:> $('div').action()Inside the function we can use the thisvariable to access the element orelements that the function has beenexecuted on, for instance in theexample above, all the div elements.

This will either represent an array ofjQuery elements, or a single jQueryelement. In our example we are alwaysgoing to assume that this is a singleelement.To begin, we will write a rudimentaryversion of the serialize function thatsimply writes the contents of the formto the console log:(function($) {

$.fn.extend({

toObject: function() {

console.log(this.serialize());

}

});

})(jQuery);

This implementation adds a newfunction to jQuery called toObject,and is going to take advantage of afunction already available in jQuerythat serializes a form into a string.Add this to the script section of the

web page, refresh the web page, andclick “Add task”. Enter values into allthe fields, and then call:> $('form').toObject()

This should print out a text string withthe contents of the form.Now that we have a basicimplementation, we can start writingthe code needed to return an objectwith properties populated from theform.Although jQuery does not have afunction for serializing a form into anobject, it does have a function forserializing a form to an array. Thisfunction returns an array where eachform field is represented by an elementin the array, and consists of a name anda value. In order to see this function inaction, execute the following:> $('form').serializeArray()

We will use this as the basis of our

implementation, and iterate over thearray using a jQuery helper functioncalled each:$.each($('form').serializeArray(), function(i, v) {

});

// jQuery has a number of utilityfunctions available with “$.”prefixes. Unlike other jQueryfunctions, these are not usedfor selecting elements, andthey cannot be invoked on aset of elements.

This particular function will iterateover an array and pass each index andvalue to the callback function weprovide. To see this in action, tryexecuting the following:> $.each([1,4,8,16,32], function(i, v) {

console.log('index: '+i);

console.log('value: '+v)

});

This should print out:index: 0

value: 1

index: 1

value: 4

index: 2

value: 8

index: 3

value: 16

index: 4

value: 32

Unlike the standard JavaScript for andwhile loops, the $.each helper has theability to iterate over both arrays andobjects.Now that the skeleton of toObject isin place, we can complete theimplementation as follows:

(function($) {

$.fn.extend({

toObject: function() {

var result = {}

$.each(this.serializeArray(), function(i, v) {

result[v.name] = v.value;

});

return result;

}

});

})(jQuery);

If you now execute the following:> o = $('form').toObject()

The variable o will contain an object,with properties reflecting the names ofthe field in the form. It is thereforepossible to execute the following:> o.task

You will notice that the implementationstarts by creating an empty object.Properties are then added to the objectfor each form element. The

implementation uses the [] bracketapproach to add properties, rather thanthe “.” notation. This is important,because the name of fields may notconform to the standards required byJavaScript when using the “.” notation.Now that we have a toObjectfunction, we can add a second functionto de-serialize an object back onto aform. In order to add a secondfunction, we simply create a newproperty in the object we are creatingto extend jQuery. This function will becalled fromObject and accepts anobject as a parameter:(function($) {

$.fn.extend({

toObject: function() {

var result = {}

$.each(this.serializeArray(), function(i, v) {

result[v.name] = v.value;

});

return result;

},

fromObject: function(obj) {

}

});

})(jQuery);

The first task of this function will be toextract all the form fields from theform this function is called on (whichagain, will be represented by the thisvariable. We can extract the inputfields with the following:this.find('input')

The only problem is that this will notinclude select boxes, since they are notconsidered types of input fields.Fortunately, jQuery provides a selectorthat does return all input fields,including select fields:this.find(':input')

Once all the form fields are found, theimplementation will iterate over all the

fields and extract their name attribute.It will then look in the object for aproperty with that name, and if there isone, it we will set the value of the fieldfrom the value of the property:fromObject: function(obj) {

$.each(this.find(':input'), function(i,v) {

var name = $(v).attr('name');

if (obj[name]) {

$(v).val(obj[name]);

} else {

$(v).val('');

}

});

}

You will notice that we add the $()construct around the references to v.This is because the value returned is anative DOM object; therefore it isnecessary to convert them to jQueryobjects in order to use the attr method.With that implementation in place you

should be able to change values in theform, and then call the following torepopulate it back to the originalvalues stored in the o variable:> $('form').fromObject(o)

The final version of the jQuery pluginis as follows:(function($) {

$.fn.extend({

toObject: function() {

var result = {}

$.each(this.serializeArray(), function(i, v) {

result[v.name] = v.value;

});

return result;

},

fromObject: function(obj) {

$.each(this.find(':input'), function(i,v) {

var name = $(v).attr('name');

if (obj[name]) {

$(v).val(obj[name]);

} else {

$(v).val('');

}

});

}

});

})(jQuery);

Using existing pluginsBefore writing your own plugin, it isuseful to check if any plugins arealready available that meet your needs.There is a vast library of pluginsavailable on the Internet. Some arewell supported and widely used;others are unsupported, or used by ahandful of people.Most plugins are available under theMIT license, meaning you are free tomodify them in any way you need.In this section we are going to use aplugin for generating HTML from atemplate. The plugin we will use isjQuery Template, and is availablehere:https://github.com/BorisMoore/jquery-tmplYou can choose to download eitherjquery.tmpl.js or jquery.tmpl.min.js.Alternatively, you can use the

following CDN version:http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js

// When a library has .min in its name, it as the one without it, but has been compressed. It iscommon to compress JavaScript files to improvedownload speed, but some people (mistakenly) also see itas a way to add obfuscation to their code to copied.If you would like to investigate this compress your own files, see this website:https://developers.google.com/speed/articles/compressing-javascript

This plugin was originally intended toform part of the core jQuery library,but these plans have not come tofruition. The library is now largelyunsupported, but is still a useful

templating library, and will be usedhere primarily to demonstrate the useof a jQuery plugin.If you would like to use a supportedtemplating library on a project, Irecommend the Underscore library,which provides templatingfunctionality that performs essentiallythe same role.In order to use a downloaded versionof jQuery Template, first copy it to thescripts folder of the project. Once inplace, add the following to the headsection of the page, but after the mainjQuery import:<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css" media="screen" />

<scriptsrc="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

<script src="scripts/jquery-tmpl.js"></script>

</head>

// You may notice that it is nolonger necessary to specifythat the language of a scriptfile is “text/javascript”.HTML5 assumes by defaultthat scripts are JavaScript.

This is all that is required in order tostart using the jQuery Template plugin.When the script loads it willautomatically add new features tojQuery, just as our own custom pluginadded new features to jQuery.When new tasks are created via theform, we need to dynamically add themto the table; this means creating a newtr element in the table, and adding theappropriate td columns.

We could achieve this with jQuerydirectly by generating a string torepresent the HTML and thenappending it to the table. As we sawearlier in this chapter, it is possible togenerate elements directly out ofHTML and add them into the DOM.Constructing HTML within code iserror prone however, and it would bemore convenient if we can write thebasic structure of the row as HTML,and leave placeholders for the dynamiccontent.

// Templating libraries arewidely used in softwaredevelopment. Like jQuerytemplate, they provide basiccontrol structures such asloops and branching, andallow placeholders forparameters.

jQuery template allows us to define thefollowing template in the HTML page:<script id="taskRow" type="text/x-jQuery-tmpl">

<tr>

<td>${task}</td>

<td><time datetime="${requiredBy}">${requiredBy} </time></td>

<td>${category}</td>

<td>

<nav>

<a href="#">Edit</a>

<a href="#">Complete</a>

<a href="#" class="deleteRow">Delete</a>

</nav>

</td>

</tr>

</script>

This can be added at the very bottomof the page, before the </html> (notinside the other script block). Note thatthis is essentially just a block of

HTML, except it contains placeholdersfor values. The placeholders are insidethe following constructs: ${}.Also note that this is not a standardJavaScript block, since it is defined astype text/x-jQuery-tmpl. The blockalso contains an ID, which is nottypically needed in standard scriptblocks.We now are going to implement arudimentary version of the savefunctionality. Start by adding an ID tothe save button:<a href="#" id="saveTask">Save task</a>

Next, add a click event listener to thesave task button. This is going toconvert the form data into an objectusing the plugin we developed in thelast section. It is then going to pass thisobject to the template we constructedabove. Notice that in the template theplaceholder names match the propertynames that will appear on our task

object.The template will generate a block ofHTML, which we will then append tothe table body. Add the following codeto the script section of tasks.htmlalongside the other event handlers:$('#saveTask').click(function(evt) {

evt.preventDefault();

var task = $('form').toObject();

$('#taskRow').tmpl(task).appendTo($('#tblTaskstbody'));

});

As you can see, two lines of code aresufficient to convert the form to anobject, and include the contents in thetable, and this could be condensed toone line with relative ease.As stated above, this is a rudimentaryversion of the save functionality. Forinstance, it does not contain anyvalidation; therefore you can addinvalid data to the table. This, andother minor issues, will be fixed once

we start to turn this into a true webapplication in a couple of chapterstime.Now that the save is implemented wecan remove the three rows that wereadded to the table by default each timethe page was loaded, and add rowsusing the “Add task” and “Save task”functionality. In addition, the rowsadded should be able to be deletedusing the “Delete task” option.The tasks.html page should nowcontain the following markup:<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css"

media="screen" />

<script src="scripts/jquery-2.0.3.js"></script>

<script src="scripts/jquery-tmpl.js"></script>

</head>

<body>

<header>

<span>Task list</span>

</header>

<main>

<section id="taskCreation" class="not">

<form>

<div>

<label>Task</label>

<input type="text" required="required"

name="task" class="large"

placeholder="Breakfast at Tiffanys" />

</div>

<div>

<label>Required by</label>

<input type="date" required="required"

name="requiredBy" />

</div>

<div>

<label>Category</label>

<select name="category">

<optionvalue="Personal">Personal</option>

<option value="Work">Work</option>

</select>

</div>

<nav>

<a href="#" id="saveTask">Save task</a>

<a href="#">Clear task</a>

</nav>

</form>

</section>

<section>

<table id="tblTasks">

<colgroup>

<col width="40%">

<col width="15%">

<col width="15%">

<col width="30%">

</colgroup>

<thead>

<tr>

<th>Name</th>

<th>Due</th>

<th>Category</th>

<th>Actions</th>

</tr>

</thead>

<tbody>

</tbody>

</table>

<nav>

<a href="#" id="btnAddTask">Add task</a>

</nav>

</section>

</main>

<footer>You have 3 tasks</footer>

</body>

<script>

$(document).ready(function() {

$('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required');

$('tbody tr:even').addClass('even');

$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

$('tbody tr').click(function(evt) {

$(evt.target).closest('td' ).siblings( ).andSelf().toggleClass( 'rowHighlight');

});

$('#tblTasks tbody').on('click', '.deleteRow',function(evt) {

evt.preventDefault();

$(evt.target).parents('tr').remove();

});

$('#saveTask').click(function(evt) {

evt.preventDefault();

var task = $('form').toObject();

$('#taskRow').tmpl(task).appendTo($('#tblTasks tbody'));

});

});

(function($) {

$.fn.extend({

toObject: function() {

var result = {}

$.each(this.serializeArray(), function(i, v) {

result[v.name] = v.value;

});

return result;

},

fromObject: function(obj) {

$.each(this.find(':input'), function(i,v) {

var name = $(v).attr('name');

if (obj[name]) {

$(v).val(obj[name]);

} else {

$(v).val('');

}

});

}

});

})(jQuery);

</script>

<script id="taskRow" type="text/x-jQuery-tmpl">

<tr>

<td>${task}</td>

<td><time datetime="${requiredBy}">${requiredBy}</time></td>

<td>${category}</td>

<td>

<nav>

<a href="#">Edit</a>

<a href="#">Complete</a>

<a href="#" class="deleteRow">Delete</a>

</nav>

</td>

</tr>

</script>

</html>

ConclusionThis chapter has introduced all theimportant aspects of jQuery that dealwith DOM manipulation. As has beendemonstrated, jQuery provides anelegant and concise set of functioncalls for selecting, traversing andmanipulating the DOM, along withadding event listeners.Although jQuery does not do anythingthat could not be done natively with theDOM API (or other libraries such asDojo for that matter), jQuery providesthe following benefits:• It takes care of any quirks that mayexist in different versions of webbrowsers.• It uses the same basic set of selectorsas CSS, meaning anyone whounderstands CSS can quickly adapt tojQuery.• It provides a concise and intuitive set

of function calls that are easy to learn,and easy to use in conjunction with oneanother.• It is easy to extend jQuery to solvenew problems.• jQuery is widely used, thereforethere is a wealth of information andhelp available online.There are several aspects of jQuerythat have not been examined as yet.Foremost amongst these are the AJAXAPI which will be introduced later inthis book. Several other jQuery topicswill be introduced at the appropriatepoint in the book.

DebuggingNow that we have some working code,it is worth taking a step back to look atthe development tools that can helpwhen writing JavaScript based webapplications.Probably the most important tool fordevelopment purposes is a debugger.Debuggers allow a software engineerto examine an application while it isrunning, and therefore analyse thecause of any problems.In order to start the debugger, firstopen the tasks.html page in Chrome.Then use one of the followingapproaches to open the developmenttools:• Command+Option+i on OSX• F12 or Ctrl+Shift+I on WindowsOnce the familiar console is open,click on the sources tab:

If you scroll to the bottom of thetasks.html page you will see theJavaScript that has been added in theprevious chapter.Find the following piece of code in thefile:$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

And click in the left hand margin on theline evt.preventDefault();. The lineshould highlight in blue; you will seethis on line 88 in the screenshot below,but the line in your version may differ:

This is a breakpoint, which indicatesthat the debugger should stop executionwhen it reaches this line.Now, keeping the development toolsopen, click the “Add Task” button onthe main web page. When you clickthis, Chrome will stop execution at thebreakpoint.

Now that the debugger has stopped at abreakpoint we have several choices.

As a first step, we can interact with theJavaScript environment, including anylocal variables that are in scope. Youcan see on the right hand side thatChrome is telling us there are twolocal variables in scope:

In order to interact with these, click onthe Console tab and type:> evt

This will display the event object,which can be opened up to show itsproperties:

In addition, we can execute our owncode here if we would like to trysomething out. Any code we type will

use the local variables currently inscope. For instance, we can executethe following code to obtain the id ofthe element that has been clicked:> $(evt.target).attr("id")

We can even change objects in scope,for instance, we could add a newattribute to the element:> $(evt.target).attr("data-test", "test")

This provides an excellentenvironment in which to write snippetsof code, because you receiveimmediate feedback from the browseron each line of code you write.We can also examine the current callstack. This is the list of calls that haveled to this line of code being called:

You can then click on any of the

function calls in the stack, and Chromewill take you to that line of code. Onceyou are taken to that line of code youwill have access to the environmentthat line has access to it, including alllocal variables (which may bedifferent from the variables that wereavailable on the line where thebreakpoint was hit).

In addition to interacting with theJavaScript environment, the other mainpurpose of the debugger is to stepthrough code. This allows you to watchthe program execute line by line inreal-time, and makes it easier tounderstand any issues or defects thatmay be encountered.Stepping through code can be achieved

with these controls:

You can hover over each button to seeits purpose:• “Resume script execution” will causeexecution to start again.• “Step over next function call” willstep to the line immediately below theone currently stopped on.• “Step into the next function call” willcause the debugger to enter anyfunction calls on the current line in theorder that they will be executed.• “Step out of current function” isuseful when you have stepped into afunction, but would now like to returnto the point where the code entered thefunction call.In cases where your code is splitbetween several files, you can clickthe “Show navigator” button in the top

right of the debugger and choose thefile that contains code you want to addbreak points to:

Another very useful feature of thedebugger is the pause button at thebottom of the menu:

If you click this once it will turn blue.This will cause the debugger to

automatically pause on any exception –including handled exceptions.If you click it once more it will turnpurple. This will cause the debugger toautomatically pause on all unhandledexceptions. This is very useful, since itis not always obvious that a JavaScripterror has occurred. As long as thissetting is in place, and you always runthe application with the developmenttools open, you will not miss anyerrors, and will be able to debug themwhile they are occurring.In order to see this in action, removethe existing breakpoint, and change thecode:$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

to$('#btnAddTask').click(function(evt) {

evt.callUnknownFunction();

$('#taskCreation').removeClass('not');

});

Since JavaScript is not a type checkedlanguage, it is not until run-time that anexception will be caused by this line.If you now refresh the screen and clickthe “Add task” button you will see thatthe debugger automatically stops onthis line:

You can now interact with theenvironment in the console. Forinstance, you can execute this line ofcode to see what is wrong with it:

> evt.callUnknownFunction();

TypeError: Object #<Object> has no method'callUnknownFunction'

Finally, you can use the button in thebottom left of the debugger to undockthe debugger into a separate window.This is very useful if you have dualscreens, since the debugger can run inone window, and the browser in theother.Before finishing, remember to changeyour add task event listener back to thecorrect implementation.

Moving to a web serverUp until this point we have beenloading the tasks.html page directlyfrom the file-system. We now need tomove to serving our pages from a webserver. Several of the APIs we will beusing in the next few chapters rely onpages being served from a specificdomain – even if that domain is“localhost” rather than“yourserver.com”.For instance, if a website wants tostore data on the client, the browsermust be able to distinguish between thedata created by one website and thedata created by another. Rules such asthis are referred to as “same-originpolicies”. The browser uses thedomain name and the port (whichusually defaults to 80 or 443 – but willbe 8080 in our case) to determine theorigin of a web page, and restrictsinteraction between pages with

different origins (except wherespecified).This chapter will help get you startedwith the Mongoose webserver. This isone of the smallest web serversavailable, and requires very minimalconfiguration.

OSXDownload the OSX installer from:http://cesanta.com/downloads.htmlOnce this has downloaded, perform thefollowing steps:1. Double click on the DMG file anddrag it to applications.2. Open the finder, and go to the“Applications” folder.3. Double click on Mongoose.The Mongoose application can now beconfigured via the icon in the taskbar atthe top of the screen:

Click on “Edit configuration”. Thiswill open in a text editor. Locate thefollowing line:# document_root/Applications/Mongoose.app/Contents/MacOS

Change the directory to be directorythat contains the tasks.html file. Inaddition, remove the # at the start ofthe line, e.g.document_root /html5/tasks

Quit the Mongoose web server usingthis menu and restart it (by doubleclicking on the application in the“Applications” folder).Open Chrome, and enter:http://localhost:8080/tasks.htmlThis should show the main tasks webpage.

WindowsDownload the Windows executable(no install required) installer from:http://cesanta.com/downloads.htmlOnce this downloads, perform thefollowing steps:1. Copy the exe file to the samedirectory that contains tasks.html.2. Double click on the executable tostart Mongoose.The Mongoose application can now beconfigured via the icon in the taskbar atthe bottom of the screen (although noconfiguration is required in this case):

Open Chrome, and enter:http://localhost:8080/tasks.htmlThis should show the main tasks webpage.

Building the Web ApplicationYou have now learned the basictechnology required to create thesample web application. Although wehave some working code on theexisting web page, it is not structuredin a manner that would allow it toscale to become a large webapplication.In the first section of this chapter aregoing to refactor the code that we havecreated into a structure that follows amore rigorous design. This will thenallow us to add additional functionalityto the web application.As a first step, we will extract thejQuery plugin that we wrote toserialize and de-serialize objects intoforms, and place this in a file calledjquery-serialization.js in the scriptsfolder.We will also want to move most of theJavaScript code from tasks.html into a

JavaScript file called tasks-controller.js. To start with, we will justcreate an empty file called tasks-controller.js in the scripts folder.We will then import these 2 script filesin the head section of the HTML page.(Ensure that these are added after thejQuery import).<script src="scripts/jquery-serialization.js"></script>

<script src="scripts/tasks-controller.js"></script>

In addition to this change, we are goingto add id attributes to a few otherelements. These will be highlighted inbold below.One of the elements that will be givenan id is a main element that will begiving this the id taskPage. Thereason we have added this is toencapsulate all the task relatedfunctionality. This ensures this couldco-exist in the same Document ObjectModel as other functionality, and havethese functional areas remain separate.

For instance, we may have a secondpage for managing a calendar, but itcould exist in the same HTML page ifrequired. We would then simplyreplace the header, footer and mainelements with the appropriate elementsfor the new page.This approach allows us to changepage without a browser refresh, andallows for a single-page webapplication (SPA). With a single-pageapplication, all content needed by theentire web-application is loaded on theinitial request (or with subsequentAJAX calls), and from that pointforward content is swapped in and outof the DOM to simulate page changes.The entire HTML page should nowlook like this:<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css"

media="screen" />

<script src="scripts/jquery-2.0.3.js"></script>

<script src="scripts/jquery-tmpl.js"></script>

<script src="scripts/jquery-serialization.js"></script>

<script src="scripts/tasks-controller.js"></script>

</head>

<body>

<header>

<span>Task list</span>

</header>

<main id="taskPage">

<section id="taskCreation" class="not">

<form id="taskForm">

<div>

<label>Task</label> <input type="text"required="required"

name="task" class="large"placeholder="Breakfast at Tiffanys" />

</div>

<div>

<label>Required by</label> <inputtype="date" required="required"

name="requiredBy" />

</div>

<div>

<label>Category</label> <selectname="category">

<optionvalue="Personal">Personal</option>

<option value="Work">Work</option>

</select>

</div>

<nav>

<a href="#" id="saveTask">Savetask</a>

<a href="#" id="clearTask">Cleartask</a>

</nav>

</form>

</section>

<section>

<table id="tblTasks">

<colgroup>

<col width="40%">

<col width="15%">

<col width="15%">

<col width="30%">

</colgroup>

<thead>

<tr>

<th>Name</th>

<th>Due</th>

<th>Category</th>

<th>Actions</th>

</tr>

</thead>

<tbody>

</tbody>

</table>

<nav>

<a href="#" id="btnAddTask">Add task</a>

</nav>

</section>

</main>

<footer>You have 3 tasks</footer>

</body>

<script>

$(document).ready(function() {

$('[required="required"]').prev('label').append('<span>*</span>').children('span').addClass('required');

$('tbody tr:even').addClass('even');

$('#btnAddTask').click(function(evt) {

evt.preventDefault();

$('#taskCreation').removeClass('not');

});

$('tbody tr').click(function(evt) {

$(evt.target).closest('td' ).siblings( ).andSelf().toggleClass( 'rowHighlight');

});

$('#tblTasks tbody').on('click', '.deleteRow',function(evt) {

evt.preventDefault();

$(evt.target).parents('tr').remove();

});

$('#saveTask').click(function(evt) {

evt.preventDefault();

var task = $('form').toObject();

$('#taskRow').tmpl(task).appendTo($('#tblTasks tbody'));

});

});

</script>

<script id="taskRow" type="text/x-jQuery-tmpl">

<tr>

<td>${task}</td>

<td><time datetime="${requiredBy}">${requiredBy}</time></td>

<td>${category}</td>

<td>

<nav>

<a href="#">Edit</a>

<a href="#">Complete</a>

<a href="#" class="deleteRow">Delete</a>

</nav>

</td>

</tr>

</script>

</html>

And the project structure will look asfollows:

We now want to start writing the codefor tasks-controller.js. This will utilizethe module pattern introduced earlierin the JavaScript chapter. This willensure the controller can encapsulatedata, and expose a public API to therest of the application.

The controller will be responsible forinitializing the form, handling events,and managing any state required by thepage. The basic structure of our taskscontroller is as follows:tasksController = function() {

return {

init : function(page) {

}

}

}();This code is implementing exactly thesame pattern as was implementedearlier with the createIncrementerfunction. The only difference here isthat we have not named the functionthat is returning the object: it is ananonymous function that we areexecuting immediately by adding () tothe end of the line.

It is important that you understand theimportance of the () at the end of thiscode block. It means that the variablerepresented by tasksController is setto the object returned by theanonymous function, not the functionitself.The main advantage of this approach isthat no other code can constructanother tasksController, since there isno function that can be invoked. As aresult, the variable tasksController isa singleton. A singleton is anotherdesign pattern that is used to ensureonly a single instance of a type ofobject (in traditional object orientatedlanguages, only a single instance of aclass) will exist in the application.It is important that our tasksControlleris a singleton, since it is going tomanage state. If multipletasksController were created theymay have different state, and would

therefore interfere with each otherwhen they attempted to update theDOM with this state.The controller will have a methodcalled init that will be responsible forperforming any initialisation tasks thatneed to occur when tasks.html loads,but this will be called explicitly withintasks.html rather than implicitly whenthe script loads. This is because wemay have multiple controllers fordifferent functional areas, and we onlywant to initialize them when the userselects to use them.When we initialize the controller weare going to pass it the main element intasks.html page as a parameter, Thiscontroller is going to be responsiblefor that specific portion of the DOM,and therefore any jQuery selects itperforms should be done within thecontext of that element.This is not going to be important in this

application, since it will only consistof a single distinct set of functionality,however in a large scale single-pageapplication, with many functionalareas, each functional area would begiven its own controller, and its ownmain element that it is responsible for.The following is our controllerimplementation:tasksController = function() {

var taskPage;

var initialised = false;

return {

init : function(page) {

if (!initialised) {

taskPage = page;

$(taskPage).find( '[required="required"]').prev('label').append( '<span>*</span>').children('span').addClass('required');

$(taskPage).find('tbody tr:even').addClass('even');

$(taskPage).find( '#btnAddTask' ).click(function(evt) {

evt.preventDefault();

$(taskPage ).find('#taskCreation').removeClass( 'not');

});

$(taskPage).find('tbody tr' ).click(function(evt){

$(evt.target ).closest('td').siblings( ).andSelf().toggleClass( 'rowHighlight');

});

$(taskPage ).find('#tblTasks tbody').on('click','.deleteRow', function(evt) {

evt.preventDefault();

$(evt.target ).parents('tr').remove();

});

$(taskPage).find( '#saveTask').click(function(evt) {

evt.preventDefault();

var task = $('form').toObject();

$('#taskRow').tmpl(task).appendTo($(taskPage ).find( '#tblTaskstbody'));

});

initialised = true;

}

}

}

}();

There are a number of features aboutthis controller that should beexplained.Firstly, the controller is storing thepage parameter in a local variablecalled taskPage. This variable ishidden from the outside world usingthe data hiding approach discussed inearlier chapters. This means it is notpossible for any other code to changethe context that this controller isworking within.Whenever the controller needs toaccess an HTML element, it does so inthe context of this page using thefollowing approach:$(taskPage).find(..)

This ensures that even if the HTMLpage contains other elements with thesame properties as the elements on ourpage, they will not be returned in anyjQuery selections.Secondly, the taskControllerremembers if it has been initialised ina local variable called initialised. Thisensures that regardless of how manytimes the init method is called, it willonly actually initilaize the controlleronce.With the controller in place, tasks.htmlneeds to be altered to invoke the initmethod when the page is loaded. Thescript block in tasks.html should nowcontain the following:<script>

$(document).ready(function() {

tasksController.init($('#taskPage'));

});

</script>

ValidationThe next feature that we will add is anessential feature of any form basedweb application: form validation.JavaScript has been used to performfield validation since it first appearedin browsers; in fact it was probably thefeature JavaScript was used for themost in its early years.Client side validation remains animportant use of JavaScript, but asmentioned earlier in the book, HTML5now contains a specification for formvalidation based on form attributes.This validation is intended to removethe need for JavaScript validation.Although it may not be obvious, thishas actually been implemented bydefault by adding the requiredattributes to our input fields. If youpress enter in the “Task” field withoutentering any input you should see thefollowing:

The message “Please fill out this field”is generated by HTML5 validation.Despite the presence of HTML5validation, we will not use it in thisweb application for two main reasons:1. All browsers do not supportHTML5 validation; therefore it isnecessary to rely on a polyfill forbrowsers that do not provide support.2. HTML5 validation does not play asnicely with JavaScript as you wouldexpect. For instance, we can not causethe HTML5 validators to fire bycalling submit() in JavaScript, theywill only fire if the user clicks asubmit button to post data to the server,or on a field by field basis when theuser presses enter in the field. Since

we will never post data to the serverthis is not helpful.For these reasons, we will use thejQuery Validation library in thisapplication. This can be downloadedfrom here:http://jqueryvalidation.org/or is available from the followingCDN:http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.jsI have downloaded version 1.11.1 andadded it to my scripts folder under thename jquery.validate.js. I have alsoadded it to the head section of the webpage:<head>

<meta charset="utf-8">

<title>Task list</title>

<link rel="stylesheet" type="text/css"href="styles/tasks.css"

media="screen" />

<script src="scripts/jquery-2.0.3.js"></script>

<script src="scripts/jquery-tmpl.js"></script>

<script src="scripts/jquery.validate.js"></script>

<script src="scripts/jquery-serialization.js"></script>

<script src="scripts/tasks-controller.js"></script>

</head>

Fortunately, jQuery validation relieson the same attributes as HTML5where possible, so the requiredattributes are valid for both HTML5and jQuery validation.jQuery validation contains a largenumber of built in validators, theseallow you to express rules for:• Validating a required field has avalue.• Validating a field contains a number.• Validating the length of input data.• Validating a number is in a range.• Validating a field contains an emailaddress.

• Validating a field contains a possiblyvalid credit card number.In addition to these default validators;you can add your own validators.In order to implement jQueryvalidation, we are first going to changethe input field with the name “task” toinclude a maximum length:<input type="text" required="required"maxlength="200" name="task" class="large"placeholder="Breakfast at Tiffanys"/>

Next we are going to change the eventlistener that is invoked when “SaveTask” is invoked. This will checkwhether the form is valid by calling thevalid function on it. As you haveprobably guessed, this is a function thathas been added to jQuery by thejQuery Validation plugin. The actualsaving of the task will only occur if theform is valid:$(taskPage).find('#saveTask').click(function(evt) {

evt.preventDefault();

if ($(taskPage).find('form').valid()) {

var task = $('form').toObject();

$('#taskRow').tmpl(task ).appendTo($(taskPage).find( '#tblTasks tbody'));

}

});

If you now attempt to save a taskwithout including mandatory fields,error messages will be generated:

In order to see the elements that jQueryValidation has added, highlight the textthat says “This field is required”, rightclick on the text, and choose “Inspectelement”: you should see thefollowing:

jQuery Validation has added a labelwith the class of error. This has thenbeen rendered in bold, red text by thefollowing class in tasks.css:label.error {

color: red;

font-weight:bold;

}

ConclusionThe web application is still far fromcomplete at this stage, but the basicproject structure is now in place.Before adding additional functionalitywe are going to pause and beginimplementing the functionality to storethe application's data and resourcesinside the browser.

Managing Client-side DataAlthough we have aspects of a workingweb application, clearly there is amajor flaw in the currentimplementation: every time the userrefreshes the tasks.html page all thetasks are lost.In this section we are going to examineways in which we can maintain thestate of the application (the tasks)between page refreshes withoututilizing server side storage.Traditionally the only mechanism forstoring data on the client in a way thatsurvives page refreshes was cookies.A cookie is a simple text basedname/value pair that is stored on theclient. The server can set a cookie onthe client by including it in an HTTPresponse.Every-time the browser sends anHTTP request to a page on the domainfrom this point forward, the cookie

(both its name and value) will beincluded in the request.Cookies can also be created andinteracted with (with somerestrictions) using JavaScript.Cookies are great for managing somedata. For instance, it is common forweb sites to store a session ID in acookie to represent each user’sindividual session. This allows theserver to differentiate each uniquesession, and keep them separate. Thisis essential, since HTTP is a statelessprotocol, and there is no other inherentway to know that two HTTP requestsare actually from the same browsersession.While cookies are great for storingsimple data on the client, they are notgreat for storing large amounts of datasuch as our task list. Cookies havesignificant limitations that make theminappropriate for storing large amounts

of data:1. They are included on each request tothe server, so unless you want theentire task list to be included on eachrequest, cookies are not a goodsolution.2. The maximum size of each cookie isapproximately 5 kilobytes.3. The maximum number of cookiesthat a single domain can store is 20(this can be browser dependent). Thismeans that the total amount of cookiestorage available to a domain is lessthan 100 kilobytes.It has therefore been evident for sometime that HTML needs some form ofoffline data storage if it is to allow forrich and dynamic web applications thatcan exist independent of a web server.Even applications that are continuallyconnected to a web server cansignificantly improve user experiencesif they could cache larger quantities of

data on the browser.There are now three distinct APIs forstoring data on the client, all of whichfall within the umbrella of HTML5.• Web storage: this is the simplest formof offline storage and supportsname/value pairs where the name andvalue must both be strings. Althoughthis is a relatively simple storagemechanism, and does come with anumber of limitations, all major webbrowsers support it.• Web SQL Database API: this APIsupports a relational database withinthe browser (similar to MySQL).Although this has many advantages,particularly for developers alreadyfamiliar with relational databases andSQL, Chrome and IE have announcedthat they will never support this API,therefore it is effectively dead.• IndexedDB: (formerlyWebSimpleDB) this API exposes an

object store. Objects (or simple datatypes) can be stored against a key, andretrieved either through this key, orother indexes added to the record.IndexedDB supports a transactionalmodel familiar to database developers,but does not include a generic querylanguage such as SQL. This is apromising API, but is not yet supportedby all browsers. In particular, Safari,and some mobile browsers do notsupport this API.In this chapter we will create a storageAPI that allows us to abstract theunderlying storage API from the webapplication. This means that the webapplication will not be aware whichunderlying API it is using, which thenallows the most appropriate API to beused (depending on browser support).This approach is another example of adesign pattern called the bridgepattern.

This chapter will provideimplementations for both Web storageand IndexedDB. We will refer to thisabstraction as a “storage engine”.

Storage Engine APIOur storage engine API will becapable of performing all the basicCRUD operations:• Create• Read• Update• DeleteThe API will operate on JavaScriptobjects. The only constraint that willbe placed on an object to be storable isthat it must have a property called id,which will be unique within thespecific type of object (e.g. tasks).All objects will be stored according totheir defined type; for instance, taskswill be stored under the type of “task”.If the data store did not have a conceptof object-type it would not be able todifferentiate related and unrelatedobjects, and all objects would need tobe stored together. For instance, if the

web application supported calendarevents and tasks, we would want away of retrieving all the calendarevents without retrieving the tasks. Ittherefore makes sense to store themseparate from one another.Finally, the API will work withcallback functions rather than directreturn values. When calling an APImethod, the invoker will pass asuccess callback function and an errorcallback function. When the processingcompletes, one of these callbackfunctions will be invoked, and passedthe result of the processing.The use of callbacks will allow us tosupport both synchronous andasynchronous storage mechanisms. Asynchronous storage mechanism is onethat performs storage operations on themain browser thread, and blocks untilit is complete. An asynchronousstorage mechanism on the other hand

may utilize background threads usingthe Web Worker API that will beintroduced in later chapters, or via anAJAX call to the server.If you are not familiar with callbacks,the examples below will provide asimple introduction. Callbacks willalso be used in several other APIs inthe chapters that follow.The section below providesdocumentation on the API that will beimplemented. Up until this point wehave largely ignored the importance ofwell-documented code. The sectionbelow therefore also serves as anexample of the way an API can bedocumented to make it usable to anaudience beyond its creator:/**

* The client must call this to initialize the storageengine before using it.

* If the storage engine initializes successfully thesuccessCallback will be invoked with a null object.

* If the errorCallback is invoked then the storageengine cannot be used.

* It should be possible to call this method multipletimes, and the same result will be returned eachtime.

*

* @param {Function} successCallback The callbackthat will be invoked if the storage engine initializes.

* @param {Function} errorCallback The callbackthat will be invoked in error scenarios.

*/

function init(successCallback, errorCallback)

/**

* The client must call this to initialize a specificobject type in the storage engine.

* If the storage engine supports the object type thesuccessCallback will be invoked with a null value.

* It should be possible to call this method multipletimes, and the same result will be returned eachtime.

* If the errorCallback is invoked then the object typecannot be stored.

*

* @param {String} type The type of object that willbe stored.

* @param {Function} successCallback The callbackthat will be invoked if the storage engine initializes.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function initObjectStore(type, successCallback,errorCallback)

/**

* This can be used to find all the objects for aspecific type.* If there are no objects found for that type this willreturn an empty array.

*

* @param {String} type The type of object thatshould be searched for.

* @param {Function} successCallback The callbackthat will be invoked after the query completes. Thiswill be passed an array of objects conforming to therequested type.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function findAll(type, successCallback,errorCallback)

/**

* This will return an object with a specific id for aspecific type.

* If no object is found this will return null

*

* @param {String} type The type of object thatshould be searched for.

* @param {String|number} id The unique ID of theobject

* @param {Function} successCallback The callbackthat will be invoked after the query completes. Thiswill be passed an object conforming to the requestedtype or null.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function findById(type, id, successCallback,errorCallback)

/**

* This will handle adding and editing objects of aspecific type.

* If the id property of the object passed in is null orundefined, an id will be assigned for the object, and itwill be saved.* If the id property is non-null then the object will beupdated.* If the id cannot be found the error callback will beinvoked.* On success, the newly saved object will bereturned to the success callback.

*

* @param {String} type The type of object that willbe stored.

* @param {Object} obj The object that will bestored.

* @param {Function} successCallback The callbackthat will be invoked after the object has beencommitted to the storage engine. This will be thestored object, including the id property.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function save(type, obj, successCallback,errorCallback)

/** This will delete an object with a specific id for aspecific type.* If no object exists with that id, the error callbackwill be invoked.* If an object is deleted this function will return theid of the deleted object to the successCallback

*

* @param {String} type The type of object that willbe deleted.

* @param {String|number} id The unique id of theobject.

* @param {Function} successCallback The callbackthat will be invoked after the object has been deletedfrom the storage engine. This will be passed theunique id of the deleted object.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function delete(type, id, successCallback,errorCallback)

/**

* This can be used for querying objects based on aproperty value.

* A single property name can be passed in, alongwith the value that matches. Any objects with thatvalue for the property specified will be returned.

*

* @param {String} type The type of object that willbe searched for.

* @param {String} propertyName The propertyname to be matched.

* @param {String|number} propertyValue The valuethat property should have.

* @param {Function} successCallback The callbackthat will be invoked after the query completes. Thiswill be an array of 0 or more objects of the specifiedtype.

* @param {Function} errorCallback The callbackthat will be invoked on error scenarios.

*/

function findByProperty(type, propertyName,propertyValue, successCallback,errorCallback)

Finally, we need to define the API forthe success and error callbacks. Theseshould be functions, and conform to thefollowing signature:

/*

* This will be called in all success scenarios.

* @param {any} result The success result, asdocumented on individual method calls.

*/

function succssCallback(result)

/*

* This will be called in all failure scenarios.

* @param {String} errorCode The type of exception

* @param {String} errorMessage A humanreadable version of the error message.

*/

function errorCallback(errorCode,errorMessage)

This simple API is sufficient toperform all our data storage needs.

Web Storage ImplementationIn order to see how simple the Webstorage API is, open the Chromeconsole (on any web page) and typethe following:> localStorage.setItem('item1', 'This is item 1')

This line of code saved the value ‘Thisis item 1’ under the key ‘item1’. Thiswill now be persisted indefinitely, andavailable to all pages from the sameorigin as this page.In order to prove that this has beenpersisted, open the “Resources” tab ofthe Chrome developer tools, and locate“Local Storage” on the left hand side.You should see the following:

If you wish to retrieve this value youcan do so with the following call:

> localStorage.getItem('item1')

And if you want to remove the valueyou can do so with the following call:> localStorage.removeItem('item1')

Or you can completely clear all datastored by this origin with:> localStorage.clear()

In addition to the localStorage object,the exact same API exists on an objectcalled sessionStorage. This performsthe same role as localStorage, but thedata is automatically cleared when thebrowser is closed. Data inlocalStorage on the other hand ispersisted indefinitely, although the useris free to clear it at any time.Web storage is a simple API, but islimited. For instance, if you try toinsert an object into localStorage itwill appear to succeed:> localStorage.setItem('item1', {})

If you retrieve the value back however,

you will see that the persisted value isa string: the result of calling toStringon the object:> localStorage.getItem('item1')

"[object Object]"

Web storage can only be used to storestrings. This turns out not to be a hugeissue due to the fact we can serializeobjects to strings easily with theJSON.stringify() function, and de-serialize them with JSON.parse();Another limitation of the Web storageAPI is that storage is limited to 5MB inmost browsers. If this limit was notsmall enough, JavaScript uses UTF-16as the character encoding for allstrings. UTF-16 represents allcharacters as at least 2 byte (16 bit)sequences. This is a limitation for mostWestern languages, since other UTFencodings (most notably UTF-8)represent the characters in the Latin

alphabet with a single byte.

// The JavaScript specificationpermits the use of either UTF-16 or UCS-2. UCS-2 was theprecursor to UTF-16, and is afixed length 2-byte encoding.This was superseded as thenumber of code-points in theUnicode code space grew.

Due to the fact JavaScript uses UTF-16, the amount of character data it canstore in 5MB is approximately half theamount as could have been stored withUTF-8 (assuming we are using mainlycharacters from the Latin alphabet).Effectively this reduces the size ofWeb storage to 2.5MB: this is still farbetter than cookies, but is a limitationwe need to bear in mind when

developing web applications.

// I successfully managed to bypass this limit one project by compressing all data with theLZW compression algorithm. This effectivelyincreased the amount of data that could bestored to 50MB in this particular case (resultswill vary depending on how repetitive datais).This page provides implementations of theLZW algorithm in a variety of languagesincluding JavaScript:http://rosettacode.org/wiki/LZW_compression

The implementation of our storageengine with Web storage will storeeach type of object in an object of itsown called an “object store” (if youare familiar with relational databases,you can think of this object as a table).

The properties of the object store willbe the id property of each object heldfor that type (the rows in the table),and the value will be the objectpersisted. This approach relies on thefact that the id property of each objectmust be unique within its type.The storage engine needs to generateunique IDs for objects. The approachwe will use with the Web storage APIis to use the current time inmilliseconds. This is not a great choicefor an id, since if two objects could becreated in quick enough successionthey will get the same id. A betterapproach is to use UUIDs (UniversallyUnique Identifiers), but we will avoidthat complexity for now.

// The most commonly used JavaScriptimplementation of UUIDs can be foundhere:

http://www.broofa.com/2008/09/javascript-uuid-function

In order to obtain the current time inmilliseconds we can use the jQueryhelper:> $.now()

The storage engine will be representedby a module. This will not have anydependencies to other code developedfor the tasks screen, therefore it iscompletely reusable by otherfunctionality if required. The modulewill be stored in a variable calledstorageEngine. The storageEngine will be initializedwhen the tasks.html page loads, andwill be available for use by thetasksController, or any otherJavaScript code, since thestorageEngine variable is bound to the

global window object.Begin by creating a JavaScript filecalled tasks-webstorage.js in thescripts folder. Next, import this intotasks.html:<script src="scripts/tasks-webstorage.js"></script>

The code below is the initial versionof the storageEngine module. Thisprovides the basic structure for themodule, along with implementations ofinit and initObjectStore:storageEngine = function() {

var initialized = false;

var initializedObjectStores = {};

return {

init : function(successCallback, errorCallback) {

if (window.localStorage) {

initialized = true;

successCallback(null);

} else {

errorCallback('storage_api_not_supported','The web storage api is not supported');

}

},

initObjectStore : function(type, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!localStorage.getItem(type)) {

localStorage.setItem(type,JSON.stringify({}));

}

initializedObjectStores[type] = true;

successCallback(null);

},

save : function(type, obj, successCallback,errorCallback) {

},

findAll : function(type, successCallback,errorCallback) {

},

delete : function(type, id, successCallback,errorCallback) {

},

findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

},

findById : function (type, id, successCallback,errorCallback) {

}

}

}();

Like the tasksController, thiscontroller implicitly creates a newobject. The object in this case will bestored in a global variable calledstorageEngine.The initial implementation abovecontains an implementation of the initand initObjectStore methods.Technically the Web storageimplementation does not need the initmethod, since there is nothing thatspecifically needs initializing in orderto use the localStorage object. Thismethod has been added to the APIhowever, since it is common for other

storage APIs to require initializationbefore use.The init method simply checks that thelocalStorage object is available in thebrowser. If it is available, it sets avariable in the storage engine calledinitialised to true. Due to thespecification of the API, the othermethods of the Web storageimplementation will not be able to beinvoked unless this method has beencalled.The initObjectStore method checks tosee whether the localStorage objectcurrently contains an item for the typepassed in (e.g. “tasks”). If not, itcreates an empty object inlocalStorage using the type as the keyfor the item. It will also keep track ofthe fact that we have initialized thisobject store.If you reload tasks.html, the followingcan be executed from the command line

to initialize the storage engine:> storageEngine.init(function(){

console.log('Storage is initialised');

},

function(errorCode, errorMessage) {

console.log(errorCode+':'+errorMessage);

}

);

The init method is passed twofunctions for the success and errorcallbacks respectively. When invoked,these functions simply log the fact thatthey have been called. This call shouldresult in the following being printed tothe console: “Storage is initialized”

Likewise, the initObjectStore methodcan be invoked as follows:> storageEngine.initObjectStore('testing',

function(){

console.log('New type added');

},

function(errorCode, errorMessage) {

console.log(errorCode+':'+errorMessage);

}

);

New type added

This call will create a new objectstore called testing, and then invokethe success callback which will logsuccess to the console. After invokingthis, the testing item will be availablein localStorage. This can be verifiedusing a shortcut to getItem():> localStorage.testing

"{}"

// localStorage is just a regularobject, therefore its items canbe accessed as regular

properties using the dotnotation (assuming theyadhere to the restictions onJavaScript variable names).

An important feature of both the initand initObjectStore methods is thatthey can be invoked multiple times andwill always return the same output forthe same inputs. This is an importantfeature, since a client may not know ifthese have been called by other code.Rather than requiring the client to findout whether the initialization hasoccurred, and call init if it hasn’t, theclient can simply call init and have ittake care of the logic of working outwhat needs to be done.The tasksController will beresponsible for calling init andinitObjectStore. Before providing theimplementation to call the initialization

methods, it is worth thinking about theerror callback. Every time a storageengine method is invoked, an errorcallback must be provided.We will therefore create a genericfunction that can be used for theerrorCallback, and store this as aprivate variable in tasksController. All this will do is log the fact that anerror has occurred, but if we want tochange the behaviour, we would beable to do so in a single place, ratherthan changing all the error callbacks.The function can be added as a privatefunction within tasksController: tasksController = function() {

function errorLogger(errorCode, errorMessage) {

console.log(errorCode +':'+ errorMessage);

}

Next, at the start of the init method intasksController, add the following

code:storageEngine.init(function() {

storageEngine.initObjectStore('task', function() {

}, errorLogger)

}, errorLogger);

This code calls the init method on thestorage engine, and when thatsucceeds, the success callback isinvoked, which in turn calls theinitObjectStore method. This fulfilsan important need: since the initsuccess callback may not be calledimmediately in other implementationsof this API (i.e. those that perform theirprocessing asynchronously), it isnecessary to ensure that init succeedsbefore calling the initObjectStoremethod. If we did not do this, we maycall initObjectStore while init wasstill processing.This highlights the challenge of

working with interfaces that canperform asynchronous processing. It isoften necessary to chain together awhole set of function calls, each insidethe callback of its predecessor. Thismakes code less elegant than the“chaining” approach we saw withjQuery.We will next implement the firstinteresting method of the storageengine: the save method. Add thefollowing as a new public method tothe storageEngine module:save: function(type, obj, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

if (!obj.id) {

obj.id = $.now();

}

var savedTypeString = localStorage.getItem(type);

var storageItem = JSON.parse(savedTypeString);

storageItem[obj.id] = obj;

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(obj);

}

As discussed above, this functionaccepts four parameters. When weinvoke this from our task application,the first parameter will always be“task”, while the second parameterwill be an object representing a task.The third and forth parameters are thesuccess and error callbacksrespectively.Let’s step through this implementationline by line.The first block of code simply checksthat init and initObjectStore havebeen invoked. If these have not been

invoked, the error callback is invoked:if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

The next section of the method checksif the object to be saved has an id ornot: if it does not have an id, a uniqueid is assigned.if (!obj.id) {

obj.id = $.now();

}

We next query localStorage for therelevant object store (e.g. “task”).Since initObjectStore has beeninvoked we can guarantee that therewill be an object for the specifiedtype:var savedTypeString = localStorage.getItem(type);

Next, we de-serialize the “stringified”version of the object store back into anobject:var storageItem = JSON.parse(savedTypeString);

We then add the object to be saved tothe object store, using the id propertyof the object as the property name.This will overwrite a value if it isalready there, which means the samecode handles creates and updates:storageItem[obj.id] = obj;

Also notice that we are not using thedot notation. Since the id starts with anumber, it is not a valid JavaScriptvariable name, and therefore the dotnotation would not work.We then serialize storedItem back intoa string and add it back intolocalStorage:localStorage.setItem(type,JSON.stringify(storageItem));

This will automatically update the item

stored against this key.Finally, the success callback isinvoked with the newly saved object:successCallback(obj);

With the save method implemented, wecan alter the save task event listener intasks-controller.js to utilize themethod:$(taskPage).find('#saveTask').click(function(evt) {

evt.preventDefault();

if ($(taskPage).find('form').valid()) {

var task = $('form').toObject();

storageEngine.save('task', task,

function(savedTask) {

$('#taskRow').tmpl( savedTask).appendTo($(taskPage).find( '#tblTasks tbody'));

}, errorLogger);

}

});

Notice that we only update the table inthe successCallback. This ensures thatwe do not update the screen unless the

actual save is successful.If you now create a task, you shouldsee the following in the Chromeresources:

The next method we will implement isfindAll. Before adding this, we willprovide a helper for obtaining the de-serialized object for a specified type.This will perfom the de-serializationlogic for us. This can be added as aprivate function at the top ofstorageEngine.storageEngine = function() {

var initialized = false;

var initializedObjectStores = {};

function getStorageObject(type) {

var item = localStorage.getItem(type);

var parsedItem = JSON.parse(item);

return parsedItem;

}

The following lines in the savemethod:var savedTypeString = localStorage.getItem(type);

var storageItem = JSON.parse(savedTypeString);

storageItem[obj.id] = obj;

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(obj);

can now be changed to:var storageItem = getStorageObject(type);

storageItem[obj.id] = obj;

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(obj);

The findAll method will allow us torepopulate the saved tasks fromlocalStorage back into the table whenthe page is refreshed. The following isthe implementation of findAll:findAll : function(type, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback(store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

var result = [];

var storageItem = getStorageObject(type);

$.each(storageItem, function(i, v) {

result.push(v);

});

successCallback(result);

}

Again, we will step through theimplementation line by line.The first section of the methodperforms the same checks as the savemethod in order to check init andinitObjectStore have both beeninvoked.Next, we initialize an array to return

the objects available for the specifiedtype. This ensures even if there are nosaved objects an empty array will bereturned:var result = [];

We then use the helper function toreturn the object store for the specifiedtype:var storageItem = getStorageObject(type);

The object store will contain a set ofproperties representing all the savedobjects for this type, therefore weiterate through them and add eachvalue to the results array using thepush method:$.each(storageItem, function(i, v) {

result.push(v);

});

The result is then returned to thesuccess callback:successCallback(result);

The findAll method can now be

invoked from the tasks-controller.jsfile. The functionality to call findAlland add all the results to the table willbe included in a new public methodafter the init method called loadTasks:loadTasks : function() {

storageEngine.findAll('task', function(tasks) {

$.each(tasks, function(index, task) {

$('#taskRow').tmpl(task ).appendTo( $(taskPage).find( '#tblTasks tbody'));

});

}, errorLogger);

}

This performs the call to findAll, andthen, in the success callback, iteratesthrough the results one by one and addsthem to the table using the template.Now, inside the tasks.html page, add acall to this method after the call to init:$(document).ready(function() {

tasksController.init($('#taskPage'));

tasksController.loadTasks();

})

If you reload tasks.html, any savedtasks should load into the table.We can now add the delete method tothe storage engine.delete : function(type, id, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializeObjectStores[type]) {

errorCallback('store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

var storageItem = getStorageObject(type);

if (storageItem[id]) {

delete storageItem[id];

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(id);

} else {

errorCallback("object_not_found","The objectrequested could not be found");

}

}

The delete implementation isstraightforward; the one aspect thatmay be new is the line:delete storageItem[id];

It is possible to delete a property (andtherefore its value) from an object byusing the delete keyword. Since we arestoring each item as a property of anobject, we can delete the individualitems with this technique. Afterinvoking this, the property specified isundefined.When the delete button is clicked weneed to know which task needs to bedeleted. We therefore need to updatethe delete button so that it knows whichtask it relates to. Change the followingline in the template:<a href="#" class="deleteRow">Delete</a>

to

<a href="#" class="deleteRow" data-task-id="${id}">Delete</a>

This uses a custom data attribute tokeep track of which task each deletebutton is responsible for.Now change the delete implementationin tasks-controller.js from this:$(taskPage).find('#tblTasks tbody').on('click','.deleteRow',

function(evt) {

$(evt.target).parents('tr').remove();

});

to this:$(taskPage).find('#tblTasks tbody').on('click','.deleteRow',

function(evt) {

storageEngine.delete('task', $(evt.target).data().taskId, function() {

$(evt.target).parents('tr').remove();

}, errorLogger);

}

);

When any delete button is clicked, theelement that was clicked is available$(evt.target). We then use the HTML5data() function to obtain all the dataattributes associated with the element.This extracts all the attributes thatbegin with “data-“ and makes themavailable in an object, where eachproperty in the object represents one ofthe data attributes.You may have noticed that the attribute“data-task-id” is available asdata().taskId. Since attribute names areconverted to lower case inside theDOM, hyphens are typically used toseparate words in attribute names. InJavaScript, the common convention isto separate words through the use ofcapitalisation. The data() objecttherefore converts attribute names intoforms more conventional for use inJavaScript.The data attribute could have also been

retrieved with the following call:$(evt.target).attr('data-task-id');

Also note that we only update the tableonce we know that the storage enginehas successfully deleted the row. Thisensures that if there is an error duringthe processing, the screen does not getout of sync with the storage engine.If you now delete a row, and refreshthe page, you will see the task has beenpermanently deleted.Finally, we will add the two remainingfunctions to the storageEngine:findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

var result = [];

var storageItem = getStorageObject(type);

$.each(storageItem, function(i, v) {

if (v[propertyName] === propertyValue) {

result.push(v);

}

});

successCallback(result);

},

findById : function (type, id, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'The objectstore '+type+' has not been initialized');

}

var storageItem = getStorageObject(type);

var result = storageItem[id];

successCallback(result);

}

The implementations of these methods

should now look fairlystraightforward. They are continuingthe same pattern of obtaining the objectstore, and accessing the relevant itemsfrom this to return to the client.With all the pieces of the storageengine in place, we can add “edit”functionality to the application. Thiswill allow tasks to be updated afterthey have been created. This willutilize the same form as the one used toadd tasks, therefore the form needs tocontain a hidden field to capture theexisting id of an object if there is one:<form id="taskForm">

<input type="hidden" name="id"/>

This will allow us to serialize and de-serialize all properties of the task, notjust the visible properties.Next, change the edit button in thetemplate from this:<a href="#">Edit</a>

to this:<a href="#" class="editRow" data-task-id="${id}">Edit</a>

This is following the same pattern thatwas established with the deletebuttons.With this in place, we can add an eventlistener in the init method of tasks-controller.js. When the user clicks toedit a task in the table, the task will beretrieved from the storage engine usingthe findById method. It will then beloaded into the form using theserialization plugin we wrote earlier inthe book:$(taskPage).find('#tblTasks tbody').on('click','.editRow',

function(evt) {

$(taskPage).find('#taskCreation' ).removeClass('not');

storageEngine.findById('task', $(evt.target ).data().taskId, function(task) {

$(taskPage).find('form').fromObject(task);

}, errorLogger);

}

);

With this in place, the existing savemethod can remain unchanged, since itwas already designed to handleupdates. The task that is passed to thesave method on an edit will contain anid property, and therefore an updatewill be performed.We do not have code in place howeverto update the table after the edit hasoccurred – the current functionalitywill simply add a new row after theedit. We will therefore change it tothis:$(taskPage).find('#saveTask').click(function(evt) {

evt.preventDefault();

if ($(taskPage).find('form').valid()) {

var task = $(taskPage).find('form').toObject();

storageEngine.save('task', task, function() {

$(taskPage).find('#tblTasks tbody').empty();

tasksController.loadTasks();

$(':input').val('');

$(taskPage).find('#taskCreation').addClass( 'not');

}, errorLogger);

}

});

This will now empty and recreate thetasks table when a task is saved. Ifthere was going to be a large numberof tasks we would probably look atproducing a more optimisedimplementation that simply updated thecorrect row, but it is best to startsimple, and optimize if required.

// There is a famous quote byDonald Knuth:"We should forget about smallefficiencies, say about 97%of the time: prematureoptimization is the root of all

evil"

This functionality will also clear theinput fields and hide the edit portion ofthe screen. This ensures that if a userclicks the “Add task” button, the fieldswill not be prepopulated with datafrom the previous edit.The final version of the Web storagebased storage engine should be asfollows:storageEngine = function() {

var initialized = false;

var initializedObjectStores = {};

function getStorageObject(type) {

var item = localStorage.getItem(type);

var parsedItem = JSON.parse(item);

return parsedItem;

}

return {

init : function(successCallback, errorCallback) {

if (window.localStorage) {

initialized = true;

successCallback(null);

} else {

errorCallback('storage_api_not_supported','The web storage api is not supported');

}

},

initObjectStore : function(type, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!localStorage.getItem(type)) {

localStorage.setItem(type, JSON.stringify({}));

}

initializedObjectStores[type] = true;

successCallback(null);

},

save: function(type, obj, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized',

'The storage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'Theobject store '+type+' has not been initialized');

}

if (!obj.id) {

obj.id = $.now();

}

var storageItem = getStorageObject(type);

storageItem[obj.id] = obj;

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(obj);

},

findAll : function(type, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'Theobject store '+type+' has not been initialized');

}

var result = [];

var storageItem = getStorageObject(type);

$.each(storageItem, function(i, v) {

result.push(v);

});

successCallback(result);

},

delete : function(type, id, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'Theobject store '+type+' has not been initialized');

}

var storageItem = getStorageObject(type);

if (storageItem[id]) {

delete storageItem[id];

localStorage.setItem(type,JSON.stringify(storageItem));

successCallback(id);

} else {

errorCallback("object_not_found","The objectrequested could not be found");

}

},

findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'Theobject store '+type+' has not been initialized');

}

var result = [];

var storageItem = getStorageObject(type);

$.each(storageItem, function(i, v) {

if (v[propertyName] === propertyValue) {

result.push(v);

}

});

successCallback(result);

},

findById : function (type, id, successCallback,

errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

} else if (!initializedObjectStores[type]) {

errorCallback('store_not_initialized', 'Theobject store '+type+' has not been initialized');

}

var storageItem = getStorageObject(type);

var result = storageItem[id];

successCallback(result);

}

}

}();

There are definite pros and cons tousing the Web storage API. The mainadvantage is that it is supported in allmajor browsers, and is extremelysimple to use.The main disadvantages with the Web

storage API would only becomeapparent if we needed to support alarge amount of data. Not only doesWeb Storage only support a maximumof 5MB data in some browsers, evenwhere it does support larger limits,accessing a minimal data set from alarge data set may be time consuming,since there is no query API foraccessing data. Data access is fastwhen it is based on the item’s key, butslow in any other scenario.There are two other disadvantageswith the Web storage API.Firstly, it does not supporttransactions. In our simple cases thishas not been an issue, but if we wantedto be able to save multiple tasks, andhave them all either succeed (commit),or all fail (rollback), we would needto write our own custom code tohandle this. This would need to use“compensating transactions”: if a

change failed after other changes hadsucceeded, we would need to writecustom code to undo the earlierchanges.Secondly, the Web storage API is asynchronous API and operates on themain browser thread. Again, this is notan issue for small data sets, but couldbecome an issue with large data sets.The API we will look at in the nextsection resolves these issues, but doesso at the cost of additional complexity.

IndexedDB ImplementationWe will now implement the storageengine using the IndexedDB API. Dueto the fact we are using the same APIwe will not need to change anythingelse in our application. The tasks-controller.js does not care how thestorage engine is implemented, onlythat the API behaves as advertised.IndexedDB is a more sophisticatedAPI than Web storage. Although it is anobject database rather than a classicrelational database, it incorporatesconcepts that are familiar to those whohave worked with relational databases,such as transactions and indexes.IndexedDB always operates withasynchronous callbacks, but by defaultit does still use the main browserthread. It is also possible for browservendors to implement the IndexedDBAPI with Web Workers (a subject thatwill be introduced in later chapters),

which allows processing to occur on aseparate thread.Not all major browsers currentlysupport IndexedDB. In addition, somebrowsers do not support it through the“indexedDB” object, only through avendor named object (e.g.mozIndexedDB in Firefox,msIndexedDB in IE). This is used toindicate that the browser does notprovide full compliance with thespecification. The implementationbelow will ignore these alternativelynamed implementations.To begin implementing the API, createa new file in the scripts folder calledtasks-indexeddb.js. Inside this add theskeleton of our API:storageEngine = function() {

return {

init : function(successCallback, errorCallback) {

},

initObjectStore : function(type, successCallback,

errorCallback) {

},

save : function(type, obj, successCallback,errorCallback) {

},

findAll : function(type, successCallback,errorCallback) {

},

delete : function(type, id, successCallback,errorCallback) {

},

findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

},

findById : function (type, id, successCallback,errorCallback) {

}

}

}();

In addition, comment out the tasks-webstorage.js from the tasks.html pageand add in tasks-indexeddb.js in itsplace. We will eventually move to a

model where the browser will choosethe best implementation, but for nowwe will concentrate on getting theIndexedDB implementation working.<!--script src="scripts/tasks-webstorage.js"></script-->

<script src="scripts/tasks-indexeddb.js"></script>

To begin with we are going toimplement the init method. As with theWeb storage implementation, this willcheck that IndexedDB is supported bythe browser, but unlike Web Storage,there is a specific operation that needsto be performed: opening the database.The following is the implementation:storageEngine = function() {

var database;

var objectStores;

return {

init : function(successCallback, errorCallback) {

if (window.indexedDB) {

var request =indexedDB.open(window.location.hostname+'DB',

1)

request.onsuccess = function(event) {

database = request.result;

successCallback(null);

}

request.onerror = function(event) {

errorCallback('storage_not_initalized', 'It isnot possible to initialized storage');

}

} else {

errorCallback('storage_api_not_supported','The web storage api is not supported');

}

},

initObjectStore : function(type, successCallback,errorCallback) {

},

save : function(type, obj, successCallback,errorCallback) {

},

findAll : function(type, successCallback,errorCallback) {

},

delete : function(type, id, successCallback,errorCallback) {

},

findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

},

findById : function (type, id, successCallback,errorCallback) {

}

}

}();

There are a number of things going onhere. Firstly, look at this line of code:var request =indexedDB.open(window.location.hostname+'DB')

This is the request to open a database.The database may or may not existbefore this call. Our implementation isgoing to create a database named forthe domain we are running in, so if weare running using the hostname

localhost, the database will belocalhostDB, whereas if we arerunning in the domainwww.testing.com, the database will becalled www.testing.comDB.The next point to note is that thisreturns a synchronous response. Theresponse does not imply the operationhas completed however, it is necessaryto add onsuccess and onerrorcallbacks to the object returned. Thesewill then be fired on success orfailure: you can see this occurring onthe next few lines.In the implementation above, theonsuccess callback also stores theresult of the function call in a privatevariable called database.If you set a breakpoint and examine theproperties of this object you will seethe following:

This shows that the database has aname and a version, but not much elseat this point. The version has beenimplicitly created for us, but we willsee later in this chapter that it ispossible to explicitly set this.Next we will implement theinitObjectStore method so that thedatabase knows how to store objectsof a specific type. Unlike the Webstorage API, IndexedDB is going tostore our objects directly rather than asserialized strings. IndexedDB can infact store any data type, includingliteral strings and numbers, but we areonly interested in storing objects.

IndexedDB also relies on the conceptof primary keys when storing objects.We can tell IndexedDB the propertyname that holds the primary key, andwe can even ask IndexedDB togenerate these for us. In the storageengine the id property of the objectalways represents the primary key.

// In relational databases, alltables typically need aprimary key. This can consistof one or more columns, andthe value for the primary keymust be unique within a table.

The following is the implementationfor creating object stores inIndexedDB.initObjectStore : function(type, successCallback,errorCallback) {

if (!database) {

errorCallback( 'storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

var exists = false;

$.each(database.objectStoreNames, function(i, v) {

if (v == type) {

exists = true;

}

});

if (exists) {

successCallback(null);

} else {

var version = database.version+1;

database.close();

var request =indexedDB.open(window.location.hostname+'DB',version);

request.onsuccess = function(event) {

successCallback(null);

}

request.onerror = function(event) {

errorCallback( 'storage_not_initalized', 'It is notpossible to initialized storage');

}

request.onupgradeneeded = function(event) {

database = event.target.result;

var objectStore =database.createObjectStore(type, { keyPath: "id",autoIncrement: true });

}

}

},

The implementation of this method maylook difficult to understand. The firstportion of this method checks whetherthe object store for this type alreadyexists in the structure of the database: $.each(database.objectStoreNames, function(i, v){

if (v == type) {

exists = true;

}

});

If it does (i.e. this is not the first time

the page has been loaded) then wehave nothing to do, and the successcallback can be invoked.If we do need to create an object storefor this type then we are altering thestructure of the database. There arevery strict rules for changing thestructure of the database withIndexedDB, specifically, it can onlyoccur during the process of opening thedatabase.In order to accommodate thisrequirement, we need to close thedatabase, but before doing that we willalso record which version of thedatabase we are using:var version = database.version+1;

database.close();

Now, the database can be re-opened,but we will tell IndexedDB that theversion number of the database haschanged. We could request any versionnumber for the database, but

incrementing by one is a naturalchoice.indexedDB.open(window.location.hostname+'DB',version);

Due to the fact that a new versionnumber has been specified, not onlywill the onsuccess and onerrorfunctions be invoked on the request,but a third function calledonupgradeneeded will also beinvoked. This function is the only placewhere we are allowed to change thestructure of the database, and we do sowith the following call:request.onupgradeneeded = function(event) {

database = event.target.result;

var objectStore =database.createObjectStore(type, { keyPath: "id",autoIncrement: true });

}

On the first line we are re-storing thelocal reference to the database.

Next we are requesting for anobjectStore to be created for ourtype. We are also going to specify thatthe primary key of the object store iscontained in the id property ofpersisted objects, and that we want thisto be auto incremented by IndexedDB.This means that we no longer need toworry about generating the IDs forobjects. Notice that we still rely on theonsuccess callback to invoke ourcallback method, otherwise we mightstart using the object store before it hasbeen created.The API we have provided hascomplicated the object store creationprocess to some extent. If we knew allthe object store names in the initmethod then we would not have neededto close and reopen the database. It hasgiven us more flexibility however,because each functional area of theapplication can be responsible forinitializing itself, without worrying

about the rest of the application.Before proceeding with the code, weneed to make a small change to thiscode in tasks.html:$(document).ready(function() {

tasksController.init($('#taskPage'));

tasksController.loadTasks();

});

The call to tasksController.init willbe responsible for initializing thestorage engine; therefore it needs toknow that it is fully initialized beforereturning. With the currentimplementation, the application maystart using the storage engine before itis fully initialized, as it would do inthe call to tasksController.loadTasks.In order to solve this we are going tomake the init method in tasks-controller.js use a callback to notify itsclient when it has truly finishedinitializing. The following are the

changes to the init method:init : function(page, callback) {

if (initialised) {

callback()

} else {

taskPage = page;

storageEngine.init(function() {

storageEngine.initObjectStore('task', function() {

callback();

}, errorLogger)

}, errorLogger);

The init method now accepts acallback parameter (which should be afunction). If the module is initializedalready, it simply invokes the callbackby executing the function. If the moduleis not initialized, the callback is notinvoked until the initObjectStoremethod succeeds.With that in place, we can now changethe code in tasks.html as follows:tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

});

The page will not attempt to load thetasks into its table until the callbackhas been invoked to notify it that thestorage engine has fully initialized.This is as important lesson to learn: assoon as you start developingasynchronous APIs you need to beconscious of the difference between afunction returning control to the caller,and a function finishing processing. Itis often not until the function hasfinished processing that you canperform subsequent actions. It is easyto overlook these situations, and theycan be a source of annoying bugs.The next step in the process is toimplement the save method. This willintroduce you to the concept ofIndexedDB transactions:save : function(type, obj, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

if (!obj.id) {

delete obj.id ;

} else {

obj.id = parseInt(obj.id)

}

var tx = database.transaction([type], "readwrite");

tx.oncomplete = function(event) {

successCallback(obj);

};

tx.onerror = function(event) {

errorCallback('transaction_error', 'It is notpossible to store the object');

};

var objectStore = tx.objectStore(type);

var request = objectStore.put(obj);

request.onsuccess = function(event) {

obj.id = event.target.result

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to store the object');

};

}

After we establish that there is adatabase to operate on we check the idof the object we have been passed. If itis a false value (e.g. null or “”) wedelete the id property itself to make itundefined. Since IndexedDB isresponsible for generating keys, it doesnot expect to find an id property at allon an unsaved object, even one with anull value. Our implementation oftoObject will produce empty stringsfor properties that are empty.If the property does exist, we ensurethat it is an integer with the parseIntfunction. For instance, if we are passeda number as a string, then we convert itto a number. This is another importantconsideration, since the toObject

implementation currently alwaysproduces strings.

// This is the first time we haveseen the native JavaScriptparseInt function. Althoughthis is a useful function, itdoes have its problems. Inorder to see these first hand,try the following call:> parseInt(010)

It will be left to the reader todiscover why this returns 8rather than 10.

Next we create a transaction in thedatabase and add onerror andonsuccess callbacks to it:var tx = database.transaction([type], "readwrite");

tx.oncomplete = function(event) {

successCallback(obj);

};

tx.onerror = function(event) {

errorCallback('transaction_error', 'It is not possibleto store the object');

};

We can only access an object store inthe context of a transaction. Atransaction groups together a set ofoperations on one or more objectstores. The transaction will auto-commit once all requests against thetransaction have completed.It is not until the transaction completesthat we will notify the client ofsuccess. If we notified the client afterthe requests had been submitted theymight encounter a situation where theycannot query the object store for theobjects. This is because all changes tothe object store will remain hiddenfrom all clients until the transactioncommits.

// The transaction is specifiedas a “readwrite” transaction:you must specify this if youwant to modify objects in anobject store. The defaulttransaction type is “read”. Itmay seem strange that atransaction is required evento read objects.

Next we perform the request to save anobject to the object store.var objectStore = tx.objectStore(type);

var request = objectStore.put(obj);

request.onsuccess = function(event) {

obj.id = event.target.result

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is not possibleto store the object');

};

Once the object store has beenretrieved from the transaction, the putmethod is used to persist the object.This method is capable of supportingupdates and inserts. If we only wantedto handle inserts we could have usedthe add method instead.Just as the transaction has callbacks,the code also adds onsuccess andonerror callbacks to the request. Inthe onsuccess callback we are going toextract the ID that has been assigned tothe object so that this can be returnedto the client. The onsuccess of therequest will always be called beforethe onsuccess of the transactionNext we will implement the findAllmethod. The following is theIndexedDB implementation. This willintroduce you to another importantIndexedDB concept: cursors. Cursorswill be familiar to those of you whohave worked with relational databases;

a cursor represents a result set, and canbe navigated to access all the recordsin the result set.findAll : function(type, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

var result = [];

var tx = database.transaction(type);

var objectStore = tx.objectStore(type);

objectStore.openCursor().onsuccess =function(event) {

var cursor = event.target.result;

if (cursor) {

result.push(cursor.value);

cursor.continue();

} else {

successCallback(result);

}

};

}

The initial portion of this should bevery familiar. We create a transaction(although we do not specify“readwrite” this time).var tx = database.transaction(type);

var objectStore = tx.objectStore(type);

Once we have a transaction we specifythe object store we wish to access andopen a cursor on it. The openCursormethod will implicitly create a cursorwith all objects in the object store inits result set.It is also possible to limit the result setreturned by openCursor to a specifickey range.In order to loop through the contents ofthe cursor we registered a callbackwith the onsuccess event of theopenCursor method. This will becalled when the cursor is open andready to be interacted with.objectStore.openCursor().onsuccess =

function(event) {

var cursor = event.target.result;

if (cursor) {

result.push(cursor.value);

cursor.continue();

} else {

successCallback(result);

}

};

Within this function we have access toa cursor object. If this is null thenthere are no further entries in the resultset. If it is not null we can callcursor.value to get the object at thecurrent cursor position, and thencursor.continue to move the cursor tothe next position in the result set.When the cursor is eventually null weknow we can return any results wehave collected from the cursor to theclient. There is no need to wait for thetransaction to complete before

returning results to the client becausethe transaction is not modifying thestate of the database.The next method we will implement isfindById. This will highlight anotherfeature of IndexedDB; it is trivial toaccess an object with a specific IDinside an object store without the needto loop through all the objects. This isbecause IndexedDB has an index onthe id property:findById : function (type, id, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

var tx = database.transaction([type]);

var objectStore = tx.objectStore(type);

var request = objectStore.get(id);

request.onsuccess = function(event) {

successCallback(event.target.result);

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to locate the requested object');

};

}

This method is very similar to thefindAll method, except we do not needto open a cursor to find the object wewish to access, instead we can call geton the object store and pass in therelevant id.As with all IndexedDB methods, this isstill an asynchronous call, therefore westill need to add an event listener toretrieve the object returned. If there isno match for the key, get will return anull result, which is also what ourstorage engine API expects.The delete implementation is similar toseveral of the methods we have seenbefore:delete : function(type, id, successCallback,errorCallback) {

var obj = {};

obj.id = id;

var tx = database.transaction([type], "readwrite");

tx.oncomplete = function(event) {

successCallback(id);

};

tx.onerror = function(event) {

console.log(event);

errorCallback('transaction_error', 'It is notpossible to store the object');

};

var objectStore = tx.objectStore(type);

var request = objectStore.delete(id);

request.onsuccess = function(event) {

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to delete the object');

};

}

As with the save method, we ensurethe transaction is opened with the

“readwrite” parameter. We are alsocareful not to tell the client we havesuccessfully performed the delete untilthe transaction (rather than the request)completes.The delete method takes advantage ofthe delete method on objectStore,which conveniently accepts an ID.Finally, we will implement thefindByProperty method. This is onearea where you may expect IndexedDBto shine brightest with its ability toquery directly for the relevant resultsrather than looping over all results inJavaScript code.In fact, IndexedDB can performqueries for properties with specificvalues, but only if an index has beencreated on that property. In a situationwhere any property can form the basisof a query, this would mean addingindexes to all properties on an object.We will not add an index in our

example, but it is worth knowing howthey work. In order to create an index,we would need to add the following tothe onupgradeneeded callback:objectStore.createIndex("category", " category ", {unique: false });

Indexes can either be unique or non-unique. The index for the categoryproperty on the task object would needto be non-unique, since many tasks canhave the same category.With that in place we could search forall tasks with a specific category byfirst obtaining a reference to the indexfrom the object store:var index = objectStore.index("category");

Next, you would specify the range youwish to search for (e.g. the indexvalue):var range = IDBKeyRange.only("Work");

and then open a cursor on that just aswe saw in the findAll example, except

the range would be passed as aparameter:index.openCursor(range).onsuccess =function(event) {

Due to the fact we are not going to addan index to the properties on task, wehave no option but to loop through theobjects ourselves and determine thosethat match: findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

var result = [];

var tx = database.transaction(type);

var objectStore = tx.objectStore(type);

objectStore.openCursor().onsuccess =function(event) {

var cursor = event.target.result;

if (cursor) {

if (cursor.value[propertyName] ==propertyValue) {

result.push(cursor.value);

}

cursor.continue();

} else {

successCallback(result);

}

};

}

The complete implementation of theIndexedDB storage engine should nowlook like this:storageEngine = function() {

var database;

var objectStores;

return {

init : function(successCallback, errorCallback) {

if (window.indexedDB) {

var request =indexedDB.open(window.location.hostname+'DB');

request.onsuccess = function(event) {

database = request.result;

successCallback(null);

}

request.onerror = function(event) {

errorCallback('storage_not_initalized', 'It isnot possible to initialized storage');

}

} else {

errorCallback('storage_api_not_supported','The web storage api is not supported');

}

},

initObjectStore : function(type, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

}

var exists = false;

$.each(database.objectStoreNames, function(i,v) {

if (v == type) {

exists = true;

}

});

if (exists) {

successCallback(null);

} else {

var version = database.version+1;

database.close();

var request =indexedDB.open(window.location.hostname+'DB',version);

request.onsuccess = function(event) {

successCallback(null);

}

request.onerror = function(event) {

errorCallback('storage_not_initalized', 'It isnot possible to initialized storage');

}

request.onupgradeneeded = function(event) {

database = event.target.result;

var objectStore =database.createObjectStore(type, { keyPath: "id",autoIncrement: true });

}

}

},

save : function(type, obj, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

}

if (!obj.id) {

delete obj.id ;

} else {

obj.id = parseInt(obj.id)

}

var tx = database.transaction([type],"readwrite");

tx.oncomplete = function(event) {

successCallback(obj);

};

tx.onerror = function(event) {

errorCallback('transaction_error', 'It is notpossible to store the object');

};

var objectStore = tx.objectStore(type);

var request = objectStore.put(obj);

request.onsuccess = function(event) {

obj.id = event.target.result

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to store the object');

};

},

findAll : function(type, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

}

var result = [];

var tx = database.transaction(type);

var objectStore = tx.objectStore(type);

objectStore.openCursor().onsuccess =function(event) {

var cursor = event.target.result;

if (cursor) {

result.push(cursor.value);

cursor.continue();

} else {

successCallback(result);

}

};

},

delete : function(type, id, successCallback,errorCallback) {

var obj = {};

obj.id = id;

var tx = database.transaction([type],"readwrite");

tx.oncomplete = function(event) {

successCallback(id);

};

tx.onerror = function(event) {

console.log(event);

errorCallback('transaction_error', 'It is notpossible to store the object');

};

var objectStore = tx.objectStore(type);

var request = objectStore.delete(id);

request.onsuccess = function(event) {

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to delete the object');

};

},

findByProperty : function(type, propertyName,propertyValue, successCallback, errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

}

var result = [];

var tx = database.transaction(type);

var objectStore = tx.objectStore(type);

objectStore.openCursor().onsuccess =function(event) {

var cursor = event.target.result;

if (cursor) {

if (cursor.value[propertyName] ==propertyValue) {

result.push(cursor.value);

}

cursor.continue();

} else {

successCallback(result);

}

};

},

findById : function (type, id, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized','The storage engine has not been initialized');

}

var tx = database.transaction([type]);

var objectStore = tx.objectStore(type);

var request = objectStore.get(id);

request.onsuccess = function(event) {

successCallback(event.target.result);

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to locate the requested object');

};

}

}

}();

Dynamically Choosing a StorageEngineWe now have two storage enginesmatching the requirements of our API,they can be used entirelyinterchangeably (assuming the browsersupports the underlying APIs). Ourpreferred approach is to use theIndexedDB storage engine if it issupported by the browser, and tofallback to the Web storage API if it isnot supported.In order to load the correct storageengine we have two distinct tasks. Thefirst is deciding which storage enginewe wish to use; the second is forcingthat storage engine to load instead ofthe other.In order to determine if it is possible touse a particular storage engine we canuse the following:if (window.localStorage) {

and if (window.indexedDB) {

If the browser supports these APIsthere will be a global property on thewindow object for that API, andtherefore the if statement will evaluateto true.This approach is not foolproof, sincethere is nothing to stop us creating ourown global property calledlocalStorage on the window object,but it is a quick and convenientmechanism that we can rely on if weare following good coding standards.Now that we have an approach fordetermining if a particular storageengine is available, we have severaloptions for loading the correct storageengine at run-time. We will achievethis through the use of AJAX. This willdynamically load the appropriateJavaScript file at run-time based on thecapabilities of the browser.

// If you are not familiar withAJAX, you do not need toconcern yourself with how itworks in this chapter. AJAXwill be covered in depth laterin the book.

To see how this works, delete both thestorage engine imports:<!--script src="scripts/tasks-webstorage.js"></script-->

<script src="scripts/tasks-indexeddb.js"></script>

And then replace the following intasks.html:$(document).ready(function() {

tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

});

});

with this:if (window.indexedDB) {

$.getScript( "scripts/tasks-indexeddb.js" )

.done(function( script, textStatus ) {

$(document).ready(function() {

tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

});

})

})

.fail(function( jqxhr, settings, exception ) {

console.log( 'Failed to load indexed db script' );

});

} else if (window.localStorage) {

$.getScript( "scripts/tasks-webstorage.js" )

.done(function( script, textStatus ) {

$(document).ready(function() {

tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

});

})

})

.fail(function( jqxhr, settings, exception ) {

console.log( 'Failed to load web storage script');

});

}

This is taking advantage of the$.getScript helper in jQuery to load theappropriate JavaScript via anasynchronous AJAX call. The result ofthe AJAX call is the script we wish toload, which jQuery is then dynamicallyadding to the DOM.Due to the fact the JavaScript is nowdynamically loading the appropriatestorage engine at run-time, we alsoneed to ensure we do not start using thestorage engine until the script has beenprocessed. We therefore initialise thescreen inside the success (done)callbacks from the AJAX calls.The current implementation duplicates

the initialisation logic for each scriptwe attempt to load; therefore we canrewrite it as follows:function initScreen() {

$(document).ready(function() {

tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

});

});

}

if (window.indexedDB) {

$.getScript( "scripts/tasks-indexeddb.js" )

.done(function( script, textStatus ) {

initScreen();

})

.fail(function( jqxhr, settings, exception ) {

console.log( 'Failed to load indexed db script' );

});

} else if (window.localStorage) {

$.getScript( "scripts/tasks-webstorage.js" )

.done(function( script, textStatus ) {

initScreen();

})

.fail(function( jqxhr, settings, exception ) {

console.log( 'Failed to load web storage script' );

});

}

An alternative approach we could havefollowed would be to download boththe scripts as traditional imports, butload them in order. We could have thenadded logic to only create a storageengine if:

1. The browser supports theunderlying API.

2. There is no storage enginealready created.

We would achieve the same result withthis approach. The only disadvantageof this is that we would be loading oneextra script that we did not need.

Tidy up the ApplicationWe now have most of the pieces of theapplication in place, but beforecontinuing there are a number offeatures we need to add. Thesefeatures will help to reinforce theknowledge you have already gained inearlier chapters. You may wish toattempt to implement these features onyour own based on the shortintroduction given to each.

Updating the CountWe need to update the count at thebottom of the screen every time there isa change to the number of tasks:

In order to do this, we will change thiselement:<footer>You have 3 tasks</footer>

to this:<footer>You have <span id="taskCount"></span>tasks</footer>

Wrapping the number in a span will notalter the presentation, but it allows usto find the element in the DOM, andupdate it when required.Now we want to add a function to thetasks-controller.js that counts thenumber of rows in the table and

updates the element appropriately:tasksController = function() {

function errorLogger(errorCode, errorMessage) {

console.log(errorCode +':'+ errorMessage);

}

var taskPage;

var initialised = false;

function taskCountChanged() {

var count = $(taskPage).find( '#tblTaskstbody tr').length;

$('footer').find('#taskCount').text(count);

}

Finally, we want to call this function inthe loadTasks method: loadTasks : function() {

storageEngine.findAll('task', function(tasks) {

$.each(tasks, function(index, task) {

$('#taskRow').tmpl(task ).appendTo( $(taskPage).find( '#tblTasks tbody'));

});

taskCountChanged();

}, errorLogger);

}

And we also need to call it afterdeleting a task – since in that case wedo not call loadTasks:$(taskPage).find('#tblTasks tbody').on('click','.deleteRow',

function(evt) {

storageEngine.delete('task', $(evt.target ).data().taskId,

function() {

$(evt.target).parents('tr').remove();

taskCountChanged();

}, errorLogger);

});

The only thing to note about thisimplementation is that the footer is notpart of the tasks page: therefore wecannot access the footer in the contextof $(taskPage).

Clear TaskNext we want to implement the cleartask functionality. This should beinvoked when the “Clear Task” buttonis clicked, but should also be invokedafter a save.There is a very convenient way toimplement the clear task functionality.Add the following code to the privatesection of tasks-controller.js:function clearTask() {

$(taskPage).find('form').fromObject({});

}

We can simply de-serialize an emptyobject into the form. This will ensurethat all form elements have theircontent cleared, since they will notfind a corresponding value in theobject passed in.Now we can add the following to theinit method of the tasks-controller.jswhere the other event listeners were

registered:$(taskPage).find('#clearTask').click(function(evt) {

evt.preventDefault();

clearTask();

});

We also want to invoke clear tasksafter a save (we added code for thispreviously, but it is worth changing toutilize the new implementation).Change line of code:$(':input').val('');

to the following:clearTask();

Overdue tasksThe next feature we will add isfunctionality to render the backgroundof rows to show tasks that are due inthe next 2 days in orange, and tasks thatare overdue in a light red colour.Before doing so, you may have noticedthat this functionality to highlight rowsno longer works:$(taskPage).find('tbody tr').click(function(evt) {

$(evt.target).closest('td').siblings().andSelf().toggleClass('rowHighlight');

});

The reason for this should now beobvious: we are adding listeners whenthe screen loads, but the tasks have notbeen loaded into the table at this point.We need to change these to be a “live”event listeners using the approachdocumented in the jQuery chapter:$(taskPage).find('#tblTasks tbody').on('click', 'tr',function(evt) {

$(evt.target).closest('td').siblings().andSelf().toggleClass('rowHighlight');

});

Now we are going to add functionalityto render the background of the tasks.This will utilize the following classesdefined in tasks.css:.overdue {

background: #F7DCE5;

}

.warning {

background: #F7F7DC;

}

We have two options for assigning thecorrect class to rows in the table: wecan do it in the template, or we can doit after all rows have been loaded inJavaScript. We will choose the lateroption.In order to implement this functionalityit is necessary to compare dates intasks to the current date. JavaScript has

a set of rudimentary functions fordealing with dates, but it is usuallyadvisable to use a specialized datelibrary if you need to performextensive date manipulation orcalculations. This application willutilize the following library:http://www.datejs.com/

// The JavaScript date objectwas modelled on the Dateclass in Java. It was such adirect copy that it evenincluded the same bugsrelated to Y2K. Thankfullythese have been resolved longago.

Download the latest version, add it tothe scripts folder, and then import it

into the tasks.html page:<script src="scripts/date.js"></script>

Now, refresh the tasks.html page in thebrowser and open the console, you cannow use function calls such as this:> Date.today()

> (2).months().ago()

> (3).days().fromNow();

As you can see, this is a very intuitivedate library, and is far superior to theinbuilt library.We can now add the following functionto tasks-controlller.js immediatelyafter the clearTasks function we justadded:function renderTable() {

$.each($(taskPage).find('#tblTasks tbody tr'),function(idx, row) {

var due =Date.parse($(row).find('[datetime]').text());

if (due.compareTo(Date.today()) < 0) {

$(row).addClass("overdue");

} else if (due.compareTo((2).days().fromNow())<= 0) {

$(row).addClass("warning");

}

});

}

This will iterate through all the rows inthe table and extract their date from theattribute called datetime (you willremember that this conformed to theISO date standard, therefore it can beparsed directly without having tospecify its format).Once the date has been identified itwill be parsed using the date libraryfrom a string to a date. We will thencompare that date to today: if the resultis less than 0 the date is in the past, andwe add the overdue class.If the date is not in the past, we see if itis less than or equal to 2 days from

now. If so we add the warning class.We could have written JavaScript toperform these operations withoutimporting a date library, but our codewould have been less succinct, andopen to bugs. The advantage of using alibrary is that it has undergone testingby everyone who has used it; thereforethe level of quality tends to be high.We now need to invoke this when thetable is loaded:loadTasks : function() {

storageEngine.findAll('task', function(tasks) {

$.each(tasks, function(index, task) {

$('#taskRow').tmpl(task).appendTo($(taskPage).find( '#tblTasks tbody'));

});

taskCountChanged();

renderTable();

}, errorLogger);

}

If you now add tasks that are overdue,

or due within the next 2 days, theyshould be rendered appropriately.

Completing tasksNext we will implement the “Completetask” functionality. If a task iscompleted we want to render the textwith a strike through it. This will beachieved with the following class fromtasks.css:.taskCompleted {

text-decoration: line-through;

}

We also need to store the fact that atask has been completed in the taskitself, therefore we will add a newproperty to a completed task calledcomplete and set this to true when itis completed.The first step in the process is tochange the complete buttons to have aclass we can identify, and make thetask id accessible to them:<script id="taskRow" type="text/x-jQuery-tmpl">

<tr>

<td>${task}</td>

<td><time datetime="${requiredBy}">${requiredBy}</time></td>

<td>${category}</td>

<td>

<nav>

<a href="#" class="editRow" data-task-id="${id}">Edit</a>

<a href="#" class="completeRow" data-task-id="${id}">Complete</a>

<a href="#" class="deleteRow" data-task-id="${id}">Delete</a>

</nav>

</td>

</tr>

</script>

Next, add a listener to these buttons.This will find the task that needs to becompleted, saves it with a completedproperty set to true, and redraw thetable:$(taskPage).find('#tblTasks tbody').on('click','.completeRow', function(evt) {

storageEngine.findById('task',$(evt.target).data().taskId, function(task) {

task.complete = true;

storageEngine.save('task', task, function() {

tasksController.loadTasks();

},errorLogger);

}, errorLogger);

});

We will also make a slight change tothe loadTasks method in tasks-controller.js to ensure incomplete taskshave the complete property set to falsewhen the table loads:loadTasks : function() {

$(taskPage).find('#tblTasks tbody').empty();

storageEngine.findAll('task', function(tasks) {

$.each(tasks, function(index, task) {

if (!task.complete) {

task.complete = false;

}

$('#taskRow').tmpl(task).appendTo($(taskPage).find( '#tblTasks tbody'));

taskCountChanged();

renderTable();

});

}, errorLogger);

}

The next step is to have the templatecheck for completed tasks. If a task iscompleted, the td elements will begiven the class taskCompleted, andthe complete and edit buttons will notbe displayed. This was why weneeded to set the completed propertyon all tasks – the template engine willerror if undefined properties areaccessed:<script id="taskRow" type="text/x-jQuery-tmpl">

<tr>

<td {{if complete ==true}}class="taskCompleted"{{/if}}>${task}</td>

<td {{if complete ==true}}class="taskCompleted"{{/if}}><timedatetime="${requiredBy}">${requiredBy}</time></td>

<td {{if complete ==

true}}class="taskCompleted"{{/if}}>${category}</td>

<td>

<nav>

{{if complete != true}}

<a href="#" class="editRow" data-task-id="${id}">Edit</a>

<a href="#" class="completeRow" data-task-id="${id}">Complete</a>

{{/if}}

<a href="#" class="deleteRow" data-task-id="${id}">Delete</a>

</nav>

</td>

</tr>

</script>

This is the first time we have used aconditional construct within atemplate, and once again, this showsthe advantages of using a templateengine.With this in place, you should be ableto complete a task and have it appear

as follows:

We can still delete a completed task,but we can no longer edit or completethem.

Sorting tasksThe final change we will make is tosort tasks so that the ones due earliestare sorted first.We will again use the date library forparsing and comparing dates, but wewill use the standard sort methodavailable on arrays to perform thesorting.The sort method accepts a comparatoras an argument. A comparator is afunction that can compare any twoelements in an array and determinewhich ranks higher. A comparatorshould return a value less than 1 toindicate the first element is higher, 0 ifthey are equal, or a number greaterthan 1 if the second element rankshigher. Date objects already have acompareTo method that performs thistask.The sort method will compare therelevant items in the array to determine

their relative order. This does notmean comparing all items with oneanother due to the fact it can rely ontransitivity:If A > B and B > C then A > C.We can add sorting with a single linein the loadTasks method:loadTasks : function() {

$(taskPage).find('#tblTasks tbody').empty();

storageEngine.findAll('task', function(tasks) {

tasks.sort(function(o1, o2) {

returnDate.parse(o1.requiredBy).compareTo(Date.parse(o2.requiredBy));

});

$.each(tasks, function(index, task) {

if (!task.complete) {

task.complete = false;

}

$('#taskRow').tmpl(task).appendTo($(taskPage).find('#tblTasks tbody'));

taskCountChanged();

renderTable();

});

}, errorLogger);

}

ConclusionThis completes the basic requirementsfor the tasks web applications. In thenext few chapters we will incorporatefeatures from more advanced HTML5APIs to allow offline storage of theweb application, and the use of files inthe application.

Offline Web ApplicationsWe have now created a webapplication that is capable of storingits content in the browser, but unlike atraditional desktop application, thisapplication is still dependent on anInternet connection to load the HTML,CSS and JavaScript resources.If we are running the Web Serverlocally this is not an issue, sinceaccessing localhost does not rely on anInternet connection, but obviously areal application would be hostedremotely, and it is sometimes desirableto allow the user to continue using theweb application even whendisconnected from the Internet.In this chapter we will writefunctionality to store the applicationresources on the client so that after thefirst time the document is loaded, theclient is no longer dependent on anInternet connection to serve the web

page. This will be achieved throughanother HTML5 specification calledthe Application Cache.The Application Cache specificationallows you to specify a set ofresources that should be stored on theclient. Once these resources arepersisted on the client, the client willnot attempt to access these resourcesfrom the server on future page loads: itwill instead use the versions in theclient side Application Cache.This functionality may sound similar tothe caching functionality that browsershave natively supported for years.Browsers typically cache anyresources that are downloaded, andthen use these versions the next timethey are requested unless they havechanged.This form of caching is not intended tosupport offline web pages however,since this caching functionality still

relies on an Internet connection todetermine whether a resource haschanged. The Application Cachespecification on the other hand isspecifically designed to storeresources offline, and only use theseversions until requested to retrieve anupdate.Before beginning this section, it isworth mentioning that the examples inthis chapter will not use CDN basedscripts: they will assume all theJavaScript resources required areserved from the scripts folder. If youhave been using CDNs to serve thejQuery resources, you may want todownload them instead and add themto the scripts folder so the examplesare the same. This is not a requirementof the application cache (provided theNETWORK property is setappropriately: more on this below),but it allows for a consistent set ofexamples.

In order to implement an ApplicationCache we will begin by creating a filecalled tasks.appcache in the samedirectory as the tasks.html page.The Application Cache will contain 3sections, so begin by adding thefollowing skeleton to the newlycreated file. An empty line mustseparate the sections from one another.CACHE MANIFEST FALLBACK: NETWORK: The first section of the file is wherewe list all the resources that we wishto store offline. The order theresources are listed is not important(please check the paths are correct forthe files you have in your development

environment):CACHE MANIFEST

tasks.html

scripts/date.js

scripts/jquery-2.0.3.js

scripts/jquery-serialization.js

scripts/jquery-tmpl.js

scripts/jquery.validate.js

scripts/tasks-controller.js

scripts/tasks-indexeddb.js

scripts/tasks-webstorage.js

styles/tasks.css

FALLBACK:

NETWORK:

These paths are all relative to theapplication cache file, but absolutepaths can also be used. It is veryimportant that all the paths are correct,

because if even one of the resources isnot available, no files will be added tothe browser appcache, and theapplication will not be availableoffline.This is part of the Application Cachespecification, even though it seemscounter intuitive. It is therefore alsovitally important that if a resource isremoved from the application it isremoved from this manifest.The purpose of the FALLBACKsection is to specify alternativeversions of a file that should be usedwhile offline. For instance, we mayhave an image called online.png that isdisplayed at the top of the screen whenwe are online, but we want to displayan image called offline.png when weare offline. In order to implement this,we would first add offline.png to thelist of cached files in the CACHEMANIFEST section; we would then

add the following to the FALLBACKsection:FALLBACK:

online.png offline.png

We will also find an alternative use ofthis section below.The final section is the networksection. This is a particularlyimportant section, because it specifiesthe network addresses the browsermay access. If we were to enter thefollowing:NETWORK:

/

Then the browser would only be ableto access resources from the server inquestion, it would not be able toaccess any other servers, for instance,Google Analytics, or files served fromCDNs.The most common setting for this

section is as follows:NETWORK:

*

This ensures the web application hasunrestricted access to the Network.The next version of the file will looklike this:CACHE MANIFEST

tasks.html

scripts/date.js

scripts/jquery-2.0.3.js

scripts/jquery-serialization.js

scripts/jquery-tmpl.js

scripts/jquery.validate.js

scripts/tasks-controller.js

scripts/tasks-indexeddb.js

scripts/tasks-webstorage.js

styles/tasks.css

FALLBACK:

NETWORK:

*

We now need to tell the tasks.html fileto download this manifest when it isloaded, this in turn will cause thebrowser to download all the files inthe manifest whether they are neededimmediately or not. In order to do this,we add a new attribute to the html tagin tasks.html:<html lang="en" manifest="tasks.appcache">

With this added, request the tasks.htmlpage from the web server. You shouldnot notice anything different, since youhave connectivity to the web server. Ifhowever you navigate to the followingURL in Chrome:chrome://appcache-internals/

You will see that the application hasbeen cached; along with a summary ofthe application size, and the date the

cache was created, last updated andlast accessed:

You can select to view the entries inthis cache; this will show you all thefiles that have been cached offline.

If you have the console open while

loading the page you should also see itdownloading all the resources. This isa good way to troubleshoot if theapplication cache is failing to cacheresources, since it will tell you theresource that is failing:

If you are using localhost for the webserver domain you will need toshutdown the web server to simulateoffline mode, since even withoutnetwork connectivity your browser canaccess the localhost domain.Unfortunately, if you shutdown the webserver and attempt to load theapplication you will discover thatthere is a problem loading theapplication:

When we attempt to conditionally loadfiles with the jQuery method$.getScript it is appending the currenttimestamp to the request, this is to stopthe browser caching the script. Thismeans that the browser does notrealise that it has a cached version ofthis file, and therefore fails to load.We could resolve this issue by askingjQuery to suppress this behaviour, butwe will instead solve the problem withthe features available in theApplication Cache API.It may seem that you should be able toresolve this with the use of a wildcardin the FALLBACK section:FALLBACK:

scripts/tasks-webstorage.js* scripts/tasks-webstorage.js

scripts/tasks-indexeddb.js* scripts/tasks-indexeddb.js

Unfortunately the fallback section does

not allow the use of wildcards.Fortunately, the first URL on each linein the FALLBACK does still representa pattern: any URL that starts with thetext in the URL will match the line inthe FALLBACK. Therefore you cansimply add the following:FALLBACK:

scripts/tasks-webstorage.js scripts/tasks-webstorage.js

scripts/tasks-indexeddb.js scripts/tasks-indexeddb.js

This will then state that any URL thatstarts with:scripts/tasks-webstorage.js

for example:scripts/tasks-indexeddb.js?_=1379463013652

should be replaced with the resource:scripts/tasks-indexeddb.js

(which has been stored offline).With this in place you should be ableto reload the tasks.html page, which in

turn will ensure the revised version ofthe manifest will be loaded. Youshould then be able to shutdown theweb server, and hit reload, and havethe page display. Even if you restartChrome with the server shutdown, youcan still load the tasks.html page.The final subject we need to addresswith the Application Cache is how doyou reload resources when they arechanged? The browser will use thecached versions of files whether it isonline or offline, therefore changingany of the resources in the applicationwill not be reflected on the client, evenif the client has access to the server.The browser will download freshcopies of resources only when themanifest file itself changes. Thissounds problematic, since you may nothave anything you wish to change in themanifest file, yet still wish to load newversions of the resources. The solution

to this is to add a comment in themanifest file, and change this commentevery time the resources change, forexample:# version 1

Any line starting with a # is acomment, however changes tocomments are sufficient to force theapplication cache to refresh. We cantherefore continue incrementing thisversion number each time we want thecache to reload the resources.If you save this change and reload thepage, Chrome should inform you thatthe cache has an “last update time” ofnow, even though the “creation time” isin the past:

If you have the console open you will

also see the resources beingdownloaded.Many features of the ApplicationCache API seem counter-intuitive. Afurther aspect that may surprise youabout the update process is that theuser will not see any updatedresources the first time they load thepage. The way the application cacheworks is to first present the user withthe web page (using the cached versionof resources), and then begin updatingand storing the new version of theapplication in the app cache. It is nottherefore until the second time the userloads the page that they will see anyupdated content.A side effect of this is that the veryfirst time the tasks.html page is loadedthe browser will access all resourcestwice. The first time will be to load allthe resources for display to the user;the second time will be to download

them for the cache. If this is a problem, it is possible tolisten for application cache events inorder to be notified of cases where thebrowser discovers it needs todownload a new version of theapplication:window.applicationCache.addEventListener('downloading',function(e) {});

In order to add a listener that fires aseach resource is downloaded you canadd the following:window.applicationCache.addEventListener('progress',function(e) {});

Finally, to register an event listener tobe notified when all resources havefinished updating add the following:window.applicationCache.addEventListener(updateready,function(e) {});

In this function it would be possible tocall the following if you want the clientto have immediate access to the

revised application:window.location.reload();

The Application Cache can be veryannoying during the developmentphase, since resources do not refreshon the client unless the manifest ischanged, and even then, not until thesecond time the page is requested. It istherefore recommended that youremove the reference to the manifest inthe html tag for the remainder of theexercises in this book.

Working with FilesWhen writing desktop applications, theability to read and write files from theuser's file-system is taken for granted.Once a client application is installedon a computer, it largely has fullaccess to all the files the user canaccess.Web applications running inside a webbrowser are naturally restricted in howthey can access the users file-system.Users would naturally be very nervousif any web site could read files on theirfile-system.Since its early days, HTML hassupported a file form element thatallowed the user to select a file fromtheir file-system, and post its contentsto the server. Even this was subject totight restrictions: it was not possible tointeract with this field via JavaScriptin any way, including accessing thecontents of a file that the user had

selected.HTML5 includes several APIs forinteracting with the users file-system.The most ambitious of these is the FileSystem and File Writer APIs. Thesespecifications have been proposed byGoogle and are currently onlysupported in Chrome. They allow aweb application to read files, createdirectories and write files in a virtualfile-system.The word “virtual” is the key here.Each origin will be given its ownvirtual file-system that it has fullcontrol over, but this will bepartitioned from both the users realfile-system, and the file-system of anypages loaded from any other origin. Inaddition, depending on how the API isimplemented, the virtual file-systemmay not exist as a set of files anddirectories on the users file-system (itcould be implemented as a binary

database).As a result of the other storage optionswe have examined in earlier chapters,these APIs are of limited use, and youmay be advised to continue using theother storage options we havediscussed.The other major file related API is theFileReader API. This is a simpler, butin many ways more interesting API. Itrelies on the HTML file form field, butonce a file is selected it provides thedeveloper access to the file contents inJavaScript. This means it is possible toperform local parsing of a file withoutever submitting it to the web server.This has several advantages:1. The user can load files when theyare offline (provided the webapplication has been made to workoffline using the other techniquesoutlined in this book).

2. The contents of a file could besubmitted to the server using an AJAXcall rather than a server post.3. The client could choose to send asubset of a file to the server rather thanthe whole file, therefore reducingbandwidth requirements.All major web browsers now supportthe FileReader API.In order to demonstrate the FileReaderAPI, we are going to allow users toimport a set of tasks from a commaseparated (CSV) file. The CSV filewill contain three columns:1. Task description.2. Date required by.3. Task category.The CSV file will contain a single rowheader, and all other lines will containtasks.The following is an example CSV file

(this is available in the chapter13 zipfile from the book’s web site):Task,Required By,Category

Prepare slide show,2013-11-20,Work

Attend Product Lanuch,2013-11-21,Work

As a first step, we will provide animport option on the main screen. Addthe following code immediately beforethe closing main tag in tasks.html:<section id="csvImport">

<div>

<label for="task">Import tasks from a CSVfile</label>

<input type="file" id="importFile"name="importFile"/>

</div>

</section>

We will next add a function to tasks-controller.js that will listen for achange event on the file input field, andthen read the file contents. Add this inthe private section of the tasks-controller.js file:

function loadFromCSV(event) {

var reader = new FileReader();

reader.onload = function(evt) {

console.log(evt.target.result);

};

reader.onerror = function(evt) {

errorLogger('cannot_read_file', 'The file specifiedcannot be read');

};

reader.readAsText(event.target.files[0]);

}

This is going to receive an event whenthe file is selected. The first thing thisfunction will do is create a newFileReader object. The FileReader isasked to read the file specified, andthen makes the contents availableasynchronously, so we also need toadd listeners for success and failure.The onload listener will be called withthe file contents; the onerror will becalled after any failure.It is possible for the user to select

multiple files at the same time;therefore the target of the event willrefer to an array of files. In our casewe will ignore the fact this is an arrayand simply choose the first file:event.target.files[0]

Now add the following code in the initmethod of tasks-controller.js to listenfor the user selecting a file:$('#importFile').change(loadFromCSV);

Once the listener has been added, tryloading the file using the file chooser.(The code will simply log the contentsof the file for now).If you examine the target of the event inthe debugger you will see it makesavailable information about the file,including its name, type and modifieddate:

Determining the type of file that hasbeen loaded can be important, sincethe FileReader makes available anumber of different mechanisms forreading different types of file. In ourcase we have used readAsText, whichmakes the file contents available as aJavaScript string, but the FileReaderalso supports the following:• readAsBinaryString: The filecontents is made available as a string,but each byte is represented by anumber. If the data is textual this willbe identical to readAsText.• readAsDataURL: The file contentsis made available as an encoded URL.If we load a text document, the contentswill be encoded in Base 64 encoding.• readAsArrayBuffer: This can beused if you wish to access a specificpart of a file.Now that we have an event handler thatis capable of extracting the contents of

the file as a string, the next step is tobreak this down into an array of lines,this will allow us to process the linesone at a time. We use the split methodsupported by JavaScript strings to splitthe string each time it encounters a newline character. This returns an array ofstrings.function loadFromCSV(event) {

var reader = new FileReader();

reader.onload = function(evt) {

var contents = evt.target.result;

var lines = contents.split('\n');

};

reader.onerror = function(evt) {

errorLogger('cannot_read_file', 'The file specifiedcannot be read');

};

reader.readAsText(event.target.files[0]);

}

Once we have an array of lines weneed to break each line down into a setof tokens, each of which we know is

separated by a comma. This may soundrelatively simple, for instance thefollowing implementation would meetmost of our needs:line.split(',')

Unfortunately, CSV files can be morecomplex than the simple example wehave used. For instance, individualtokens may contain commas; thereforea CSV file can wrap a token insidedouble quotes to ensure that thesecommas are treated literally rather thanas token separators.Whenever you encounter a problemthat looks common (such as parsing aline in a CSV file) it is worth lookingfor libraries that have already beenwritten. The authors of these librarieswill have thought about most issuesthat may arise, and any library with alarge number of users is likely to havebeen tested in a large number ofscenarios, and therefore should prove

more stable.In this scenario we will use thislibrary:https://code.google.com/p/jquery-csv/Download the latest version and add itto the scripts folder of the application.I am using version 0.71.Next, remember to include the importin the page at the end of the headsection of tasks.htmk, and alsoremember to add a reference to the filein tasks.appcache, since we want thislibrary to be available offline.<script src="scripts/jquery.csv-0.71.js"></script>

You can check you have installed thescript correctly by executing thefollowing call in the console andchecking an object is returned:$.csv

We can now write code to parse andcreate tasks:function loadTask(csvTask) {

var tokens = $.csv.toArray(csvTask);

if (tokens.length == 3) {

var task = {};

task.task = tokens[0];

task.requiredBy = tokens[1];

task.category = tokens[2];

return task;

}

return null;

}

function loadFromCSV(event) {

var reader = new FileReader();

reader.onload = function(evt) {

var contents = evt.target.result;

var lines = contents.split('\n');

var tasks = [];

$.each(lines, function(indx, val) {

if (indx >= 1 && val) {

var task = loadTask(val);

if (task) {

tasks.push(task);

}

}

});

};

reader.onerror = function(evt) {

errorLogger('cannot_read_file', 'The file specifiedcannot be read');

};

reader.readAsText(event.target.files[0]);

}

After we read each line from the CSV,we send it to another function calledloadTask which tokenizes it using theCSV library, and constructs a task.Notice also that we skip the first linein the file (since it is the header line),along with any empty lines by using thefollowing code:if (indx >= 1 && val) {

We now have an array of tasks that wewish to save. At this point it may beworth adding another method to our

storage engines that performs asaveAll operation. This would meanwe can leverage transaction support inthe underlying storage API (ifavailable) to make sure either all thetasks are persisted or none are. ThesaveAll method will return all theobjects saved in the transaction.The following is the saveAllimplementation in tasks-webstorage.js(it does not provide transactionsupport):saveAll : function(type, objs, successCallback,errorCallback) {

if (!initialized) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

} else if (!initializedTables[type]) {

errorCallback('table_not_initialized', 'The table'+type+' has not been initialized');

}

var storageItem = getStorageObject(type);

$.each(objs, function(indx, obj) {

if (!obj.id) {

obj.id = $.now();

}

storageItem[obj.id] = obj;

localStorage.setItem(type,JSON.stringify(storageItem));

});

successCallback(objs);

}

And the following is theimplementation in tasks-indexeddb.js:saveAll : function(type, objs, successCallback,errorCallback) {

if (!database) {

errorCallback('storage_api_not_initialized', 'Thestorage engine has not been initialized');

}

var tx = database.transaction([type], "readwrite");

tx.oncomplete = function(event) {

successCallback(objs);

};

tx.onerror = function(event) {

errorCallback('transaction_error', 'It is notpossible to store the object');

};

var objectStore = tx.objectStore(type);

$.each(objs, function(indx, obj) {

if (!obj.id) {

delete obj.id ;

} else {

obj.id = parseInt(obj.id)

}

var request = objectStore.put(obj);

request.onsuccess = function(event) {

obj.id = event.target.result

}

request.onerror = function(event) {

errorCallback('object_not_stored', 'It is notpossible to store the object');

};

});

}

Notice that we only create onetransaction and then add multiple

requests to it: one for each task. It isnot until all these requests completethat the transaction is consideredcomplete, and the client is notified ofthe success.Finally, lets add the call to saveAll inour code:function loadFromCSV(event) {

var reader = new FileReader();

reader.onload = function(evt) {

var contents = evt.target.result;

var lines = contents.split('\n');

var tasks = [];

$.each(lines, function(indx, val) {

if (indx >= 1 && val) {

var task = loadTask(val);

if (task) {

tasks.push(task);

}

}

});

storageEngine.saveAll('task', tasks,

function() {

tasksController.loadTasks();

},errorLogger);

};

reader.onerror = function(evt) {

errorLogger('cannot_read_file', 'The file specifiedcannot be read');

};

reader.readAsText(event.target.files[0]);

}

With this in place, you should be ableto load a CSV file and have thecontents immediately reflected in thetasks table. In addition; it is alsopossible to use this functionalitywithout connectivity to a web server,since all the processing is occurringentirely on the client.

Web WorkersEarlier in this book we discussed howJavaScript utilizes a single thread toperform all processing, and that this isthe same thread the browser uses torender the web page. Although thereare rudimentary ways of controllingwhen a piece of code executes usingsetTimeout, there is no way to executeJavaScript on a seperate thread, or inmultiple threads concurrently.Most modern computers, and evenmost smart phones, are capable ofexecuting multiple threads concurrentlysince most devices now containmultiple processors or multiple cores.In addition, most software engineersexpect multithreading libraries to bebuilt into modern languages.There are very good reasons whyJavaScript is limited to a single thread,for instance, to prevent multiplethreads attempted to update the same

portion of the Document Object Modelsimultaneously. There is however a lotof other computation where therewould be no issue with multiplethreads executing simultaneously.As an example, consider the CSV filethat was processed in the previouschapter. The process of converting aJavaScript string into a set of objectsis a self-contained operation, and hasno bearing on the DOM (at least untilwe refreshed the table at the end of theprocessing). It should therefore betheoretically possible to execute thisprocessing on a separate thread, andonly revert back to the main browserthread when we need to update theHTML table.HTML5 contains an API called WebWorkers that allow some degree ofmulti-threading in HTML applications.This chapter will introduce the WebWorker API, and examine some use-

cases where it may be appropriate.A Web Worker is a block of code in itsown JavaScript file. The Web Workertypically listens for messages to beposted to it from the main browserthread. When it receives messages, itperforms whatever computation isrequired of it, but the big difference isthat browsers will execute thiscomputation on a separate thread, andtherefore if the underlying hardwaresupports it, this processing can happenconcurrently with processing on themain browser thread.When the Web Worker has finished itsprocessing it can post a message backto the main browser thread, which willperform whatever it needs to with thisresult, such as updating the DOM.Before looking at what Web Workerscan do, we will first look at theirrestrictions. Web Workers do not haveaccess to any of the following objects:

• The window object• The Document Object Model• The localstorage object• The document objectWeb Workers can however invokeAJAX calls, and they do have accessto all the JavaScript features weexamined in the JavaScript section ofthis book.As a result of their restrictions, theuse-cases for Web Workers is limited.There are however a number of caseswhere they are relevant. If we envisagea word processing application inside aweb browser, there are a number ofactivities we may want to perform on aregular basis in the background, thesemight include: 1. Checking which words in thedocument are misspelt.

2. Checking the grammar of thedocument against a set of rules.3. Checking where the page breaksshould be placed in the document.4. Collecting statistics for the numberof words and pages in the document.All of the processing associated withthese activities could be done in a WebWorker. The Web Worker could beposted the word processor documenton a regular basis, it could performthese potentially intensive activities,and then the results could be postedback to the main thread so that theDOM could be updated to reflect theresults.If all these activities were performedon the main browser thread it is likelythat the user would experience lags anddelays every time these activities wereperformed, and as the documentincreased in size it is likely that theselags would become worse.

We are going to implement a WebWorker that is posted a JavaScriptstring representing a CSV version of aset of tasks. It is then going to processthese and post back an array of tasks.The first step in this process is thecreation of a new JavaScript file forthe Web Worker: the code cannot existin the same JavaScript file as any othercode, and each Web Worker must haveits own JavaScript file. Create a newfile in the scripts folder called tasks-csvparser.js.The following is the basic structure ofour Web Worker:self.addEventListener('message', function(msg) {

var data = msg.data;

self.postMessage(null);

}, false);

It uses a reference to the self object inorder to add an event listener thatlistens for messages. When a message

is received, the function passed in thesecond argument will be invoked(along with the message). The thirdparameter specifies whether the eventneeds to be captured or not, if in doubtuse false.Let's now move the relevant code fromtasks-controller.js to the Web Worker:self.addEventListener('message', function(msg) {

var data = msg.data;

var lines = data.split('\n');

var tasks = [];

jQuery.each(lines, function(indx, val) {

if (indx >= 1 && val) {

var task = loadTask(val);

if (task) {

tasks.push(task);

}

}

});

self.postMessage(tasks);

}, false);

function loadTask(csvTask) {

var tokens = $.csv.toArray(csvTask);

if (tokens.length == 3) {

var task = {};

task.task = tokens[0];

task.requiredBy = tokens[1];

task.category = tokens[2];

return task;

}

return null;

}

Unfortunately we immediately have aproblem: there are two references inthis code to the jQuery function “$”.This object is registered on thewindow object, and therefore is notaccessible from the Web Worker.The first of these (the $.each) caneasily be replaced with a for loop:for (var indx = 0; indx < lines.length; indx++) {

var val = lines[indx];

if (indx >= 1 && val) {

var task = loadTask(val);

if (task) {

tasks.push(task);

}

}

};

Unfortunately we are stuck when itcomes to the use of the csv function:$.csv.toArray(csvTask);

It is not even possible to pass thejQuery object into the Web Worker.Ultimately we would have no choicebut to find a different library forparsing CSV files.Although this would not be a problem,it is not the subject of this chapter, sowe will simply replace that line withthe simplified code for splitting theline each time a comma is encountered.As discussed above, there are manyreal world issues with this code:

function loadTask(csvTask) {

var tokens = csvTask.split(',');

if (tokens.length == 3) {

var task = {};

task.task = tokens[0];

task.requiredBy = tokens[1];

task.category = tokens[2];

return task;

}

return null;

}

The JavaScript file containing the WebWorker does not need to be explicitlyimported in tasks.html. Because wewant the worker to be available offlinehowever, we do need to add it totasks.appcache. This will ensure theWeb Worker is stored on the clientrather than read from the server ondemand when the Web Worker iscreated.You will notice that when the Web

Worker finishes it posts back an arrayof task objects to a listener. Now weneed to write the code that initializesthe Web Worker, posts a message to it,and listens for a message in response.This is the code that will execute onthe main browser thread.In order to instantiate a Web Workerwe use the following code:var worker = new Worker('scripts/tasks-csvparser.js');

Note that this contains the URL of theJavaScript file that will constitute theWeb Worker.Once the Web Worker is created weneed to add an event listener to it sothat we can hear when it postsmessages back to the main browserthread. In our case, this event listenerwill receive an array of tasks, which itwill then save:worker.addEventListener('message', function(e) {

var tasks = e.data;

storageEngine.saveAll('task', tasks, function() {

tasksController.loadTasks();

},errorLogger);

}, false);

Finally we need to post a message tothe Web Worker:worker.postMessage(contents);

If we put all of that together, theloadFromCSV function should nowlook like this:function loadFromCSV(event) {

var reader = new FileReader();

reader.onload = function(evt) {

var contents = evt.target.result;

var worker = new Worker('scripts/tasks-csvparser.js');

worker.addEventListener('message', function(e) {

var tasks = e.data;

storageEngine.saveAll('task', tasks, function() {

tasksController.loadTasks();

},errorLogger);

}, false);

worker.postMessage(contents);

};

reader.onerror = function(evt) {

errorLogger('cannot_read_file', 'The file specifiedcannot be read');

};

reader.readAsText(event.target.files[0]);

}

If you execute the load from CSVfunctionality now you will not noticeanything different (unless you loadedan enormous file). Despite that, theparsing of the CSV file is nowoccurring on a background threadrather than the main browser thread.The Web Worker will remain openeven after it has processed ourmessage, and would accept additionalmessages if we were to send them. TheWeb Worker can close itself with acall to:self.close()

Or in our case the Web Worker will

close when the loadFromCSV functionends, and the worker variable falls outof scope.

Accessing browser functionalityThe only main browser object a WebWorker object has access to is thenavigator object. This object can beused to obtain information about thebrowser, such as the browser vendorand version.Due to the fact Web Workers areexecuting in a different environmentfrom the main browser thread they donot have access to the objects orfunctions created by any importedscripts. Web Workers can howeverload additional JavaScript files if theyrequire. This can be done with thefollowing function call:importScripts('foo.js');

Shared vs Dedicated Web WorkersThe Web Workers we have been usingup until this point are called DedicatedWeb Workers. The only script file thatis allowed to post messages to the WebWorker is the one that loaded it. AShared Web Worker on the other handcan be interacted with from any scriptthat is loaded from the same origin.This may save on operating systemresources if you need to access a webworker from multiple script files.Shared Web Workers are not supportedby all browsers that currently supportWeb Workers, therefore it is worthchecking browser support beforeimplementing Shared Web Workers.Shared Web Workers are instantiatedin a similar way to dedicated WebWorkers, except the class name isdifferent:var worker = new SharedWorker('scripts/tasks-csvparser.js');

The client interaction with Shared WebWorkers is also similar to DedicatedWeb Workers, except there is anadditional abstraction of a port. Eventlisteners are added to ports:worker.port.addEventListener

and messages are posted to portsworker.port.postMessage

In addition, a port must be explicitlyopened before any messages areposted to it:worker.port.start();

Finally, the implementation of the WebWorker itself needs to take into accountthe different ports. The following is askeleton for the implementation:self.addEventListener("connect", function (e) {

var port = e.ports[0];

port.addEventListener("message", function (e) {

var data = e.data;

port.postMessage(data);

}, false);

port.start();

}, false);

Notice that the first event listener weare creating allows generalconnections to the Web Worker. Whena connection is received for a newport, we then add a separate eventlistener for this port, and start the port.The idea behind Shared Web Workersis that they expose a service to yourapplication, just as an applicationserver might expose a service.Multiple clients can then interact withthis service, and their messages willbe kept separate.

ConclusionWeb Workers offer interestingpotentials to Web Applications: the keyis finding the appropriate use-cases.The most viable use-cases arescenarios where the foreground threadcan continue to be utilized whileadditional code is executed on thebackground thread. The foregroundthread may be doing something astrivial as updating a progress bar forthe user: but the benefit of WebWorkers is that they will not preventthis happening since they are nothogging the foreground thread.The other main use-case for WebWorkers is algorithms that cannaturally be multi-threaded. In thesecases we can spawn multiple WebWorkers, and have each of themcomplete a portion of the algorithm. Ondevices with multiple cores orprocessors this is likely to lead to

improved performance. For instance,on a device with 4 cores, a singlethread can use at most 25% of theprocessing power. If 4 Web Workerswere spawned we could theoreticallyuse 100% of the processing power, andcomplete the operation 4 times quicker.

AJAXThe web application we have writtenin this book is largely independent ofits web server. The web server isresponsible for serving resources, andproviding an origin for APIs thatimplement single-origin policies, butbeyond that it is not playing anymeaningful role, and in fact, once theapplication is loaded it can existindependent of the web server.Most real world web applicationsneed to send or receive data to a webserver at some point in their lifecycles.For instance, users may wish tosynchronize their task list in ourapplication between multiple devices.There are two ways a web applicationcan interact with a web server. Themost common approach is to performHTTP POST or GET to the server, andload the HTTP response into thebrowser.

An HTTP GET request is the mostcommon type of request, and occurswhen a page is requested from thebrowser address bar, or the user clickson a hyperlink. A GET requestspecifies a specific resource, but it canalso pass data to the server usingname/value pairs encoded in the URL,for instance:http://localhost/viewprofile?username=daneThis GET request contains a singleparameter (username); which has beenset to a value (“dane”).In order to send larger quantities ofdata to the server POST requests aregenerally used. A POST requestserializes the data in an HTTP form asa set of key/value pairs. The name ofeach input field becomes a key, whilethe current value of the input fieldbecomes the value.A side effect of traditional HTTP GET

and POST requests is that a new webpage is loaded as a result (the HTTPresponse). Even if the URL does notchange, and there is only a change to aminor part of the page, there will be alag as the HTTP request is sent and theresponse is received and rendered.A second limitation of traditionalHTTP GET and POST requests is thatthey are synchronous. It is not possibleto continue using the web applicationwhile the request is in progress: theuser must wait for the response to bereceived and updated in the browser.If you consider the web application wehave developed, a traditional web sitewould cause a page refresh when theuser selects to edit a task. A GETrequest would be sent to the server,perhaps:http://localhost/tasks.html?edit=122And the response would contain thetasks.html page, with the edit section

populated. To the user it would looklike all the page content disappearedand then reappeared a second or twolater.The alternative approach is AJAX(Asynchronous JavaScript and XML).AJAX started life as an approachrather than a standard. In 1998Microsoft implemented a componentcalled XMLHTTP. This allowedcontent to be dynamically requestedfrom the server and incorporated intothe current page without a page refresh.This functionality was later adopted byother web browsers as theXMLHttpRequest object. TheXMLHttpRequest is currentlyundergoing the standards process andis considered part of HTML5.The XMLHttpRequest object allows aweb page to send HTTP POST andGET requests to the server, andreceive data in response, but without

refreshing the entire web page. Forinstance, the request may return afragment of the page that is thendynamically added to the DOM.It is worth examing the key aspects ofAJAX:• Asynchonous: AJAX requests areasynchronous because the mainbrowser thread does not block whilethe request is in flight. Responses torequests are handled with callbacks.This means the user does not need tobe aware that a request is in flight, andthey can continue using the webapplication as though nothing washappening.• JavaScript: The requests areperformed using JavaScript objects,and the response is made available asa JavaScript object.• XML: Originally XMLHttpRequestutilized XML as the data exchangeformat. In fact, XMLHttpRequest

allows any data format to be used, andis now commonly used with JSONrather than XML. It is also common toreturn HTML from an AJAX call,therefore allowing it to be inserteddirectly into the DOM.

// In fact, XMLHttpRequest isnot dependent on HTTPeither; it is supported withother protocols such as FTP.In many respectsXMLHttpRequest is the worstnamed object in the history ofJavaScript.

Essentially AJAX is a mechanism forasynchronously sending and/orreceiving data from a web server usingJavaScript without a page refresh.It is possible to perform AJAX calls

using the inbuilt JavaScript object,however jQuery provides an AJAXwrapper that provides a moreconvenient mechanism for performingAJAX calls.In order to try out some AJAXexamples, we will make our serverreturn static JSON when a particularURL is requested.Create a new directory in the directorycontaining tasks.html called “server”.Add a file to this called tasks.json, andadd the following content:[{"id":100,"task":"first task","requiredBy":"2013-09-03","category":"Personal"},

{"id":101,"task":"second task","requiredBy":"2013-10-03","category":"Work"},

{"id":102,"task":"third task","requiredBy":"2013-09-05","category":"Work"},

{"id":103,"task":"last task","requiredBy":"2013-09-08","category":"Personal"}]

This JSON contains an array, which inturn contains 4 task objects. Each of

these task objects have the sameproperties as those created by the webapplication.In order to request this using AJAX,first browse to the tasks.html page.AJAX calls can only be made to thesame server name and port as the pagethat has been loaded in the browser:this is known as the same-originpolicy. There are ways around thesame-origin policy if necessary, butthese tend to rely on hacks: JSONP isthe most prominent approach for this ifyou are interested.Next open up the console, and type thefollowing:$.ajax({

type : "GET",

dataType: "json",

url : "/server/tasks.json",

cache : false,

success : function(data) {

console.log(data);

}

});

This request is taking advantage of thejQuery static function $.ajax. Althoughthis is relatively simple, there is quitea lot here that needs explaining:• The request is an HTTP GET request:this is the default so could have beenomitted.• We specify that the data type returnedwill be json. This is used by jQuery todetermine how to parse the result.jQuery does a good job guessing this ifit is omitted, so it is not generallynecessary to specify it. Other acceptedvalues are xml, script, or html.• Next we specify the URL of theresource we are accessing: this can bean absolute URL as shown here or arelative URL. This does not specify thehost and port of the server, since thesingle-origin policy specifies that this

must be the host and port of thedocument loaded into the browser.• We indicate that we do not want thebrowser to cache the result. jQuerywill ensure the resource is not cachedby appending the current timestamp tothe request, exactly as we saw earlierwhen dynamically loading JavaScriptscripts. This is a useful feature, since itis generally not desirable to cacherequests for data.• A callback is provided for successscenarios. This will be calledasynchronously when the HTTPresponse is received, and passed thedata received from the request.jQuery offers a set of shorthandmethods that reduce the code requiredstill further. We have already comeacross these for requesting JavaScriptscripts from the server. For instance,the example above could be written asfollows:

$.getJSON( "/server/tasks.json", function( data ) {

console.log(data);

});

Due to the fact we are using the JSONdata format, the data object passed tothe callback function will be aJavaScript object, automatically de-serialized from the data received. Inthis case the object is an arraycontaining four task objects. There istherefore no need to transform theresult into a format applicable to ourapplication.Before continuing, it is worth notingthat as of jQuery 1.5 there is a betterway to register callbacks using atechnique called “promises”.The call to $.ajax actuallysynchronously returns a type of objectcalled a “promise”. Any asynchronous(or potentially asynchronous) API canutilize jQuery promises, and they arewidely used both within jQuery and

beyond.If you inspect this object in thedebugger it looks like this:

A promise has a lifecycle. At any pointin time it may be in one of three states:“unfulfilled”, “fulfilled” or “failed”.The promise may only move from“unfulfilled” to “fulfilled”, or“unfulfilled” to “failed”. Once apromise has been “fulfilled” or“failed”, its value cannot not bechanged.The following code shows the sameexample written to work with

promises.promise = $.ajax({

type : "GET",

url : "/server/tasks.json",

cache : false

});

promise.done(function(data) {

console.log(data);

});

promise.fail(function() {

console.log('A failure occurred');

});

When the promise is initially created ithas a state of “unfulfilled”. Once theresponse is successfully received, thepromise is set to “fulfilled”, and therelevant callback (“done”) is invoked.If an error occurred, the promisedwould be set to the state of “failed”,and the relevant callback would beinvoked (“fail”).There are several advantages to using

promises over traditional callbacks,both in this AJAX example, and inyour own libraries. The first is that itis possible to add multiple success orfailure callbacks:promise = $.ajax({

type : "GET",

url : "/server/tasks.json",

cache : false

});

promise.done(function(data) {

console.log(data);

});

promise.done(function(data) {

console.log('Also do this');

});

promise.fail(function() {

console.log('A failure occurred');

});

Secondly, even after the AJAX call hasfinished, you can still call done andfail to register callbacks, and these

will be executed immediately. Thismay not sound useful, but consider acase where we do not know if a callwill be synchronous or asynchronous.This may happen in cases where weare caching data on the client: if thedata is cached it will be availablesynchronously, otherwise it will beavailable asynchronously. This meansthat when we add a callback, the resultmay be available immediately, and thepromise will actually have beenfulfilled when we register ourcallback. An example of this will beprovided below.The third major benefit of promises isthat it is possible to delay a callbackuntil multiple promises havecompleted. This may be useful if youneed to perform multiple AJAX calls,aggregate the data, and update theDOM:promise1 = $.ajax({

url : "/server/tasks.json",

});

promise2= $.ajax({

url : "/server/tasks.json",

});

$.when(promise1, promise2).done(function(data1,data2) {

console.log(data1[0]);

console.log(data2[0]);

console.log("Both requests have completed");

});

promise.fail(function() {

console.log('A failure occurred');

});

The great news about promises is thatyou can use them yourself in your owncode APIs. Let's consider a functionthat performs caching scenariodescribed above:cachedTasks = function() {

var tasks = null;

return {

getTasks : function() {

var deferred = $.Deferred();

if (tasks) {

deferred.resolve(tasks);

return deferred.promise();

} else {

var promise1 = $.ajax({

url : "/server/tasks.json",

});

promise1.done(function(data) {

tasks = data;

setTimeout(function(){deferred.resolve(tasks)}, 5000);

})

return deferred.promise();

}

}

}

}();

This function is using a closure to holdthe cached version of the tasks in avariable called tasks. If this is not

null, then the tasks have already beencached, and are available for clients. Iftasks is null an AJAX call is requiredto retrieve the tasks: this will bothpopulate the cache and return the tasks.You can see that in either case apromise is being synchronouslyreturned from an instance of$.Deferred() to the client. You can alsosee that in both cases, this object is setto resolved when the result isavailable for the client. This callautomatically moves the promise intothe “fulfilled” state, and ensures anycallbacks registered with done areinvoked.You will also see that this promise isrelying on the promise returned fromthe $.ajax call in the case where theserver is invoked. To help you see theresult easier, this code also has addeda 5 second delay in cases where weare performing an AJAX call.

In order to get the tasks, we invoke thegetTasks method on this module. Justas with the AJAX calls, we add acallback to the promise returned bygetTasks:promise = cachedTasks.getTasks();

promise.done(function(data) {

console.log('I have finished')

});

If you execute this you should see theconsole print out “I have finished”after roughly 5 seconds.Now, run the exact same code again.You should see “I have finished”printed immediately to the console,since this will use the cached versionof the tasks, and therefore the resultwill be available as soon as thecallback is registered with the donemethod.If you trace the code through you willsee that the promise is actually already

fulfilled when we call the done methodto add our callback, and therefore ourcallback is executed immediately. Infact, even after the callback isexecuted, it is possible to add a secondcallback to the promise:promise.done(function(data) {

console.log('I have finished again')

});

This will execute immediately, sincethe promise is already fulfilled.The use of promises adds an extradimension to callback-basedprogramming. When writingasynchronously libraries from scratchit is highly recommended to considerbasing them on promises.We will now return to AJAX. So farwe have examined AJAX GETrequests. It is also possible to performHTTP POSTs with AJAX. The mostcommon use of this is to POST thecontents of a form to a server, but

POST is flexible enough to allow anydata structure to be posted.It is often more convenient to poststructured data rather than raw formdata. This is because the servercomponents will often be capable ofde-serializing structured data (such asJSON or XML) in to a rich hierarchyof objects, whereas form data consistsof name/value pairs.The following is an example of afunction that sends a task object to theserver, and returns a promise to thecaller:function sendTask(task) {

return $.ajax({

type : "POST",

url : "/submittask",

contentType : "application/json",

data : JSON.stringify(task)

})

}

You will notice that we have set thecontent type to application/json. Thedefault content type is application/x-www-form-urlencoded, which is theappropriate content type for an HTMLform submission.It is actually possible to simplify thiscode significantly with one of jQuery’sshorthand methods:return $.post( "/submittask", task );

jQuery will infer the appropriateoptions, and implicitly stringify thetask object provided.There are a number of other optionsthat can be provided when using the$.ajax() method. Most of these are notrequired in most scenarios, but thefollowing are worth knowing about:• async: AJAX calls do not have to beasynchronous (despite the “A” inAJAX). It is possible to performsynchronous AJAX calls by setting

async to false. This is notrecommended without a very goodreason however, since the mainbrowser thread will block until theresponse is received.• beforeSend: This is a pre-requestcallback that allows you to modify therequest before it is sent, for instance,adding specific headers to the request.• timeout: Sets the timeout inmilliseconds for AJAX calls. Thisensures that calls that do not return in areasonable amount of time willgenerate an error to the error callback.

Server Sent Events and WebSocketsAJAX has been an enormouslyimportant technique in allowing thecreation of rich and dynamic webapplications. It is worth pausing toconsider however that AJAX is stillusing the same basic underlyingcommunication protocol that has beenused since the beginning of the WorldWide Web: the client (the webbrowser) sends an HTTP request to theserver (a web server). The web serverresponds with a synchronous HTTPresponse. Once the response isreceived the communication isconsidered complete.Although this technique works wellenough in most scenarios, it is not wellsuited to two key scenarios:1. The server wishes to pushinformation to the client. For instancethe server may have a notification that

needs to be sent to the client.2. The client and server wish to hold along running conversation with manysmall messages transferred back andforth. For instance, consider a realtime multi-player game: data must betransferred back and forward to eachclient on a regular basis as each userperforms activities that affect the otherusers.Although both of these use-cases canbe supported by HTTP, HTTP is notthe optimal protocol for either of thesescenarios, due both to its overheads,and its stateless nature. In this chapterwe will look at the problems HTTPhas adapting to these use-cases, and thesolutions offered by HTML5.Before continuing however, it is worthnoting that the APIs examined in thischapter are different from all the APIsexamined so far. Not only do they relyon the browser adopting the APIs, they

rely on servers implementing theseAPIs as well, since they do not playwell with most existing web servers orweb infrastructure (such as firewallsand proxy servers).This chapter will not provide workingexamples due to the fact it is notpossible to provide simple server-sideexamples.

Server sent eventsThe first problem we will deal with isthe server sending unsolicitednotifications to the client. This is avery common problem in webapplications, for instance, consider theGmail application. This needs to alertusers to the fact that a new email hasbeen received.It is not possible for the server to opena connection to a client to send itnotifications. In order to achieve this,the client would need to act as aserver, and open a port for the serverto connect to. This would open up theclient to major security vulnerabilities,and would be prohibited by firewalls.Instead, the functionality can beachieved with polling. In the Gmailscenario, the client could send amessage to the server every fewseconds to ask if any new emails havearrived.

There are two main problems withpolling:1. It is very wasteful on networkresources, since most of the time therewill be no new emails. If we envisagea user receiving 2 emails an hour,polling ever 5 seconds would mean359 requests informing the user thereare no new emails for each 1 informingthem there is a new email.2. It involves latency, since it will takeon average half the polling interval tonotify the user of a new email. Forinstance, if we increased the pollingperiod to every 10 seconds, it will takeon average 5 seconds to inform theuser a new email has arrived(excluding network latency).Software engineers have attempted tosolve these problems using a technique(or rather a set of techniques) referredto as COMET.COMET is usually implemented by

having the client poll the server with astandard HTTP request. If the serverhas a notification for the client it willreturn it immediately. If the serverdoes not have a notification for theclient it will block the connection onthe server until a notification isavailable, at which point an HTTPresponse will be returned. Thistechnique is also sometimes referred toas “long-polling”.There are problems with this approachthat make it unattractive for most sites:1. Due to the way most web serversimplement connection management,while the request is blocked on theserver it is represented by an openoperating system thread. Thissignificantly reduces the number ofclients that can be supported by asingle server, since there are limits tothe number of active threads.2. Many clients sit behind firewalls,

and firewalls are often suspicious ofconnections that remain open forsignificant periods of time. In order tocircumvent this COMETimplementations usually only leave therequest open for a limited period(perhaps 20 seconds). After thisperiod, the request times out and a newrequest is sent from the client. Thistherefore reduces the latency forreceiving notifications, but does notreally reduce network traffic.Essentially COMET is a hack. It is aset of techniques for implementing acommon problem that lacks a goodsolution. The Server Sent Events APIon the other hand is a solution to theunderlying problem.The Server Sent Events API isrelatively simple from the point ofview of the client. The browserindicates it wishes to receive serversent events by creating an Event

Source, which in turn sends an HTTPrequest to the server. The HTTPrequest is sent to the URL specified inthe EventSource: this must be a servicecapable of handling Server SentEvents:var eventSource = newEventSource("/newtasks.php");

The server will respond to this HTTPrequest with an HTTP response withthe MIME type of text/event-stream.The server can then begin using theconnection to send messages to theclient. The client identifies the end ofone message, and the start of new one,with two empty new lines in thepayload, although this detail is hiddenfrom you as a JavaScript programmer;instead a listener is attached to theevent source to access the server sentevents:eventSource.onmessage = function(event) {

console.log(event.data)

}

The data sent by server sent events isjust plain text, encoded with the UTF-8character encoding. The messages canof course conform to a data formatstandard such as XML or JSON, butthis is not a requirement.If it is so simple to implement serversent events you may be wondering whyyou have not heard more about them.Unfortunately server sent events sufferfrom the same problems as COMET:1. Many web servers (includingApache) are not capable of leaving aconnection open for an extendedperiod of time (which Server SentEvents requires) without utilizingresources on the server. Many serverswill need to change the way theyperform connection management beforethey can effectively support ServerSent Events.2. Many clients are behind firewalls

which prevent connections being leftopen for an extended period of time.A new class of server has begun toemerge designed specifically to workwith this new paradigm; this isresolving the first of these problems.The most prominent amongst theseservers is probably Node.js. Node.jsutilizes JavaScript as its programminglanguage, proving that JavaScript canlive outside the browser.Node.js is only a solution to thisproblem however if clients connectdirectly to it. Many IT infrastructuresproxy all requests through a proxyserver in a less secure area of theirnetwork (often referred to as theDMZ), and therefore the use of ServerSent Events could still cause issues ifthis proxy server was incapable ofhandling long-lived connections.The second problem can be mitigatedwith error handling. If the underlying

connection is closed by a firewall, anexception will be raised which theclient can listen for:eventSource.onerror = function(e) {

console.log("EventSource error occurred");

};

When an error occurs, the EventSourcecan be re-established with the server.Due to the fact that Server Sent Eventsare HTTP based, it is possible toprovide Polyfills for browsers lackingsupport based on COMET techniques,but obviously these suffer from thesame limitations as current COMETbased techniques.

Web SocketsAs discussed above, Server SentEvents continue to utilize standardHTTP requests and responses, butallow the server (rather than the client)to initiate requests.Web sockets on the other hand are anAPI for real-time, bi-directionalcommunication between the client andserver using a TCP based protocol.HTTP does use TCP as the underlyingtransport protocol, but HTTP isdesigned for larger payloads, and isnot intended to be conversational.Web Sockets are designed to allow theclient and server to be as chatty witheach other as they like by imposingminimal overhead on each messagesent and received. In addition, WebSocket connections are full duplex: soit is possible to send and receive datasimultaneously on the same connection.Although Web Sockets uses a distinct

protocol from HTTP, they do continueto use the same HTTP ports (typically80 and 443). This ensures thatadditional ports do not need to beopened to use Web Sockets.The initial handshake between theclient and the server to establish theconnection looks like a regular HTTPGET request, except it contains arequest to upgrade the HTTPconnection:GET /tasklist HTTP/1.1

Host: testing.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key:f4JUFGdKI3ReHYt8JHETuo==

Sec-WebSocket-Protocol: chat

Sec-WebSocket-Version: 13

The server will then respond with anHTTP request, confirming that theHTTP connection has been upgraded toa Web Socket connection:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept:HjGT6d6YJHyyERmm5HY5TreKjWk=

Sec-WebSocket-Protocol: chat

Once the connection has beenestablished, either the client or theserver are able to initiate the transferof text data to the other party, and thiscommunication will utilize the WebSocket (TCP based) protocol.The complexity of the HTTP handshakeis largely irrelevant from theprogrammers point of view. Thefollowing code will establish a WebSocket connection:var connection = newWebSocket('ws://localhost/tasklist', ['json']);

Notice that the URL is not prefixedwith HTTP:ws://localhost/tasklist

This could also be set to “wss” in

order to use a secure connection.The second parameter contains a list ofsub-protocols (or data formats) that theclient accepts. This is used to ensurethe client and the server are speakingthe same language on top of the WebSocket protocol. For instance, someapplications may wish to use JSONdata formats, while others will useXML, while the server may supportboth data formats. If multiple sub-protocols are specified, the server candetermine the preferred protocol. It iseven possible to utilize a customprotocol specific to the application youare writing.It is possible to attach a callback to theconnection to hear that the connectionhas been established:connection.onopen = function () {

console.log('The connection is open');

};

If the client specified that it acceptedmultiple protocols, it can alsodetermine which one the serverselected in the onopen method:connection.onopen = function () {

if (ws.protocol == 'json') {

console.log('Json was selected');

}

}

As soon as the connection is declaredyou can also add the usual callbacks tolisten for messages or errors:connection.onerror = function (error) {

console.log('Error ' + error);

};

connection.onmessage = function (event) {

console.log(event.data);

};

In addition, once the connection isestablished, the client can sendmessages to the server any time:connection.send('this is a message');

Another major benefit of Web Socketsis that they can be used to performcross-origin calls. As we have seenabove, AJAX calls are limited by thesame-origin policy: Web Sockets haveno such restrictions. It is up to theserver to determine if it will acceptrequests from all origins, or restrictrequests to specific origins.Web sockets are a young technology,and currently lack support in most webservers. In addition, despite the effortsmade with the protocol, it may notwork with proxy servers or firewalls.Node.js does however provide supportfor Web Sockets via various libraries.There are also servers available usingPython, Ruby, PHP and Java.It is likely to be a number of yearsbefore Web Sockets see widespreaduse, but it is a technology to watch.Once the implementation hurdles havebeen addressed, and common web

servers begin to provide support, theyare likely to see significant use.

Error HandlingThroughout this book we havedeveloped a web application. There isone notable step that we have missedin this development however: astrategy for handling errors.Errors can occur in a web applicationfor many reasons, but it is worthsubdividing errors into two categories:1. Errors that can be anticipated. Anexample of this is an AJAX call thatfails because the user is not connectedto the Internet. We will call theseexceptions, since they are exceptionsto the rule.2. Errors that are not anticipated.These errors normally arise fromprogramming bugs, such as accessingan element in an array that does notexist, or accessing a property on anundefined object. We will call theseerrors, since they are errors in theimplementation of the software rather

than run-time conditions.

Detecting ErrorsThe first step in implementing an errorhandling strategy is detecting the factthat errors have occurred. The firsttype of error can be handled by thetry/catch block within functions, or viaregistered callbacks on asynchronousAPIs. All APIs that utilizeasynchronous callbacks differentiatebetween success and failure scenarios,and we have also seen jQuerypromises provide direct support forthis.The second type of exception can behandled with try/catch blocks, but ingeneral should not be. By definition,these errors should not occur, thereforeyou should prevent them fromoccurring rather than handling them.For instance, consider a scenariowhere we have been passed an objectthat may be undefined, and we wish toaccess a property on it. We could write

this as follows:function accept(obj) {

try {

console.log(obj.property1);

} catch (e){}

}

It is far better to write this as follows:function accept(obj) {

if (obj) {

console.log(obj.property1);

}

}

It is still important to know thatunexpected errors have occurred,otherwise you will have no way ofknowing the code contains a bug.Rather than adding try/catch blocks toall our functions, a more effectivestrategy for learning than anunanticipated error has occurred is byadding an onerror listener to thewindow:

window.onerror=function(message, url, lineNumber){

console.log('Message:'+message);

console.log('URL:'+url);

console.log('Line:'+lineNumber);

}

Add the following to the tasks.htmlpage.Now, we will add the following buggyfunction to the public section of tasks-controller.js:printProperty: function(obj, property) {

console.log(obj[property]);

}

Back in tasks.html, we are then goingto call this after initialisation:tasksController.init($('#taskPage'), function() {

tasksController.loadTasks();

tasksController.printProperty(undefined, 'test');

});

If you run this example, you should seethe following printed to the console:

Handling ErrorsNow that we have detected errors, thenext step is deciding what to do withthem. It is important that you, as theapplication programmer, understandthat these errors have occurred. Unlikewith a server however, there is nocentralized log file containing all theerrors that have occurred.In the case of exceptions, therequirements should specify what to doif an exception occurs. For instance, ifan AJAX call cannot be performed:

· Should the user be informed?· Should we try to carry on the

best we can without the datafrom the AJAX call?

· Should we prevent the userperforming any other actions onthe web page?

The answers to these questions dependon the requirements. Detecting theexception is the first step, but detection

cannot help you determine what shouldbe done with the exception.When an error is detected there is notusually anything that can be doneexcept document the fact that the errorhas occurred. Due to the fact thaterrors are unanticipated, they shouldnot be handled by the code, but unlessyou document the fact they haveoccurred it is unlikely you will evernotice that they have occurred, sinceyou cannot see a log of the usersconsole.My preferred approach for handlingerrors is to log them with the log4jslibrary. A link to this library isprovided in Appendix B. This libraryallows you to define a strategy forhandling errors, which may includesending them to the server via AJAXso that they can be logged in acentralized file.

ConclusionWhen assessing technology for newprojects I like to apply a 10-year rule:“what will people think of thistechnology in 10 years time?”• Will the software continue to function“as-is” on the devices commonly usedin 10-years time?• Will the software continue to functionon existing devices, but need to berewritten for new devices?• Will the software need to beupgraded (and maybe rewritten) tocontinue its relevance?• Will the software be obsolete andneed to be discarded?• Will anyone even remember thistechnology?The 10-year horizon seems sensiblefor me. Vendors make a hugeinvestment in the software they

develop, and 10-years seems areasonable period of time to expectsoftware to at least remain relevant. Inaddition, vendors need to support andmaintain their applications forextended periods of time, and thisbecomes challenging when technologybecomes obsolete or “end-of-lifed”.There is no way to know for sure whatthe future holds for any technology.When Java was first introduced it wasassumed Java Applets (applicationsthat run inside browsers) would be ahuge selling point for vendors, andwould become a ubiquitous presenceon the Internet. Although they can befound occasionally, Applets are all butobsolete, even as Java has gone fromstrength to strength as a server sidelanguage.I firmly believe that the languagespresented in this book will survive the10-year rule. Web applications based

on these languages may need to bemodified to support new devices, butthe underlying languages are in a strongposition to maintain or strengthen theirdominance. This chapter will examinethe reasons I believe this.

History of backwards compatibilityHTML and JavaScript both have atremendous track record when it comesto backwards compatibility. Web siteswritten in the late 1990’s, relying onCGI scripts and early versions ofHTML, still work largely unchanged.They typically do not look any betterthan they did in the 1990’s, but they dostill work.Browser vendors take amazing carewith backwards compatibility. Theyare aware that their users will holdthem accountable if they ruin theirbrowsing experience on a popular website. As such, browser vendors investhuge resources in compatibility andregression testing every time a newrelease of a browser occurs.This process is not perfect. Asbrowser vendors have moved to fasterand faster release cycles bugs dooccasionally appear in existing web

applications. Although this is anannoyance, at least it is possible forweb application vendors to providepatches to their applications withoutrequiring users to perform any upgradesteps.Although bugs do sometimes appeartherefore, the underlying APIs andfeature sets remain remarkably stableonce they are implemented in all majorbrowsers.As a result, web standards tend to be aprocess of extension rather thanchange, and this process looks set tocontinue. As mentioned earlier,HTML5 is considered a livingstandard, and will gradually changeover time, without ever being replaced in a wholesale manner.

Monopoly PowerHTML and JavaScript are in aparticularly strong position due to theirmonopoly position in the web browser,and the fact that web browsers existfor virtually all consumer computingdevices (from phones, to gamesconsoles, to tablets and laptops, toPCs).Until recently Micorsoft Windows heldsuch a dominant position in operatingsystems that it made sense for vendorsto produce applications that workedonly in Microsoft Windows. Thanks tothe explosion of hand-held devices,and the resurgence of Apple, this is nolonger the case. Many people now use2 or 3 distinct operating systems on adaily basis:• A Microsoft Windows PC at work• An Adnroid mobile phone• An OSX laptop at home

• An iOS based iPadIncreasingly users expect to use thesame applications across all thesedevices, and for data to besynchronised between the devices.Web Applications written for webbrowsers offer enormous potentials inthis area. Using the languages outlinedin this book it is relatively trivial towrite an application that runs on allthese platforms, and performssynchronization to each device via acentral server.Ironically, unless any vendorestablishes monopoly power overdevices the way Microsoft did in theperiod from 1995-2005 it is unlikelythat JavaScript and HTML will loosetheir monopoly. This is partly becauseof the strengths of HTML5 andJavaScript, and partly because it is sodifficult for multiple vendors to agreeon a new set of technologies to replace

them.

HTML as a Living StandardAnother reason I am confident in thefuture prospects of HTML5 is that it isa living standard. As we saw earlier inthe book, even the HTML5 DOCTYPEdoes not have a version numberassociated with it for this reason. Webbased technologies will continue toevolve over time, new standards willbe released, and some older featuresmay be deprecated. Despite this, thevast majority of HTML5 will still bein place in 10 years time, just as thevast majority of HTML4 is stillsupported.Living standards do have theirproblems. Browser vendors willimplement new standards according totheir own timeframes, therefore theneed for polyfills is unlikely to goanywhere anytime soon. Thecompetition between browser vendorsto support these features is ultimately

good for browser technology however.The evolution of web standards islikely to focus on adding more andmore APIs that will ultimately makeweb applications as powerful asdesktop applications.Consider mobile phone applications:the vast majority of these are writtenfor iPhone and Android using nativeSDKs. This is largely due to the factthat these provide APIs for featuressuch as: • Accessing the camera• Using Bluetooth• Accessing the phone book• Accessing files• Accessing the compassNative SDKs represent a challenge tosoftware engineers and companiesproducing commercial software

however, since the same applicationneeds to be written multiple times tosupport each SDK. In addition,applications need to be verified andpossibly modified each time a newoperating system is released.Ideally mobile phones and tabletswould present a unified developmentplatform with a suite of APIs that weresupported on all mobile operatingsystems.It is likely HTML5 will grow overtime to fill this desire. There is noreason that these features of mobilephones could not be supported in across platform JavaScript API, andmade available inside the browser.An interesting project began a fewyears ago called PhoneGap (theunderlying software is now calledApache Cordoba). This allowsapplications to be written for a varietyof mobile phone platforms using

HTML5 features. Where features arenot supported in HTML5 (such asBluetooth), these are provided via acustom JavaScript library.PhoneGap applications are packagedas native applications, but underneaththey are using HTML, JavaScript andCSS.The goal of PhoneGap is to make itselfobsolete over time. This has alreadybegun to happen with APIs such as theGeoLocation API now availablenatively inside browsers. The mainobstacle that would need to beovercome to make PhoneGap obsoleteis security. HTML based applicationsrun inside the browser sandbox, andare not given access to the file-systemand other aspects of the operatingsystem.Mobile phone applications also runinside a sandbox, and ask the user forpermissions to perform restricted

tasks. There is therefore no reason thatweb browsers could not adopt thissame model, in fact some browsersalready ask the user for permissionbefore allowing usage of the storageAPIs.

The EndI hope this book has convinced you notonly the value and utility of HTML5,JavaScript and jQuery; but also theirunderlying beauty and elegance. Thefuture is remarkably bright for theselanguages, and the software engineerswho harness their power. I wish youall the best in your endeavours, andhope this book has provided thefoundations you need to write yourown web applications.I would like to thank you for choosingto read this book. As an independentpublisher of Software Engineeringbooks, reviews from readers are animportant tool both to improve ourbooks, and spread the word to newreaders. If possible, please take thetime to review this book on Amazon,or email me directly [email protected].

Appendix A: Cascading StyleSheetsUp until this point we have notexamined the manner in which HTMLdocuments are styled within thebrowser. HTML itself should notcontain presentational information(colors, fonts, borders etc), in factmost of the remaining presentationalaspects of HTML have been removedin HTML5. Presentation of documentsis left to the Cascading Style Sheets(CSS) style sheet language.This provides a separation ofconcerns: the HTML page provides thecontent, while CSS provides thepresentation information. This ensuresthat either can be changedindependently of the other.CSS3 is the latest version of the CSSspecification, and is being progressedin parallel with the HTML5specification.

This appendix will provide a briefintroduction to layout with CSS,without focusing on the latest featuresadded to CSS in CSS3, and withoutfocusing on how individual elementscan be styled. As such, thisintroduction is aimed at softwareengineers and programmers rather thandesigners.There are four keys to understandingCSS to a level sufficient to layoutcomplex pages.The first aspect is to understand howelements are selected by CSS to havestyles applied to them. As discussedearlier, jQuery uses the same selectionsyntax as CSS, therefore this should beintuitive to you even if you have notused CSS before.The second is to understand the boxmodel. This is the model that describesthe rectangle that is rendered torepresent each element in the document

tree. If you look at the elements thatcompose an HTML document, eachvisible element is represented by arectangle. When an element is a childof another element, its rectangle isinside its parent's rectangle.

// This is slightly simplistic,rectangles can overlap otherrectangles, and sit on top off,rather than inside, otherrectangles, but we will usethis simplistic model to begin.

The third is to understand howelements are positioned on screen, andhow they interact with one another.There are several ways to positionelements on screen, and severaldifferent ways elements of different

types can interact with one another.The forth is to understand the waystyles do or don’t inherit styles fromtheir parents. For instance, if a tableelement has a background color ofblue, should its tr and td childreninherit this style. Some styles cascade,and some (for good reason) do not.

Selecting elementsCSS consists of a set of stylisticproperties that should be applied to aset of elements. The following is anexample of two properties beingapplied to all elements of type footer:footer {

font-size: 12px;

text-align:center;

}

As with jQuery, you can specify rulesfor elements with specific classes:.classname {

}

With specific IDs:#idvalue {

}

Or with pseudo classes (the jQueryequivalent of filters):a:visited {

}

As with jQuery, you can also combinemultiple rules in the same selector.This will match all td elements insidea table with the ID tblOne:#tblOne td {

}

While this will match all td elementsthat have the class underlined:.underlined.td {

}

All matched elements will have thestyles specified applied to them, and aswe will see below, these styles willsometimes be inherited by theirchildren.Elements can be styled by more thanone set of rules. For instance, if wehave a footer defined as follows:<footer class=”myfooter” id=”footer1”>

And the following rules:footer {

color:black;

}

.myfooter {

background:blue;

}

# footer1 {

font-size:12pt;

}

Then the footer will have all threestyles applied to it:font-size:12pt;

background:blue;

color:black;

This does not present a problem whenthe properties are unique, but what ifthe styles had been defined as follows:footer {

color:black;

}

.myfooter {

color:blue;

}

# footer1 {

color:red;

}

In this case, CSS needs to find the mostprecise rule, and select the appropriatecolor based on that. There are severalways this is done.Firstly, CSS uses a priority system todetermine which rule has the mostweight to it:• If a match is based on element type,the rule is assigned 1 point.• If it matches on class, the rule isassigned 10 points.• If it matches on ID, the rule isassigned 100 points.This means that a match against thefollowing rule will be assigned 11points (it has one element match, andone class match):footer .myclass

The rule with the highest score wins.

This means that in our case, the colorselected would be red, since the IDbased rule is awarded 100 points. Thisprocess is referred to as “specificity”.This is already getting complex, butunfortunately it gets even morecomplex.Rules can be specified in 3 differentways:1. We can create an external CSS file,and import it into the HTML file.2. We can create styles “inline” in theHTML document by placing thembetween <style></style> tags.3. We can specify styles directly on anelement, for instance, <footerstyle=”color:blue;font-size:12pt”>Any styles assigned specifically on theelement are awarded an extra 1000points, meaning they will almostalways override any other styles.Even after applying all these rules, it is

possible that two rules will have thesame specificity. In this case, the onedefined last will win. This means thatrules inside <style></style> blocksoverride those defined in external CSSfiles, and if multiple rules in the sameCSS file have the same specificity, thelast rule, in the last file listed is thewinner.Finally, if you are unable to increasethe specificity of a rule sufficiently totrump another rule, but have one ormore styles that should never beoverridden, you can use the !importantflag. When this is used only inlinestyles will be able to override thestyle:.myfooter {

color:blue !important;

}

In general it is best not to have to relyon this setting.

The Box ModelThe box model dictates the area that anelement takes up on screen, andtherefore impacts the positioning ofother elements that need to bepositioned around it.Each element in the document tree isrepresented on screen by a rectangularbox. This includes div elements, spanelements, a elements, and any otherelement in the document tree that has avisual aspect.In order to understand CSS layout it isnecessary to understand the variousstylistic properties that affect the sizeof a box.• Firstly, each box needs an area whereits content should appear.• Secondly, you may specify paddingbetween the content and the border.• Thirdly, you may specify the size ofthe border.

• And fourthly, you can specify themargin that should occur between theborder of this component and thecomponents positioned adjacent to it.In addition, you need to consider whatit means to set the background color ofthe element, should that fill the entirespace, just the content, or something inbetween?These four properties constitute thebox model that can be seen in thediagram below:

The height and width propertiesapplied to the element dictate thecontent size, while the combination ofpadding, border and margin around thisdictate the overall size of the box onscreen.As can be seen, the background colorfills the content and padding portionsof the box. The border will typicallyhave its own color, while the margin

will inherit the background color of theelement's parent.All of these aspects of the box modelcan be controlled by CSS. Forinstance, consider the following set ofproperties:.element {

border: 1px solid #AAA;

padding: 10 0 10 0px;

margin-right: 15px;

width: 200px;

height: 100px;

}

In this example, the content of theelement will consume a total of200x100px.The padding has then been declared asa single property with 4 values (ratherthan as padding-left, padding-rightetc). This is applying 10px to the topand bottom, and 0 to the left and right.The way to remember the order of the

4 values is TRouBLe (Top, Right,Bottom, Left).One more pixel is then being added forthe border, and 15 pixels of margin tothe right of the element.This means that the height of theelement will be 100+10+10+1+1 =122px, while the width will be200+1+1+15=217px.It is worth mentioning that the marginset on an element can be negative. Thiscauses an element to take up less spacethan it otherwise would.

Positioning ElementsIn order to fully understand the position an element will take onscreen, and the way it interacts withadjacent elements, it is also necessaryto take into account the value of thedisplay property.This can be one of 4 primary values:• inline: this is the default for span, aand td elements.• block: this is the default for mostother elements, including div, p andmost other elements.• inline-block: this is only the defaultfor the img element, but is commonlyassigned to other elements in CSS.• none: the element should be hiddenfrom view.It is possible to override the displayproperty of any elements as follows:.myclass {

display:inline-block;

}

The primary difference between thesedisplay types is as follows:• An inline element does not have aline break either before or after it, andcan sit vertically adjacent to otherelements. In addition, you cannot setthe height or width properties for aninline element, although you can setline-height (this property dictates thedistance from the top of the first line oftext to the top of the second).• An inline-block element is like aninline element in that it doesn’t force aline break (so elements can sitvertically adjacent to other elements),but it can be given height and width.• A block element forces a new linebefore and after the element, thereforeby default, two block elements cannotsit vertically adjacent to each other.

• An element set to the display value ofnone does not take up any space inscreen, not even the space it wouldtake up if it was made visible.The default display type of elements isnot always appropriate when layingout the screen. Consider a screen withthe following layout:

The menu and content will both beblock elements, but we want them to sitalongside each other. In order toachieve that we can use the floatproperty: this tells an element to floatto the left or right of the precedingelement, instead of above or below theelement.The following is the sample code toproduce the desired results: <!DOCTYPE html>

<html>

<head>

<style>

header {

height:100px;

background: blue;

}

.menu {

float:left;

width:20%;

height:400px;

background: red;

}

.content {

float:right;

height:400px;

width:80%;

background: green;

}

footer {

clear:both;

height: 100px;

background: orange;

}

</style>

</head>

<body>

<header>

Header

</header>

<div class="menu">

This is the menu

</div>

<div class="content">

This is the content

</div>

<footer>

Footer

</footer>

</body>

</html>

The header is a header element, whichis of type display:block. This meansthat by default it takes up 100% of the

width and creates a new line after it.Therefore we only need to set theheight.The menu and content need to sitalongside each other; in order toachieve this, we set the menu tofloat:left, and the content tofloat:right, and assign them each apercentage of the overall width.You may now think that the footerelement only needs to be given aheight (as per the header element). Infact, once we start floating elements,the page will keep floating blockelements until it is told to stop,therefore we need to add theclear:both property (both refers to leftand right, they can be clearedindependently).This simple example shows a lot ofwhat you need to know in order tolayout elements on screen.

We could have achieved a similarresult by setting menu and content toinline-block, but the disadvantagewould be that the content would wrapto the next line if it did not fit besidemenu.

// The browser has a defaultstylesheet, and this specifiesthat the body should have amargin of 8px around it. Thiscauses an overflow for us. Itis customary to remove thebrowser defaults whenstarting a project. This iscustomary done in a filecalled reset.css – there aremany examples on theInternet.

By now it should be relatively obvioushow to position elements on screenwhen they are positioned via theirinteractions with other elements. Thisis called static positioning.It is possible to specify elementpositioning as relative:postion:relative

By itself this does absolutely nothing,but it makes it possible to move anelement with the left, right, top andbottom properties, and move it fromthe position it would otherwise hold inthe flow.It is also possible to use absolutepositioning. This removes the elementfrom the main flow of elements, andplaces it explicitly at the positionspecified with the left, right, top,bottom properties. Absolutelypositioned elements do not interact

with other elements on the page: theycan sit on top of or behind otherelements. In order to control whichelement is on top, the z-index propertycan be used: the element with thehighest z-index is positioned on top ofthe other elements.The final type of positioning is fixed:position:fixed

This can be used to fix elements in thebrowser even when the main page isscrolled. This is not a particularlycommon positioning, but does have itsuses.

InheritanceThe final fundamental aspect tounderstanding CSS is understandingwhen styles from the parent areinherited by their children and whenthey are not. For instance, consider thefollowing HTML:<div>

<span>this is text</span>

<span>this is more text</span>

</div>

If we apply a style to the div, it may ormay not make sense to apply that styleto the span elements. For instance, itdoes make sense to cascade the font,since it is a reasonable assumption thatparents and children will use the samefonts. This means we can set a font forthe body of the document, andautomatically have it apply to allelements unless it is overridden.Consider the case of a border though.

If we were to specify a border for thediv, we would not want this to cascadeto the span, since that would cause aborder to be rendered around the spanelements. Likewise, positioning andspacing styles such as padding, margin,top and left are not inherited.There are some styles where it isdubious whether they should beinherited. Background color is anexample, this does not get inherited,although there are many cases wherethis would make sense. It is howeverpossible for a child to inherit this if itwants using:background-color: inherit;

DebuggingChrome makes it relatively simple todebug elements, and dynamically addstyles. It is possible to right click onany element and select “InspectElement”. This will load the elementinto the “Elements” tab of thedeveloper tools, and show the CSSproperties that have been applied tothe element.

Any styles that have been overriddenare shown with a line through them,indicating they ae having no impact on

the visual styling of the element.It is also possible to dynamically addCSS properties in the top section ofthis window, allowing you to try outpossibilities in real time.

ConclusionThe goal of this chapter is to provideyou the fundamentals of CSS. Likemany of the other web languages in thisbook, CSS appears simple, but withoutunderstanding the fundamentals it canbe enormously frustrating.

Appendix B: RecommendedLibrariesThis chapter will provide a briefintroduction to some of the JavaScriptlibraries I have found useful whendeveloping web applications.

UnderscoreIf you ever find yourself asking “whydoesn’t JavaScript have a function todo x?”, chances are it will exist in theUnderscore library. Underscorecontains a wide array of utilityfunctions for managing arrays, objectsand functions, along with templatingfunctionality similar to that used withjQuery Template.The library, along with its API can befound here:http://underscorejs.org/

jQuery UIjQuery UI contains a wide range of UIwidgets, ranging from progress bars, todialogs, to drag and drop based lists.The library itself is reasonably large,but the capabilities of the widgets areextensive.It is also possible to selectivelyinclude widgets from the library inyour applications.The project can be found here:http://jqueryui.com/

DatatableOne important widget not included injQuery UI is a table. It is common forweb applications to require tablessupporting of sorting, filtering andpagination.The Datatable library provides awrapper over top of regular HTMLtables, and converts them into the richand dynamic tables programmers areused to in desktop GUI toolkits:https://datatables.net/

D3D3 is a library for producing datadriven documents. Charts and graphsare examples of data drivendocuments, but D3 can produce databound documents of amazingcomplexity and elegance.A full set of demos can be found at theproject home page:http://d3js.org/

Log4j JSThis library provides a logging API forJavaScript similar to the log4j (andrelated) library popular with Java.This API allows you to write customappenders to dictate logging strategies,and provides an AJAX appender tosend logs to the server.http://log4js.berlios.de/