PhoneGap and AngularJS for Cross-platform Development · Simon Basset is a cross-platform mobile...

Post on 27-Oct-2019

6 views 0 download

Transcript of PhoneGap and AngularJS for Cross-platform Development · Simon Basset is a cross-platform mobile...

PhoneGapandAngularJSforCross-platformDevelopment

TableofContents

PhoneGapandAngularJSforCross-platformDevelopment

Credits

AbouttheAuthor

AbouttheReviewers

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmore

Whysubscribe?

FreeaccessforPacktaccountholders

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Errata

Piracy

Questions

1.IntroductiontoAngularJS

AbriefoverviewofAngularJS

Coreconcepts

Controllers

Data-binding

Directives

Aconceptualexample

Asimpleto-dolistusingAngularJS

Preparingyourcodestructure

HTMLforourto-dolist

AddinginJavaScriptwithAngularJS

Summary

2.GettingReadyforPhoneGap

PreparingforPhoneGapdevelopment

InstallingAndroid

InstallingiOS

Command-lineinterfaceforbothAndroidandiOS

Runningonrealdevices

AngularJSonPhoneGap

Whatjusthappened?

Creatingato-dolistappusingAngularJSonPhoneGap

Abasicversionofato-dolistusingAngularJSonPhoneGap

Summary

3.FromaSimpleTo-doListtoanAdvancedTo-doList

Rewritingthesimpleto-dolistapp

Splittingindex.htmlintomultiplefiles

Splittingtodo.jsintomultiplefiles

Checkpoint

Wiringupabackendserver

Codingourserver

ChangingAngularJStoperformRESTfulrequests

Usingthe$httpmoduleofAngularJS

Rewritingcontrollerstomakeuseofthe$httpmodule

Checkingourcode

PreparingforPhoneGap

TestingourcodeoniOS

TestingourcodeonAndroid

Summary

4.AddingAuthenticationCapabilitiesUsingPhoneGapPlugins

AddingFacebookConnecttotheto-dolistapp

InitializingandpreparingforFacebookConnect

Writingtheusercontroller

Addingaloginpage

Addingalogoutfunction

Checkingtheloginstatus

FacebookloginforPhoneGap

InstallingtheFacebookplugin

TestingoutFacebookLoginonPhoneGap

FromwebtoPhoneGap

ImportingFacebookandPhoneGapplugins

ChangingFBtofacebookConnectPlugin

Theto-dolistappwithFacebookLoginonPhoneGap

Summary

5.SprucingUptheAppUsingAnimationsandMobileDesign

Addinganimationstoyourwebapp

AddingmobileCSSstylestoyourapp

PortingyourwebapptoPhoneGap

TestingyourapponiOS

TestingyourapponAndroid

Summary

6.GettingReadytoLaunch

Deployingserver.py

Usingphonegap.com

PreparingyourPhoneGapappforanAndroidrelease

Testingyourapponrealdevices

Exportingyourapptoinstallonotherdevices

Preparingpromotionalartworkforrelease

Buildingyourappforrelease

Signingtheapp

iOS

RunningyourapponaniOSdevice

Othertechniques

UsingXcode

Summary

A.References

AngularJSandrelatedlibraries

PhoneGapandrelatedreferences

Others

Othertutorials

Index

PhoneGapandAngularJSforCross-platformDevelopment

PhoneGapandAngularJSforCross-platformDevelopmentCopyright©2014PacktPublishing

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

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

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:October2014

Productionreference:1241014

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78398-892-1

www.packtpub.com

CoverimagebyAniketSawant(<aniket_sawant_photography@hotmail.com>)

CreditsAuthor

Yuxian,EugeneLiang

Reviewers

SimonBasset

RaziMahmood

CommissioningEditor

KunalParikh

AcquisitionEditor

MeetaRajani

ContentDevelopmentEditor

PriyankaShah

TechnicalEditors

VeronicaFernandes

AnandSingh

CopyEditors

RoshniBanerjee

AdithiShetty

ProjectCoordinator

KartikVedam

Proofreaders

MariaGould

ElinorPerry-Smith

Indexers

MonicaAjmeraMehta

TejalSoni

ProductionCoordinators

KyleAlbuquerque

NileshR.Mohite

CoverWork

NileshR.Mohite

AbouttheAuthorYuxian,EugeneLiangisafrontendengineerwithworkingknowledgeofUXanddatamining/machinelearning.HebuildsapplicationspredominantlyusingJavaScript/Python,andrelatedframeworkssuchasAngularJS,ReactJS,Node.js,Tornado,andDjango.Heledateamoftwo(includinghimself)towinStartupWeekendatTaiwanrecently.Hehasalsocompletedacademicresearchonsocialnetworkanalysis(linkprediction)usingmachinelearningtechniques,whileinterningasafrontendengineeratYahoo!.Toknowmoreabouthim,visithttp://www.liangeugene.com.

IamgratefulforthisopportunityandIwanttothankthefollowingpeopleatPacktPublishing:PriyankaShah,KartikVedam,SageerParkar,MeetaRajani,andAnandSingh.

SpecialthankstoProfessorDaphneYuan,ProfessorTsai-YenLi,andProfessorPailinChenoftheNationalChengChiUniversity,Taipei,Taiwan,forprovidingmewithtimelyandpracticaladviceonhowtocarryoutgreatresearchandhowtodealwithlife.

TothegoodpeopleofServiceScienceResearchCenter,IntelligentMediaLab,andtheresearchteamoftheFloodandFireresearchproject,thankyouforhelpingmeoutwhenIneededitthemost.

IalsowanttothankXJLforhelpingmeoutandstayingputwhenImostneededsupport.

Lastbutnotleast,Iwanttothankmyfamilymembersandfriendsfortheircontinuedsupport.

AbouttheReviewersSimonBassetisacross-platformmobileandfrontendengineerlivinginParis.Heworkshardeverydaytocreateattractivemobileandwebapps.

HeworkedforyearsatSmileOpenSourceSolutions,technicallyleadingateamspecializinginmobiledevelopment,andhasrecentlyjoinedthefrontendexpertteamofAXAFrance.

Heisatechnologyenthusiast.Helikestotryandusecutting-edgetechnologiesandlovestheWebandopensource.Healsolovesanimals,hastwocats,andisavegetarian.

RaziMahmoodhasaMaster’sdegreeinITwith14yearsofworkingexperience,andisanaccomplishedandexperiencedsoftwaretrainingconsultant.Hisinterestintechnologyneverfadesandhealwayskeepshimselfupdatedwiththelatesttechnology.Asaresult,hehassucceededinmanyareasinhiscareer.Heismotivatedandisaquicklearner,andhastheabilitytohandleprojectswithminimumsupervision;thesearehispersonalstrengthsineveryachievement.

RazistartedhiscareerasanexecutiveinanengineeringfirminKualaLumpur.Overtheyears,hehasdevelopedcustomsoftwaresolutionstoexpediteworkinaccounting,humanresources,andprojectmanagementreporting.ThesesolutionswereeventuallydocumentedandpresentedaspartofhisprojectthesisforhisMaster’sdegree.UponcompletionofhisMaster’sdegree,hejoinedtheSchoolOfTechnologyManagement,BinaryUniversityasalecturerinSoftwareEngineeringandAccountingInformationSystem.Sincethen,hehassupervisedvariousapplicationdevelopmentprojectsundertakenbystudentsusingvariousplatformssuchasWindows,Linux,OSX,Android,andiOS.In2008,hewasappointedasamemberofthePanelofAssessorsofMalaysianQualityAssuranceProgramme,specializingindatabases.Heisalsoaco-developerforaneducation-basedmobileappsprojectendorsedbytheMalaysianMinistryOfEducationtohelpstudentslearnlocalhistorysubjects.ThisappisnowfeaturedonGoogle’sPlaystore(https://play.google.com/store/apps/details?id=com.fiziazezan2gmail.com.ism2&hl=en).

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmoreYoumightwanttovisitwww.PacktPub.comforsupportfilesanddownloadsrelatedtoyourbook.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<service@packtpub.com>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

http://PacktLib.PacktPub.com

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcanaccess,readandsearchacrossPackt’sentirelibraryofbooks.

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,printandbookmarkcontentOndemandandaccessibleviawebbrowser

FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandviewnineentirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

PrefaceWelcometoAngularJSwithPhoneGap!Inthisbook,youwillreceivepracticalknowledgeaboutAngularJSandPhoneGap.Inparticular,youwilllearnhowtobuildacomplete,workablewebappusingAngularJS,afterwhichyouwillconvertvariousversionsofthiswebapptoaPhoneGapapp.YoushouldalsopickupsomethingnewregardingPhoneGapinparticular:howtousethecommand-lineinterfacetogeneratePhoneGapapps.

WhatthisbookcoversChapter1,IntroductiontoAngularJS,willteachyoutheabsolutebasicsofbuildinganAngularJSapp.

Chapter2,GettingReadyforPhoneGap,willcoverthePhoneGapcommand-lineinterface.Byendofthischapter,youwillhavelearnedthatthecommand-lineinterfaceisoneofthebestthingsaboutPhoneGap3.x.TheexampleyoucodedinChapter1,IntroductiontoAngularJS,willbeputtouseinthischapter.

Chapter3,FromaSimpleTo-doListtoanAdvancedTo-doList,willcoversomeoftheslightlymoreadvancedconceptsofAngularJS,suchascodeorganization,makingRESTfulcalls,andmore.ThisadvancedappwillthenbeconvertedtoaPhoneGapapp.

Chapter4,AddingAuthenticationCapabilitiesUsingPhoneGapPlugins,willaddFacebookauthenticationcapabilitiesviaPhoneGapplugins.Onceagain,youwillseehowwecanaddtheFacebookpluginusingthecommand-lineinterface.

Chapter5,SprucingUptheAppUsingAnimationsandMobileDesign,willcoveraslightlymoreadvancedAngularJStopic:animations.

Chapter6,GettingReadytoLaunch,willteachyouhowtolaunchtheapp,bothinAndroidandiOSdevices.

Appendix,References,hasalistofreferencesthatyoushouldfinduseful.

WhatyouneedforthisbookThisbookassumesthatyouhaveabasiccodeeditor.YouwillneedaMacifyouintendtodevelopiOSversionsofthePhoneGapapp.YouwillmostdefinitelyrequireanInternetconnectionandtheGoogleChromebrowser.

WhothisbookisforThisbookisintendedforpeoplewhoarenotfamiliarwithAngularJSbuthavebeginnerexperienceinPhoneGap,andwhomightwanttoimprovetheirPhoneGapskillsbylearningthecommand-lineinterfaceforPhoneGap3.x,anddevelopPhoneGapappsusingAngularJS.

ConventionsInthisbook,youwillfindanumberofstylesoftextthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestyles,andanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Feelfreetocopythecodeandsaveitasconcepts.html.”

Ablockofcodeissetasfollows:

project/

css/

js/

controllers/

todo.js

services/

todo.js

app.js

partials/

detail.html

list.html

index.html

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

<ling-repeat="todointodos">

<inputtype="checkbox"ng-model="todo.done">

<spanclass="done-{{todo.done}}">{{todo.text}}</span>

<buttonng-click="showDetail(todo.text)">Detail</button>

</li>

Anycommand-lineinputoroutputiswrittenasfollows:

cordovaemulateandroid

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,inmenusordialogboxesforexample,appearinthetextlikethis:“ClickonEdit/DetailsfortheAndroiditemandstartediting.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedormayhavedisliked.Readerfeedbackisimportantforustodeveloptitlesthatyoureallygetthemostoutof.

Tosendusgeneralfeedback,simplysendane-mailto<feedback@packtpub.com>,andmentionthebooktitleviathesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideonwww.packtpub.com/authors.

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

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

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyouwouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheerratasubmissionformlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedonourwebsite,oraddedtoanylistofexistingerrata,undertheErratasectionofthattitle.Anyexistingerratacanbeviewedbyselectingyourtitlefromhttp://www.packtpub.com/support.

PiracyPiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucomeacrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.

QuestionsYoucancontactusat<questions@packtpub.com>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.

Chapter1.IntroductiontoAngularJSWelcometotheworldofAngularJSwithPhoneGap!Inthisbook,youwilllearnhowtomergetwoveryexcitingtechnologies,namelyAngularJSandPhoneGap.Bytheendofthisbook,youwillhaveaworkingmobileappthatworksacrossiOSandAndroid,basedonAngularJSandPhoneGap.Asmentionedpreviously,thisbookistargetedatprogrammerswhohaveknowledgeofPhoneGap,butmayormaynothaveknowledgeregardingAngularJS.YoushouldhavesomeideaaboutJavaScriptthough,foryoutogetmaximumbenefitoutofthisbook.Thatsaid,letusbeginwithAngularJS.

AbriefoverviewofAngularJSAngularJS(https://angularjs.org/)isasuperheroicJavaScriptMVCframework,whichismaintainedbyGoogle.Itisopensourceanditsmaingoalistoassistwithcreatingsinglepageapplications.Thesearetypicallyone-pagewebapplicationsthatonlyrequireHTML,CSS,andJavaScriptontheclientside.

Whileonemayarguethattherearealreadymanyframeworksoutthereinthemarketthathelpwiththisissue,IwouldliketosaythatAngularJSisdifferentinafewways.Andinquiteafewoftheseinstances,itmakesyourlifemucheasierasafrontendprogrammer.

CoreconceptsTherearemanyconceptsrelatedtoAngularJS,butIwillcoverthemostcommonlyusedonesforthesakeofprogressingthroughthischapter.Aswegoalonginthisbook,I’lltouchonotherconcepts,suchastheuseofself-defineddirectivesandperformingRESTfulrequestsviaAngularJS.Themainconceptsthatyoushouldunderstandinthissectionaredirectives,controllers,anddatabinding.

ControllersIfyouhavealreadyusedJavaScriptframeworks,suchasBackBone.js,Can.js,Ember.js,orKnockOut.js,youshouldbefamiliarwiththisconcept.ControllersarethebehaviorbehindtheDOMelements.AngularJSletsyouexpressthebehaviorinacleanreadableformwithouttheusualboilerplateofupdatingtheDOM,registeringcallbacks,orwatchingmodelchanges.

Data-bindingData-bindingisanautomaticwaytoupdatetheviewwheneverthemodelchanges,aswellasupdatingthemodelwhenevertheviewchanges.Thecoolestaspectofthisconceptisthatitisatwowaydata-bindingprocess.Usedintandemwithcontrollers,thiscansaveyoualotofcode,asthereisnoneedforyoutowritetheusualupdatingoftheDOMelements.

DirectivesDirectivesareanotherawesomeconceptinAngularJS.WhattheydoisteachyourapplicationnewHTMLsyntaxandnewthingsspecifictoyourapplication.Directivescanbeself-definedandpredefined.Someofthemorenotablepredefineddirectivesinclude:

ng-app:Thisdeclaresanelementasarootelementoftheapplication,allowingitsbehaviortobemodifiedthroughcustomHTMLtags.ng-bind:ThisautomaticallychangesthetextofanHTMLelementtothevalueofagivenexpression.ng-model:Thisissimilartong-bind,butallowstwo-waybindingbetweentheviewandscope.ng-controller:ThisspecifiesaJavaScriptcontrollerclass,whichevaluatesHTMLexpressions.Inlayman’sterms,whatng-controllerdoesisthatitappliesaJavaScriptfunctiontothisblockofHTMLsothatthisparticularJavaScriptfunction(includingitsaccompanyinglogic,expressions,andmore)canonlyoperateinthisblockofHTML.ng-repeat:Youcanseethisasaloopthroughacollection.

AconceptualexampleNow,let’stakealookathowsomeofthepreviousconceptsplaytogether.Considerthefollowingpieceofcode:

<!doctypehtml>

<htmlng-app>

<head>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"

></script>

</head>

<body>

<div>

<label>SayHelloWorld</label>

<inputtype="text"ng-model="yourHelloWorld"placeholder="Type

anythinghere.">

<hr>

<h1>Hello{{yourHelloWorld}}!</h1>

</div>

</body>

</html>

TipDownloadingtheexamplecode

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

Let’sgothroughthecode.

WedefinedanHTML5HTMLdocumentinthiscase,asseeninthefirstlineNext,noticeng-appinthesecondlineofthecode;thisisanAngularJSdirective,whichtellsAngularJSthatthisistherootoftheAngularJSapplicationInordertouseAngularJS,weobviouslyhavetoinstallthescriptonthiswebpage,asshowninthe<script>tagWithinthebodytag,weseealabel,aninput,andanh1tag.Takenoteoftheinputtag,thereisang-modeldirective,whichismappedtoh1tag's{{yourHelloWorld}}

Whatthepreviouspieceofcodedoesisthatanythingthatistypedintotheinputbox,willbeshowninplaceof{{yourHelloWorld}}

Takenoteoftheversionofthecodeweareusinginthischapter,version1.2.12;shouldyoubeusingnewerversionsofAngularJS,thereisnoguaranteethatthecodewillwork.

Nowthatwehavebrieflywalkedthroughthecode,letuscopythecodeandrunitonourwebbrowser.Feelfreetocopythecodeandsaveitasconcepts.html.Thesourcecodeforthischaptercanbefoundintheconcepts.htmlfileintheChapter1folder.

Copiedthecode?Ifso,openthefileinyourfavoritewebbrowser.Youshouldseethe

followingscreenshotinyourbrowser:

Asampleconceptwebpage

Gotthepreviouscode?Okgreat!SonowyoucantrytypingintotheinputboxandseenewtextbeingappendedtoHelloandbefore!inthescreen.

Forinstance,whenwetypeworld,wewillseethenewcharactersbeingappendedtothescreenasIcontinuetotype.Bytheendoftypingtheword“World”,weshouldseethefollowingscreenshot:

AftertypingWorld

NowthatwehaveabriefideaastohowasimpleAngularJSappworks,letusmovetoamorecomplicatedapp.

Asimpleto-dolistusingAngularJSInthisexample,wewillcoverindetailastohowtowritecodeforaslightlymorecomplicatedAngularJSapp.Thisappismodifiedfromtheofficialexamplefoundatangularjs.org.ThisexamplewillbeusedasabasewhenweconvertitfromawebapplicationtoaPhoneGapapplication.

PreparingyourcodestructureForstarters,createtheindex.htmlandtodo.jsfiles.Justforyourinformation,thecodefoundinthissectioncanbefoundinthetodofolderinChapter1.

HTMLforourto-dolistWeneedtoprepareourHTMLfilesothatwecanmakeuseofAngularJS.Similartothepreviousconcepts.htmlfile,youwillseethatwehaveincludedtheuseofAngularJSviascript.Openupyourindex.htmlfileinyourfavoriteeditorandyoucanstartbyaddingthefollowingcode:

<!doctypehtml>

<htmlng-app>

<head>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"

></script>

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

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">

<style>

body{

padding:40px;

}

#todoDetails{

visibility:hidden;

}

</style>

</head>

<body>

<divclass="row"ng-controller="todoCtrl">

<divclass="col-md-6">

<h2>Todo</h2>

<div>

<span>{{getRemaining()}}of{{todos.length}}remaining</span>

[<buttonng-click="archive()">archive</button>]

<ulclass="unstyled">

<ling-repeat="todointodos">

<inputtype="checkbox"ng-model="todo.done">

<spanclass="done-{{todo.done}}">{{todo.text}}</span>

<buttonng-click="showDetail(todo.text)">Detail</button>

</li>

</ul>

<formng-submit="addTodo()">

<inputtype="text"ng-model="todoText"size="30"

placeholder="addnewtodohere">

<inputclass="btn-primary"type="submit"value="add">

</form>

</div>

</div>

<divid="todoDetails"class="col-md-6">

<h2>Details</h2>

Title:<spanid="title">{{currentText}}</span>

<br>

AddDetails:

<formng-submit="addDetails()">

<textareaid="details"ng-model="currentDetails">

{{currentDetails}}</textarea>

<p>

<inputclass="btn-primary"type="submit"value="AddDetails">

<inputclass="btn-primary"type="submit"value="Cancel"ng-

click="closeThis()">

</p>

</form>

</div>

</div>

</body>

</html>

Now,tomakesurethatyouareonthesamepageasIam,Iwantyoutoopenthisfileinyourfavoritebrowser.Youshouldseesomethinglikethefollowingscreenshot:

OurHTMLtemplate

Gotthepreviouscode?ItlooksweirdnowduetothefactthatwehavenotaddedthemainJavaScriptfunctionalities.Wewillbeworkingonitinthenextsection.

Now,letmeexplainthecode;noticethatIhavehighlightedafewlinesofit.Thesearethemostimportantlinesofthecodethatyoushouldtakenoteofinthisexample.TheremaininglinesarejusttheusualHTMLcode.

ThefirsttwolinesofthehighlightedcodesimplyinstallAngularJSandincludeBootStrap3’sCSSforstylingpurposes.Withoutboth,theprojectwillnotworkandmaynotlookgood.Theng-controllerdirectiveiswhatwecoveredbrieflyearlieroninthischapter.WeareapplyingtodoCtrltothisblockofHTML.Theng-clickdirectiveisanotherdirectivethatwedidnottouchonintheprevioussection.Whatng-clickdoesisthatitexecuteswhateverfunctionisdefinedforthisdirective.Inourexample,ng-click="archive()"meansthatonclickingit,archive()willbeexecuted.TheJavaScriptfunctionarchive()iswritteninourtodo.jsfile,whichwewillcoverlater.Theng-repeatdirectiveisadirectivethatloopsthroughacollection.Noticehowwe

implementedng-repeatinourHTMLcode:

<ling-repeat="todointodos">

<inputtype="checkbox"ng-model="todo.done">

<spanclass="done-{{todo.done}}">{{todo.text}}</span>

<buttonng-click="showDetail(todo.text)">Detail</button>

</li>

Anythingthatiswithin<li>isdependentonthetodoobject,whichispartofthetodoscollection.

Theng-submitdirectiveisgenerallyusedinforms.Thisisadirectivewhichcontrolswhatisbeingdoneonthesubmitform.Inthiscase,onthesubmitform,wewillexecutetheJavaScriptfunctionaddToDo().The[]optionencapsulates<buttonng-click="archive()">archive</button>,whichsimplyaddsasquarebracketaroundthebutton.

AddinginJavaScriptwithAngularJSNowwewillopenourtodo.jsfile,whichwecreatedintheprevioussection.Opentodo.jsinyourfavoritetexteditor.Letusbeginbycodingthefollowing:

functiontodoCtrl($scope){

}

Wearefirstgoingtodefineacontroller,whichwewillbeusingforourapp.NoticethatwehavenamedittodoCtrl,whichismappedontong-controllerintheHTMLfile(index.html),whereng-controller="todoCtrl"meansthattodoCtrlwillbecontrollingthisportionofthewebpage.

Also,noticetheuseof$scope,whichisanobjectthatreferstotheapplicationmodel;itistheexecutioncontextforrelatedexpressions,suchasng-click,ng-model,andsoon.Anysuchexpressionsofapredefineddirectiveoutsidethisscopewillnotbeexecuted.

Let’sstartbyinitializingourto-dolist.WithintodoCtrl,addthefollowingcode:

$scope.todos=[

{text:'hereismyfirsttodo',done:true,details:''},

{text:'continuewritingchapter1forthisbook',done:false,

details:''},

{text:'workonchapter2examples',done:false,details:''}

];

$scope.currentText='';//makethetextempty

$scope.currentDetails='';//makethetextempty

What$scope.todosdoesisthatitsimplycreatesalistofobjects,whichcontainsthetext,details,andwhetherthisto-doisexecutedornot(trueorfalse).Noticethattodoshereismappedtothecollectiontodosasseeninindex.html,whereng-repeatisbeingused.

Let’smoveonbyaddingmorefunctionalities.After$scope.currentDetails,addthefollowingthreeJavaScriptfunctions:

$scope.addTodo=function(){

$scope.todos.push({text:$scope.todoText,done:false,details:''});

$scope.todoText='';

};

$scope.remaining=function(){

varcount=0;

angular.forEach($scope.todos,function(todo){

count+=todo.done?0:1;

});

returncount;

};

$scope.archive=function(){

varoldTodos=$scope.todos;

$scope.todos=[];

angular.forEach(oldTodos,function(todo){

if(!todo.done)$scope.todos.push(todo);

});

};

The$scope.todoTextfunctionresetstodoTextafterithasbeenpushedintothearray.The$scope.addTodofunctiondoeswhatitissupposetodo,simplyaddinganewto-dotothelistoftodosasdefinedearlier.ThebeautyofAngularJSisthatitusesstandardJavaScriptdatastructuresthatmakemanipulationsomucheasier.

The$scope.getRemainingfunctionsimplycalculatesthenumberofitemsthatarenotdoneyet.Here,wecanseetwo-waydata-bindinginactionasthisfunctionexecuteswheneverthereisachangeinthelengthoftodos.

The$scope.archivefunctionmarksato-doasdone:trueinstandardJavaScriptmanner.

Bynow,youshouldhavenoticedthatalltheJavaScriptfunctionsdefinedherearebeingusedinindex.htmlunderng-controller="todoCtrl".

Let’snowaddthreemoreJavaScriptfunctionstocompletethefinishingtouchforthissampleapplication.

Afterthe$scope.archivefunction,addthefollowingfunctions:

$scope.showDetail=function(text){

varresult=$scope.todos.filter(function(obj){

returnobj.text==text;

})

$scope.currentText=result[0].text;

$scope.currentDetails=result[0].details;

document.getElementById('todoDetails').style.visibility='visible';

}

$scope.closeThis=function(){

$scope.currentText='';

$scope.currentDetails='';

document.getElementById('todoDetails').style.visibility='hidden';

}

$scope.addDetails=function(text){

varresult=$scope.todos.filter(function(obj){

returnobj.text==text;

})

angular.forEach($scope.todos,function(todo){

if(todo.text==text){

todo.details=$scope.currentDetails;

}

});

document.getElementById('todoDetails').style.visibility='hidden';

}

The$scope.showDetailfunctionsimplyretrievesthecurrentto-dobeingclickedonandshowsitonthedivwithID#todoDetails.Thevisibilityofthe#todoDetailsfunctionisthensettovisible.

The$scope.closefunctionsimplychangesthevisibilityof#todoDetailstohidden.

Finally,$scope.addDetailsaddsthedetailsofthetodoitem,andchangesthevisibilityof#todoDetailstohiddenoncedone.

Okay,sotoseeifweareonthesamepage,wenowneedtocheckourcode.Savethisfileastodo.js.Refreshyourbrowserandyoushouldstillseethesameuserinterfaceasperthepreviousscreenshot.

Now,tryclickingontheDetailbuttoninfrontofworkonchapter2examples,andyoushouldseethefollowingscreenshot:

DetailsoftheToDoitemshowsonclickingonthecorrespondingdetailbutton

Youwillseethedetailsofaparticularto-doitem.YoucantrytoaddsomedetailsforthisitemandclickonAddDetails.Youcanthenclickonotheritemsandcomebacktothisitemlater(withoutrefreshingthebrowser),andyoushouldstillseethedetailsinthetextarea.

Youcanalsocheckoffanyoftheitemsandyouwillseethatthenumberofremainingto-doitemdecreases:

Numberofitemschangesdynamicallyasyoucheckoffitems

Andofcourse,youcanaddnewitemsbysimplytypingintheinputboxandclickingontheaddbutton.Youshouldnoticethatthenumberofitemsnowincreases:

Addingnewto-doschangesthenumberofitemsdynamicallyandalsoshowsonthescreenimmediately

SummaryTosummarizewhatwehavedoneinthischapter;wehavewalkedthroughthebasicsofbuildinganAngularJSappandfamiliarizedourselveswiththebasicconceptsusedinAngularJS.Wehavemadeuseofng-app,ng-controller,ng-click,ng-repeat,andng-submitingeneral.Theseexpressions,suchasng-clickandng-submitaretypicallymappedontoJavaScriptfunctionsdefinedinAngularJScontrollers,asseenintodo.jsinourexample.NoticehowlittlecodewehavewritteninordertoachievesuchspeedyUXthroughtheconceptoftwo-waydata-bindinganditscontrollers.

Inthenextchapter,wewillstarttoportthisappinamoreorganizedmannertoPhoneGap.

Chapter2.GettingReadyforPhoneGapAsyoumightalreadyknow,PhoneGap(http://phonegap.com/)isareallycoolopensourceproject(nowownedbyAdobe),thatallowsyoutocreatecrossplatformmobileappsusingJavaScript/CSS/HTML.

Thismeansthatyoucanreadilyuseyourwebdevelopmentskillstodevelopingmobileapps.SincethisbookassumesbasicfamiliaritywithPhoneGap,IwilladvancetohowtoinstallPhoneGap.YouwillprimarilyseeexamplesrelatedtoAndroidandiOSsincewearegoingtocreatemobilesappsthatonlysupportAndroidandiOS.

NotethatwearefocusingonusingPhoneGapVersion3.3.0and,asmuchaspossible,wewillbebuildingtheappsviathelatestcommand-lineinterfaceprovidedbyPhoneGap.

Justforyourinformation,allsourcecodefoundinthischapter—whetherautomaticallygeneratedbyPhoneGaporcodedbyus—canbefoundinthesourcecodefolder,chapter2.

PreparingforPhoneGapdevelopmentWewillnowgoquicklythroughtheinstallationprocessforAndroidandiOSplatforms.Thebasicinstructionsforthissectioncanbefoundathttp://docs.phonegap.com/en/3.3.0/guide_platforms_index.md.html#Platform%20Guides.

InstallingAndroidTheinstructionstoinstallAndroidSDKcanbefoundathttp://docs.phonegap.com/en/3.3.0/guide_platforms_android_index.md.html#Android%20Platform%20Guide

Inordertobenefitfromthischapter,youneedtofollowtheinstructionstillthepointwhereyoucanruntheHelloWorldexampleinyourAndroidemulator.ThiswillincludethingslikeinstallingtheAndroidSDK,EclipseTools,andsoon.

InstallingiOSIfyouareusingMacandwanttodevelopanappforiOS,thenyouwillneedtoinstalltheSDKforiOSaswell.Ingeneral,youwillneedtoinstallXcodefromtheAppStoreandyouwillneedtoregisterasanAppleDeveloperinordertodeploytheappintheAppStore.

Youcanfollowtheinstructionsgivenathttp://docs.phonegap.com/en/3.3.0/guide_platforms_ios_index.md.html#iOS%20Platform%20Guide

PleasemakesurethatyoucanatleastrunthePhoneGapHelloWorldexampleinyouriOSsimulatorinordertobenefitfromthischapter.

Command-lineinterfaceforbothAndroidandiOSOnceyouhavefinishedinstallingtheindividualplatforms,it’stimetomoveontothecommand-lineinterface.Thissectioncontainsthemostimportantcommandsforthecommand-lineinterface.Tostartoff,youneedtoinstallNode.js(www.nodejs.org).Onceyouhaveinstallednode.js,performthefollowingsteps:

1. Runthenpm–ginstallcordovacommand.Thisinstallsthecommand-lineinterfaceonyourcomputer.

2. Changethedirectorytotheplacewhereyouwillbesavingyourprojectfilesforthischapter.

3. Onceinthedirectory,issuethecordovacreatetodocom.project.todoToDocommand.ThiswillcreateafoldercontainingyourbasicfilesforPhoneGap.

4. Now,changedirectoryto/todo.5. Onceinthedirectory,weneedtoinstallthevariousplatformswewillbesupporting:

ForiOS,usethecordovaplatformaddioscommandForAndroid,usethecordovaplatformaddandroidcommand

6. Now,let’strytoruntheHelloWorldexampleinAndroidusingthecordovaemulateandroidcommand.IfyouseeanareawhereyouhavenotdefinedanAVD,runtheandroidcreateavd–nametodo–target1command.

7. Then,runthecordovaemulateandroidagaincommand.Ifeverythingworkscorrectly,youshouldseethefollowingscreenshot:

HelloWorldworkinginandroid

Cool,sonowlet’strytoruntheHelloWorldexampleinaniOSsimulator.Forastart,issuethenode–ginstallios-simcommand.Now,runthecordovaemulateioscommand.Ifeverythingrunscorrectly,youshouldseethefollowingscreenshot:

RunningonrealdevicesSofar,wehavelearnedhowtoruntheHelloWorldapponemulators.However,whatifwewanttorunourcodeonourdevices?It’seasy;forandroid,runthefollowingcommands:

cordovabuildandroid

cordovarunandroid

ForiOS,runthefollowingcommands:

cordovabuildios

cordovarunios

Gotthepreviousexamplerunning?Ifso,great!Let’snowmoveontothenextsectionwhereweimplementAngularJSonPhoneGap.

AngularJSonPhoneGapBeforewebeginthissection,let’stakealookathowmuchmagicthePhoneGapcommand-lineinterfacehas.Navigatetothedirectorywhereyousavedyourcode;youshouldseesomethinglikethefollowingscreenshot:

Directorylayoutofthecode

ThepreviousscreenshotishowmycodedirectorylooksafterissuingthePhoneGapcommandsoftheprevioussection.NoticethatI’vecreatedthefolderphonegap/,andthePhoneGapcommandlinehelpeduscreatethetodo/projectfolderwithotherfolderssuchashooks/,merges/,platforms/,plugins/,andsoon.Ourplatform-specificcommandscreatedthefoldersandroid/andios/andtheyarefoundundermerges/andplatforms/respectively.

NoteTheautomaticallycreatedfoldersaremeanttoholdimportantfilesthatbelongtodifferentplatforms.Forexample,youwillfindAndroid-relatedfilesinandroid,whileyouwillfindiOSrelatedfilesinios/.Intheplugins/folder,youwillfindthevariouspluginsthatyouhaveinstalled.Laterinthisbook,youwillseeandexperiencetheFacebookconnect

plugin.

Inmyopinion,thecommand-lineinterfacesavesusalotofwork.Mostimportantly,wearenottieddowntoanyparticularcodeeditor;wecanjustusetheterminalandanycodeeditorthatweprefer(IuseSublimeText).

Now,goingbacktoyoursourcecode,navigatetothewww/folderundertodo/.Asyoumightalreadyknow,www/containsoursourcecodefortheJavaScript,CSS,andHTMLfiles.

Lookfortheindex.htmlfileandrenameitindex_backup.html.Now,createanewindex.htmlfileunderthewww/directory.

Next,copyandpastethecontentsfromconcepts.html,butmakeafewchangestoit.Foryourconvenience,thecodethatwewilluseisasfollows:

<!doctypehtml>

<htmlng-app>

<head>

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

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"

></script>

<style>

body{

padding:40px;

}

#holder{

border:2pxsolidred;

}

</style>

</head>

<body>

<divid="holder">

<label>SayHelloWorld</label>

<inputtype="text"ng-model="yourHelloWorld"placeholder="Type

anythinghere.">

<hr>

<h1>Hello{{yourHelloWorld}}!</h1>

</div>

</body>

</html>

Thecodeisgenerallythesameastheconcepts.htmlfileasseeninthechapter1folder,butwithafewchangesasshowninthehighlightedlinesofcode:

Inthe<header>tag,weinstalledPhoneGapbyusing<scripttype="text/javascript"src="cordova.js">

Next,weaddedsimplestylessothatwecanseewhatweareconcernedwithboundedinaredbox

Now,saveyourcodeasindex.html.Makesureitissavedunderthewww/folder.Afteryouhavesavedit,weneedtotestthecodeandmakesurethatthecodeisworkingasperwhatwehaveseeninthechapter1folder.Weshouldexpecttoseethataswetypeany

textintotheinputbox,itshouldbeappendedaftertheHello!text.

Sonow,let’sstarttestingourcode.Let’sstartwithiOS.Gotoyourterminalandmakesureyouchangethedirectorytotodo/.Onceinthedirectory,issuethecommandcordovaemulateios.Onceyouremulatorhasstarted,youshouldseethefollowingscreenshot:

AngularJSHelloWorldexampleonPhoneGapiOSSimulator

Allisgood.Nowlet’stestbytypingintothetextinputandseeifitworksasintended.Inmycase,Ityped,hey,andIgotthefollowingscreenshot:

Typingheytomakesurethatthecodeworks

Understoodtheexample?Makesurethatthecharactersgetprintedoutasyoutypealong!IfiOSisworkingoutfine,weshouldnothaveanyproblemwithAndroid.However,forsafety’ssake,let’sfireupAndroid’semulatortomakesurethingsaregoingasintended.

QuityouriOSsimulatorifyouwantto.Now,returntoyourterminalandissuethecommandcordovaemulateandroid.OnceAndroid’semulatorhasstarted,youshouldseethefollowingscreenshot:

AngularJSHelloWorldonAndroidemulator

Ifyougottheoutput,that’sgood.Let’stestbytypingintothetextinputbox.Thistime,ItypedworldandIgotthefollowingscreenshot:

AngularJSHelloWorldoniOSsimulator

Whatjusthappened?Bynow,youshouldhavenoticedthatenablingAngularJSonPhoneGapappsareprettystraightforward,justcodeasifyouarewritinganAngularJSapp.ToportitovertoPhoneGap,justmakesureyourunthecommandsshownintheprevioussectionsandinstallthecordova.jsscriptinyourAngularJSapp.

NowthatwehavemadesurethatAngularJSworksinPhoneGap,it’stimetomoveontothemaintopicofthischapter:buildingaTodoapp.

Creatingato-dolistappusingAngularJSonPhoneGapForthissection,we’llstartoffbytransferringtheto-dolistappfromthechapter1foldertoPhoneGap.Asyoumayhavealreadyguessed,shiftingtheto-dolistapptoaPhoneGapversionsimplyrequirestheinstallationofcordova.js.Let’sseehowthisisdoneinthenextsection.

Abasicversionofato-dolistusingAngularJSonPhoneGapLet’squicklygetstartedbyshiftingtheto-dolistappfromchapter1toPhoneGap.Performthefollowingsteps:

1. Changethedirectorytochapter2andnavigatetowww/whereyourPhoneGapfilesarelocated.

2. Changeindex.htmltoindex_concepts.html.3. Now,copythecontentsfromindex.htmlfromchapter1(wherethebasicHTML

structurefortodoappresides)toournewindex.htmlfile.4. Copytodo.jsfromtodo/inchapter1tojs/inwww/inthechapter2folder.

Yourdirectoryshouldlooklikethisfortodoappofchapter2:

Thecodedirectory

5. So,asofnow,yourindex.htmlfileforthischaptershouldlooklikethefollowingcode:

<!doctypehtml>

<htmlng-app>

<head>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min

.js"></script>

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

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.

css">

<style>

body{

padding:40px;

}

#todoDetails{

visibility:hidden;

}

</style>

</head>

<body>

<divclass="row"ng-controller="todoCtrl">

<divclass="col-md-6">

<h2>Todo</h2>

<div>

<span>{{remaining()}}of{{todos.length}}remaining</span>

[<ahref=""ng-click="archive()">archive</a>]

<ulclass="unstyled">

<ling-repeat="todointodos">

<inputtype="checkbox"ng-model="todo.done">

<spanclass="done-{{todo.done}}">{{todo.text}}</span>

<buttonng-click="showDetail(todo.text)">Detail</button>

</li>

</ul>

<formng-submit="addTodo()">

<inputtype="text"ng-model="todoText"size="30"

placeholder="addnewtodohere">

<inputclass="btn-primary"type="submit"value="add">

</form>

</div>

</div>

<divid="todoDetails"class="col-md-6">

<h2>Details</h2>

Title:<spanid="title">{{currentText}}</span>

<br>

AddDetails:

<formng-submit="addDetails(currentText)">

<textareaid="details"ng-model="currentDetails">

{{currentDetails}}</textarea>

<p>

<inputclass="btn-primary"type="submit"value="AddDetails">

<inputclass="btn-primary"type="submit"value="Cancel"ng-

click="closeThis()">

</p>

</form>

</div>

</div>

</body>

</html>

Let’smakesomeCSSchangestothecodethatyouaregoingtouseforindex.html;weneedtochangethehighlightedlineofcodetopadding:40px20px020px;.

6. Now,weneedtofireupourcodetomakesurethatitisworkingasintended.We’lltestitoutoniOSfirst.Gotoyourterminal,changethedirectorytotodo/andissuethecommandcordovaemulateios.OncetheiOSsimulatorisfiredup,youshouldseethefollowingscreenshot:

TodoApponiOS

7. Nowtestthefollowingtomakesurethatitisworkingasperwhatweseeinchapter1:

TickoffthecheckboxestoseeifthenumberoftasksremainingandtotaltasksarecorrectTryaddinganewtodoitemandseeifitaddstothelistoftodosClickonDetailandseeiftheitemwillshowupbelowtheinputbox.Forinstance,youshouldseesomethinglikethefollowingscreenshot:

Detailsforeachtodoitem

Ifyouaregettingtheprecedingtestsright,thencongratulations;allisworkingwellandgood.NowweneedtotestthecodeonAndroid.Goingbacktoyourterminal,issuethecommandcordovaemulateandroid.Aftertheemulatorisfiredup,youshouldseethefollowing:

TodoapponAndroid

Now,asusual,carryoutthetestthatyouhavedoneforiOS.Similarly,whenyouclickontheDetailbutton,youshouldseethefollowingscreenshot:

TododetailsforeachtodoonAndroid

SummaryLet’squicklydiscusswhatwehavedoneinthischapter.WehavepreparedourselvesforPhoneGapdevelopmentbyinstallingSDKsforbothAndroidandiOS.Next,wetouchedonhowwecanmakeuseofPhoneGapcommand-lineinterfacetosetupourapp,install,andpreparefordifferentplatformsandrunourappsoniOSandAndroidemulators.We’vealsolearnedthecommandstorunourappsonrealdevices.

However,wearestillfarawayfromadecentmobileapp.WhatwehavenowisjustabasicversionofthetodoapponPhoneGap;weneedtoimproveonit.Specifically,weneedtomakeitlookmorelikeamobileapp.Forinstance,canwedesignthelookandfeeloftheto-dolistsothatitwhenwetaponit,weareshowntheindividualtodoitemonasinglepage,insteadofjustappendingittothebottomofthepage?We’lldothisandmoreinthenextchapter.

Chapter3.FromaSimpleTo-doListtoanAdvancedTo-doListNowthatwehaveourbasicsinplace,let’smoveontosomethingmoreadvanced.InChapter1,IntroductiontoAngularJS,andChapter2,GettingReadyforPhoneGap,webuiltasimpleto-dolist,whichworkswell,butthecodeorganizationisamateurishatbest.Thecodearrangementinthepreviouschapterspreventsusfromwritinglargeappsshouldwewantto.Hence,inthischapter,wewillstartoffbyreorganizingthecodefirst,beforewiringupwithabackendserver.

WewillbebuildingonthetopicscoveredinChapter1,IntroductiontoAngularJS,andChapter2,GettingReadyforPhoneGap.Specifically,wearegoingtocoverthreemainareas:

ReorganizingthecodeWritingourserverusingtheTornadowebserverWiringourappwiththebackendserver

Rewritingthesimpleto-dolistappInChapter2,GettingReadyforPhoneGap,wewrotearathersimplisticversionoftheto-dolistapp.Asyoumayhavealreadynoticed,manythingsweremissing;therewasnobackendservertosaveyourto-dolists,andtherewasnocodeorganization,aseverythingwasjustwrittenwithinafolderandwithminimalbreakupofthecode.

Inthissection,wearegoingtodojustthat;rewritethecodesothattherearesomelevelsofcodeorganization.

Let’sreviewthecodeorganizationfirst.TheappwebuiltinChapter1,IntroductiontoAngularJS,lookslikethefollowing:

todo/

todo.js

index.html

Wearegoingtobreakupthecodesothatthecodeorganizationlooksasfollows:

project/

css/

js/

controllers/

todo.js

services/

todo.js

app.js

partials/

detail.html

list.html

index.html

Sowhatisgoingtohappenisthatproject.jsfromChapter2,GettingReadyforPhoneGap,willbebrokenupintotodo.js,controllers/todo.js,services/todo.js,andapp.js.Wewillalsobreakupindex.htmlintomultipleHTMLsnippetsandplacethemunderthepartials/folder.

Sobeforeyoustartwiththenextsection,youmightwanttocreatethedirectoriesandemptyfilesbasedonthecodeorganization.

Splittingindex.htmlintomultiplefilesWewillstartworkonindex.htmlfirst.Tostartoff,thisiswhatindex.htmlwilllooklikeinthischapter:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"

>

<style>

body{

padding:40px20px020px;

}

</style>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"

></script>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-

resource.min.js">

</script>

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-

route.min.js">

</script>

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</head>

<body>

<h2>Todos</h2>

<divng-view></div>

</body>

</html>

TheprecedingcodestructureisessentiallythesameaswhatwesawinChapter2,GettingReadyforPhoneGap.Themaindifferenceisthatmuchofthedetails(suchaslistingtheto-dolistsandeditview)arenowbeingabstractedaway.

Themainthingtonoteistheuseofng-viewinindex.html;youcanthinkofng-viewasacontainerthatwillholddifferentsnippetsofHTMLbasedonthecurrentURL.

Nowlet’sbegincoding:

1. Let’sworkonpartials/detail.html:

<formname="myForm">

<divclass="control-group">

<label>Name</label>

<inputtype="text"name="text"ng-model="todoText">

</div>

<divclass="control-group">

<label>Details</label>

<textareaname="description"ng-model="todoDetails"></textarea>

</div>

<br>

<ahref="#/"class="btn">Cancel</a>

<buttonng-click="save()"

class="btnbtn-primary">Save</button>

<buttonng-click="destroy()"

ng-show="project.$remove"class="btnbtn-

danger">Delete</button>

</form>

2. Youwillseesomeofthedetailsofthedetail.htmlfileinthepreviouschapter;thehighlightedlinesofcodearethenewadditions:

<ahref="#/"class="btn">Cancel</a>simplyperformsachangeintheURLroutewhenweperformacancelaction.Noticethatweareusing#/insteadof/.Insteadofusingng-submittoaddnewto-dolists,wenowuseng-click="save()"toeithercreateoreditthecurrentto-doitem,shouldtherebeany.

3. Onceyou’redonewiththeprecedingstep,let’smovetopartials/list.html:

<span>{{remaining()}}of{{todos.length}}remaining</span>

<table>

<thead>

<tr>

<th>Todo</th>

<th>Done</th>

<th>Details</th>

<th><ahref="#/new"><iclass="icon-plus-sign">NEW</i></a></th>

</tr>

</thead>

<tbody>

<trng-repeat="todointodos">

<td>{{todo.text}}</td>

<td><inputtype="checkbox"ng-model="todo.done"></td>

<td>

<ahref="#/edit/{{todo.text}}"><iclass="icon-

pencil">Edit/Details</i></a>

</td>

</tr>

</tbody>

</table>

4. Thelist.htmlfileissimilartowhatwehavedoneinChapter2,GettingReadyforPhoneGap;theonlychangewasthatwesplitthepartwhereweloopthroughthelistofto-dosintoaseparateHTMLfile.

NowthatwearedonewiththeHTMLportionofthecode,let’smoveontothemeatofthisrewrite:rearrangingtheJavaScriptcode.

Splittingtodo.jsintomultiplefilesWewillfirstworkonapp.jsfoundundertheproject/jsfolder.Bearinmindthatthisisthefirsttimewewritethecodeforapp.js.ItcontainstheroutestodifferentviewsoftheappbymakinguseofanAngularJSmodulecalledngRoute.

Nowlet’sseehowwecanmakeuseofngRoute:

1. Tostartoff,here’swhatapp.jslookslikenow:

angular.module('todoApp',[

'ngRoute',

'todoApp.controllers',

'todoApp.services'

])

.config(function($routeProvider){

$routeProvider

.when('/',{

controller:'ListCtrl',

templateUrl:'partials/list.html'

})

.when('/edit/:todoText',{

controller:'EditCtrl',

templateUrl:'partials/detail.html'

})

.when('/new',{

controller:'CreateCtrl',

templateUrl:'partials/detail.html'

})

.otherwise({

redirectTo:'/'

});

})

2. Let’sgothroughwhat’shappeningherelinebyline:

WefirstdefinetodoApp;somethingwehavedoneinChapter1,IntroductiontoAngularJS,andChapter2,GettingReadyforPhoneGap.Next,weincludedthemodulesandcodethatwewanttouse,namelyngRoute,todoApp.controller,andtodoApp.services.TakenotethatwehavenotcreatedtodoApp.controllerandtodoApp.servicesyet.Finally,wemakeuseofthengRoutemoduletodefinetherouteswewanttouse,anditsassociatedcontrollerandtemplate.when('/'meansthatwhentheURLlocationis'/',wewillbeusingListCtrlandthepartials/list.htmltemplate.ControllersineachoftheroutearedefinedastodoApp.controllers(whichisthecontroller.jsfilewewillbeworkingoninthenextsection).templateurlissimplytheHTMLsnippetthatwewouldliketoshowforeachdifferentURL.

3. Nowlet’screatethecontrollerfoundatcontroller/todo.js.Thecodeisthesame

asinChapter2,GettingReadyforPhoneGap:

angular.module('todoApp.controllers',[])

.controller('ListCtrl',function($scope,$http,Todos){

$scope.todos=Todos;

$scope.remaining=function(){

varcount=0;

angular.forEach($scope.todos,function(todo){

count+=todo.done?0:1;

});

returncount;

};

})

.controller('CreateCtrl',function($scope,$location,$timeout,

Todos){

$scope.todoText="";

$scope.todoDetails=""

$scope.save=function(){

Todos.push({text:$scope.todoText,done:false,

details:$scope.todoDetails});

$location.path('/');

};

})

.controller('EditCtrl',

function($scope,$location,$routeParams,Todos){

$scope.todos=Todos;

varresult=$scope.todos.filter(function(obj){

returnobj.text==$routeParams.todoText;

});

$scope.todoText=result[0].text;

$scope.todoDetails=result[0].details;

$scope.save=function(){

vartext=$scope.todoText;

vardetails=$scope.todoDetails;

vardone=$scope.todoDone;

alert(text);

angular.forEach($scope.todos,function(todo){

if(todo.text==text){

todo.text=text;

todo.details=details;

}

});

$location.path('/');

};

$scope.destroy=function(){

$scope.project.$remove();

$location.path('/');

};

});

4. Theonlylineofcodeyouneedtotakenoteofisthefirstline;wehavedefinedtodoApp.controllers,whichwasreferencedfromjs/app.jsearlieron.

5. Wecannowmoveontojs/services/todo.js.Asusual,wefirstdeclaretodoApp.services,followedbyTodos.Wesimplyreturnalistofto-doitemshere.Thecodelooksasfollows:

angular.module('todoApp.services',[])

.factory('Todos',function(){

varitems=[

{text:'hereismyfirsttodo',done:true,details:''},

{text:'continuewritingchapter1forthisbook',done:false,

details:''},

{text:'workonchapter2examples',done:false,details:''}

]

returnitems;

})

Nowthatwehavemoreorlessreorganizedourcode,weshouldcheckthatourcodeisworking.Saveyourcodeandopenupindex.htmlinyourwebbrowser.YoushouldexpecttoseethatthecodeisworkingasperChapter2,GettingReadyforPhoneGap.Theinterfacewilllookthesamewiththeexceptionthattheunderlyingcode’sorganizationhaschanged.

Isitallworkingwell?Ifso,great!YoucanproceedtocreateaPhoneGapversionofthiscodebycopyingandpastingthecontentsoftodos_advance/intothewww/folderfoundinyourPhoneGapproject.

Next,youcantestyourcodeintheAndroidandiOSemulatorsbyrunningcordovaemulatorandroidandcordovaemulatorios,respectively,andmakingsurethatthecodeisworkingfine.

CheckpointNowthatwehaverewrittenthecodeandtransferredittoPhoneGap,checkifthewww/directoryinyourPhoneGapapplookslikethefollowing:

www/

css/

js/

controllers/

todo.js

services/

todo.js

partials/

detail.html

list.html

index.html

Mostimportantly,makesurethatyourcodeinPhoneGapisworkingasperChapter2,GettingReadyforPhoneGap.Also,yourappshouldlookandworksimilarlytotheversionwehavecodedwehaveinChapter2,GettingReadyforPhoneGap.Ifthecodeisconfirmedandworkingcorrectly,let’smoveontothenextsectionwherewewireabackendserverandcreateanadvancedversionoftheto-dolistapp.

WiringupabackendserverInthissection,wewillmakeuseofthe$httpmoduleofAngularJStomakeRESTfulcallstoasimplebackendserver.ThebackendserverhereisbasedonFacebook’sTornadoFramework(https://github.com/facebook/tornado/),butthefactisthatyoucanmakeRESTfulcallsusingExpress.js(http://expressjs.com/)oranyotherframeworkthatyoulike.

Beforeyougetstartedwiththissection,youwillneedtohaveMongoDB(http://www.mongodb.org/),Python2.7.x,andtheTornadowebserverinstalled.YouwillalsoneedtoinstallaPythonlibrarycalledtornado-cor(https://github.com/globocom/tornado-cors),whichfacilitatestheuseofcross-originresourcesbetweenyourAngularJSappandserver.

CodingourserverThemainideaofthePythonTornadoserverisasfollows:

Wehaveoneendpoint,wherethisendpointwillreceiveaGETorPOSTrequestfromourAngularJSapp.DependingontheURLargumentreceived,thecorrespondinghandlerwillperformGETonallto-doitemsoroneto-doitem.IftherequestisaPOSTrequest,itwilleithereditorcreateanewto-doitem.

SincetheTornadowebserverusesclass-basedviews,weonlyneedtodefineoneclass,whichacceptsaGETorPOSTrequest.Youcanrefertothesourcecodefoundatchapter3/server/server.py.Thefullcodeforourserverisasfollows:

importtornado.httpserver

importtornado.ioloop

importtornado.options

importtornado.web

importpymongo

frombson.objectidimportObjectId

fromtornado_corsimportCorsMixin

fromtornado.optionsimportdefine,options

importjson

define("port",default=8000,help="runonthegivenport",type=int)

classApplication(tornado.web.Application):

def__init__(self):

handlers=[(r"/todos",Todos)]

conn=pymongo.Connection("localhost")

self.db=conn["todos"]

settings=dict(

xsrf_cookies=False,

debug=True

)

tornado.web.Application.__init__(self,handlers,**settings)

classTodos(CorsMixin,tornado.web.RequestHandler):

CORS_ORIGIN='*'

CORS_METHODS='POST,GET,OPTIONS'

CORS_HEADERS='Origin,X-Requested-With,Content-Type,Accept,

content-type'

CORS_MAX_AGE=1728000

CORS_CREDENTIALS=False

defget(self):

Todos=self.application.db.todos

todo_id=self.get_argument("id",None)

iftodo_id:

todo=Todos.find_one({"_id":ObjectId(todo_id)})

todo["_id"]=str(todo['_id'])

self.write(todo)

else:

todos=Todos.find()

result=[]

data={}

fortodointodos:

todo["_id"]=str(todo['_id'])

result.append(todo)

data['todos']=result

self.write(data)

defoptions(self):

todo_id=self.get_argument("id",None)

Todos=self.application.db.todos

#ifself.request['Access-Control-Request-Method']=='POST':

self.set_header("Access-Control-Allow-Headers","content-type")

defpost(self):

data=json.loads(self.request.body)

Todos=self.application.db.todos

todo_id=self.get_argument("id",None)

iftodo_id:

#performanedit

todo=Todos.find_one({"_id":ObjectId(todo_id)})

#hereshouldperformtheupdate…

todo['text']=data['text']

todo['details']=data['details']

todo['done']=data['done']

Todos.save(todo)

#cos_idisnotJSONserializable.

todo["_id"]=str(todo['_id'])

self.write(todo)

else:

data=json.loads(self.request.body)

todo={

'text':data['text'],

'details':data['details'],

'done':data['done']

}

a=Todos.insert(todo)

#cos_idisnotJSONserializable.

todo['_id']=str(a)

self.write(todo)

defmain():

tornado.options.parse_command_line()

http_server=tornado.httpserver.HTTPServer(Application())

http_server.listen(options.port)

tornado.ioloop.IOLoop.instance().start()

if__name__=="__main__":

main()

Here’swhat’shappeninginourcode:

Rightatthetopofserver.py,wesimplyimportvariouslibrariesrequiredforoursever.Next,wehavetheApplicationclassdefined,whereweinitializethehandlersrequiredforourserver.HandlersaresimplyURLsthataremappedtoclass-basedviewsintheTornadowebserver.TheTodosclasscontainsthreefunctions:

get:ThisfunctionsupportstheGEToperationsoptions:ThisfunctionsupportstheCORSOPTIONSstringpost:ThisfunctionsupportsthePOSToperations

Finally,wedefineamain()function,whichissupposedtorunourTornadoserverwhencalled.

TomakesurethattheTornadoPythonserverisworking,youmustfirstrunMongoDBonyourcomputer,navigatetothefolderwhereserver.pyresides,andthenrunthefollowingcommand:

pythonserver.js

Onceyouissuetheprecedingcommand,openupyourwebbrowserandnavigatetohttp:/localhost:8000;youwillseethefollowingscreen:

GettinganerrorsincewehavenotdefinedahandlerforthisURL

WegetanerrormessagebecausewedidnotdefineanyhandlersfortheURLathttp://localhost:8000.Solet’snowchangeourURLtohttp://localhost:8000/todos.Youshouldtechnicallyreceiveanemptypage,butbecausewealreadyhavesometestdatasavedinMongoDB,youwillseethefollowingscreen:

Asamplelistofdatareturned

SowhenweperformaGETrequestat/todos,wesimplyretrieveafulllistofto-dos.Similarly,whenweperformaGETrequestwithanID,youwillseethatonlyoneto-doitemisbeingreturned.

Oneto-doitemreturned

ChangingAngularJStoperformRESTfulrequestsNowthatourserverisready,weneedtostartcodingourAngularJSapptomakeitreadyforRESTfuloperations.We’llbemakingchangestothecodefoundinjs/controllersandjs/services,ingeneral.We’llstartwithjs/services/todo.jsfirst.

Usingthe$httpmoduleofAngularJSLet’sgetbacktojs/services/todo.js.Wearegoingtoincludefourbasicoperationsinthismodule,namelygettingallto-doitems,gettingoneto-doitem,savingto-dolists,andfinally,editingto-doitemoperations.

ThecodethatwillconsumetheRESTfulAPIsisasfollows:

angular.module('todoApp.services',[])

.config(function($httpProvider){

$httpProvider.defaults.useXDomain=true;

delete$httpProvider.defaults.headers.common['X-Requested-With'];

})

.factory('Todos',function($http){

return{

getAll:function(){

//return$http.get('http://10.0.2.2:8000/todos');//ifusing

android

return$http.get('http://localhost:8000/todos');

},

getTodo:function(id){

//return$http.get('http://10.0.2.2:8000/todos?id='+id);//ifusing

android

return$http.get('http://localhost:8000/todos?id='+id);

},

save:function(todoData){

//return$http.post('http://10.0.2.2:8000/todos',todoData);//if

usingandroid

return$http.post('http://localhost:8000/todos',todoData);

},

edit:function(id,todoData){

//return$http.post('http://10.0.2.2:8000/todos',todoData);//if

usingandroid

return$http.post('http://localhost:8000/todos?id='+id,

todoData);

},

delete:function(id){

console.log("idontthinkIhaveadeletehere.")

}

}

})

Firstandforemost,noticethatwehavea.configfilewhereweused$httpProviderandmadesomechangestothedefaultbehavioroftheAngularJS$httprequests.Thefirsttwohighlightedlineswith.configaretheretoensurethatcross-domainrequestscanbedone,sinceourAngularJSappresidesinadifferentlocationasourserver.

Secondly,noticethattheservicesmodulesimplyreturnstheoperationsweneed,withtherelevantRESTfulendpoints.Forexample,getAllisafunctionthatreturnstheendpointhttp://localhost:8000/todosusingaGETrequest.

Rewritingcontrollerstomakeuseofthe$httpmoduleIntheprevioussection,werewroteservices/todo.jssothatitnowperformsRESTfulrequests.Howdoweconsumetheseservicesinthecontroller?WecansimplydosobyincludingTodounderthecontrollersthatwewanttousetheservicesprovidedforbyTodo.Takeforinstance,ListCtrl:

.controller('ListCtrl',function($scope,$rootScope,$http,Todos){

Todos.getAll().success(function(data){

$rootScope.todos=data['todos'];

})

$scope.remaining=function(){

varcount=0;

angular.forEach($scope.todos,function(todo){

count+=todo.done?false:true;

});

returncount;

};

})

Inthehighlightedlineintheprecedingcode,noticethatwehaveincludedTodos.Next,inordertoretrieveallto-doitems,wesimplymakea.getAlI()callbydoingTodos.getAll().Ifthecallissuccessful,wereturntheJSONdataandassignitto$rootScope.todos.

Weuse$rootScopeinsteadof$scope,becauseIwantedallthecontrollerstobeabletoaccessthecurrentstateoftodoswithoutmakinganothercalltothebackendserver.

Next,forCreateCtrl,wesimplymakea.save()tothebackendwithourto-dodata:

.controller('CreateCtrl',function($scope,$rootScope,$location,$timeout,

Todos){

$scope.todoText="";

$scope.todoDetails="";

$scope.save=function(){

vartodo={

text:$scope.todoText,

done:false,

details:$scope.todoDetails

};

console.log($rootScope.todos);

$rootScope.todos.push(todo);

console.log($rootScope.todos);

Todos.save(todo);

$location.path('/');

};

})

NoticethatwesimplymakeaTodos.save()calltosaveourdatatoourbackendserver.

Finally,let’stakealookatEditCtrl.Thistimearound,wesimplygettheto-doitembyitsID,andperformedit()whenwehavemadechangestotheitem.Thisisshownbythehighlightedlineinthefollowingcode:

.controller('EditCtrl',

function($scope,$location,$routeParams,Todos){

//$scope.todos=Todos;

console.log($location.$$path.split("/"));

varid=$location.$$path.split("/")[2];

varresult=Todos.getTodo(id).success(function(data){

console.log("andthereturneddatais");

console.log(data);

$scope.todoText=data.text;

$scope.todoDetails=data.details;

returndata;

})

$scope.save=function(){

vartodo={

id:$location.$$path.split("/")[2],

text:$scope.todoText,

details:$scope.todoDetails,

done:true

}

Todos.edit(id,todo);

}

});

CheckingourcodeNowthatwehaverewrittenourAngularJSapp,it’stimetocheckifitworkscorrectly.Asusual,fireupyourserverbyissuingthePythonserver.pyandstartyourAngularJSappusingalocalserver.WhenyoufirstloadyourAngularJSapp,youwillseeaGETrequestonyourserverinthebackend.Here’swhatitlookslikeonmyterminal:

AGETrequest

Let’strycreatinganewto-doitembyclickingonNEW.Asusual,youshouldseethefollowingscreen:

Ourinputfieldstoaddato-dolist

Nowtypeinthenameanddetails.I’mgoingtojusttypehelloworldasthenameandhelloworlddescriptionasthedetails.Oncedone,clickonSave.Youshouldseethatyouarenowredirectedtothepagecontainingthelistoftodoswiththenewto-doitematthebottom.

Ifyoulookatyourterminal,youwillalsoseethefollowingscreen:

AseriesofHTTPrequestscomingfromourAngularJSapp

TheOPTIONSrequestissentfromAngularJS.Youarethenredirectedbacktothehomepage(that’swheretheGETrequestoccurs),andfinally,thePOSTactioniscompleted,asshownbythelastlineinthisterminal.

Nowyoucanattempttoperformaneditoperation.Wewilledittheitemthatwehavejustadded:

Addingato-doitem

Wewillnowaddnewdetailstotheto-doitem:

Makingchangestotheto-doitem

NowclickonSave.Wewillseethefollowingscreenwhenweareredirectedbacktothehomepage:

Theto-doitemisbeingeditedandisreflectedonthelistofto-doitems

Ifeverythingworksasexpected,wecannowtestourcodeonAndroidandiOS.

PreparingforPhoneGapAsusual,wewillneedtotransferthecodethatwehavewrittenunder/www.MakesureyoutransferthecodecorrectlytoPhoneGap.Ifyou’vedoneitcorrectly,yourPhoneGapfoldershouldlookasfollows:

Codearrangementatthispointintime

Ifyouhaveperformedtheprevioussteps,let’stestitoutoniOSandAndroid.

TestingourcodeoniOSTotestourcodeoniOS,wesimplynavigatetoourPhoneGapproject(phonegap/todo)andissuethefollowingcommand:

cordovaemulateios

RemembertoturnonyourserverandMongoDBaswell.YoushouldseethefollowingscreenonyourAndroidemulator:

Yourto-dolistappshouldlookandworkasexpected

Thisissimplysomeofthedatathatwecreatedbeforehand.Let’sgoaheadandcreateanewto-doitem:

Yourto-dolistappshouldlookandworkasexpected

Nowgoaheadandsaveit.Youwillseethefollowingscreen:

Yourto-dolistappshouldlookandworkasexpected;creatingato-doitemworks

I’mjustgoingtogoaheadandeditthelatestto-doitem:

Editingato-doitemshouldworkasexpected

NowclickonSave.Youshouldseethelatestitemsavedasshowninthefollowingscreenshot:

Aftereditingandsavingtheto-doitem,theappworksasexpected

TestingourcodeonAndroidWeneedtomakesomechangesinordertotestourcodeonAndroid.Wealsoneedtomakechangestotheendpointthatwearecalling;http://localhost:8000willneedtobechangedtohttp://10.0.2.2.

ForthisAndroidversion,yourjs/services/todo.jswilllookasfollows:

angular.module('todoApp.services',[])

.config(function($httpProvider){

$httpProvider.defaults.useXDomain=true;

delete$httpProvider.defaults.headers.common['X-Requested-With'];

})

.factory('Todos',function($http){

return{

getAll:function(){

return$http.get('http://10.0.2.2:8000/todos');//ifusingandroid

//return$http.get('http://localhost:8000/todos');

},

getTodo:function(id){

return$http.get('http://10.0.2.2:8000/todos?id='+id);//ifusing

android

//return$http.get('http://localhost:8000/todos?id='+id);

},

save:function(todoData){

return$http.post('http://10.0.2.2:8000/todos',todoData);//if

usingandroid

//return$http.post('http://localhost:8000/todos',todoData);

},

edit:function(id,todoData){

return$http.post('http://10.0.2.2:8000/todos',todoData);//if

usingandroid

//return$http.post('http://localhost:8000/todos?id='+id,todoData);

},

delete:function(id){

console.log("idontthinkIhaveadeletehere.")

}

}

})

Noticethatwearecommentingoutthehttp://localhost:8000versionandusingthehttp://10.0.2.2version.

Next,wesimplynavigatetoourPhoneGapprojectphonegap/todoandissuethefollowingcommand:

cordovaemulateandroid

RemembertoturnonyourserverandMongoDBaswell.YoushouldseethefollowingscreenonyourAndroidemulator:

Onthefirstload,theto-doappshowsalistofitemswehaveinthedatabase

Thisissimplyjustsomeofthedatathatwehavecreatedbeforehand.Asyoucansee,theitemcreatedoniOSispresent.SoI’mjustgoingtogoaheadandcreateanothernewto-doitem:

Addinganewto-doitemtoyourAndroidapp

Let’sgoaheadandsaveit.Youshouldseethenewitemonourto-dolist.

Addinganewitemworksasexpected

Finally,I’mgoingtomakesomeeditstomakesurethatourcodeisworkingfine.ClickonEdit/DetailsfortheAndroiditemontheemulatorandstarteditingit:

Editingato-doitem

Onceyou’vesavedtheitem,youwillseethattheAndroiditemisnowedited.

SummaryThat’sit!Wewentthroughquiteabitofdetailinthischapter.BynowyoushouldseethatshiftinganAngularJSapptoPhoneGapisverystraightforward;allyouneedtodoisplaceyourfilesinthewww/folder.YoualsolearnedhowtocreateRESTfulappsontopofAnguarJSandtheTornadowebserver.

Inthenextchapter,wewillcoveradvanced-leveltopics,suchasoptimizingourAngularJSappfortouchdevices,usingPhoneGappluginssuchastheFacebookplugin,andhowtocreatedirectivesforourAngularJSapp.Seeyouthere.

Chapter4.AddingAuthenticationCapabilitiesUsingPhoneGapPluginsInthischapter,wewillbeaddingauthenticationcapabilitiestoourto-dolistapp.Tobespecific,wearegoingtoaddFacebookLogincapabilitiestoourapp.Wewillstartworkingontheweb-basedversionofourappbeforeportingthecodeovertothePhoneGapversion.InthePhoneGapversion,wewillbeleveragingonthePhoneGapplugininordertoachievewhatwehavedonefortheweb-basedversion.TheportingofcodewillbeslightlylessstraightforwardduetotherecentchangestoPhoneGap’sFacebookplugin.Sosittightandseehowwecanaddlogincapabilitiesinthischapter.

AddingFacebookConnecttotheto-dolistappAddingFacebookConnecttoourweb-basedversionoftheappisstraightforward.Youwillneedtosignupforanewapp(orusethecurrentone)fromhttps://developers.facebook.com/andtakenoteoftheappIDandapp’ssecretkey.Then,asusual,youwillneedtoinitiateyourappusingsomeFacebook-specificJavaScriptandlibrary“namely”Facebook’sJavaScriptSDK.

Incaseyouarewondering,theFacebookConnectpluginisusedtoperformFacebooklogininPhoneGapapps.

InitializingandpreparingforFacebookConnectLet’squicklydiveintothesourcecodeforindex.html:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"

>

<style>

body{

padding:40px20px020px;

}

</style>

</head>

<body>

<divid="fb-root"></div>

<scriptsrc="http://connect.facebook.net/en_US/all.js"></script>

<script>

FB.init({

appId:XXX',

xfbml:true,

version:'v1.0'

});

</script>

<h2>Todos</h2>

<divng-view></div>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-resource.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-route.min.js"></script>

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/controllers/user.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</body>

</html>

Takenoteofthefollowinghighlightedlinesofcode:

<divid="fb-root"></div>

<scriptsrc="http://connect.facebook.net/en_US/all.js"></script>

<script>

FB.init({

appId:'XXX',

xfbml:true,

version:'v1.0'

});

</script>

TheprecedingcodeisbasicallyFacebook-specificandisrequiredinorderforyoutouseFacebookLoginforyourwebapplication.YouwillneedtoreplaceXXXwithyourownappID,andmakesurethatthesiteURL(foundunderyourappsettingsonFacebookDevelopers)issettoyourloginlocation.

Next,wehave<scriptsrc="js/controllers/user.js"></script>.Thiswillbeasmallsnippetofcode,wherewewilladdthelogincapabilitiesforourapp.

WritingtheusercontrollerWe’llnowstartwiththecontrolleraspectoftheapp.Solet’sstartbycreatinganewfilecalleduser.jsinjs/controllers/user.js.Asusual,wewillneedtodefineangular.moduleandwearegoingtonamethiscontrollerUserLoginCtrl.WecansimplymakecallstoFacebookusingtheFBobject,whichwasinitiatedearlierinindex.html.Sohere’swhatyouruser.jsshouldlooklike:

angular.module('todoApp.userControllers',[])

.controller('UserLoginCtrl',function($scope,$rootScope,$http,

$location,Todos){

$scope.login=function(){

//sothisisfordesktoptesting

FB.login(function(response){

if(response.authResponse){

console.log('Welcome!Fetchingyourinformation….');

FB.api('/me',function(response){

console.log('Goodtoseeyou,'+response.name+'.');

$location.path('/');

if(!$scope.$$phase)$scope.$apply();

});

}else{

console.log('Usercancelledloginordidnotfullyauthorize.');

}

});

};

Themainfunctionhereis$scope.login,whichsimplywrapsaroundtheFB.logincallwhereweattempttologintheuser.TheAngularJS-specificstuffisfoundinthefollowingcode:

$location.path('/');

if(!$scope.$$phase)$scope.$apply();

Thismeansthatwewillredirecttheuserbacktotheindexpageafterhe/shehasloggedinsuccessfully.

NoteThe$apply()optionismeanttostarta$digestcycle.Agreattutorialthatexplainsthisoperationisavailableathttp://www.sitepoint.com/understanding-angulars-apply-digest/.

Nowyoumaybewonderingifthere’sanypagewherelogintakesplace.Yes,ofcourse,andthisisexactlywhatwearegoingtodointhenextsection.

AddingaloginpageWearegoingtocreateanewfilecalledlogin.html.Thisfilewillresideinthepartialsfolder,whereallHTMLsnippetsarefound.However,first,weneedtodefinetheroutewherethisHTMLpartialwillbeloaded.Solet’stakealookatapp.js:

angular.module('todoApp',[

'ngRoute',

'todoApp.controllers',

'todoApp.userControllers',

'todoApp.services'

])

.config(function($routeProvider){

$routeProvider

.when('/',{

controller:'ListCtrl',

templateUrl:'partials/list.html'

})

.when('/edit/:id',{

controller:'EditCtrl',

templateUrl:'partials/detail.html'

})

.when('/new',{

controller:'CreateCtrl',

templateUrl:'partials/detail.html'

})

.when('/login',{

controller:'UserLoginCtrl',

templateUrl:'partials/login.html'

})

.otherwise({

redirectTo:'/'

});

})

Therearetwohighlightedpartsinourcode,todoApp.userControllers,whichmeansthatweareloadingthiscontrollersoitcanbeusedinourapp.

Thesecondinstanceisthefollowingcode:

.when('/login',{

controller:'UserLoginCtrl',

templateUrl:'partials/login.html'

})

Theprecedingcodemeansthatwhentherouteis/login,wewillbeusingUserLoginCtrlandlogin.html.NowthatwehavedefinedtherouteandcodedUserLoginCtrl,it’stimetoworkonlogin.html.Thelogin.htmlfileissimpleandstraightforward;itcontainsatitleandLoginbutton:

<h3>Pleaselogin</h3>

<buttonng-click="login()">Login</button>

Yup,that’sright,simpleandstraightforward.Soifyousaveyourfilesandvisityourappat

/login,youwillgetthefollowingscreenshot:

LoginScreen

Sorightnow,wecantryoutbyclickingonLogin.Ifeverythingworkscorrectly,youwillberedirectedbacktoyourindexpage.ThispagewillshowyouacompletelistofTodos,asshowninthefollowingscreenshot:

ListofTodos

Alright,prettycoolyeah?However,wearemissingoutsomestuff.Forexample,whathappensiftheuserwantstologout?Orwhathappenswhentheusergoesstraighttotheindexpagewithoutlogginginfirst?Wewilldealwiththatinthenexttwosections.

AddingalogoutfunctionPerformthefollowingstepstoaddalogoutfunction:

1. Toaddalogoutfunctionality,wewillfirstneedtohavealogoutbutton.So,wecanaddthisfunctionalityintheindexpagebyplacingthelogoutbuttoninpartials/list.html:

<buttonng-click="logout()"style="float:right">Logout</button>

<span>{{remaining()}}of{{todos.length}}remaining</span>

<table>

<thead>

<tr>

<th>Todo</th>

<th>Done</th>

<th>Details</th>

<th><ahref="#/new"><iclass="icon-plus-sign">NEW</i></a></th>

</tr>

</thead>

<tbody>

<trng-repeat="todointodos">

<td>{{todo.text}}</td>

<td><inputtype="checkbox"ng-model="todo.done"value="todo._id">

</td>

<td>

<ahref="#/edit/{{todo._id}}"><iclass="icon-

pencil">Edit/Details</i></a>

</td>

</tr>

</tbody>

</table>

2. Theentirepartials/list.htmlfileisthesameasbefore,exceptforthehighlightedlinewherethelogoutbuttonisadded.

3. Next,sincethelogoutbuttonisfoundinpartials/list.html,thismeansthatweneedtoaddafunctiontologoutoftodo.js.Now,goingtocontrollers/todo.js,prependthe$scope.logoutfunctionjustbeforeTodos.getAll():

$scope.logout=function(){

alert('loggingout')

//thisisthedesktopversion

FB.logout(function(response){

alert('loggedout');

$location.path('/login');

if(!$scope.$$phase)$scope.$apply();

});

}

Todos.getAll().success(function(data){

$rootScope.todos=data['todos'];

})

4. Thehighlightedlinesofcodearethelinesofcodethatwillbehandlingthelogout.So

basically,whathappensisthatonclickingtheLogoutbutton,youwillseeanalertboxthatsaysloggedout,afterwhichyouwillberedirectedtotheloginpage.

5. Saveyourfilesandrefreshyourbrowser.Youshouldseethefollowingscreenshot:

ListoftodoswiththeLogoutbutton

6. NoticethatwehaveaLogoutbuttontotherightofthepage.Nowclickonitandyoushouldseethefollowingscreenshot,ifeverythingisworkingcorrectly:

7. AfterclickingonOK,youwillberedirectedbacktotheloginpage.

Now,let’smoveontothelastrequirement,whichischeckingfortheloginstatus.

CheckingtheloginstatusCheckingoftheloginstatuswillbedoneintheindexpage,forsimplicity.Soweneedtoaddafunctionincontrollers/todo.js.Weneedtoprependthefunctionsusedinthefollowingcode,beforethe$scope.logoutfunctionthatweaddedintheprevioussection:

$scope.checkLogin=function(){

FB.getLoginStatus(function(response){

if(response.status=='connected'){

//alert('loggedin');

console.log("loggedinbro");

}

else{

//alert('notloggedin');

$location.path('/login');

if(!$scope.$$phase)$scope.$apply();

}

});

}

$scope.checkLogin();

Nowsavethefileandrefreshyourbrowser.Ifyouarestillloggedout,youshouldberedirectedtothe/loginpage,whereyouwillbeaskedtologin.Forexample,asIamstillloggedoutfromtheprevioussection,Iamredirectedtotheloginpage.AfterclickingontheLoginbutton,Iampromptedtologin,asshowninthefollowingscreenshot:

FacebookLogin

Afterenteringmycredentials,Iamloggedinsuccessfully.Feelfreetotryoutotherfunctionalitiesthatwehavecodedintheprevioussection,justtomakesurethatthingsareworkingasexpected.

Ifeverythingisgoodtogo,it’stimetomoveonandportourcodetoPhoneGap.Itwillbeslightlydifferentfromwhatwehavedoneintheprevioussections,astherearesomeextrastepsandprecautionsthatwehavetotake.Youmightwanttotakeashortbreakbeforecontinuingtothenextsection.

FacebookloginforPhoneGapPhoneGaphasgonethroughquiteabitofchangesnotonlyforthemainlibrary,butalsothepluginsystem.Inthissection,youwillseethatwecanquicklyinstallPhoneGappluginsusingthecommand-linetool,withouttheusualmultiplestepsthatwehavetofollowifwewanttoinstallitmanually.

InstallingtheFacebookpluginSincewehavealreadyaddediOSandAndroidplatforms,thisplugininstallationwilladdpluginsforbothiOSandAndroid.ToinstalltheFacebookplugin,youwillneedtonavigatetoyourtodoappproject.Next,issuethefollowingcommand:

cordovapluginadd

https://github.com/phonegap/phonegap-facebook-plugin,--variable

APP_ID="XXXXX"--variableAPP_NAME="AngularPhoneGapTest".

YouwillneedtoreplaceXXXXwithyourappIDandyoucannameyourapp_nameappanynameyouwant.

Theinstallationprocessisnowcomplete.ForAndroid,youwillneedthreemoresteps:

1. ImportyourtodoappintoyourEclipsedevelopmentenvironmentasanAndroidproject.

2. WhilestillinyourEclipseeditor,intheleft-handcolumnwhereallyourprojectsarelisted,rightclickonProperties.

3. MakesurethatyouimportFacebookLibandCordovaLibundertheLibrarysection(atthebottomofthenextscreenshot):

Oncethisisdone,wehavecompletedinstallationforbothiOSandAndroid.Now,it’stimetotestthecode.MostoftheexamplesrunoniOS,butbearinmindthatthesamepieceofcodewillrunproperlyandcorrectlyonAndroidaswell.

TestingoutFacebookLoginonPhoneGapInordertotestifourFacebookLoginpluginisinstalledcorrectlyonPhoneGap,weneedtowriteasimpleexamplejusttoseeiftheappisworkingcorrectly.TherearemanyexamplesoutthereontheInternet,butI’vewrittenasimpleoneherethatshouldquicklyshowifourappisworking.Atthesametime,youwillalsoseethatcallingtheFBSDKisalsoslightlydifferent.Let’sjumpstraightintothecodebywritinganewindex.htmlpageforourPhoneGapapp:

<!DOCTYPEhtml>

<html>

<head>

</head>

<body>

<buttononclick="login()">Login</button>

<divid="data">loading…</div>

<divid="fb-root"></div>

<!--cordova-->

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

<!--cordovafacebookplugin-->

<scriptsrc="cdv-plugin-fb-connect.js"></script>

<!--facebookjssdk-->

<scriptsrc="facebook-js-sdk.js"></script>

<script>

if((typeofcordova=='undefined')&&(typeofCordova=='undefined'))

alert('Cordovavariabledoesnotexist.Checkthatyouhaveincluded

cordova.jscorrectly');

if(typeofCDV=='undefined')alert('CDVvariabledoesnotexist.

Checkthatyouhaveincludedcdv-plugin-fb-connect.jscorrectly');

if(typeofFB=='undefined')alert('FBvariabledoesnotexist.Check

thatyouhaveincludedtheFacebookJSSDKfile.');

FB.Event.subscribe('auth.login',function(response){

alert('auth.loginevent');

});

FB.Event.subscribe('auth.logout',function(response){

alert('auth.logoutevent');

});

FB.Event.subscribe('auth.sessionChange',function(response){

alert('auth.sessionChangeevent');

});

FB.Event.subscribe('auth.statusChange',function(response){

alert('auth.statusChangeevent');

});

varfbLoginSuccess=function(userData){

alert("UserInfo:"+JSON.stringify(userData));

}

functionlogin(){

facebookConnectPlugin.login(["basic_info"],

fbLoginSuccess,

function(error){alert(""+error)}

);

}

document.addEventListener('deviceready',function(){

try{

alert('Deviceisready!Makesureyousetyourapp_idbelowthis

alert.');

FB.init({appId:"XXXX",nativeInterface:CDV.FB,useCachedDialogs:

false});

document.getElementById('data').innerHTML="";

}catch(e){

alert(e);

}

},false);

</script>

<divid="log"></div>

</body>

</html>

Theprecedingcodeissomewhatsimilartotheofficialexamples,butwiththreesubtledifferences,asshownbythehighlightedlines:

<buttononclick="login()">Login</button>

Weareonlyfocusedonlogin()here,sowewillremovetheremainingfunctionalitiessuchaspostingtothewallandsoon

Thesecondsectionofthecodeisasfollows:

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

<!--cordovafacebookplugin-->

<scriptsrc="cdv-plugin-fb-connect.js"></script>

<!--facebookjssdk-->

<scriptsrc="facebook-js-sdk.js"></script>

WearestillrequiredtoinstallallPhoneGap-relatedfiles,includingthoserelatedtotheFacebookplugins

Thethirdandmostimportantsectionisasfollows:

varfbLoginSuccess=function(userData){

alert("UserInfo:"+JSON.stringify(userData));

}

functionlogin(){

facebookConnectPlugin.login(["basic_info"],

fbLoginSuccess,

function(error){alert(""+error)}

);

}

NoticethatwearemakingalogincalltoFacebookusingfacebookConnectPlugin.logininsteadofFB.login.ThisisduetothemajorchangeinpluginsbythePhoneGapteam.

WhenweareportingourcodetoPhoneGapfromthewebversion,ourFacebookcallswillbechangedtoreflectthis.Fornow,followonwiththissection.Oncethecodeiswritten,savethefileandruntheiOSemulator.Issuethefollowingcommand:

cordovaemulateios

YouwillthenseeyouriOSemulatorgetfiredup,andyouwillbegreetedwiththefollowingscreenshot:

Onenteringtheapp

AfterclickingonOK,youwillseethattheloading…messagehasvanished.Next,youcanclickonLoginandyouwillbepresentedwithFacebook’sloginpage:

FacebookLoginScreen

Sincewehavealreadyauthorizedtheapp,there’snoneedtologinorauthorizetheappagain.ClickonOKandyoushouldseeanewscreenwithanalertboxshowingaJSONrepresentationofyourdata:

Ifyougetthepreviousscreenshot,thismeansthateverythingyouhavedonetillnowisrightandshouldworkwellforAndroidtoo.Ifso,timetoportourweb-basedversionofthecodetothePhoneGapversion.

FromwebtoPhoneGapIfyouremember,intheprevioussection,IbrieflymentionedthatmakingcallstoFacebookusingtheJavaScriptSDKisnowslightlydifferentinPhoneGap,comparedtotheweb-basedversion.InsteadofasimplisticFB.login()callinthewebversion,weneedtomakeafacebookConnectPlugin.login()callinthePhoneGapversion.Inthissection,we’lltakecarefulstepstoportourcodefromtheweb-basedversiontoaPhoneGapversion.

ImportingFacebookandPhoneGappluginsFirst,weneedtoimportFacebook-andPhoneGap-relatedplugins.WealsoneedtoslightlychangehowweinitiatetheFBobject.Sogoingbacktoyourindex.htmlfile,here’swhatyouneedtodo:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"

>

<style>

body{

padding:40px20px020px;

}

</style>

</head>

<body>

<divid="fb-root"></div>

<h2>Todos</h2>

<divng-view></div>

<!--thisisforphonegap-->

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

<!--cordovafacebookplugin-->

<scriptsrc="cdv-plugin-fb-connect.js"></script>

<!--facebookjssdk-->

<scriptsrc="facebook-js-sdk.js"></script>

<script>

document.addEventListener('deviceready',function(){

try{

alert('Deviceisready!Makesureyousetyourapp_idbelowthis

alert.');

FB.init({appId:"135542699836039",nativeInterface:CDV.FB,

useCachedDialogs:false});

}catch(e){

alert(e);

}

},false);

</script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-resource.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-route.min.js"></script>

<!--

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-touch.min.js"></script>

-->

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/controllers/user.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</body>

</html>

Youwillfirstneedtoimportcordova.js,cdv-plugin-fb-connect.js,andfaceboo-js-sdk.jsasshownhere:

<!--thisisforphonegap-->

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

<!--cordovafacebookplugin-->

<scriptsrc="cdv-plugin-fb-connect.js"></script>

<!--facebookjssdk-->

<scriptsrc="facebook-js-sdk.js"></script>

Next,weinitiatetheFBobjectbywaitingforthedevicereadyeventspecifictoPhoneGap:

<script>

document.addEventListener('deviceready',function(){

try{

alert('Deviceisready!Makesureyousetyourapp_idbelowthis

alert.');

FB.init({appId:"XXXXX",nativeInterface:CDV.FB,useCachedDialogs:

false});

}catch(e){

alert(e);

}

},false);

</script>

Asusual,remembertoreplacetheXXXXXwithyourownappIDfromFacebooksothatyourloginredirectscorrectly,andhastherightcredentials.

ChangingFBtofacebookConnectPluginThenextthingthatweneedtodoischangeFBtofacebookConnectPlugin.Wewillstartwithcontroller/user.js.Thecodeshouldlooklikethefollowing,afterthechange:

angular.module('todoApp.userControllers',[])

.controller('UserLoginCtrl',function($scope,$rootScope,$http,

$location,Todos){

$scope.login=function(){

//placewheretheuserjustclickandlogin

varfbLoginSuccess=function(userData){

alert("UserInfo:"+JSON.stringify(userData));

$location.path('/');

if(!$scope.$$phase)$scope.$apply();

}

//thisisusedforPhoneGaPver

facebookConnectPlugin.login(["basic_info"],

fbLoginSuccess,

function(error){alert(""+error)}

);

};

})

WehaveanewvariablenamedfbLoginSuccess,whichiscalledaftertheuserlogsinsuccessfully.Next,wehavefacebookConnectPlugin.login,whichmakesacalltologintoFacebookviaPhoneGap’splugin.

Next,weneedtoworkoncontroller.js.Thetwofunctionsthatyouneedtochangeare$scope.checkLoginand$scope.logout.WesimplyreplaceFBwithfacebookConnectPlugin.Sohere’swhatthecodelookslikenow:

$scope.checkLogin=function(){

facebookConnectPlugin.getLoginStatus(function(response){

alert(response);

if(response.status=='connected'){

//alert('loggedin');

console.log("loggedinbro");

$location.path('/');

if(!$scope.$$phase)$scope.$apply();

}

else{

//alert('notloggedin');

$location.path('/login');

if(!$scope.$$phase)$scope.$apply();

}

});

}

$scope.logout=function(){

alert('loggingout')

//thisisthePhoneGapversion

facebookConnectPlugin.logout(function(response){

alert('loggedout');

$location.path('/login');

if(!$scope.$$phase)$scope.$apply();

});

}

Nowthatwehavemadetherequiredchanges,it’stimethatwetestthefunctionalities.

Theto-dolistappwithFacebookLoginonPhoneGapAsusual,weneedtorunourcodeusingPhoneGap’scommand-lineinterface.Sotochangeyourcurrentdirectorybacktothetodolistapp,issuethefollowingcommand:

cordovabuildios

cordovaemulateios

Onceyouhaveissuedthecommand,youshouldseeyouriOSemulatorfiredup.Next,youwillseethefollowingscreenshot:

OnEnteringtheApp

Aswearestillloggedinfromtheprevioussections,wegettoseeourto-dolistitemsevenafterclickingonOK.Atthispoint,ifyouarestillloggedin,feelfreetoclickonLogout,afterwhichyoushouldseethefollowingscreenshot:

LoginScreen

Asusual,youcanloginandbegreetedbythepreviousscreenshot.AfterclickingonOK,youcanstarttoplayaroundwithyourapp.

Successfullogin

Feelfreetoaddnewitems,editthem,andloginandoutjusttoseeifthecodeisworkingcorrectly.Ifallgoeswell,congratulations!YounowhaveaworkingPhoneGapappmakingRESTfulcallscoupledwithFacebookLogincapabilities.

SummaryTosummarize,weworkedourwayfromaverysimpleAngularJSapptoonewhichcanmakeRESTfulcallscoupledwithFacebookLogincapabilities.Ateachstage,wealsoportedthecodetoPhoneGapandmadesureitworks.Theimportanttakeawayhere,isthatusingacommand-lineinterfacecandrasticallyreducethenumberofstepsrequiredtosetupourPhoneGapproject.Inthenextchapter,wewillbeworkingonanimations;variousanimationtechniqueswillbeusedforourPhoneGapapp.

Chapter5.SprucingUptheAppUsingAnimationsandMobileDesignWelcometothischapter!Inthischapter,wewillspruceupourappusinganimationandstylesthatmimicthemobileuserinterface.Thiswillbeashortyetusefulchapter.Asusual,thecodeshowninthischaptercanbeappliedacrossiOSandAndroidapps.

Inthischapter,we’lllearnabout:

PerforminganimationsusingngAnimatePitfallstoavoidwhenperforminganimationsinPhoneGap

AddinganimationstoyourwebappAddinganimationsissurprisinglyeasyusingAngularJS.ThengAnimatemoduleofAngularJSwilltakeuserstherewithCSSanimations.

We’llstartbyaddinganimationtoourwebappbeforeportingitovertoPhoneGap.Todothis,headbacktoyourweb-basedversionofthecodeandopenindex.html.Therearethreechangesthatyouneedtomake:

1. Addanewindex.cssfile.2. Addclass="todos"inyour<divng-view></div>.3. Add<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-animate.min.js"></script>tothelistofimportedJavaScript.4. Theendresultofyourcodeinindex.htmlshouldlooklikethis:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.

css">

<linkrel="stylesheet"href="css/index.css">

<style>

body{

padding:40px20px020px;

}

</style>

</head>

<body>

<divid="fb-root"></div>

<scriptsrc="http://connect.facebook.net/en_US/all.js"></script>

<script>

FB.init({

appId:'XXXXX',

xfbml:true,

version:'v1.0'

});

</script>

<h2>Todos</h2>

<divng-viewclass="todos"></div>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-resource.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-route.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-animate.min.js"></script>

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/controllers/user.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</body>

</html>

Thehighlightedlinesofcodearetheonesthatyouneedtoaddtoindex.html.Youmayhavenoticedthatwehavenotcreatedindex.css;that’swhatwearegoingtodorightnow:

1. Openyoureditor,createanewfileinthecssfolder,andnameitindex.css.Wearegoingtocreatetheinitialstateoftodosanddefinehowtheanimationwilllook.Ourgoalistomakeourappslideinfromtheleftoninitialization.ClickingonEdit/DetailsorNewshouldshiftittowardstheright.ByclickingonCancel,thescreenshouldshiftleftwards.Ourindex.cssfileshouldlooklikethefollowing:

.todos{

position:absolute;

background:coral;

display:block;

width:90%;

border-left:1pxsolidblack;

}

.todos.ng-enter,.todos.ng-leave{

transition:500msease-inall;

}

.todos.ng-enter.ng-enter-active,.todos.ng-leave{

left:0;

}

.todos.ng-leave.ng-leave-active,.todos.ng-enter{

left:200%;

}

The.todosclasssimplydefinestheinitialstateofthetodosclass.Next,wehave.todos.ng-enterand.todos.ng-leave,wherewedefineatransitiontimeof500msandanease-ineffect.

2. Nextcomesthefunpart..todos.ng-enter.ng-enter-active,.todos.ng-leaveisdefinedasleft:0,whichmeansthatonenteringanewroute,thepartialinquestionwillshiftinfromrighttolefttillthedistancefromtheleftsideoftheparentdivis0px.

3. Similarly,onleaving,itisdefinedby.todos.ng-leave.ng-leave-active,.todos.ng-enteratleft:200%.

Sowhatarewedoinghere?Ifyounoticed,wefirstdefined<divng-view>withclass="todos",andthenweattachedAngularJSspecificanimationsbyusingng-enter,ng-leave,ng-enter-active,andng-leave-active.Thesearethefourbasicstatesthatyoucandefineforananimation.

4. Nowsavethefileandopenindex.htmlonyourfavoritewebbrowser.PleaseremembertorunyourserverandtheMongoDBserverinorderforthisapptowork.Youshouldbegreetedwiththefollowingscreen:

TheTodoslistapp

5. ClickonNEWorEdit/Detailsandyoushouldseeanimationsshiftinginfromrightorleft,dependingonwhetheryoucanceltheactionornot.Forinstance,youcanclickonEdit/Detailsfirstandmakesurethatyouaremovingtowardstherightwithanewscreenasfollows:

Makingchangestoouritemsandshouldworkasexpectedwithanimationeffects

6. IfyouclickonCancel,youwillseeyourscreenshiftleftwards,whichisadirectionthatyouwouldexpect.

Assoonasyougettheprecedingresult,youknowthatallisworkingright.It’stimetoaddinCSSstylesthatmimictheusualmobileuserinterface.

AddingmobileCSSstylestoyourappInordertofurtherspruceupourapp,wewillbeleveragingontheCSSlibrariesofTopCoat.YoucangetTopCoatCSSlibrariesfromhttp://topcoat.io/.Wealsoneedtochangeourindex.htmlfileabitmoreinordertoleverageonthestylesprovidedbyTopCoat.

1. Forastart,replacethestylesheetwhichpointstoBootstrapCDNwiththefollowingcode:

<linkrel="stylesheet"

href="//cdnjs.cloudflare.com/ajax/libs/topcoat/0.8.0/css/topcoat-

mobile-light.css">

2. Afterthis,justbefore<divng-viewclass="todos"></div>,prependthefollowingcode:

<divclass="topcoat-navigation-bar">

<divclass="topcoat-navigation-bar__itemcenterfull">

<h1class="topcoat-navigation-bar__title">Todos</h1>

</div>

</div>

Thisistogiveauniversalheaderthatwecommonlyseeinmobileapps.

Afterthesechanges,yourindex.htmlfileshouldlooklikethis:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="//cdnjs.cloudflare.com/ajax/libs/topcoat/0.8.0/css/topcoat-

mobile-light.css">

<linkrel="stylesheet"href="css/index.css">

</head>

<body>

<divid="fb-root"></div>

<scriptsrc="http://connect.facebook.net/en_US/all.js"></script>

<script>

FB.init({

appId:'XXX',

xfbml:true,

version:'v1.0'

});

</script>

<divclass="topcoat-navigation-bar">

<divclass="topcoat-navigation-bar__itemcenterfull">

<h1class="topcoat-navigation-bar__title">Todos</h1>

</div>

</div>

<divng-viewclass="todos"></div>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-resource.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-route.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-animate.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/

angularjs/1.3.0-beta.7/angular-touch.min.js"></script>

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/controllers/user.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</body>

</html>

3. There’sstillonemorethingweneedtochange,andthatisthelistingoftodos.So,inpartials/list.html,weneedtochangethestylisticelementssothatitappearscorrectlywhenshownonamobiledevice.WearesimplyapplyingTopCoatCSSclasseshere:

<divclass="topcoat-list__containerscroller">

<astyle="padding-left:10px"href="#/new"><iclass="icon-plus-

sign">NEW</i></a>

<spanstyle="padding-left:10px">

{{remaining()}}of{{todos.length}}remaining

</span>

<buttonng-click="logout()"

style="position:absolute;right:10px;">Logout</button>

<ulclass="topcoat-listlist">

<ling-repeat="todointodos"class="topcoat-list__item">

<astyle="display:block;padding-left:10px"

href="#/edit/{{todo._id}}">{{todo.text}}</a>

</li>

</ul>

</div>>

4. Thenextandthefinalstepbeforewetestourapponthebrowseristoremovecertainpartsofindex.csssothatourself-definedstylesdonotgetconfusedwithTopCoatCSSstyles.

5. Inyourindex.cssfile,lookfor.todosandremovebackground:coralandborder-left:1pxsolidblack.So,yourfinalindex.cssfileshouldlooklikethis:

.todos{

position:absolute;

display:block;

width:100%;

}

.todos.ng-enter,.todos.ng-leave{

transition:500msease-inall;

}

.todos.ng-enter.ng-enter-active,.todos.ng-leave{

left:0;

}

.todos.ng-leave.ng-leave-active,.todos.ng-enter{

left:200%;

}

6. Now,openyournewindex.htmlfileinyourbrowser.Youshouldseesomethinglikethefollowingscreenshot:

Amobileappwithuniversalheader

Onceyouhavethisresult,youmightwanttoplayaroundwithittoseeifitisworkingoutasexpected.

PortingyourwebapptoPhoneGapNowweareatthefinalstep,whichisportingourapptoPhoneGap.Thestepsareverysimilartothepreviouschapters:weneedtoincludetherequiredPhoneGapandFacebookplugins.Mostimportantly,weneedtoincludethengTouchmoduleofAngularJS.Here’showourindex.htmlfileshouldlookforourPhoneGap’sversion:

<!doctypehtml>

<htmlng-app="todoApp">

<head>

<linkrel="stylesheet"

href="http://cdnjs.cloudflare.com/ajax/libs/topcoat/0.8.0/css/topcoat-

mobile-light.css">

<linkrel="stylesheet"href="css/index.css">

</head>

<body>

<divid="fb-root"></div>

<divclass="topcoat-navigation-bar">

<divclass="topcoat-navigation-bar__itemcenterfull">

<h1class="topcoat-navigation-bar__title">Todos</h1>

</div>

</div>

<divng-viewclass="todos"></div>

<!--thisisforphonegap-->

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

<!--cordovafacebookplugin-->

<scriptsrc="cdv-plugin-fb-connect.js"></script>

<!--facebookjssdk-->

<scriptsrc="facebook-js-sdk.js"></script>

<script>

document.addEventListener('deviceready',function(){

try{

alert('Deviceisready!Makesureyousetyourapp_idbelowthis

alert.');

FB.init({appId:"XXXX",nativeInterface:CDV.FB,useCachedDialogs:

false});

}catch(e){

alert(e);

}

},false);

</script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-resource.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-route.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-animate.min.js"></script>

<scriptsrc="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-

beta.7/angular-touch.min.js"></script>

<scriptsrc="js/controllers/todo.js"></script>

<scriptsrc="js/controllers/user.js"></script>

<scriptsrc="js/services/todo.js"></script>

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

</body>

</html>

It’sgenerallythefinalversionaspertheprevioussection;buttheinitializationforPhoneGapandFacebookisincludedinthisversion.Asusual,remembertouseyourownappIDforthisfile.

WealsoneedtoconvertourcontrollerstousethePhoneGapversionforFacebookAPIcallsthatwepreviouslycodedfor.Inthesourcecodeprovidedwiththisbook,youwillseethattherearetwocodeblocksforeachofthefunctions:oneforthedesktop/webversionandtheotherisforthePhoneGapversion.

AsmentionedinChapter4,AddingAuthenticationCapabilitiesUsingPhoneGapPlugins,thePhoneGapversionconnectstoFacebookusingthefacebookConnectPluginnamespaceinsteadoftheusualFBnamespace(comparedtopreviousversions).

TestingyourapponiOSTotestyourapponiOS,runthefollowingcommandsfromtherootofyourapp’sdirectory:

cordovabuildios

cordovaemulateios

YoushouldseethefollowingoutputinyouriOSemulator:

Theto-dolistapponiOS

Inmycase,Ihavesomeitemsleftinmydatabaseandhencethat’swhatIgotinmyemulator.Feelfreetoclickaround,addnewitems,editthem,orloginandout.Itshouldworkasexpected,withanimationsbuiltin.

TestingyourapponAndroidNowthatwehavetestedoniOS,it’stimetogetyourapptestedonAndroidaswell.NotethatsinceAndroidreadsthehttp://localhostaddressdifferently,youwillneedtochangehttp://localhost:8000tohttp://10.0.2.2:8000atservices/todo.jsinorderforthecodetowork.

Also,remembertochangeyourfacebookConnectPluginnamespacetotheusualFBnamespaceinorderfortheFacebookConnectplugintowork.

Oncethatisdone,youshouldissuethefollowingcommand:

cordovabuildandroid

cordovaemulateandroid

Yourappshouldbeworkingasexpected.

SummaryTosumup,wecreatedanimationsforourappandalsomadeuseofTopCoatCSSskinstogiveourappamobilelook.Therearemanyotherareasthatwecanimproveon,suchasit’sdesignorevenuseotherframeworkssuchastheIonicframework;noticethatwedidnotmakeuseofthepopularjQueryMobile,sincewewantedtomakeuseofAngularJSasmuchaspossible.Mostimportantly,bynowyoushouldseethatthecodebasesforbothiOSandAndroidarealmostthesame,withtheexceptionofchangingtheURLofourserver’slocation.Inthenextandfinalchapter,youwilllearnaboutdistributingandgettingreadytolaunchourmobileapps.

Chapter6.GettingReadytoLaunchInthisfinalchapter,wewillrunthroughsomeofthestuffthatyoushouldbedoingbeforelaunchingyourapptotheworld,whetherit’sthroughAppleAppStoreorGoogleAndroidPlayStore.

Wewillbecoveringthefollowingtopics:

TestingyourapponyourdeviceforrealHowtochangetheartworkforyourappDeployingserver.py

Wewillalsodiscussotherusefultipsbeforeyoulaunchtheappintherealworld,andwe’llstartbylaunchingserver.py.

Deployingserver.pyTodeployserver.py,youwillneedaccesstoanactualserver.ItcanberentedfromAmazonEC2,Linode,orDigitalOcean.TheoperationsystemIamusinghereisUbuntu12.04,althougholdervariantsofUbuntucanworktoo,whichinclude10.04and11.04.SincetheserverisessentiallyaTornadoapp,youwillneedtoprependsudotoeverycommandthatfollowsinthissection,ifyouarenotrunningitasroot.

1. Tostartoff,youwillneedtoputSSHintoyourserverandstartinstallingtherequiredtoolsanddependencies:

apt-getinstallpython-setuptools

easy_installpip

pipinstalltornado

2. YouwillalsoneedtoinstallMongoDB:

sudoapt-keyadv--keyserverhkp://keyserver.ubuntu.com:80--recv

7F0CEB10

echo'debhttp://downloads-distro.mongodb.org/repo/ubuntu-upstartdist

10gen'|sudotee/etc/apt/sources.list.d/mongodb.list

3. Reloadthelocalpackagedatabase:

apt-getupdate

4. InstalltheMongoDBpackages:

apt-getinstallmongodb-org

ForthelatestinstructionsoninstallingMongoDB,refertohttp://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/.

5. Next,makeadirectoryforyoutohostyourapp:

mkdir/srv/www/

mkdir/srv/www/app_name

6. Now,youcansimplycreateafilecalledserver.pyunder/srv/www/app_nameandcopythecontentsofserver.py,whichwecodedintheprevioussections.However,beforewerunserver.pyweneedtoinstallonemorepackage:

pipinstalltornado-cors

7. Nowthatyouhaveinstalledourrequiredpackages,youcanruntheserverbyissuingthefollowingcommand:

pythonserver.py–host=80

8. Tocheckiftheserverisworking,gotohttp://XXX.XX.XX/todosandseeifyougetanemptylist.YourservershouldalsoshowaGETresponse.

Atthispoint,shouldyouwanttotestyourwebapporPhoneGapversionoftheapp,you

havetoupdatejs/services/todo.jssothattheURLsreflectthenewIPaddressordomainnameoftheapp.

Thereareotherwaystosetupserver.py,suchasusingnginxandsupervisor.Formoredetails,feelfreetocheckouttheguidesprovidedbyDigitalOcean(https://www.digitalocean.com/)andLinode(https://www.linode.com/)formoredetails.

Nowthatwearedonewithserver.py,it’stimetomoveontotheapps.

Usingphonegap.comTheservicesonhttps://build.phonegap.com/areastraightforwardwayforyoutogetyourappcompiledforvariousdevices.Whilethisisapaidservice,thereisafreeplanifyouonlyhaveoneappthatyouwanttoworkon.Thiswouldbefineinourcase,forthischapter.

ChooseaplanfromPhoneGap

YouwillneedtohaveanAdobeIDinordertousePhoneGapservices.Ifnot,feelfreetocreateone.SincetheprocessforgeneratingcompiledappsfromPhoneGapmaychange,it’sthatyouvisithttps://build.phonegap.com/andsignupfortheirservicesandfollowtheirinstructions.

PreparingyourPhoneGapappforanAndroidreleaseThissectiongenerallyfocusesonthingsthatarespecificfortheAndroidplatform.Thisisbynomeansacomprehensivechecklist,butsomeofthecommontasksthatyoushouldgothroughbeforereleasingyourapptotheAndroidworld.

TestingyourapponrealdevicesFormostofthisbook,wetestedourappontheAndroidemulator.Itisalwaysgoodtorunyourapponanactualhandsettoseehowtheappisworking.TorunyourPhoneGapapponarealdevice,issuethefollowingcommandafteryouplugyourhandsetintoyourcomputer:

cordovarunandroid

Youwillseethatyourappnowrunsonyourhandset.

ExportingyourapptoinstallonotherdevicesIntheprevioussectionwetalkedaboutinstallingyourapponyourdevice.WhatifyouwanttoexporttheAPKsothatyoucantesttheapponotherdevices?Here’swhatyoucando:

Asusual,buildyourappusingcordovabuildandroidAlternatively,ifyoucan,runcordovabuildrelease

ThepreviousstepwillcreateanunsignedreleaseAPKat/path_to_your_project/platforms/android/ant-build.ThisappiscalledYourAppName-release-unsigned.apk.

Now,youcansimplycopyYourAppName-release-unsigned.apkandinstallitonanyandroidbaseddeviceyouwant.

PreparingpromotionalartworkforreleaseIngeneral,youwillneedtoincludescreenshotsofyourappforuploadtoGooglePlay.Incaseyourdevicedoesnotallowyoutotakescreenshots,here’swhatyoucando:

Thefirsttechniquethatyoucanuseistosimplyrunyourappintheemulatorandtakescreenshotsoffit.Thesizeofthescreenshotmaybesubstantiallylarger,soyoucancropitusingGIMPorsomeotheronlineimageresizer.Alternatively,usethewebappversionandopenitinyourGoogleChromeBrowser.Resizeyourbrowserwindowsothatitisnarrowenoughtoresemblethewidthofmobiledevices.

BuildingyourappforreleaseTobuildyourappforrelease,youwillneedEclipseIDE.

1. TostartyourEclipseIDE,navigatetoFile|New|Project.2. Next,navigatetoExistingCode|Android|AndroidProject.3. ClickonBrowseandselecttherootdirectoryofyourapp.TheProjecttoImport

windowshouldshowplatforms/android.4. Now,selectCopyprojectsintoworkspaceifyouwantandthenclickonFinish.

SigningtheappWehavepreviouslyexportedtheapp(unsigned)sothatwecantestitondevicesotherthanthosepluggedintoourcomputer.However,toreleaseyourapptothePlayStore,youneedtosignthemwithkeys.Thestepsherearethegeneralstepsthatyouneedtofollowinordertogenerate“signed”APKappstouploadyourapptothePlayStore.

1. Right-clickontheprojectthatyouhaveimportedintheprevioussection,andthennavigatetoAndroidTools|ExportSignedApplicationPackage.YouwillseetheProjectChecksdialog.

2. IntheProjectChecksdialog,youwillseeifyourprojecthasanyerrorsornot.3. Next,youshouldseetheKeystoreselectiondialog.Youwillnowcreatethekey

usingtheappname(withoutspace)andtheextension.keystore.Sincethisappisthefirstversion,thereisnopriororiginalnametouse.Now,youcanbrowsetothelocationandsavethekeystore,andinthesamebox,givethenameofthekeystore.IntheKeystoreelectiondialog,addyourdesiredpasswordtwiceandclickonNext.YouwillnowseetheKeyCreationdialog.

4. IntheKeyCreationdialog,useapp_nameasyouralias(withoutanyspaces)andgivethepasswordofyourkeystore.Feelfreetoenter50forvalidity(whichmeansthepasswordisvalidfor50years).Theremainingfieldssuchasnames,organization,andsoonareprettystraightforward,soyoucanjustgoaheadandfillthemin.

5. Finally,selecttheDestinationAPKfile,whichisthelocationtowhichyouwillexportyour.apkfile.

Bearinmindthattheprecedingstepsarenotacomprehensivelistofinstructions.Fortheofficialdocumentation,feelfreetovisithttp://developer.android.com/tools/publishing/app-signing.html.

NowthatwearedonewithAndroid,it’stimetoprepareourappforiOS.

iOSAsyoumightalreadyknow,preparingyourPhoneGapappforAppleAppStorerequiressimilarlevels,ifnotmore,ascomparedtoyourusualAndroiddeployment.Inthissection,IwillnotbecoveringthingslikemakingsureyourappisintandemwithAppleUserInterfaceguidelines,butrather,howtoimproveyourappbeforeitreachestheAppStore.Beforewegetstarted,therearesomebasicrequirements:

AppleDeveloperMembership(ifyouultimatelywanttodeploytotheAppStore)Xcode

RunningyourapponaniOSdeviceIfyoualreadyhaveaniOSdevice,allyouneedtodoistoplugyouriOSdevicetoyourcomputerandissuethefollowingcommand:

cordovarunios

YoushouldseethatyourPhoneGapappwillbuildandlaunchonyourdevice.Notethatbeforerunningtheprecedingcommand,youwillneedtoinstalltheios-deploypackage.Youcaninstallitusingthefollowingcommand:

sudonpminstall–gios-deploy

OthertechniquesThereareotherwaystotestanddeployyourapps.Thesemethodscanbeusefulifyouwanttodeployyourapptoyourowndevicesorevenforexternaldevicetesting.

UsingXcodeNowlet’sgetstartedwithXcode:

1. Afterstartingyourprojectusingthecommand-linetoolandafteraddinginiOSplatformsupport,youmayactuallystartdevelopingusingXcode.YoucanstartyourXcodeandclickonOpenOther,asshowninthefollowingscreenshot:

2. OnceyouhaveclickedonOpenOther,youwillneedtobrowsetoyourToDoappfolder.

3. DrilldownuntilyouseeToDo.xcodeproj(navigatetoplatforms|ios).Selectandopenthisfile.

4. YouwillseeyourXcodedeviceimportingthefiles.Afterit’salldone,youshouldseesomethinglikethefollowingscreenshot:

FilesimportedintoXcode

5. NoticethatallthefilesarenowimportedtoyourXcode,andyoucanstartworkingfromhere.Youcanalsodeployyourappeithertodevicesorsimulators:

Deployonyourdeviceoronsimulators

SummaryInthischapter,wewentthroughthebasicsofpackagingyourappbeforesubmissiontotherespectiveappstores.That’sitforthisbook.Wehavecoveredquiteabitinthisbookinsixchapters.Ingeneral,youshouldhaveagoodideaofhowtodevelopAngularJSappsandapplymobileskinsonthemsothatitcanbeusedonPhoneGap.YoushouldalsonoticethatdevelopingforPhoneGapappstypicallytakesthepatternofcreatingawebappfirst,beforeconvertingittoaPhoneGapversion.Ofcourse,youmaystructureyourprojectsothatyoucanbuildaPhoneGapversionfromdayone,butitmaymaketestingmoredifficult.Anyway,Ihopethatyouenjoyedthisbookandfeelfreetofollowmeathttp://www.liangeugene.comandhttp://growthsnippets.com.

AppendixA.ReferencesThefollowingaresomecommonresourcesthatyoucanuseforreference.

AngularJSandrelatedlibrariesThemainAngularJSisavailableathttps://angularjs.org/;hereyoucanlearnaboutthebasicfunctionalitiesofAngularJSAlistofpopularadd-ons,modules,andpluginsforAngularJSisavailableathttp://ngmodules.org/CanJS,aframeworkthatmakesdevelopingcomplexapplicationssimpleandfastisavailableathttp://canjs.com/Ember.js,aframeworkthatincorporatescommonidiomssothatdeveloperscanfocusonwhatmakesyourappspecial,isavailableathttp://emberjs.com/Knockoutisaframeworkthatdeveloperscanusetobuildsinglepageapplications,custombindings,andsoitisavailableathttp://knockoutjs.com/

PhoneGapandrelatedreferencesThePhoneGapmainwebsiteisavailableathttp://phonegap.com/PhoneGapPluginsareavailableathttps://build.phonegap.com/pluginsTheApacheCordovamainwebsiteisavailableathttp://cordova.apache.org/TheAndroidDevelopersmainwebsiteisavailableathttp://developer.android.com/index.html

OthersTheiOSmainwebsiteisavailableathttps://developer.apple.com/devcenter/ios/index.actionTheFacebookloginpageisavailableathttps://developers.facebook.com/docs/facebook-login/v2.0FacebookPhoneGappluginisavailableathttps://github.com/phonegap/phonegap-facebook-pluginTheIonicframeworkisavailableathttp://ionicframework.com/

OthertutorialsInadditiontothepreviouslinks,herearesomeusefultutorialsregardingtheuseofAngularJSandPhoneGap.Thoughsomeofthemareslightlyoutdated(especiallyforPhoneGap),itisstillgenerallyusefulforyoutounderstandhowbothPhoneGapandAngularJSworktogetherbyreferringtothefollowinglinks:

HowtousePhoneGapandAngularJStogetherisavailableathttp://tech.pro/tutorial/1336/phonegap-and-angularjs-the-startSampleMobileApplicationwithAngularJSandPhoneGapisavailableathttp://coenraets.org/blog/2013/11/sample-mobile-application-with-angularjs/SampleMobileApplicationwithIonicFrameworkandPhoneGapisavailableathttp://coenraets.org/blog/2014/02/sample-mobile-application-with-ionic-and-angularjs/

IndexA

$apply()option/WritingtheusercontrollerAndroid

installing/InstallingAndroidinstalling,URL/InstallingAndroidcommand-lineinterface/Command-lineinterfaceforbothAndroidandiOScode,testingon/TestingourcodeonAndroidapp,testingon/TestingyourapponAndroid

AndroidDevelopersURL/PhoneGapandrelatedreferences

AngularJSabout/AbriefoverviewofAngularJSURL/AbriefoverviewofAngularJScoreconcepts/Coreconceptsconceptualexample/Aconceptualexampleto-dolist/Asimpleto-dolistusingAngularJSchanging,toperformRESTfulrequests/ChangingAngularJStoperformRESTfulrequests$httpmodule,using/Usingthe$httpmoduleofAngularJSreferences/AngularJSandrelatedlibrariesURL,formodules/AngularJSandrelatedlibrariesreferences,fortutorials/Othertutorials

AngularJSonPhoneGapabout/AngularJSonPhoneGapused,forcreatingtodolistapp/Creatingato-dolistappusingAngularJSonPhoneGapused,forbasicversiontodolistapp/Abasicversionofato-dolistusingAngularJSonPhoneGap

animationsadding,towebapp/Addinganimationstoyourwebapp

ApacheCordovaURL/PhoneGapandrelatedreferences

appmobileCSSstyles,adding/AddingmobileCSSstylestoyourapp

app,PhoneGaptesting,onrealdevices/Testingyourapponrealdevicesexporting,toinstallonotherdevices/Exportingyourapptoinstallonotherdevicesbuilding,forrelease/Buildingyourappforreleasesigning/Signingtheapp

Bbackend

about/Wiringupabackendserverserver,coding/Codingourservercode,checking/Checkingourcode

CCanJS

about/AngularJSandrelatedlibrariesURL/AngularJSandrelatedlibraries

codetesting,oniOS/TestingourcodeoniOStesting,onAndroid/TestingourcodeonAndroid

code,backendchecking/Checkingourcode

command-lineinterfaceforAndroid/Command-lineinterfaceforbothAndroidandiOSforiOS/Command-lineinterfaceforbothAndroidandiOSrealdevices,runningon/Runningonrealdevices

conceptualexample,AngularJS/Aconceptualexamplecontrollers

about/Controllersrewriting,touse$httpmodule/Rewritingcontrollerstomakeuseofthe$httpmodule

coreconcepts,AngularJSabout/Coreconceptscontrollers/Controllersdata-binding/Data-bindingdirectives/Directives

D$digest

URL/Writingtheusercontrollerdata-binding

about/Data-bindingDigitalOcean

URL/Deployingserver.pydirectives

about/Directivesng-app/Directivesng-bind/Directivesng-model/Directivesng-controller/Directivesng-repeat/Directives

EEmber.js

about/AngularJSandrelatedlibrariesURL/AngularJSandrelatedlibraries

ExpressURL/Wiringupabackendserver

FFacebookConnect

adding,totodolistapp/AddingFacebookConnecttotheto-dolistappURL/AddingFacebookConnecttotheto-dolistapppreparingfor/InitializingandpreparingforFacebookConnectinitializing/InitializingandpreparingforFacebookConnectusercontroller,writing/Writingtheusercontrollerloginpage,adding/Addingaloginpagelogoutfunction,adding/Addingalogoutfunctionloginstatus,checking/Checkingtheloginstatus

facebookConnectPluginFB,changingto/ChangingFBtofacebookConnectPlugin

FacebookloginforPhoneGap/FacebookloginforPhoneGapinstalling/InstallingtheFacebookplugintesting,forPhoneGap/TestingoutFacebookLoginonPhoneGap

FacebookloginpageURL/Others

FacebookPhoneGappluginURL/Others

Facebookpluginsimporting/ImportingFacebookandPhoneGapplugins

FBchanging,tofacebookConnectPlugin/ChangingFBtofacebookConnectPlugin

H$httpmodule

ofAngularJS,using/Usingthe$httpmoduleofAngularJSusing,controllersrewritingfor/Rewritingcontrollerstomakeuseofthe$httpmodule

Iindex.html

splitting,intomultiplefiles/Splittingindex.htmlintomultiplefilesIonicframework

URL/OthersiOS

installing/InstallingiOSinstalling,URL/InstallingiOScommand-lineinterface/Command-lineinterfaceforbothAndroidandiOScode,testingon/TestingourcodeoniOSapp,testingon/TestingyourapponiOSabout/iOSapp,running/RunningyourapponaniOSdeviceURL/Others

KKnockout

about/AngularJSandrelatedlibrariesURL/AngularJSandrelatedlibraries

LLinode

URL/Deployingserver.pyloginpage,FacebookConnect

writing/Addingaloginpageloginstatus,FacebookConnect

checking/Checkingtheloginstatuslogoutfunction,FacebookConnect

adding/Addingalogoutfunction

MmobileCSSstyles

adding,toapp/AddingmobileCSSstylestoyourappMongoDB

URL/Wiringupabackendserverinstalling,URL/Deployingserver.py

multiplefilesindex.html,splittinginto/Splittingindex.htmlintomultiplefilestodo.js,splittinginto/Splittingtodo.jsintomultiplefiles

Nng-appdirective/Directivesng-binddirective/Directivesng-clickdirective/HTMLforourto-dolistng-controllerdirective/Directives,HTMLforourto-dolistng-modeldirective/Directivesng-repeatdirective/Directives,HTMLforourto-dolistng-submitdirective/HTMLforourto-dolistngAnimatemodule/Addinganimationstoyourwebapp

PPhoneGap

development,preparingfor/PreparingforPhoneGapdevelopmentURL/PreparingforPhoneGapdevelopmentAndroid,installing/InstallingAndroidiOS,installing/InstallingiOSAngularJS/AngularJSonPhoneGap,Whatjusthappened?preparingfor/PreparingforPhoneGapFacebooklogin/FacebookloginforPhoneGapFacebooklogin,testingout/TestingoutFacebookLoginonPhoneGapfromWebto/FromwebtoPhoneGapwebapp,portingto/PortingyourwebapptoPhoneGapreferences/PhoneGapandrelatedreferencesreferences,fortutorials/Othertutorials

phonegap.comusing/Usingphonegap.com

PhoneGapapppreparing,forAndroidrelease/PreparingyourPhoneGapappforanAndroidreleasetesting,onrealdevices/Testingyourapponrealdevicesexporting,toinstallonotherdevices/Exportingyourapptoinstallonotherdevicespromotionalartwork,preparingforrelease/Preparingpromotionalartworkforreleasebuilding,forrelease/Buildingyourappforreleasesigning/Signingtheappsigning,URL/Signingtheapp

PhoneGappluginsimporting/ImportingFacebookandPhoneGapplugins

PhoneGapPluginsURL/PhoneGapandrelatedreferences

promotionalartwork,PhoneGappreparing,forrelease/Preparingpromotionalartworkforrelease

Rrealdevices

runningon/Runningonrealdevicesapp,testingon/Testingyourapponrealdevices

RESTfulrequestsperforming,AngularJSchanged/ChangingAngularJStoperformRESTfulrequests

S$scope.addDetailsfunction/AddinginJavaScriptwithAngularJS$scope.addTodofunction/AddinginJavaScriptwithAngularJS$scope.archivefunction/AddinginJavaScriptwithAngularJS$scope.closefunction/AddinginJavaScriptwithAngularJS$scope.getRemainingfunction/AddinginJavaScriptwithAngularJS$scope.showDetailfunction/AddinginJavaScriptwithAngularJS$scope.todoTextfunction/AddinginJavaScriptwithAngularJSserver,backend

coding/Codingourserverserver.py

deploying/Deployingserver.pysimpleto-dolistapp

rewriting/Rewritingthesimpleto-dolistappindex.html,splittingintomultiplefiles/Splittingindex.htmlintomultiplefilestodo.js,splittingintomultiplefiles/Splittingtodo.jsintomultiplefilesCheckpoint/Checkpoint

Tto-doList,AngularJS

HTML/HTMLforourto-dolistto-dolist,AngularJS

about/Asimpleto-dolistusingAngularJScodestructure,preparing/Preparingyourcodestructureadding,inJavaScript/AddinginJavaScriptwithAngularJS

todo.jssplitting,intomultiplefiles/Splittingtodo.jsintomultiplefiles

todolistappcreating,AngularJSonPhoneGapused/Creatingato-dolistappusingAngularJSonPhoneGapbasicversion,AngularJSonPhoneGapused/Abasicversionofato-dolistusingAngularJSonPhoneGapFacebookConnect,adding/AddingFacebookConnecttotheto-dolistappwithFacebookLogin/Theto-dolistappwithFacebookLoginonPhoneGapwithPhoneGap/Theto-dolistappwithFacebookLoginonPhoneGap

Todosclass/CodingourserverTopCoatCSSlibraries

URL/AddingmobileCSSstylestoyourapptornado-cor

URL/WiringupabackendserverTornadoFramework

URL/Wiringupabackendserver

Uusercontroller,FacebookConnect

writing/Writingtheusercontroller

WWeb

toPhoneGap/FromwebtoPhoneGapwebapp

animations,adding/Addinganimationstoyourwebappporting,toPhoneGap/PortingyourwebapptoPhoneGaptesting,oniOS/TestingyourapponiOStesting,onAndroid/TestingyourapponAndroid

XXcode

using/UsingXcode