1.1
1.2
1.3
2.1
2.1.1
2.1.1.1
2.1.1.2
2.1.1.3
2.1.1.4
2.1.1.5
2.1.1.6
2.1.1.7
2.1.1.8
2.1.1.9
2.1.1.10
2.1.2
2.1.2.1
2.1.2.2
2.1.2.3
2.1.2.4
2.1.2.5
2.1.2.6
2.1.2.7
2.1.2.8
2.1.2.9
2.1.2.10
2.1.2.11
2.1.2.12
2.1.2.13
2.1.2.14
TableofContentsIntroduction
License
WhyAngular2?
EcmaScript6andTypeScriptFeatures
ES6
Classes
Refresheron'this'
ArrowFunctions
TemplateStrings
Inheritance
Delegation
ConstantsandBlockScopedVariables
...spreadand...rest
Destructuring
Modules
TypeScript
GettingStartedWithTypeScript
WorkingWithtsc
Typings
Linting
TypeScriptFeatures
TypeScriptClasses
Interfaces
Shapes
TypeInference
TypeKeyword
Decorators
PropertyDecorators
ClassDecorators
ParameterDecorators
2
3.1
3.1.1
3.1.2
3.1.3
3.1.4
3.1.5
3.1.6
4.1
4.1.1
4.1.2
5.1
5.1.1
5.1.2
5.1.2.1
5.1.2.2
5.1.2.3
5.1.2.4
5.1.3
5.1.4
5.1.5
6.1
6.1.1
6.1.1.1
6.1.1.2
6.1.2
6.1.2.1
6.1.2.2
6.1.2.3
6.1.2.4
7.1
7.1.1
7.1.2
7.1.3
7.1.4
TheJavaScriptToolchain
SourceControl:git
TheCommandLine
CommandLineJavaScript:NodeJS
Back-EndCodeSharingandDistribution:npm
ModuleLoading,BundlingandBuildTasks:Webpack
Chrome
BootstrappinganAngular2Application
UnderstandingtheFileStructure
BootstrappingProviders
ComponentsinAngular2
CreatingComponents
ApplicationStructurewithComponents
PassingDataintoaComponent
RespondingtoComponentEvents
UsingTwo-WayDataBinding
AccessingChildComponentsfromTemplate
Projection
StructuringApplicationswithComponents
UsingOtherComponents
Directives
AttributeDirectives
NgStyleDirective
NgClassDirective
StructuralDirectives
NgIfDirective
NgForDirective
NgSwitchDirectives
UsingMultipleStructuralDirectives
AdvancedComponents
ComponentLifecycle
AccessingOtherComponents
ViewEncapsulation
ElementRef
3
8.1
8.1.1
8.1.2
8.1.3
8.1.4
8.1.5
8.1.6
8.1.7
8.1.8
9.1
9.1.1
9.1.2
9.1.3
9.1.3.1
9.1.3.2
9.1.3.3
9.1.3.4
10.1
10.1.1
10.1.2
10.1.2.1
10.1.2.2
10.1.2.3
10.1.3
10.1.4
11.1
11.1.1
11.1.2
11.1.3
11.1.4
11.1.5
11.1.6
12.1
Observables
UsingObservables
ErrorHandling
DisposingSubscriptionsandReleasingResources
ObservablesvsPromises
UsingObservablesFromOtherSources
ObservablesArrayOperations
ColdvsHotObservables
Summary
Angular2DependencyInjection
WhatisDI?
DIFramework
Angular2'sDI
@Inject()and@Injectable
InjectionBeyondClasses
AvoidingInjectionCollisions:OpaqueToken
TheInjectorTree
Http
MakingRequests
CatchingRejections
CatchandRelease
CancelaRequest
Retry
Searchwithflatmap
RequestsasPromises
ChangeDetection
ChangeDetectionStrategiesinAngular1vsAngular2
HowChangeDetectionWorks
ChangeDetectorClasses
ChangeDetectionStrategy:OnPush
EnforcingImmutability
AdditionalResources
Zone.js
4
13.1
13.1.1
13.1.1.1
13.1.1.1.1
13.1.1.1.2
13.1.1.2
13.1.1.2.1
13.1.1.2.2
13.1.2
13.1.2.1
13.1.2.2
14.1
14.1.1
14.1.2
14.1.3
14.1.3.1
14.1.3.2
14.1.4
14.1.4.1
14.1.4.1.1
14.1.4.2
14.1.4.2.1
14.1.4.2.2
14.1.4.3
14.1.4.4
14.1.4.5
15.1
15.1.1
15.1.2
15.1.3
16.1
16.1.1
16.1.2
16.1.2.1
AdvancedAngular
Directives
CreatinganAttributeDirective
ListeningtoanElementHost
SettingPropertiesinaDirective
CreatingaStructuralDirective
ViewContainersandEmbeddedViews
ProvidingContextVariablestoDirectives
AoT
AoTlimitations
AoTConfiguration
Immutable.js
WhatisImmutability?
TheCaseforImmutability
JavaScriptSolutions
Object.assign
Object.freeze
Immutable.jsBasics
Immutable.Map
Map.merge
NestedObjects
DeletingKeys
MapsareIterable
Immutable.List
PerformanceandTransientChanges
OfficialDocumentation
Pipes
UsingPipes
CustomPipes
StatefulPipes
Forms
GettingStarted
Template-DrivenForms
NestingFormData
5
16.1.2.2
16.1.2.3
16.1.3
16.1.3.1
16.1.3.2
16.1.3.3
16.1.4
17.1
17.1.1
17.1.2
17.1.3
17.1.4
17.1.5
17.1.6
17.1.7
17.1.8
18.1
18.1.1
18.1.2
18.1.3
18.1.4
18.1.5
18.1.6
18.1.7
18.1.8
18.1.9
18.1.10
19.1
19.1.1
19.1.2
19.1.3
19.1.4
19.1.5
UsingTemplateModelBinding
ValidatingTemplate-DrivenForms
Reactive/Model-DrivenForms
FormBuilderBasics
ValidatingFormBuilderForms
FormBuilderCustomValidation
VisualCuesforUsers
Modules
WhatisanAngular2Module?
AddingComponents,PipesandServicestoaModule
CreatingaFeatureModule
DirectiveDuplications
LazyLoadingaModule
LazyLoadingandtheDependencyInjectionTree
SharedModulesandDependencyInjection
SharingtheSameDependencyInjectionTree
Routing
WhyRouting?
ConfiguringRoutes
RedirectingtheRoutertoAnotherRoute
DefiningLinksBetweenRoutes
DynamicallyAddingRouteComponents
UsingRouteParameters
DefiningChildRoutes
ControllingAccesstoorfromaRoute
PassingOptionalParameterstoaRoute
UsingAuxiliaryRoutes
ReduxandNgrx
ReviewofReducersandPureFunctions
ReducersasStateManagement
ReduxActions
ConfiguringyourApplicationtouseRedux
UsingReduxwithComponents
6
19.1.6
19.1.7
20.1
20.1.1
20.1.2
20.1.2.1
20.1.2.2
20.1.2.3
20.1.2.4
20.1.2.5
20.1.3
20.1.4
20.1.5
20.1.5.1
20.1.5.2
20.1.5.2.1
20.1.5.3
20.1.5.4
20.1.6
20.1.6.1
20.1.6.2
20.1.6.2.1
20.1.6.2.2
20.1.6.2.3
20.1.6.3
20.1.7
20.1.7.1
20.1.7.2
20.1.7.3
20.1.7.4
21.1
21.1.1
21.1.1.1
21.1.1.2
ReduxandComponentArchitecture
GettingMoreFromReduxandNgrx
TDDTesting
TheTestingToolchain
TestSetup
FilenameConventions
KarmaConfiguration
TestBedConfiguration(Optional)
Typings
ExecutingTestScripts
SimpleTest
UsingChai
TestingComponents
VerifyingMethodsandProperties
InjectingDependenciesandDOMChanges
OverridingComponentsforTesting
TestingAsynchronousActions
RefactoringHard-to-TestCode
TestingServices
TestingStrategiesforServices
TestingHTTPRequests
UsingMockBackend
AlternativeMockingStrategy
TestingJSONPandXHRBack-Ends
ExecutingTestsAsynchronously
TestingRedux
TestingSimpleActions
TestingComplexActions
TestingReducers
Afterthoughts
MigratingAngular1.xProjectstoAngular2
MigrationPrep
UpgradingToAngular1.3+Style
UsingWebpack
7
21.1.1.3
21.1.2
21.1.3
21.1.4
21.1.4.1
21.1.4.2
21.1.5
21.1.5.1
21.1.5.2
21.1.5.3
21.1.5.4
21.1.5.5
21.1.5.6
21.1.5.7
21.1.5.8
22.1
22.1.1
22.1.1.1
22.1.1.2
22.1.1.3
22.1.1.4
22.1.2
23.1
23.1.1
23.1.2
23.1.3
23.1.4
23.1.5
23.1.6
23.1.7
23.1.8
23.1.9
23.1.10
MigratingToTypeScript
ChoosinganUpgradePath
AvoidingTotalConversion
Usingng-metadata(Angular1.xUsing2Style)
Bootstrappingng-metadata
ComponentsandServices
Usingng-upgrade(Angular1.xCoexistingWithAngular2)
OrderofOperations
ReplacingServiceswithTypeScriptClasses
Bootstrappingng-upgrade
DowngradingComponents
UpgradingComponents
ProjectingAngular1ContentintoAngular2Components
TranscludingAngular2ComponentsintoAngular1Directives
InjectingAcrossFrameworks
ProjectSetup
Webpack
InstallationandUsage
Loaders
Plugins
Summary
NPMScriptsIntegration
AngularCLI
Setup
CreatingaNewApp
ServingtheApp
CreatingComponents
CreatingRoutes
CreatingOtherThings
Testing
Linting
CLICommandOverview
AddingThirdPartyLibraries
8
23.1.11
24.1
24.1.1
24.1.2
24.1.2.1
24.1.2.2
24.1.2.3
24.1.3
24.1.3.1
24.1.3.2
24.1.3.3
24.1.3.4
24.1.4
25.1
25.1.1
25.1.2
25.1.3
25.1.4
25.1.4.1
25.1.4.2
26.1
26.2
IntegratinganExistingApp
AccessibilityinAngular2
WhyMakemyApplicationAccessible?
KeyConcernsofAccessibleWebApplications
SemanticMarkup
KeyboardAccessibility
VisualAssistance
TestingforAccessibility
IsmyApplicationReadable?
IsmyApplicationPredictable?
IsmyApplicationNavigable?
TestingwithScreenReaders
AdditionalResources
InternationalizationinAngular2
Whatistheprocesslikeandhowisinvolved?
Markingtextinourtemplates
ExtractingtranslationtextusingtheAngularCLI
Howtoimportthecompletedtranslationfiles
UsingtheAoTCompiler
UsingtheJiTCompiler
Glossary
FurtherReadingAndReference
9
Rangle'sAngular2TrainingBook
Overthelastthreeandahalfyears,AngularJShasbecometheleadingopensourceJavaScriptapplicationframeworkforhundredsofthousandsofprogrammersaroundtheworld.The"1.x"versionofAngularJShasbeenwidelyusedandbecameextremelypopularforcomplexapplications.Thenew"Angular2"hasalsoannounceditsfinalreleaseversion.
AboutRangle’sAngular2TrainingBookWedevelopedthisbooktobeusedascoursematerialforRangle'sAngular2training,butmanypeoplehavefoundittobeusefulforlearningAngular2ontheirown.ThisbookwillcoverthemostimportantAngular2topics,fromgettingstartedwiththeAngular2toolchaintowritingAngular2applicationsinascalableandmaintainablemanner.
Ifyoufindthismaterialuseful,youshouldalsoconsiderregisteringforoneofRangle’strainingcourses,whichfacilitatehands-onlearningandareagreatfitforcompaniesthatneedtotransitiontheirtechnologytoAngular2,orindividualslookingtoupgradetheirskills.
Rangle.ioalsohasanAngular1.xbookwhichisgearedtowardswritingAngular1.xapplicationsinanAngular2style.Wehopeyouenjoythisbook.WewelcomeyourfeedbackintheDiscussionArea.
Introduction
10
http://angularjs.blogspot.ca/2016/09/angular2-final.htmlhttp://go.rangle.io/angular-2-traininghttp://go.rangle.io/angular-2-traininghttp://ngcourse-1.rangle.io/https://www.gitbook.com/book/rangle-io/ngcourse2/discussions
Introduction
11
LicenseCreativeCommonsAttribution-ShareAlike4.0International(CCBY-SA4.0)
Thisisahuman-readablesummaryof(andnotasubstitutefor)thelicense.
Youarefreeto:Share—copyandredistributethematerialinanymediumorformat
Adapt—remix,transformandbuilduponthematerialforanypurpose,evencommercially.
Thelicensorcannotrevokethesefreedomsaslongasyoufollowthelicenseterms.
Underthefollowingterms:Attribution—Youmustgiveappropriatecredit,providealinktothelicense,andindicateifchangesweremade.Youmaydosoinanyreasonablemanner,butnotinanywaythatsuggeststhelicensorendorsesyouoryouruse.
ShareAlike—Ifyouremix,transformorbuilduponthematerial,youmustdistributeyourcontributionsunderthesamelicenseastheoriginal.
Noadditionalrestrictions—Youmaynotapplylegaltermsortechnologicalmeasuresthatlegallyrestrictothersfromdoinganythingthelicensepermits.
License
12
https://creativecommons.org/licenses/by-sa/4.0/legalcodehttps://creativecommons.org/licenses/by-sa/4.0/legalcode
WhyAngular2?Therearemanyfront-endJavaScriptframeworkstochoosefromtoday,eachwithitsownsetoftrade-offs.ManypeoplewerehappywiththefunctionalitythatAngular1.xaffordedthem.Angular2improvedonthatfunctionalityandmadeitfaster,morescalableandmoremodern.OrganizationsthatfoundvalueinAngular1.xwillfindmorevalueinAngular2.
Angular2'sAdvantagesThefirstreleaseofAngularprovidedprogrammerswiththetoolstodevelopandarchitectlargescaleJavaScriptapplications,butitsagehasrevealedanumberofflawsandsharpedges.Angular2wasbuiltonfiveyearsofcommunityfeedback.
Angular2IsEasier
ThenewAngular2codebaseismoremodern,morecapableandeasierfornewprogrammerstolearnthanAngular1.x,whilealsobeingeasierforprojectveteranstoworkwith.
WithAngular1,programmershadtounderstandthedifferencesbetweenControllers,Services,Factories,Providersandotherconceptsthatcouldbeconfusing,especiallyfornewprogrammers.
Angular2isamorestreamlinedframeworkthatallowsprogrammerstofocusonsimplybuildingJavaScriptclasses.Viewsandcontrollersarereplacedwithcomponents,whichcanbedescribedasarefinedversionofdirectives.EvenexperiencedAngularprogrammersarenotalwaysawareofallthecapabilitiesofAngular1.xdirectives.Angular2componentsareconsiderablyeasiertoread,andtheirAPIfeatureslessjargonthanAngular1.x'sdirectives.Additionally,tohelpeasethetransitiontoAngular2,theAngularteamhasaddeda.componentmethodtoAngular1.5,whichhasbeenback-portedbycommunitymemberToddMottotov1.3.
TypeScript
Angular2waswritteninTypeScript,asupersetofJavaScriptthatimplementsmanynewES2016+features.
WhyAngular2?
13
https://toddmotto.com/angular-component-method-back-ported-to-1.3/
Byfocusingonmakingtheframeworkeasierforcomputerstoprocess,Angular2allowsforamuchricherdevelopmentecosystem.Programmersusingsophisticatedtexteditors(orIDEs)willnoticedramaticimprovementswithauto-completionandtypesuggestions.TheseimprovementshelptoreducethecognitiveburdenoflearningAngular2.FortunatelyfortraditionalES5JavaScriptprogrammersthisdoesnotmeanthatdevelopmentmustbedoneinTypeScriptorES2015:programmerscanstillwritevanillaJavaScriptthatrunswithouttranspilation.
Familiarity
Despitebeingacompleterewrite,Angular2hasretainedmanyofitscoreconceptsandconventionswithAngular1.x,e.g.astreamlined,"nativeJS"implementationofdependencyinjection.ThismeansthatprogrammerswhoarealreadyproficientwithAngularwillhaveaneasiertimemigratingtoAngular2thananotherlibrarylikeReactorframeworklikeEmber.
PerformanceandMobile
Angular2wasdesignedformobilefromthegroundup.Asidefromlimitedprocessingpower,mobiledeviceshaveotherfeaturesandlimitationsthatseparatethemfromtraditionalcomputers.Touchinterfaces,limitedscreenrealestateandmobilehardwarehaveallbeenconsideredinAngular2.
Desktopcomputerswillalsoseedramaticimprovementsinperformanceandresponsiveness.
Angular2,likeReactandothermodernframeworks,canleverageperformancegainsbyrenderingHTMLontheserveroreveninawebworker.Dependingonapplication/sitedesignthisisomorphicrenderingcanmakeauser'sexperiencefeelevenmoreinstantaneous.
Thequestforperformancedoesnotendwithpre-rendering.Angular2makesitselfportabletonativemobilebyintegratingwithNativeScript,anopensourcelibrarythatbridgesJavaScriptandmobile.Additionally,theIonicteamisworkingonanAngular2versionoftheirproduct,providinganotherwaytoleveragenativedevicefeatureswithAngular2.
ProjectArchitectureandMaintenance
ThefirstiterationofAngularprovidedwebprogrammerswithahighlyflexibleframeworkfordevelopingapplications.Thiswasadramaticshiftformanywebprogrammers,andwhilethatframeworkwashelpful,itbecameevidentthatitwasoftentooflexible.Overtime,bestpracticesevolved,andacommunity-drivenstructurewasendorsed.
WhyAngular2?
14
https://www.nativescript.org/
Angular1.xtriedtoworkaroundvariousbrowserlimitationsrelatedtoJavaScript.Thiswasdonebyintroducingamodulesystemthatmadeuseofdependencyinjection.Thissystemwasnovel,butunfortunatelyhadissueswithtooling,notablyminificationandstaticanalysis.
Angular2.xmakesuseoftheES2015modulesystem,andmodernpackagingtoolslikewebpackorSystemJS.Modulesarefarlesscoupledtothe"Angularway",andit'seasiertowritemoregenericJavaScriptandplugitintoAngular.Theremovalofminificationworkaroundsandtheadditionofrigidprescriptionsmakemaintainingexistingapplicationssimpler.Thenewmodulesystemalsomakesiteasiertodevelopeffectivetoolingthatcanreasonbetteraboutlargerprojects.
NewFeatures
SomeoftheotherinterestingfeaturesinAngular2are:
FormBuilderChangeDetectionTemplatingRoutingAnnotationsObservablesShadowDOM
DifferencesBetweenAngular1&2Notethat"TransitionalArchitecture"referstoastyleofAngular1applicationwritteninawaythatmimicsAngular2'scomponentstyle,butwithcontrollersanddirectivesinsteadofTypeScriptclasses.
WhyAngular2?
15
OldSchoolAngular1.x
Angular1.xBest
Practices
TransitionalArchitecture Angular2
Nestedscopes("$scope",watches)
Usedheavily Avoided Avoided Gone
Directivesvscontrollers
Useasalternatives Usedtogether
Directivesascomponents
Componentdirectives
Controllerandserviceimplementation
Functions Functions ES6classes ES6classes
Modulesystem Angular'smodulesAngular'smodules ES6modules
ES6modules
Transpilerrequired No No TypeScript TypeScript
WhyAngular2?
16
EcmaScript6andTypeScriptFeatures
Figure:ES6andTypeScript
Thelanguageweusuallycall"JavaScript"isformallyknownas"EcmaScript".ThenewversionofJavaScript,knownas"ES6",offersanumberofnewfeaturesthatextendthepowerofthelanguage.
ES6isnotwidelysupportedintoday'sbrowsers,soitneedstobetranspiledtoES5.Youcanchoosebetweenseveraltranspilers,butwe'llbeusingTypeScript,whichiswhattheAngularteamusestowriteAngular2.Angular2makesuseofanumberoffeaturesofES6andTypeScript.
EcmaScript6andTypeScriptFeatures
17
ES6JavaScriptwascreatedin1995,butthelanguageisstillthrivingtoday.Therearesubsets,supersets,currentversionsandthelatestversionES6thatbringsalotofnewfeatures.
Someofthehighlights:
ClassesArrowFunctionsTemplateStringsInheritanceConstantsandBlockScopedVariablesSpreadandRestoperatorsDestructuringModules
ES6
18
ClassesClassesareanewfeatureinES6,usedtodescribetheblueprintofanobjectandmakeEcmaScript'sprototypicalinheritancemodelfunctionmorelikeatraditionalclass-basedlanguage.
classHamburger{constructor(){//Thisistheconstructor.}listToppings(){//Thisisamethod.}}
Traditionalclass-basedlanguagesoftenreservethewordthistoreferencethecurrent(runtime)instanceoftheclass.InJavascriptthisreferstothecallingcontextandthereforecanchangetobesomethingotherthantheobject.
ObjectAnobjectisaninstanceofaclasswhichiscreatedusingthenewoperator.Whenusingadotnotationtoaccessamethodontheobject,thiswillrefertotheobjecttotheleftofthedot.
letburger=newHamburger();burger.listToppings();
Inthesnippetabove,wheneverthisisusedfrominsideclassHamburger,itwillrefertoobjectburger.
ChangingCallerContextJavaScriptcodecanoptionallysupplythistoamethodatcalltimeusingoneofthefollowing.
Function.prototype.call(object[,arg,...])Function.prototype.bind(object[,arg,...])Function.prototype.apply(object[,argsArray])
Classes
19
Classes
20
ARefresheron thisInsideaJavaScriptclasswe'llbeusingthiskeywordtorefertotheinstanceoftheclass.E.g.,considerthiscase:
classToppings{...
formatToppings(){/*implementationdetails*/}
list(){returnthis.formatToppings(this.toppings);}}
HerethisreferstoaninstanceoftheToppingsclass.Aslongasthelistmethodiscalledusingdotnotation,likemyToppings.list(),thenthis.formatToppings(this.toppings)invokestheformatToppings()methoddefinedontheinstanceoftheclass.ThiswillalsoensurethatinsideformatToppings,thisreferstothesameinstance.
However,thiscanalsorefertootherthings.Therearetwobasiccasesthatyoushouldremember.
1. Methodinvocation:
someObject.someMethod();
Here,thisusedinsidesomeMethodwillrefertosomeObject,whichisusuallywhatyouwant.
2. Functioninvocation:
someFunction();
Here,thisusedinsidesomeFunctioncanrefertodifferentthingsdependingonwhetherwearein"strict"modeornot.Withoutusingthe"strict"mode,thisreferstothecontextinwhichsomeFunction()wascalled.Thisrarelywhatyouwant,anditcanbeconfusingwhenthisisnotwhatyouwereexpecting,becauseofwherethefunctionwascalledfrom.In"strict"mode,thiswouldbeundefined,whichisslightlylessconfusing.
Refresheron'this'
21
ViewExample
Oneoftheimplicationsisthatyoucannoteasilydetachamethodfromitsobject.Considerthisexample:
varlog=console.log;log('Hello');
Inmanybrowsersthiswillgiveyouanerror.That'sbecauselogexpectsthistorefertoconsole,butthereferencewaslostwhenthefunctionwasdetachedfromconsole.
Thiscanbefixedbysettingthisexplicitly.Onewaytodothisisbyusingbind()method,whichallowsyoutospecifythevaluetouseforthisinsidetheboundfunction.
varlog=console.log.bind(console);log('Hello');
YoucanalsoachievethesameusingFunction.callandFunction.apply,butwewon'tdiscussthishere.
Anotherinstancewherethiscanbeconfusingiswithrespecttoanonymousfunctions,orfunctionsdeclaredwithinotherfunctions.Considerthefollowing:
classServerRequest{notify(){...}fetch(){getFromServer(functioncallback(err,data){this.notify();//thisisnotgoingtowork});}}
Intheabovecasethiswillnotpointtotheexpectedobject:in"strict"modeitwillbeundefined.ThisleadstoanotherES6feature-arrowfunctions,whichwillbecoverednext.
Refresheron'this'
22
http://jsbin.com/vekawimihe/2/edit?js,console
ArrowFunctionsES6offerssomenewsyntaxfordealingwiththis:"arrowfunctions".Arrowfunctionsalsomakehigherorderfunctionsmucheasiertoworkwith.
Thenew"fatarrow"notationcanbeusedtodefineanonymousfunctionsinasimplerway.
Considerthefollowingexample:
items.forEach(function(x){console.log(x);incrementedItems.push(x+1);});
Thiscanberewrittenasan"arrowfunction"usingthefollowingsyntax:
items.forEach((x)=>{console.log(x);incrementedItems.push(x+1);});
Functionsthatcalculateasingleexpressionandreturnitsvaluescanbedefinedevensimpler:
incrementedItems=items.map((x)=>x+1);
Thelatterisalmostequivalenttothefollowing:
incrementedItems=items.map(function(x){returnx+1;});
Thereisoneimportantdifference,however:arrowfunctionsdonotsetalocalcopyofthis,arguments,super,ornew.target.WhenthisisusedinsideanarrowfunctionJavaScriptusesthethisfromtheouterscope.Considerthefollowingexample:
ArrowFunctions
23
classToppings{constructor(toppings){this.toppings=Array.isArray(toppings)?toppings:[];}outputList(){this.toppings.forEach(function(topping,i){console.log(topping,i+'/'+this.toppings.length);//nothis})}}
varctrl=newToppings(['cheese','lettuce']);
ctrl.outputList();
Let'strythiscodeonES6Fiddle(http://www.es6fiddle.net/).Aswesee,thisgivesusanerror,sincethisisundefinedinsidetheanonymousfunction.
Now,let'schangethemethodtousethearrowfunction:
classToppings{constructor(toppings){this.toppings=Array.isArray(toppings)?toppings:[];}outputList(){this.toppings.forEach((topping,i)=>console.log(topping,i+'/'+this.toppings.length)//`this`works!)}}
varctrl=newToppings(['cheese','lettuce']);
Herethisinsidethearrowfunctionreferstotheinstancevariable.
Warningarrowfunctionsdonothavetheirownargumentsvariable,whichcanbeconfusingtoveteranJavaScriptprogrammers.superandnew.targetarealsoscopedfromtheouterenclosure.
ArrowFunctions
24
http://www.es6fiddle.net/
TemplateStringsIntraditionalJavaScript,textthatisenclosedwithinmatching"or'marksisconsideredastring.Textwithindoubleorsinglequotescanonlybeononeline.Therewasnowaytoinsertdataintothesestrings.Thisresultedinalotofuglyconcatenationcodethatlookedlike:
varname='Sam';varage=42;
console.log('hellomynameis'+name+'Iam'+age+'yearsold');
ES6introducesanewtypeofstringliteralthatismarkedwithbackticks(`).Thesestringliteralscanincludenewlines,andthereisastringinterpolationforinsertingvariablesintostrings:
varname='Sam';varage=42;
console.log(`hellomynameis${name},andIam${age}yearsold`);
Thereareallsortsofplaceswherethiskindofstringcancomeinhandy,andfront-endwebdevelopmentisoneofthem.
TemplateStrings
25
InheritanceJavaScript'sinheritanceworksdifferentlyfrominheritanceinotherlanguages,whichcanbeveryconfusing.ES6classesprovideasyntacticsugarattemptingtoalleviatetheissueswithusingprototypicalinheritancepresentinES5.
Toillustratethis,let'simagewehaveazooapplicationwheretypesofbirdsarecreated.Inclassicalinheritance,wedefineabaseclassandthensubclassittocreateaderivedclass.
SubclassingTheexamplecodebelowshowshowtoderivePenguinfromBirdusingtheextendskeyword.AlsopayattentiontothesuperkeywordusedinthesubclassconstructorofPenguin,itisusedtopasstheargumenttothebaseclassBird'sconstructor.
TheBirdclassdefinesthemethodwalkwhichisinheritedbythePenguinclassandisavailableforusebyinstanceofPenguinobjects.LikewisethePenguinclassdefinesthemethodswimwhichisnotavilabletoBirdobjects.Inheritanceworkstop-downfrombaseclasstoitssubclass.
ObjectInitializationTheclassconstructoriscalledwhenanobjectiscreatedusingthenewoperator,itwillbecalledbeforetheobjectisfullycreated.Aconsturctorisusedtopassinargumentstoinitializethenewlycreatedobject.
Theorderofobjectcreationstartsfromitsbaseclassandthenmovesdowntoanysubclass(es).
Inheritance
26
//BaseClass:ES6classBird{constructor(weight,height){this.weight=weight;this.height=height;}
walk(){console.log('walk!');}}
//SubclassclassPenguinextendsBird{constructor(weight,height){super(weight,height);}
swim(){console.log('swim!');}}
//Penguinobjectletpenguin=newPenguin(...);penguin.walk();//walk!penguin.swim();//swim!
BelowweshowhowprototypalinheritancewasdonebeforeclasswasintroducedtoJavaScript.
Inheritance
27
//JavaScriptclassicalinheritance.
//BirdconstructorfunctionBird(weight,height){this.weight=weight;this.height=height;}
//AddmethodtoBirdprototype.Bird.prototype.walk=function(){console.log("walk!");};
//Penguinconstructor.functionPenguin(weight,height){Bird.call(this,weight,height);}
//Prototypalinheritance(Penguinis-aBird).Penguin.prototype=Object.create(Bird.prototype);Penguin.prototype.constructor=Penguin;
//AddmethodtoPenguinprototype.Penguin.prototype.swim=function(){console.log("swim!");};
//CreateaPenguinobject.letpenguin=newPenguin(50,10);
//CallsmethodonBird,sinceit'snotdefinedbyPenguin.penguin.walk();//walk!
//CallsmethodonPenguin.penguin.swim();//swim!
Inheritance
28
DelegationIntheinheritancesectionwelookedatonewaytoextendaclassfunctionality,thereissecondwayusingdelegationtoextendfunctionality.Withdelegation,oneobjectwillcontainareferencetoadifferentobjectthatitwillhandoffarequesttoperformthefunctionality.
ThecodebelowshowshowtousedelegationwiththeBirdclassandPenguinclass.ThePenguinclasshasareferencetotheBirdclassanditdelegratescallmadetoit'swalkmethodovertoBird'swalkmethod.
//ES6classBird{constructor(weight,height){this.weight=weight;this.height=height;}walk(){console.log('walk!');}}
classPenguin{constructor(bird){this.bird=bird;}walk(){this.bird.walk();}swim(){console.log('swim!');}}
constbird=newBird(...);constpenguin=newPenguin(bird);penguin.walk();//walk!penguin.swim();//swim!
Agooddiscussionon'behaviourdelegation'canbefoundhere.
Delegation
29
https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch6.md
ConstantsandBlockScopedVariablesES6introducestheconceptofblockscoping.BlockscopingwillbefamiliartoprogrammersfromotherlanguageslikeC,Java,orevenPHP.InES5JavaScriptandearlier,varsarescopedtofunctions,andtheycan"see"outsidetheirfunctionstotheoutercontext.
varfive=5;varthreeAlso=three;//error
functionscope1(){varthree=3;varfiveAlso=five;//==5varsevenAlso=seven;//error}
functionscope2(){varseven=7;varfiveAlso=five;//==5varthreeAlso=three;//error}
InES5functionswereessentiallycontainersthatcouldbe"seen"outof,butnotinto.
InES6varstillworksthatway,usingfunctionsascontainers,buttherearetwonewwaystodeclarevariables:constandlet.
constandletuse{and}blocksascontainers,hence"blockscope".Blockscopingismostusefulduringloops.Considerthefollowing:
vari;for(i=0;i<10;i+=1){varj=i;letk=i;}console.log(j);//9console.log(k);//undefined
Despitetheintroductionofblockscoping,functionsarestillthepreferredmechanismfordealingwithmostloops.
letworkslikevarinthesensethatitsdataisread/write.letisalsousefulwhenusedinaforloop.Forexample,withoutlet,thefollowingexamplewouldoutput5,5,5,5,5:
ConstantsandBlockScopedVariables
30
for(varx=0;xconsole.log(x),0)}
However,whenusingletinsteadofvar,thevaluewouldbescopedinawaythatpeoplewouldexpect.
for(letx=0;xconsole.log(x),0)}
Alternatively,constisread-only.Onceconsthasbeenassigned,theidentifiercannotbereassigned.
Forexample:
constmyName='pat';letyourName='jo';
yourName='sam';//assignsmyName='jan';//error
Theread-onlynaturecanbedemonstratedwithanyobject:
constliteral={};
literal.attribute='test';//fineliteral=[];//error;
Howevertherearetwocaseswhereconstdoesnotworkasyouthinkitshould.
1. Aconstobjectliteral.2. Aconstreferencetoanobject.
ConstObjectLiteral
constperson={name:'Tammy'};
person.name='Pushpa';//OK,namepropertychanged.
person=null;//"TypeError:Assignmenttoconstantvariable.
ConstantsandBlockScopedVariables
31
Theexampleabovedemonstratesthatweareabletochangethenamepropertyofobjectperson,butweareunabletoresetthereferencepersonsinceithasbeenmarkedasconst.
ConstReferenceToAnObjectSomethingsimilartotheabovecodeisusingaconstreference,belowwe'veswitchtousingletfortheliteralobject.
letperson={name:'Tammy'};
constp=person;
p.name='Pushpa';//OK,namepropertychanged.
p=null;//"TypeError:Assignmenttoconstantvariable.
Takeaway,markinganobjectreferenceconstdoesnotmakepropertiesinsidetheobjectconst.
Ref:.
ConstantsandBlockScopedVariables
32
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
OperatorsSpreadandRestASpreadoperatorallowsin-placeexpansionofanexpressionforthefollowingcases:
1. Array2. Functioncall3. Multiplevariabledestructuring
TheRestoperatorworksintheoppositedirectionofthespreadoperator,itcollectsanindefinitenumberofcommaseparatedexpressionsintoanarray.
OperatorSpreadSpreadexample:
constadd=(a,b)=>a+b;letargs=[3,5];add(...args);//sameas`add(args[0],args[1])`,or`add.apply(null,args)`
Functionsaren'ttheonlyplaceinJavaScriptthatmakesuseofcommaseparatedlists-arrayscannowbeconcatenatedwithease:
letcde=['c','d','e'];letscale=['a','b',...cde,'f','g'];//['a','b','c','d','e','f','g']
Similarly,objectliteralscandothesamething:
letmapABC={a:5,b:6,c:3};letmapABCD={...mapABC,d:7};//{a:5,b:6,c:3,d:7}
OperatorRestRestargumentssharetheellipsislikesyntaxofrestoperatorsbutareusedforadifferentpurpose.Restargumentsareusedtoaccessavariablenumberofargumentspassedtoafunction.Forexample:
...spreadand...rest
33
functionaddSimple(a,b){returna+b;}
functionadd(...numbers){returnnumbers[0]+numbers[1];}
addSimple(3,2);//5add(3,2);//5
//orines6style:constaddEs6=(...numbers)=>numbers.reduce((p,c)=>p+c,0);
addEs6(1,2,3);//6
TechnicallyJavaScriptalreadyhadanargumentsvariablesetoneachfunction(exceptforarrowfunctions),howeverargumentshasalotofissues,oneofwhichisthefactthatitisnottechnicallyanarray.
Restargumentsareinfactarrays.Theotherimportantdifferenceisthatrestargumentsonlyincludeargumentsnotspecificallynamedinafunctionlikeso:
functionprint(a,b,c,...more){console.log(more[0]);console.log(arguments[0]);}
print(1,2,3,4,5);//4//1
...spreadand...rest
34
DestructuringDestructuringisawaytoquicklyextractdataoutofan{}or[]withouthavingtowritemuchcode.
ToborrowfromtheMDN,destructuringcanbeusedtoturnthefollowing:
letfoo=['one','two','three'];
letone=foo[0];lettwo=foo[1];letthree=foo[2];
into
letfoo=['one','two','three'];let[one,two,three]=foo;console.log(one);//'one'
Thisisprettyinteresting,butatfirstitmightbehardtoseetheusecase.ES6alsosupportsobjectdestructuring,whichmightmakeusesmoreobvious:
letmyModule={drawSquare:functiondrawSquare(length){/*implementation*/},drawCircle:functiondrawCircle(radius){/*implementation*/},drawText:functiondrawText(text){/*implementation*/},};
let{drawSquare,drawText}=myModule;
drawSquare(5);drawText('hello');
Destructuringcanalsobeusedforpassingobjectsintoafunction,allowingyoutopullspecificpropertiesoutofanobjectinaconcisemanner.Itisalsopossibletoassigndefaultvaluestodestructuredarguments,whichcanbeausefulpatternifpassinginaconfigurationobject.
Destructuring
35
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
letjane={firstName:'Jane',lastName:'Doe'};letjohn={firstName:'John',lastName:'Doe',middleName:'Smith'}functionsayName({firstName,lastName,middleName='N/A'}){console.log(`Hello${firstName}${middleName}${lastName}`)}
sayName(jane)//->HelloJaneN/ADoesayName(john)//->HeloJohnSmithDoe
Therearemanymoresophisticatedthingsthatcanbedonewithdestructuring,andtheMDNhassomegreatexamples,includingnestedobjectdestructuringanddynamicdestructuringwithfor...inoperators".
Destructuring
36
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
ES6ModulesES6introducedmodulesupport.AmoduleinES6issinglefilethatallowscodeanddatatobeisolated,ithelpsinorganizingandgroupingcodelogically.Inotherlanguagesit'scalledapackageorlibrary.
Allcodeanddatainsidethemodulehasfilescope,whatthismeansistheyarenotaccessiblefromcodeoutsidethemodule.Tosharecodeordataoutsideamodule,itneedstobeexportedusingtheexportkeyword.
//File:circle.js
exportconstpi=3.141592;
exportconstcircumference=diameter=>diameter*pi;
ThecodeaboveusestheArrowfunctionforcircumference,whichwasintroducedinES6,andisashortformforthefollowing.
exportfunctioncircumference(diameter){returndiameter*pi;}
ModuleSystemsUsingamoduleonthebackend(serverside)isrelativelystraightforward,yousimplymakeuseoftheimportkeyword.HoweverWebBrowsershavenoconceptofmodulesorimport,theyjustknowhowtoloadjavascriptcode.Weneedawaytobringinajavascriptmoduletostartusingitfromotherjavascriptcode.Thisiswhereamoduleloadercomesin.
Wewon'tgetintothevariousmodulesystemsoutthere,butit'sworthunderstandingtherearevariousmoduleloadersavailable.Thepopularchoicesoutthereare:
RequireJSSystemJSWebpack
LoadingaModuleFromaBrowser
Modules
37
BelowwemakeuseofSystemJStoloadamodule.ThescriptfirstloadsthecodefortheSystemJSlibrary,thenthefunctioncallSystem.importisusetoimport(load)theappmodule.
LoadingES6modulesisalittletrickier.InanES6-compliantbrowseryouusetheSystemkeywordtoloadmodulesasynchronously.Tomakeourcodeworkwithcurrentbrowsers,however,wewillusetheSystemJSlibraryasapolyfill:
varpromise=System.import('app').then(function(){console.log('Loaded!');}).then(null,function(error){console.error('Failedtoload:',error);});
Modules
38
TypeScriptES6isthecurrentversionofJavaScript.TypeScriptisasupersetofES6,whichmeansallES6featuresarepartofTypeScript,butnotallTypeScriptfeaturesarepartofES6.Consequently,TypeScriptmustbetranspiledintoES5toruninmostbrowsers.
OneofTypeScript'sprimaryfeaturesistheadditionoftypeinformation,hencethename.ThistypeinformationcanhelpmakeJavaScriptprogramsmorepredictableandeasiertoreasonabout.
Typesletdeveloperswritemoreexplicit"contracts".Inotherwords,thingslikefunctionsignaturesaremoreexplicit.
WithoutTS:
functionadd(a,b){returna+b;}
add(1,3);//4add(1,'3');//'13'
WithTS:
functionadd(a:number,b:number){returna+b;}
add(1,3);//4//compilererrorbeforeJSisevenproducedadd(1,'3');//'13'
TypeScript
39
GettingStartedWithTypeScriptInstalltheTypeScripttranspilerusingnpm:
$npminstall-gtypescript
ThenusetsctomanuallycompileaTypeScriptsourcefileintoES5:
$tsctest.ts$nodetest.js
NoteAboutES6Examples
OurearlierES6classwon'tcompilenow.TypeScriptismoredemandingthanES6anditexpectsinstancepropertiestobedeclared:
classPizza{toppings:string[];constructor(toppings:string[]){this.toppings=toppings;}}
Notethatnowthatwe'vedeclaredtoppingstobeanarrayofstrings,TypeScriptwillenforcethis.Ifwetrytoassignanumbertoit,wewillgetanerroratcompilationtime.
Ifyouwanttohaveapropertythatcanbesettoavalueofanytype,however,youcanstilldothis:justdeclareitstypetobe"any":
classPizza{toppings:any;//...}
GettingStartedWithTypeScript
40
WorkingWith tscSofartschasbeenusedtocompileasinglefile.Typicallyprogrammershavealotmorethanonefiletocompile.Thankfullytsccanhandlemultiplefilesasarguments.
Imaginetwoultrasimplefiles/modules:
a.ts
exportconstA=(a)=>console.log(a);
b.ts
exportconstB=(b)=>console.log(b);
$tsc./a.ts./b.tsa.ts(1,1):errorTS1148:Cannotcompilemodulesunlessthe'--module'flagisprovided.
Hmmm.What'sthedealwiththismoduleflag?TypeScripthasahelpmenu,let'stakealook:
$tsc--help|grepmodule-mKIND,--moduleKINDSpecifymodulecodegeneration:'commonjs','amd','system','umd'or'es2015'--moduleResolutionSpecifiesmoduleresolutionstrategy:'node'(Node.js)or'classic'(TypeScriptpre-1.6).
(TypeScripthasmorehelpthanwhatwe'veshown;wefilteredbygrepforbrevity.)Therearetwohelpentriesthatreference"module",and--moduleistheoneTypeScriptwascomplainingabout.ThedescriptionexplainsthatTypeScriptsupportsanumberofdifferentmoduleschemes.Forthemomentcommonjsisdesirable.Thiswillproducemodulesthatarecompatiblewithnode.js'smodulesystem.
$tsc-mcommonjs./a.ts./b.ts
[email protected],tschasadefaultrulefor--moduleoption:target==='ES6'?'ES6':'commonjs'(moredetailscanbefoundhere),sowecansimplyrun:
WorkingWithtsc
41
https://www.typescriptlang.org/docs/handbook/compiler-options.html
$tsc./a.ts./b.ts
tscshouldproducenooutput.Inmanycommandlinetraditions,nooutputisactuallyamarkofsuccess.ListingthedirectorycontentswillconfirmthatourTypeScriptfilesdidinfactcompile.
$lsa.jsa.tsb.jsb.ts
Excellent-therearenowtwoJavaScriptmodulesreadyforconsumption.
Tellingthetsccommandwhattocompilebecomestediousandlaborintensiveevenonsmallprojects.FortunatelyTypeScripthasameansofsimplifyingthis.tsconfig.jsonfilesletprogrammerswritedownallthecompilersettingstheywant.Whentscisrun,itlooksfortsconfig.jsonfilesandusestheirrulestocompileJavaScript.
ForAngular2projectsthereareanumberofspecificsettingsthatneedtobeconfiguredinaproject'stsconfig.json
{"compilerOptions":{"module":"commonjs","target":"es5","emitDecoratorMetadata":true,"experimentalDecorators":true,"noImplicitAny":false,"removeComments":false,"sourceMap":true},"exclude":["node_modules","dist/"]}
Target
Thecompilationtarget.TypeScriptsupportstargetingdifferentplatformsdependingonyourneeds.Inourcase,we'retargetingmodernbrowserswhichsupportES5.
Module
WorkingWithtsc
42
Thetargetmoduleresolutioninterface.We'reintegratingTypeScriptthroughwebpackwhichsupportsdifferentinterfaces.We'vedecidedtousenode'smoduleresolutioninterface,commonjs.
Decorators
DecoratorsupportinTypeScripthasn'tbeenfinalizedyetbutsinceAngular2usesdecoratorsextensively,theseneedtobesettotrue.Decoratorshavenotbeenintroducedyet,andwillbecoveredlaterinthissection.
TypeScriptwithWebpack
Wewon'tberunningtscmanually,however.Instead,webpack'sts-loaderwilldothetranspilationduringthebuild:
//webpack.config.js//...rules:[{test:/\.ts$/,loader:'ts',exclude:/node_modules/},//...]
Thisloadercallstscforus,anditwilluseourtsconfig.json.
WorkingWithtsc
43
http://rbuckton.github.io/ReflectDecorators/typescript.html
TypingsAstutereadersmightbewonderingwhathappenswhenTypeScriptprogrammersneedtointerfacewithJavaScriptmodulesthathavenotypeinformation.TypeScriptrecognizesfileslabelled*.d.tsasdefinitionfiles.ThesefilesaremeanttouseTypeScripttodescribeinterfacespresentedbyJavaScriptlibraries.
TherearecommunitiesofpeoplededicatedtocreatingtypingsforJavaScriptprojects.Thereisalsoautilitycalledtypings(npminstall--save-devtypings)thatcanbeusedtomanagethirdpartytypingsfromavarietyofsources.(DeprecatedinTypeScript2.0)
InTypeScript2.0,userscangettypefilesdirectlyfrom@typesthroughnpm(forexample,npminstall--save@types/lodashwillinstalllodashtypefile).
Typings
44
LintingManyeditorssupporttheconceptof"linting"-agrammarcheckforcomputerprograms.Lintingcanbedoneinaprogrammer'seditorand/orthroughautomation.
ForTypeScriptthereisapackagecalledtslint,(npminstall--save-devtslint)whichcanbepluggedintomanyeditors.tslintcanalsobeconfiguredwithatslint.jsonfile.
Webpackcanruntslintbeforeitattemptstoruntsc.Thisisdonebyinstallingtslint-loader(npminstall--save-devtslint-loader)whichplugsintowebpacklikeso:
//...module:{preLoaders:[{test:/\.ts$/,loader:'tslint'}],loaders:[{test:/\.ts$/,loader:'ts',exclude:/node_modules/},//...]//...}
Linting
45
TypeScriptFeaturesNowthatproducingJavaScriptfromTypeScriptcodehasbeende-mystified,someofitsfeaturescanbedescribedandexperimentedwith.
TypesInterfacesShapesDecorators
TypesManypeopledonotrealizeit,butJavaScriptdoesinfacthavetypes,they'rejust"ducktyped",whichroughlymeansthattheprogrammerdoesnothavetothinkaboutthem.JavaScript'stypesalsoexistinTypeScript:
boolean(true/false)numberintegers,floats,InfinityandNaNstringcharactersandstringsofcharacters[]Arraysofothertypes,likenumber[]orboolean[]{}Objectliteralundefinednotset
TypeScriptalsoadds
enumenumerationslike{Red,Blue,Green}anyuseanytypevoidnothing
Primitivetypeexample:
TypeScriptFeatures
46
letisDone:boolean=false;letheight:number=6;letname:string="bob";letlist:number[]=[1,2,3];letlist:Array=[1,2,3];enumColor{Red,Green,Blue};letc:Color=Color.Green;letnotSure:any=4;notSure="maybeastringinstead";notSure=false;//okay,definitelyaboolean
functionshowMessage(data:string):void{alert(data);}showMessage('hello');
ThisillustratestheprimitivetypesinTypeScript,andendsbyillustratingashowMessagefunction.Inthisfunctiontheparametershavespecifictypesthatarecheckedwhentscisrun.
InmanyJavaScriptfunctionsit'squitecommonforfunctionstotakeoptionalparameters.TypeScriptprovidessupportforthis,likeso:
functionlogMessage(message:string,isDebug?:boolean){if(isDebug){console.log('Debug:'+message);}else{console.log(message);}}logMessage('hi');//'hi'logMessage('test',true);//'Debug:test'
Usinga?letstscknowthatisDebugisanoptionalparameter.tscwillnotcomplainifisDebugisomitted.
TypeScriptFeatures
47
TypeScriptClassesTypeScriptalsotreatsclassesastheirowntype:
classFoo{foo:number;}classBar{bar:string;}
classBaz{constructor(foo:Foo,bar:Bar){}}
letbaz=newBaz(newFoo(),newBar());//validbaz=newBaz(newBar(),newFoo());//tscerrors
Likefunctionparameters,classessometimeshaveoptionalmembers.Thesame?:syntaxcanbeusedonaclassdefinition:
classPerson{name:string;nickName?:string;}
Intheaboveexample,aninstanceofPersonisguaranteedtohaveaname,andmightoptionallyhaveanickName
TypeScriptClasses
48
InterfacesAninterfaceisaTypeScriptartifact,itisnotpartofECMAScript.Aninterfaceisawaytodefineacontractonafunctionwithrespecttotheargumentsandtheirtype.Alongwithfunctions,aninterfacecanalsobeusedwithaClassaswelltodefinecustomtypes.
Aninterfaceisanabstracttype,itdoesnotcontainanycodeasaclassdoes.Itonlydefinesthe'signature'orshapeofanAPI.Duringtranspilation,aninterfacewillnotgenerateanycode,itisonlyusedbyTypescriptfortypecheckingduringdevelopment.
HereisanexampleofaninterfacedescribingafunctionAPI:
interfaceCallback{(error:Error,data:any):void;}
functioncallServer(callback:Callback){callback(null,'hi');}
callServer((error,data)=>console.log(data));//'hi'callServer('hi');//tscerror
SometimesJavaScriptfunctionscanacceptmultipletypesaswellasvaryingarguments,thatis,theycanhavedifferentcallsignatures.Interfacescanbeusedtospecifythis.
interfacePrintOutput{(message:string):void;//commoncase(message:string[]):void;//lesscommoncase}
letprintOut:PrintOutput=(message)=>{if(Array.isArray(message)){console.log(message.join(','));}else{console.log(message);}}
printOut('hello');//'hello'printOut(['hi','bye']);//'hi,bye'
Hereisanexampleofaninterfacedescribinganobjectliteral:
Interfaces
49
interfaceAction{type:string;}
leta:Action={type:'literal'}
Interfaces
50
ShapesUnderneathTypeScriptisJavaScript,andunderneathJavaScriptistypicallyaJIT(Just-In-Timecompiler).GivenJavaScript'sunderlyingsemantics,typesaretypicallyreasonedaboutby"shapes".TheseunderlyingshapesworklikeTypeScript'sinterfaces,andareinfacthowTypeScriptcomparescustomtypeslikeclassesandinterfaces.
Consideranexpansionofthepreviousexample:
interfaceAction{type:string;}
leta:Action={type:'literal'}
classNotAnAction{type:string;constructor(){this.type='Constructorfunction(class)';}}
a=newNotAnAction();//validTypeScript!
DespitethefactthatActionandNotAnActionhavedifferentidentifiers,tscletsusassignaninstanceofNotAnActiontoawhichhasatypeofAction.ThisisbecauseTypeScriptonlyreallycaresthatobjectshavethesameshape.Inotherwordsiftwoobjectshavethesameattributes,withthesametypings,thosetwoobjectsareconsideredtobeofthesametype.
Shapes
51
TypeInferenceOnecommonmisconceptionaboutTypeScript'stypesisthatcodeneedstoexplicitlydescribetypesateverypossibleopportunity.Fortunatelythisisnotthecase.TypeScripthasarichtypeinferencesystemthatwill"fillintheblanks"fortheprogrammer.Considerthefollowing:
type-inference-finds-error.ts
letnumbers=[2,3,5,7,11];numbers=['thiswillgenerateatypeerror'];
tsc./type-inference-finds-error.tstype-inference-finds-error.ts(2,1):errorTS2322:Type'string[]'isnotassignabletotype'number[]'.Type'string'isnotassignabletotype'number'.
Thecodecontainsnoextratypeinformation.Infact,it'svalidES6.Ifvarhadbeenused,itwouldbevalidES5.YetTypeScriptisstillabletodeterminetypeinformation.
Typeinferencecanalsoworkthroughcontext,whichishandywithcallbacks.Considerthefollowing:
type-inference-finds-error-2.ts
interfaceFakeEvent{type:string;}
interfaceFakeEventHandler{(e:FakeEvent):void;}
classFakeWindow{onMouseDown:FakeEventHandler}constfakeWindow=newFakeWindow();
fakeWindow.onMouseDown=(a:number)=>{//thiswillfail};
TypeInference
52
tsc./type-inference-finds-error-2.tstype-inference-finds-error-2.ts(14,1):errorTS2322:Type'(a:number)=>void'isnotassignabletotype'FakeEventHandler'.Typesofparameters'a'and'e'areincompatible.Type'number'isnotassignabletotype'FakeEvent'.Property'type'ismissingintype'Number'.
Inthisexamplethecontextisnotobvioussincetheinterfaceshavebeendefinedexplicitly.Inabrowserenvironmentwitharealwindowobject,thiswouldbeahandyfeature,especiallythetypecompletionoftheEventobject.
TypeInference
53
TypeKeywordThetypekeyworddefinesanaliastoatype.
typestr=string;letcheese:str='gorgonzola';letcake:str=10;//Type'number'isnotassignabletotype'string'
Atfirstglance,thisdoesnotappeartobeveryuseful(eventheerrormentionstheoriginaltype),butastypeannotationsbecomemorecomplex,thebenefitsofthetypekeywordbecomeapparent.
UnionTypes
Uniontypesallowtypeannotationstospecifythatapropertyshouldbeoneofasetoftypes(either/or).
functionadmitAge(age:number|string):string{return`Iam${age},alright?!`;}
admitAge(30);//'Iam30,alright?!'admitAge('Forty');//'IamForty,alright?!'
Thetypekeywordsimplifiesannotatingandreusinguniontypes.
typeAge=number|string;
functionadmitAge(age:Age):string{return`Iam${age},alright?!`;}
letmyAge:Age=50;letyourAge:Age='OneHundred';admitAge(yourAge);//'IamOneHundred,alright?!'
Auniontypeofstringliteraltypesisaveryusefulpattern,creatingwhatisbasicallyanenumwithstringvalues.
TypeKeyword
54
typePartyZone="pizzahut"|"waterpark"|"bowlingalley"|"abandonedwarehouse";
functiongoToParty(place:PartyZone):string{return`letsgotothe${place}`;}
goToParty("pizzahut");goToParty("chucke.cheese");//Argumentoftype`"chucke.cheese"'isnotassignabletoparameteroftype'PartyZone'
IntersectionTypes
Intersectiontypesarethecombinationoftwoormoretypes.Usefulforobjectsandparamsthatneedtoimplementmorethanoneinterface.
interfaceKicker{kick(speed:number):number;}
interfacePuncher{punch(power:number):number;}//assignintersectiontypedefinitiontoaliasKickPunchertypeKickPuncher=Kicker&Puncher;
functionattack(warrior:KickPuncher){warrior.kick(102);warrior.punch(412);warrior.judoChop();//Property'judoChop'doesnotexistontype'KickPuncher'}
FunctionTypeDefinitions
Functiontypeannotationscangetmuchmorespecificthantypescriptsbuilt-inFunctiontype.Functiontypedefinitionsallowyoutoattachafunctionsignaturetoit'sowntype.
typeMaybeError=Error|null;typeCallback=(err:MaybeError,response:Object)=>void;
functionsendRequest(cb:Callback):void{if(cb){cb(null,{});}}
ThesyntaxissimilartoES6fat-arrowfunctions.([params])=>[returntype].
TypeKeyword
55
Toillustratethehowmuchthetypekeywordimprovedthereadabilityoftheprevioussnippet,hereisthefunctiontypedefinedinline.
functionsendRequest(cb:(err:Error|null,response:Object)=>void):void{if(cb){cb(null,{});}}
TypeKeyword
56
DecoratorsDecoratorsareproposedforafutureversionofJavaScript,buttheAngular2teamreallywantedtousethem,andtheyhavebeenincludedinTypeScript.
Decoratorsarefunctionsthatareinvokedwithaprefixed@symbol,andimmediatelyfollowedbyaclass,parameter,methodorproperty.Thedecoratorfunctionissuppliedinformationabouttheclass,parameterormethod,andthedecoratorfunctionreturnssomethinginitsplace,ormanipulatesitstargetinsomeway.Typicallythe"something"adecoratorreturnsisthesamethingthatwaspassedin,butithasbeenaugmentedinsomeway.
DecoratorsarequitenewinTypeScript,andmostusecasesdemonstratetheuseofexistingdecorators.However,decoratorsarejustfunctions,andareeasiertoreasonaboutafterwalkingthroughafewexamples.
Decoratorsarefunctions,andtherearefourthings(class,parameter,methodandproperty)thatcanbedecorated;consequentlytherearefourdifferentfunctionsignaturesfordecorators:
class:declaretypeClassDecorator=(target:TFunction)=>TFunction|void;
property:declaretypePropertyDecorator=(target:Object,propertyKey:string|symbol)=>void;
method:declaretypeMethodDecorator=(target:Object,propertyKey:string|symbol,descriptor:TypedPropertyDescriptor)=>TypedPropertyDescriptor|void;
parameter:declaretypeParameterDecorator=(target:Object,propertyKey:string|symbol,parameterIndex:number)=>void;
ReaderswhohaveplayedwithAngular2willnoticethatthesesignaturesdonotlooklikethesignaturesusedbyAngular2specificdecoratorslike@Component().
Noticethe()[email protected]@ComponentiscalledonceJavaScriptencounters@Component().Inturn,thismeansthattheremustbeaComponentfunctionsomewherethatreturnsafunctionmatchingoneofthedecoratorsignaturesoutlinedabove.Thisisanexampleofthedecoratorfactorypattern.
Ifdecoratorsstilllookconfusing,perhapssomeexampleswillclearthingsup.
Decorators
57
PropertyDecoratorsPropertydecoratorsworkwithpropertiesofclasses.
functionOverride(label:string){returnfunction(target:any,key:string){Object.defineProperty(target,key,{configurable:false,get:()=>label});}}
classTest{@Override('test')//invokesOverride,whichreturnsthedecoratorname:string='pat';}
lett=newTest();console.log(t.name);//'test'
Theaboveexamplemustbecompiledwithboththe--experimentalDecoratorsand--emitDecoratorMetadataflags.
Inthiscasethedecoratedpropertyisreplacedbythelabelpassedtothedecorator.It'simportanttonotethatpropertyvaluescannotbedirectlymanipulatedbythedecorator;insteadanaccessorisused.
Here'saclassicpropertyexamplethatusesaplaindecorator
functionReadOnly(target:any,key:string){Object.defineProperty(target,key,{writable:false});}
classTest{@ReadOnly//noticethereareno`()`name:string;}
constt=newTest();t.name='jan';console.log(t.name);//'undefined'
Inthiscasethenamepropertyisnotwritable,andremainsundefined.
PropertyDecorators
58
PropertyDecorators
59
ClassDecorators
functionlog(prefix?:string){return(target)=>{//saveareferencetotheoriginalconstructorvaroriginal=target;
//autilityfunctiontogenerateinstancesofaclassfunctionconstruct(constructor,args){varc:any=function(){returnconstructor.apply(this,args);}c.prototype=constructor.prototype;returnnewc();}
//thenewconstructorbehaviorvarf:any=function(...args){console.log(prefix+original.name);returnconstruct(original,args);}
//copyprototypesoinstanceofoperatorstillworksf.prototype=original.prototype;
//returnnewconstructor(willoverrideoriginal)returnf;};}
@log('hello')classWorld{}
constw=newWorld();//outputs"helloWorld"
Intheexamplelogisinvokedusing@,andpassedastringasaparameter,@log()returnsananonymousfunctionthatistheactualdecorator.
Thedecoratorfunctiontakesaclass,orconstructorfunction(ES5)asanargument.ThedecoratorfunctionthenreturnsanewclassconstructionfunctionthatisusedwheneverWorldisinstantiated.
Thisdecoratordoesnothingotherthanlogoutitsgivenparameter,anditstarget'sclassnametotheconsole.
ClassDecorators
60
ClassDecorators
61
ParameterDecorators
functionlogPosition(target:any,propertyKey:string,parameterIndex:number){console.log(parameterIndex);}
classCow{say(b:string,@logPositionc:boolean){console.log(b);}}
newCow().say('hello',false);//outputs1(newline)hello
Theabovedemonstratesdecoratingmethodparameters.ReadersfamiliarwithAngular2cannowimaginehowAngular2implementedtheir@Inject()system.
ParameterDecorators
62
TheJavaScriptToolchainInthissection,we'lldescribethetoolsthatyou'llbeusingfortherestofthecourse.
Figure:HandToolsbyM338islicensedunderPublicDomain(http://commons.wikimedia.org/wiki/File:Hand_tools.jpg)
TheJavaScriptToolchain
63
SourceControl:GitAsourcecontrol,sometimescalledaversioncontrolbringschangemanagementtosavingfilesatdifferentpointsinthedevelopmentprocess.AVersioncontrolsystem(VCS)thatwillwemakeuseofisGit.
Gitisadecentralizeddistributedversioningsystem,itallowsprogrammerstocollaborateonthesamecodebasewithoutsteppingoneachother'stoes.Ithasbecomethede-factosourcecontrolsystemforopensourcedevelopmentbecauseofitsdecentralizedmodelandcheapbranchingfeatures.
FormoreinformationonhowtouseGit,headovertoProGit
SourceControl:git
64
http://git-scm.com/https://www.gitbook.com/book/gitbookio/progit/details
TheCommandLineJavaScriptdevelopmenttoolsareverycommandlineoriented.IfyoucomefromaWindowsbackgroundyoumayfindthisunfamiliar.Howeverthecommandlineprovidesbettersupportforautomatingdevelopmenttasks,soit'sworthgettingcomfortablewithit.
Wewillprovideexamplesforallcommandlineactivitiesrequiredbythiscourse.
TheCommandLine
65
CommandLineJavaScript:NodeJSNode.jsisaJavaScriptruntimeenvironmentthatallowsJavaScriptcodetorunoutsideofabrowserusingGoogleV8JavaScriptengine.Node.jsisusedforwrittingfastexecutingcodeontheservertohandleeventsandnon-blockingI/Oefficently.
REPL(Read-Eval-Print-Loop)toquicklywriteandtestJavaScriptcode.TheV8JavaScriptinterpreter.ModulesfordoingOStaskslikefileI/O,HTTP,etc.
WhileNode.jswasinitiallyintendedforwritingservercodeinJavaScript,todayitiswidelyusedbyJavaScripttools,whichmakesitrelevanttofront-endprogrammerstoo.Alotofthetoolsyou'llbeusinginthiscourseleverageNode.js.
CommandLineJavaScript:NodeJS
66
http://nodejs.org
Back-EndCodeSharingandDistribution:npmnpmisthe"nodepackagemanager".ItinstallswithNodeJS,andgivesyouaccesstoawidevarietyof3rd-partyJavaScriptmodules.
Italsoperformsdependencymanagementforyourback-endapplication.Youspecifymoduledependenciesinafilecalledpackage.json;runningnpminstallwillresolve,downloadandinstallyourback-endapplication'sdependencies.
Back-EndCodeSharingandDistribution:npm
67
https://www.npmjs.com/
ModuleLoading,BundlingandBuildTasks:WebpackWebpackisaJavaScriptmodulebundler.Ittakesmoduleswiththeirdependenciesandgeneratesstaticassetsrepresentingthosemodules.WebpackknownonlyhowtobundleJavaScript.TobundleotherassetslikesCSS,HTML,imagesorjustaboutanythingitusesadditionalloaders.Webpackcanalsobeextendedviaplugins,forexampleminificationandmanglingcanbedoneusingtheUglifyJSpluginforwebpack.
ModuleLoading,BundlingandBuildTasks:Webpack
68
http://webpack.github.io/docs/what-is-webpack.html
WebBrowsersWeuseGoogle'sChromebrowserforthiscoursebecauseofitscutting-edgeJavaScriptengineandexcellentdebuggingtools.
Howeveryouarefreetouseotherbrowsers.Notwellknown,thereisaMozillaFirefoxDeveloperEditionavailablewithsupportforgreatdevelopmentanddebuggingtools.CodewrittenwithJavaScriptshouldworkonanymodernwebbrowser(Firefox,IE9+,Chrome,Safari,Opera).
Chrome
69
https://www.mozilla.org/en-US/firefox/developer/
BootstrappinganAngular2ApplicationBootstrappingisanessentialprocessinAngular-itiswheretheapplicationisloadedwhenAngularcomestolife.
BootstrappingAngular2applicationsiscertainlydifferentfromAngular1.x,butisstillastraightforwardprocedure.Let'stakealookathowthisisdone.
BootstrappinganAngular2Application
70
UnderstandingtheFileStructureTogetstartedlet'screateabare-bonesAngular2applicationwithasinglecomponent.Todothisweneedthefollowingfiles:
app/app.component.ts-thisiswherewedefineourrootcomponentapp/app.module.ts-theentryAngularModuletobebootstrappedindex.html-thisisthepagethecomponentwillberenderedinapp/main.ts-isthegluethatcombinesthecomponentandpagetogether
app/app.component.ts
import{Component}from'@angular/core'
@Component({selector:'app-root',template:'BootstrappinganAngular2Application'})exportclassAppComponent{}
index.html
Loading...
app/app.module.ts
import{BrowserModule}from'@angular/platform-browser';import{NgModule}'@angular/core';import{AppComponent}from'./app.component'
@NgModule({imports:[BrowserModule],declarations:[AppComponent],bootstrap:[AppComponent]})exportclassAppModule{}
app/main.ts
UnderstandingtheFileStructure
71
import{platformBrowserDynamic}from'@angular/platform-browser-dynamic';import{AppModule}from'./app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
Ifyou'remakinguseofAhead-of-Time(AoT)compilation,youwouldcodemain.tsasfollows.
import{platformBrowser}from'@angular/platform-browser';import{AppModuleNgFactory}from'../aot/app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
ViewExample
Thebootstrapprocessloadsmain.tswhichisthemainentrypointoftheapplication.TheAppModuleoperatesastherootmoduleofourapplication.ThemoduleisconfiguredtouseAppComponentasthecomponenttobootstrap,andwillberenderedonanyapp-rootHTMLelementencountered.
ThereisanappHTMLelementintheindex.htmlfile,andweuseapp/main.tstoimporttheAppModulecomponentandtheplatformBrowserDynamic().bootstrapModulefunctionandkickstarttheprocess.Asshownabove,youmayoptionallyuseAoTinwhichcaseyouwillbeworkingwithFactories,intheexample,AppModuleNgFactoryandbootstrapModuleFactory.
WhydoesAngular2bootstrapitselfinthisway?Wellthereisactuallyaverygoodreason.SinceAngular2isnotaweb-onlybasedframework,wecanwritecomponentsthatwillruninNativeScript,orCordova,oranyotherenvironmentthatcanhostAngular2applications.
Themagicistheninourbootstrappingprocess-wecanimportwhichplatformwewouldliketouse,dependingontheenvironmentwe'reoperatingunder.Inourexample,sincewewererunningourAngular2applicationinthebrowser,weusedthebootstrappingprocessfoundin@angular/platform-browser-dynamic.
It'salsoagoodideatoleavethebootstrappingprocessinitsownseparatemain.tsfile.Thismakesiteasiertotest(sincethecomponentsareisolatedfromthebootstrapcall),easiertoreuseandgivesbetterorganizationandstructuretoourapplication.
ThereismoretounderstandingAngularModulesand@NgModulewhichwillbecoveredlater,butfornowthisisenoughtogetstarted.
UnderstandingtheFileStructure
72
https://plnkr.co/edit/X0EBXA?p=preview
UnderstandingtheFileStructure
73
BootstrappingProvidersThebootstrapprocessalsostartsthedependencyinjectionsysteminAngular2.Wewon'tgooverAngular2'sdependencyinjectionsystemhere-thatiscoveredlater.Insteadlet'stakealookatanexampleofhowtobootstrapyourapplicationwithapplication-wideproviders.
Forthis,wewillregisteraservicecalledGreeterServicewiththeproviderspropertyofthemoduleweareusingtobootstraptheapplication.
app/app.module.ts
import{BrowserModule}from'@angular/platform-browser';import{NgModule}'@angular/core';import{AppComponent}from'./app.component'import{GreeterService}from'./greeter.service';
@NgModule({imports:[BrowserModule],providers:[GreeterService],declarations:[AppComponent],bootstrap:[AppComponent]})exportclassAppModule{}
ViewExample
BootstrappingProviders
74
https://plnkr.co/edit/bcpliM?p=preview
ComponentsinAngular2
Figure:components
ThecoreconceptofanyAngular2applicationisthecomponent.Ineffect,thewholeapplicationcanbemodeledasatreeofthesecomponents.
ThisishowtheAngular2teamdefinesacomponent:
Acomponentcontrolsapatchofscreenrealestatethatwecouldcallaview,anddeclaresreusableUIbuildingblocksforanapplication.
Basically,acomponentisanythingthatisvisibletotheenduserandwhichcanbereusedmanytimeswithinanapplication.
InAngular1.xwehadrouterviewsanddirectiveswhichworkedsortoflikecomponents.Theideaofdirectivecomponentsbecamequitepopular.TheywerecreatedbyusingdirectivewithacontrollerwhilerelyingonthecontrollerAsandbindToControllerproperties.Forexample:
ComponentsinAngular2
75
angular.module('ngcourse').directive('ngcHelloComponent',()=>({restrict:'E',scope:{name:'='},template:'Hello,{{ctrl.name}}.',controller:MyComponentCtrl,controllerAs:'ctrl',bindToController:true}));
Infact,thisconceptbecamesopopularthatinAngular1.5the.componentmethodwasintroducedassyntacticsugar.
angular.module('ngcourse').component('ngcHelloComponent',{bindings:{name:'='},template:'Hello,{{$ctrl.name}}.',controller:MyComponentCtrl});
ComponentsinAngular2
76
CreatingComponentsComponentsinAngular2builduponthelessonslearnedfromAngular1.5.Wedefineacomponent'sapplicationlogicinsideaclass.Tothisweattach@Component,aTypeScriptdecorator,whichallowsyoutomodifyaclassorfunctiondefinitionandaddsmetadatatopropertiesandfunctionarguments.
selectoristheelementpropertythatweusetotellAngulartocreateandinsertaninstanceofthiscomponent.templateisaformofHTMLthattellsAngularwhatneedstobetorenderedintheDOM.
TheComponentbelowwillinterpolatethevalueofnamevariableintothetemplatebetweenthedoublebraces{{name}},whatgetrenderedintheviewis
HelloWorld
.
import{Component}from'@angular/core';
@Component({selector:'rio-hello',template:'
Hello,{{name}}!
',})exportclassHelloComponent{name:string;
constructor(){this.name='World';}}
WeneedtoimporttheComponentdecaratorfrom@angular/corebeforewecanmakeuseofit.TousethiscomponentwesimplyaddtotheHTMLfileoranothertemplate,andAngularwillinsertaninstanceoftheHelloComponentviewbetweenthosetags.
ViewExample
CreatingComponents
77
http://plnkr.co/edit/bXrxWVkP2MWD8yNDYqVD?p=preview
ApplicationStructurewithComponentsAusefulwayofconceptualizingAngularapplicationdesignistolookatitasatreeofnestedcomponents,eachhavinganisolatedscope.
Forexampleconsiderthefollowing:
Attherootwehaverio-todo-appwhichconsistsofario-todo-listandario-todo-form.Withinthelistwehaveseveralrio-todo-items.Eachofthesecomponentsisvisibletotheuser,whocaninteractwiththesecomponentsandperformactions.
ApplicationStructurewithComponents
78
PassingDataintoaComponentTherearetwowaystopassdataintoacomponent,with'propertybinding'and'eventbinding'.InAngular2,dataandeventchangedetectionhappenstop-downfromparenttochildren.HoweverforAngular2eventswecanusetheDOMeventmentalmodelwhereeventsflowbottom-upfromchildtoparent.So,Angular2eventscanbetreatedlikeregularHTMLDOMbasedeventswhenitcomestocancellableeventpropagation.
The@Input()decaratordefinesasetofparametersthatcanbepasseddownfromthecomponent'sparent.Forexample,wecanmodifytheHelloComponentcomponentsothatnamecanbeprovidedbytheparent.
import{Component,Input}from'@angular/core';
@Component({selector:'rio-hello',template:'
Hello,{{name}}!
',})exportclassHelloComponent{@Input()name:string;}
Thepointofmakingcomponentsisnotonlyencapsulation,butalsoreusability.Inputsallowustoconfigureaparticularinstanceofacomponent.
Wecannowuseourcomponentlikeso:
ViewExample
UnlikeAngular1.x,thisisone-waybinding.
PassingDataintoaComponent
79
http://plnkr.co/edit/LEtEN9?p=preview
RespondingtoComponentEventsAneventhandlerisspecifiedinsidethetemplateusingroundbracketstodenoteeventbinding.Thiseventhandleristhencodedintheclasstoprocesstheevent.
import{Component}from'@angular/core';
@Component({selector:'rio-counter',template:`
Count:{{num}}
Increment`})exportclassCounterComponent{num=0;
increment(){this.num++;}}
ViewExample
Tosenddataoutofcomponentsviaoutputs,startbydefiningtheoutputsattribute.Itacceptsalistofoutputparametersthatacomponentexposestoitsparent.
app/counter.component.ts
import{Component,EventEmitter,Input,Output}from'@angular/core';
@Component({selector:'rio-counter',templateUrl:'app/counter.component.html'})exportclassCounterComponent{@Input()count=0;@Output()result=newEventEmitter();
increment(){this.count++;this.result.emit(this.count);}}
RespondingtoComponentEvents
80
http://plnkr.co/edit/l4FweMxodN8I26OeqhGH?p=preview
app/counter.component.html
Count:{{count}}
Increment
app/app.component.ts
import{Component,OnChange}from'@angular/core';
@Component({selector:'rio-app',templateUrl:'app/app.component.html'})exportclassAppComponentimplementsOnChange{num=0;parentCount=0;
ngOnChange(val:number){this.parentCount=val;}}
app/app.component.html
ParentNum:{{num}}
ParentCount:{{parentCount}}
ViewExample
Togetherasetofinput+outputbindingsdefinethepublicAPIofyourcomponent.Inourtemplatesweusethe[squareBrackets]topassinputsandthe(parenthesis)tohandleoutputs.
RespondingtoComponentEvents
81
http://plnkr.co/edit/5RYLZ0?p=preview
UsingTwo-WayDataBindingTwo-waydatabindingcombinestheinputandoutputbindingintoasinglenotationusingthengModeldirective.
Whatthisisdoingbehindthescenesisequivalentto:
Tocreateyourowncomponentthatsupportstwo-waybinding,youmustdefinean@Outputpropertytomatchan@Input,butsuffixitwiththeChange.Thecodeexamplebelow,insideclassCounterComponentshowshowtomakepropertycountsupporttwo-waybinding.
app/counter.component.ts
import{Component,Input,Output,EventEmitter}from'@angular/core';
@Component({selector:'rio-counter',templateUrl:'app/counter.component.html'})exportclassCounterComponent{@Input()count=0;@Output()countChange=EventEmitter();
increment(){this.count++;this.countChange.emit(this.count);}}
app/counter.component.html
Count:{{count}}-Increment
UsingTwo-WayDataBinding
82
ViewExample
UsingTwo-WayDataBinding
83
http://plnkr.co/edit/nkww1Ov2AWZRMHFyjhjl?p=preview
AccessChildComponentsFromtheTemplateInourtemplates,wemayfindourselvesneedingtoaccessvaluesprovidedbythechildcomponentswhichweusetobuildourowncomponent.
Themoststraightforwardexamplesofthismaybeseendealingwithformsorinputs:
app/app.component.html
NameSubmitFormValue:{{formValue}}
app/app.component.ts
import{Component}from'@angular/core';
@Component({selector:'rio-app',templateUrl:'app/app.component.html'})exportclassAppComponent{formValue=JSON.stringify({});
onSubmit(form:NgForm){this.formValue=JSON.stringify(form.value);}}
ViewExample
Thisisn'tamagicfeaturewhichonlyformsorinputshave,butratherawayofreferencingtheinstanceofachildcomponentinyourtemplate.Withthatreference,youcanthenaccesspublicpropertiesandmethodsonthatcomponent.
app/app.component.html
AccessingChildComponentsfromTemplate
84
https://plnkr.co/edit/hfv5RC?p=preview
Mynameis{{profile.name}}
app/profile.component.ts
@Component({selector:'rio-profile',templateUrl:'app/profile.component.html'})exportclassProfileComponent{name='JohnDoe';}
ViewExample
Thereareothermeansofaccessingandinterfacingwithchildcomponents,butifyousimplyneedtoreferencepropertiesormethodsofachild,thiscanbeasimpleandstraightforwardmethodofdoingso.
AccessingChildComponentsfromTemplate
85
https://plnkr.co/edit/wEFOta?p=preview
ProjectionProjectionisaveryimportantconceptinAngular2.Itenablesdeveloperstobuildreusablecomponentsandmakeapplicationsmorescalableandflexible.Toillustratethat,supposewehaveaChildComponentlike:
@Component({selector:'rio-child',template:`ChildComponent{{childContent}}`})exportclassChildComponent{childContent="Defaultcontent";}
Whatshouldwedoifwewanttoreplace{{childContent}}toanyHTMLthatprovidedtoChildComponent?Onetemptingideaistodefinean@Inputcontainingthetext,butwhatifyouwantedtoprovidestyledHTML,orothercomponents?Tryingtohandlethiswithan@Inputcangetmessyquickly,andthisiswherecontentprojectioncomesin.Componentsbydefaultsupportprojection,andyoucanusethengContentdirectivetoplacetheprojectedcontentinyourtemplate.
So,changeChildComponenttouseprojection:
app/child/child.component.ts
import{Component}from'@angular/core';
@Component({selector:'rio-child',template:`ChildComponent`})exportclassChildComponent{}
Then,whenweuseChildComponentinthetemplate:
Projection
86
app/app.component.html
...
Myprojectedcontent.
...
ThisistellingAngular,thatforanymarkupthatappearsbetweentheopeningandclosingtagof,toplaceinsideof.
Whendoingthis,wecanhaveothercomponents,markup,etcprojectedhereandtheChildComponentdoesnotneedtoknowaboutorcarewhatisbeingprovided.
ViewExample
Butwhatifwehavemultipleandwanttospecifythepositionoftheprojectedcontenttocertainng-content?Forexample,forthepreviousChildComponent,ifwewanttoformattheprojectedcontentintoanextraheaderandfootersection:
app/child-select.component.html
ChildComponentwithSelect
Theninthetemplate,wecanusedirectives,say,tospecifythepositionofprojectedcontenttotheng-contentwithselect="header":
app/app.component.html
Projection
87
http://plnkr.co/edit/QAQ6BFuwuzEDVvqAmN9L?p=preview
...
SectionContentdivwith.class-selectFooterContentHeaderContent
...
Besidesusingdirectives,developerscanalsoselectang-contentthroughcssclass:
app/app.component.html
divwith.class-select
ViewExample
Projection
88
http://plnkr.co/edit/rH2vGgFluLXHCsgfkNjF?p=preview
StructuringApplicationswithComponentsAsthecomplexityandsizeofourapplicationgrows,wewanttodivideresponsibilitiesamongourcomponentsfurther.
Smart/Containercomponentsareapplication-specific,higher-level,containercomponents,withaccesstotheapplication'sdomainmodel.
Dumb/PresentationalcomponentsarecomponentsresponsibleforUIrenderingand/orbehaviorofspecificentitiespassedinviacomponentsAPI(i.ecomponentpropertiesandevents).Thosecomponentsaremorein-linewiththeupcomingWebComponentstandards.
StructuringApplicationswithComponents
89
UsingOtherComponentsComponentsdependonothercomponents,directivesandpipes.Forexample,TodoListComponentreliesonTodoItemComponent.Toletacomponentknowaboutthesedependencieswegroupthemintoamodule.
import{NgModule}from'@angular/core';
import{TodoListComponent}from'./components/todo-list.component';import{TodoItemComponent}from'./components/todo-item.component';import{TodoInputComponent}from'./components/todo-input.component';
@NgModule({imports:[...],declarations:[TodoListComponent,TodoItemComponent,TodoInputComponent],bootstrap:[...]})exportclassToDoAppModule{}
Thepropertydeclarationsexpectsanarrayofcomponents,directivesandpipesthatarepartofthemodule.
PleaseseetheModulessectionformoreinfoaboutNgModule.
UsingOtherComponents
90
DirectivesADirectivemodifiestheDOMtochangeapperance,behaviororlayoutofDOMelements.DirectivesareoneofthecorebuildingblocksAngular2usestobuildapplications.Infact,Angular2componentsareinlargepartdirectiveswithtemplates.
FromanAngular1perspective,Angular2componentshaveassumedalotoftherolesdirectivesusedto.Themajorityofissuesthatinvolvetemplatesanddependencyinjectionruleswillbedonethroughcomponents,andissuesthatinvolvemodifyinggenericbehaviourisdonethroughdirectives.
TherearethreemaintypesofdirectivesinAngular2:
Component-directivewithatemplate.Attributedirectives-directivesthatchangethebehaviorofacomponentorelementbutdon'taffectthetemplateStructuraldirectives-directivesthatchangethebehaviorofacomponentorelementbyaffectinghowthetemplateisrendered
Directives
91
AttributeDirectivesAttributedirectivesareawayofchangingtheappearanceorbehaviorofacomponentoranativeDOMelement.Ideally,adirectiveshouldworkinawaythatiscomponentagnosticandnotboundtoimplementationdetails.
Forexample,Angular2hasbuilt-inattributedirectivessuchasngClassandngStylethatworkonanycomponentorelement.
AttributeDirectives
92
NgStyleDirectiveAngular2providesabuilt-indirective,ngStyle,tomodifyacomponentorelement'sstyleattribute.Here'sanexample:
@Component({selector:'app-style-example',template:`
`})exportclassStyleExampleComponent{borderStyle='1pxsolidblack';}
ViewExample
Noticethatbindingadirectiveworkstheexactsamewayascomponentattributebindings.Here,we'rebindinganexpression,anobjectliteral,tothengStyledirectivesothedirectivenamemustbeenclosedinsquarebrackets.ngStyleacceptsanobjectwhosepropertiesandvaluesdefinethatelement'sstyle.Inthiscase,wecanseethatbothkebabcaseandlowercamelcasecanbeusedwhenspecifyingastyleproperty.AlsonoticethatboththehtmlstyleattributeandAngular2ngStyledirectivearecombinedwhenstylingtheelement.
Wecanremovethestylepropertiesoutofthetemplateintothecomponentasapropertyobject,whichthengetsassignedtoNgStyleusingpropertybinding.Thisallowsdynamicchangestothevaluesaswellasprovidestheflexibilitytoaddandremovestyleproperties.
NgStyleDirective
93
https://plnkr.co/edit/akK3Gw8W6EgUQ4PRQp4h?p=preview
@Component({selector:'app-style-example',template:`
`})exportclassStyleExampleComponent{borderStyle='1pxsolidblack';
alertStyles={'color':'red','font-weight':'bold','borderBottom':this.borderStyle};}
NgStyleDirective
94
NgClassDirectiveThengClassdirectivechangestheclassattributethatisboundtothecomponentorelementit'sattachedto.Thereareafewdifferentwaysofusingthedirective.
BindingastringWecanbindastringdirectlytotheattribute.Thisworksjustlikeaddinganhtmlclassattribute.
@Component({selector:'app-class-as-string',template:`
`,styles:[`.centered-text{text-align:center;}
.underlined{border-bottom:1pxsolid#ccc;}
.orange{color:orange;}`]})exportclassClassAsStringComponent{}
ViewExample
Inthiscase,we'rebindingastringdirectlysoweavoidwrappingthedirectiveinsquarebrackets.AlsonoticethatthengClassworkswiththeclassattributetocombinethefinalclasses.
Bindinganarray
NgClassDirective
95
https://plnkr.co/edit/uUtjY1Qlkx5dOB8gsqCm?p=preview
@Component({selector:'app-class-as-array',template:`
`,styles:[`.warning{color:red;font-weight:bold;}
.big{font-size:1.2rem;}`]})exportclassClassAsArrayComponent{}
ViewExample
Here,sincewearebindingtothengClassdirectivebyusinganexpression,weneedtowrapthedirectivenameinsquarebrackets.Passinginanarrayisusefulwhenyouwanttohaveafunctionputtogetherthelistofapplicableclassnames.
BindinganobjectLastly,anobjectcanbeboundtothedirective.Angular2applieseachpropertynameofthatobjecttothecomponentifthatpropertyistrue.
NgClassDirective
96
https://plnkr.co/edit/uUtjY1Qlkx5dOB8gsqCm?p=preview
@Component({selector:'app-class-as-object',template:`
ToggleFlat
`,styles:[`.card{border:1pxsolid#eee;padding:1rem;margin:0.4rem;font-family:sans-serif;box-shadow:2px2px2px#888888;}
.dark{background-color:#444;border-color:#000;color:#fff;}
.flat{box-shadow:none;}`]})exportclassClassAsObjectComponent{flat:boolean=true;}
ViewExample
Herewecanseethatsincetheobject'scardandflatpropertiesaretrue,thoseclassesareappliedbutsincedarkisfalse,it'snotapplied.
NgClassDirective
97
https://plnkr.co/edit/uUtjY1Qlkx5dOB8gsqCm?p=preview
StructuralDirectivesStructuralDirectivesareawayofhandlinghowacomponentorelementrendersthroughtheuseofthetemplatetag.Thisallowsustorunsomecodethatdecideswhatthefinalrenderedoutputwillbe.Angular2hasafewbuilt-instructuraldirectivessuchasngIf,ngFor,andngSwitch.
Note:Forthosewhoareunfamiliarwiththetemplatetag,itisanHTMLelementwithafewspecialproperties.Contentnestedinatemplatetagisnotrenderedonpageloadandissomethingthatismeanttobeloadedthroughcodeatruntime.Formoreinformationonthetemplatetag,visittheMDNdocumentation.
Structuraldirectiveshavetheirownspecialsyntaxinthetemplatethatworksassyntacticsugar.
@Component({selector:'app-directive-example',template:`
Underastructuraldirective.
`})
Insteadofbeingenclosedbysquarebrackets,ourdummystructuraldirectiveisprefixedwithanasterisk.Noticethatthebindingisstillanexpressionbindingeventhoughtherearenosquarebrackets.That'sduetothefactthatit'ssyntacticsugarthatallowsusingthedirectiveinamoreintuitivewayandsimilartohowdirectiveswereusedinAngular1.Thecomponenttemplateaboveisequivalenttothefollowing:
@Component({selector:'app-directive-example',template:`
Underastructuraldirective.
`})
Here,weseewhatwasmentionedearlierwhenwesaidthatstructuraldirectivesusethetemplatetag.Angular2alsohasabuilt-intemplatedirectivethatdoesthesamething:
StructuralDirectives
98
https://developer.mozilla.org/en/docs/Web/HTML/Element/template
@Component({selector:'app-directive-example',template:`
Underastructuraldirective.
`})
StructuralDirectives
99
NgIfDirectiveThengIfdirectiveconditionallyaddsorremovescontentfromtheDOMbasedonwhetherornotanexpressionistrueorfalse.
Here'sourappcomponent,wherewebindthengIfdirectivetoanexamplecomponent.
@Component({selector:'app-root',template:`ToggleComponentHello`})exportclassAppComponent{exists=true;
toggleExists(){this.exists=!this.exists;}}
ViewExample
ClickingthebuttonwilltogglewhetherornotIfExampleComponentisapartoftheDOMandnotjustwhetheritisvisibleornot.Thismeansthateverytimethebuttonisclicked,IfExampleComponentwillbecreatedordestroyed.Thiscanbeanissuewithcomponentsthathaveexpensivecreate/destroyactions.Forexample,acomponentcouldhavealargechildsubtreeormakeseveralHTTPcallswhenconstructed.InthesecasesitmaybebettertoavoidusingngIfifpossible.
NgIfDirective
100
https://plnkr.co/edit/Kb0KW89265F0e9pYJ118?p=preview
NgForDirectiveTheNgFordirectiveisawayofrepeatingatemplatebyusingeachitemofaniterableasthattemplate'scontext.
@Component({selector:'app-root',template:`{{episode.title}}`})exportclassAppComponent{episodes=[{title:'WinterIsComing',director:'TimVanPatten'},{title:'TheKingsroad',director:'TimVanPatten'},{title:'LordSnow',director:'BrianKirk'},{title:'Cripples,Bastards,andBrokenThings',director:'BrianKirk'},{title:'TheWolfandtheLion',director:'BrianKirk'},{title:'AGoldenCrown',director:'DanielMinahan'},{title:'YouWinorYouDie',director:'DanielMinahan'},{title:'ThePointyEnd',director:'DanielMinahan'}];}
ViewExample
TheNgFordirectivehasadifferentsyntaxfromotherdirectiveswe'veseen.Ifyou'refamiliarwiththefor...ofstatement,you'llnoticethatthey'realmostidentical.NgForletsyouspecifyaniterableobjecttoiterateoverandthenametorefertoeachitembyinsidethescope.Inourexample,youcanseethatepisodeisavailableforinterpolationaswellaspropertybinding.Thedirectivedoessomeextraparsingsothatwhenthisisexpandedtotemplateform,itlooksabitdifferent:
@Component({selector:'app',template:`{{episode.title}}`})
NgForDirective
101
https://plnkr.co/edit/dXU4K13piTYotDX5Nhi6?p=previewhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
ViewExample
Noticethatthereisanoddlet-episodepropertyonthetemplateelement.TheNgFordirectiveprovidessomevariablesascontextwithinitsscope.let-episodeisacontextbindingandhereittakesonthevalueofeachitemoftheiterable.
LocalVariablesNgForalsoprovidesothervaluesthatcanbealiasedtolocalvariables:
index-positionofthecurrentitemintheiterablestartingat0first-trueifthecurrentitemisthefirstitemintheiterablelast-trueifthecurrentitemisthelastitemintheiterableeven-trueifthecurrentindexisanevennumberodd-trueifthecurrentindexisanoddnumber
@Component({selector:'app-root',template:`{{i+1}}.{{episode.title}}
Desugared
{{i+1}}.{{episode.title}}`})
ViewExample
trackBy
NgForDirective
102
https://plnkr.co/edit/dXU4K13piTYotDX5Nhi6?p=previewhttps://plnkr.co/edit/58A5p8cWpVIY7Ne4O7aO?p=preview
OftenNgForisusedtoiteratethroughalistofobjectswithauniqueIDfield.Inthiscase,wecanprovideatrackByfunctionwhichhelpsAngularkeeptrackofitemsinthelistsothatitcandetectwhichitemshavebeenaddedorremovedandimproveperformance.
Angular2willtryandtrackobjectsbyreferencetodeterminewhichitemsshouldbecreatedanddestroyed.However,ifyoureplacethelistwithanewsourceofobjects,perhapsasaresultofanAPIrequest-wecangetsomeextraperformancebytellingAngular2howwewanttokeeptrackofthings.
Forexample,iftheAddEpisodebuttonwastomakearequestandreturnanewlistofepisodes,wemightnotwanttodestroyandre-createeveryiteminthelist.IftheepisodeshaveauniqueID,wecouldaddatrackByfunction:
NgForDirective
103
@Component({selector:'app-root',template:`AddEpisode{{episode.title}}`})exportclassAppComponent{
otherEpisodes=[{title:'TwoSwords',director:'D.B.Weiss',id:8},{title:'TheLionandtheRose',director:'AlexGraves',id:9},{title:'BreakerofChains',director:'MichelleMacLaren',id:10},{title:'Oathkeeper',director:'MichelleMacLaren',id:11}]
episodes=[{title:'WinterIsComing',director:'TimVanPatten',id:0},{title:'TheKingsroad',director:'TimVanPatten',id:1},{title:'LordSnow',director:'BrianKirk',id:2},{title:'Cripples,Bastards,andBrokenThings',director:'BrianKirk',id:3},{title:'TheWolfandtheLion',director:'BrianKirk',id:4},{title:'AGoldenCrown',director:'DanielMinahan',id:5},{title:'YouWinorYouDie',director:'DanielMinahan',id:6}{title:'ThePointyEnd',director:'DanielMinahan',id:7}];
addOtherEpisode(){//WewanttocreateanewobjectreferenceforsakeofexampleletepisodesCopy=JSON.parse(JSON.stringify(this.episodes))this.episodes=[...episodesCopy,this.otherEpisodes.pop()];}trackById(index:number,episode:any):number{returnepisode.id;}}
ToseehowthiscanaffecttheForExamplecomponent,let'saddsomeloggingtoit.
NgForDirective
104
exportclassForExampleComponent{@Input()episode;
ngOnInit(){console.log('componentcreated',this.episode)}ngOnDestroy(){console.log('destroyingcomponent',this.episode)}}
ViewExample
Whenweviewtheexample,asweclickonAddEpisode,wecanseeconsoleoutputindicatingthatonlyonecomponentwascreated-forthenewlyaddeditemtothelist.
However,ifweweretoremovethetrackByfromthe*ngFor-everytimeweclickthebutton,wewouldseetheitemsinthecomponentgettingdestroyedandrecreated.
ViewExampleWithouttrackBy
NgForDirective
105
https://plnkr.co/edit/jQmozF?p=previewhttps://plnkr.co/edit/hC2cIK?p=preview
NgSwitchDirectivesngSwitchisactuallycomprisedoftwodirectives,anattributedirectiveandastructuraldirective.It'sverysimilartoaswitchstatementinJavaScriptandotherprogramminglanguages,butinthetemplate.
@Component({selector:'app-root',template:`Tab1Tab2Tab3
Tabcontent1Tabcontent2Selectatab`})exportclassAppComponent{tab:number=0;
setTab(num:number){this.tab=num;}
isSelected(num:number){returnthis.tab===num;}}
ViewExample
HereweseethengSwitchattributedirectivebeingattachedtoanelement.Thisexpressionboundtothedirectivedefineswhatwillcomparedagainstintheswitchstructuraldirectives.IfanexpressionboundtongSwitchCasematchestheonegiventongSwitch,thosecomponentsarecreatedandtheothersdestroyed.Ifnoneofthecasesmatch,thencomponentsthathavengSwitchDefaultboundtothemwillbecreatedandtheothersdestroyed.NotethatmultiplecomponentscanbematchedusingngSwitchCaseandinthosecasesallmatchingcomponentswillbecreated.Sincecomponentsarecreatedordestroyedbeawareofthecostsindoingso.
NgSwitchDirectives
106
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/switchhttps://plnkr.co/edit/QWxD0DIZi6QiISafwfgu?p=preview
NgSwitchDirectives
107
UsingMultipleStructuralDirectivesSometimeswe'llwanttocombinemultiplestructuraldirectivestogether,likeiteratingusingngForbutwantingtodoanngIftomakesurethatthevaluematchessomeormultipleconditions.Combiningstructuraldirectivescanleadtounexpectedresultshowever,soAngular2requiresthatatemplatecanonlybeboundtoonedirectiveatatime.Toapplymultipledirectiveswe'llhavetoexpandthesugaredsyntaxornesttemplatetags.
@Component({selector:'app-root',template:`{{item}}`})
ViewExample
TheprevioustabsexamplecanusengForandngSwitchifthetabtitleandcontentisabstractedawayintothecomponentclass.
UsingMultipleStructuralDirectives
108
https://plnkr.co/edit/V2nWlGOwIITPrUDksGNG?p=preview
import{Component}from'@angular/core';
@Component({selector:'app-root',template:`
{{tab.title}}
{{tab.content}}Selectatab`})exportclassAppComponent{tabNumber:number=-1;
tabs=[{title:'Tab1',content:'Tabcontent1'},{title:'Tab2',content:'Tabcontent2'},{title:'Tab3',content:'Tabcontent3'},];
setTab(num:number){this.tabNumber=num;}
isSelected(num:number){returnthis.tabNumber===i;}}
ViewExample
UsingMultipleStructuralDirectives
109
https://plnkr.co/edit/YOT4G4buUZduwvVi8cMA?p=preview
AdvancedComponents
Figure:GBNetworkPCICardbyHarkeislicensedunderP