busy developer's workshop: angularjs - neward & … · busy developer's workshop:...
TRANSCRIPT
BusyDeveloper'sWorkshop:AngularJS
TedNewardNeward&Associates
http://www.tedneward.com|[email protected]
Credentials
Whoisthisguy?– TedNeward
•Principal-- Neward&Associates•Director-- DeveloperRelations,Smartsheet.com•Blog:http://blogs.tedneward.com•Writing:http://www.newardassociates.com/#/writing•Twitter:@tedneward•Formore,seehttp://www.newardassociates.com/#/about
Angular:TheWorkshop
Howarewegonnadothis?
Assumptions
Weareassumingthefollowing:– Youarecomfortablewithcommand-linetoolsandeditor– YouarecomfortablewithHTMLandwebappsingeneral– Youareatleastcomfortablewith"modern"JavaScript
ifnot,considerCrockford's"JavaScript:TheGoodParts"– YouknownothingaboutAngularorTypeScript
exceptmaybethatitexistsandthat"it'scool"
Objectives
GetupandrunningwithAngular– getthebasics
butcertainlynotanexhaustiveexploration!– exploresomeofthecoreconcepts
setyouuptoexploremoreonyourown– see"theAngularWay"upcloseandpersonal
andavoidsomeofthementalminefields– practice,practice,practice
Objectives
Whatshouldwebuildtoday?
Objectives
Enter...NgJoke!– anapplicationtoallowpeopletobrosedifferentjokes
•ChuckNorrisjokes?•Dadjokes?•Goodjokes?Badjokes?•Clearlytheworldneedsacomprehensiverepository
– Basicmaster-detailCRUDapplication
Objectives
Onlineresourcesforthisworkshopinclude:– Slides
http://www.newardassociates/slides/Workshops/AngularJS.pdf
– Labcode(withbranchesateachstep)https://github.com/tedneward/VSLive-AngularHOL
– Typescriptreference/docs•https://github.com/Microsoft/TypeScript•https://github.com/Microsoft/TypeScript/blob/2.1/doc/TypeScript%20Language%20Specification.pdf
– AngularJSwebsitedocumentationhttps://angular.io/docs/ts/latest
– AngularJS"cheatsheet"https://angular.io/docs/ts/latest/guide/cheatsheet.html
Lab0
IterationZero(15mins)
Overview
TypeScriptinanutshell
Overview
TypeScriptisMicrosoft'sentryintothefieldofJavaScripttranspilers– StaticallytypedsupersetofECMAScript2015
•AnyEScodeislegitimateTScode•SupportsES6class-basedOOPstyle•Entirely"friendly"totheECMAScriptecosystem
– ChosenlanguageforAngular2
Syntax
Startingwiththecore
Syntax
TypeScriptissyntacticallycompatiblewithECMAScript– anylegalECMAScriptcodeislegalTypeScriptcode– youdon'tneedtobeanECMAScriptexpert
...butithelps
Syntax
TypeScriptisthusaC-familylanguage– curlybracesdenotecodeblocks– (optional)semicolonterminator– if/else/elseif,switch,for,...
alltheusualsuspectsfromaC-basedlanguage
Syntax
Variabledeclarations– "var"declaresafunction-localvariable– "let"declaresablock-localvariable– "const"declaresablock-localvalue(immutable)– prefer"let"and"const"
Hello,World
Local variablesvar v_hello = "Hello";let l_hello = "Hello";const c_hello = "Hello";
Hello,World
Function scoping// Function scopefunction sumMatrix(matrix: number[][]) {
var sum = 0;for (var i = 0; i < matrix.length; i++) {
var currentRow = matrix[i];for (var i = 0; i < currentRow.length; i++) {
sum += currentRow[i];}
}return sum;
}
Syntax
Ambientdeclarations– sometimesavariablecomesfrom"outofnowhere"
•ala"document"or"window"inthebrowser•or"console"inthecommand-line
– TypeScriptallowsfor"ambientvariabledeclarations"•usesthe"declare"keyword•uses"var"declarationbyconvention
BasicTypes
Theatomsofthelanguage
BasicTypes
SupportedTypeScriptbasictypes– any– number,boolean,string– void,null,undefined– symbol
BasicTypes
TypeScriptdoeslimitedtypeinference– localvariabledeclarations– functionparameters
...butNOTafull-blowntype-inferencedlanguage– compilerwillrequiretypeannotationsinanumberofplaces
– ruleofthumb:startwithout,addwhenneededorwanted
BasicTypes
BasicTypes– Any:primevalroottype,allowsforuncheckedtypes– Number:numerics– Boolean:true/false– String:collectionsof0-ncharacters
•fullyUnicode-supported•singleordouble-quotedliterals•'backtick'literalsprovidemulti-lineand${}-styleinterpolation
BasicTypes
Basic typeslet isDone: boolean = false;
let decimal: number = 6;let hex: number = 0xf00d;let binary: number = 0b1010;let octal: number = 0o744;
let color: string = "blue";color = 'red';
let fullName: string = `Bob Bobbington`;let age: number = 37;let sentence: string = `Hello, my name is ${ fullName }.
I'll be ${ age + 1 } years old next month.`
BasicTypes
Symboltype– Symbolinstancesareuniquenames– typicallyconstructedbasedfromstrings– typicallyusedaskeysforproperties
avoidsaccidentalname-clashesacrosslibraries/modules– SymbolhasanumberofpredefinedSymbolinstances
hasInstance,iterator,match,replace,split,...
BasicTypes
Voidtype– usedtoindicatelackofreturn– technically,caninstantiateavoidinstance
nottypicallyuseful--canonlyreceivenullorundefinedvalues
BasicTypes
Nulltype– thetypeofthe"null"literal– Nulltypeisasubtypeofalltypes(exceptUndefined)
makes"null"avalidvalueforallprimitivetypes– typenotdirectlyreferencable
BasicTypes
Undefinedtype– thetypeofthe"undefined"literal– Undefinedtypeisasubtypeofalltypes(exceptNull)
•makes"undefined"avalidvalueforallprimitivetypes•languagespecifiesthisasthedefaultuninitializedvalue
– typenotdirectlyreferencable
BasicTypes
Typescanbemarkednullableornot-nullable– "?"suffixondeclarationaddsnullabilitycapability– "!"suffixonusagerequiesnon-nullability– in2.0,"null"and"undefined"becometypenames
makesiteasytodeclarenullableinstancesmoreexplicitlyw/unions
BasicTypes
Basic types// turn on --strictNullChecks//let foo1: string = null; // Error!let foo2: string | null = null; // OK
let strs: string[] | undefined;let upperCased = strs!.map(s => s.toUpperCase());
// Error! 'strs' is possibly undefined
let lowerCased = strs!.map(s => s.toLowerCase());// OK: 'strs' cannot be undefined
BasicTypes
Typealiases– "type"keywordcandeclareanaliasforanothertype– purelysyntacticsugar
meaning,thisisjustaname,notanewtype
BasicTypes
Stringliteraltypes– acuriousformofstring-basedenumerations– use"type"keywordand"|"-edstringliterals
BasicTypes
Basic typestype Music = "metal" | "punk" | "jazz" | "symphonic";let m : Music = "metal"; // OK//m = "rap"; // Error!
SimpleCompoundTypes
Buildingmoleculesoutofatoms
SimpleCompoundTypes
Arrays:fixed-sizecollectionofoneparticulartype– Syntaxcaneitherbe
•traditionalC-family"[]"•explicitgenericizeddeclarationof"Array<type>"
– indexedaccessstartingfrom0
SimpleCompoundTypes
Arrays and Tupleslet list1: number[] = [1, 2, 3];let list2: Array<number> = [1, 2, 3];
// These are functionally equivalent
SimpleCompoundTypes
Uniontypes– similarto"union"typesfromC++/C
doneatthedeclaration;notanewtype– usestheverticalpipecharactertodenote"or"– anythingassignabletooneoftheunion'smembersisaccepted
– anypropertyfromanyoftheunion'smembersareaccessible
SimpleCompoundTypes
Union typeslet a : string | number = "a"; // OKa = 10; // OK//a = false; // Error!
SimpleCompoundTypes
Intersectiontypes– representvaluesthatsimultaneouslyhavemultipletypes
avalueoftype"A&B"isavaluethatisbothoftypeAandtypeB
– typicallyusedforobjecttypes"string&number"effectivelymutually-exclusive
– canbeveryusefulforfunctionsignatures,however
SimpleCompoundTypes
Intersection typestype F1 = (a: string, b: string) => void; type F2 = (a: number, b: number) => void;
var f: F1 & F2 = (a: string | number, b: string | number) => { };
f("hello", "world"); // OKf(1, 2); // OK//f(1, "test"); // Error!
SimpleCompoundTypes
Tuples:fixed-sizecollectionofanydifferenttypes– unnamedfieldnames– accessusing"indices"intofields– tuplesarestructurallytyped
SimpleCompoundTypes
Arrays and Tuples// Declare a tuple typelet tuple: [string, number];tuple = ["hello", 10]; // OK//x = [10, "hello"]; // Error!console.log(tuple[0].substr(1)); // OK//console.log(x[1].substr(1)); // Error! 'number' does not have 'substr'
SimpleCompoundTypes
TypeScriptsupports"destructuring"declarations– Localscanbedeclaredas"parts"ofalargerthing
suchaselementsinatupleorarray– doingsoisessentiallyshorthand– emptycommacanignoreanelementinthesource– ...("spread")cancapturetherestintooneelement
SimpleCompoundTypes
Arrays and Tupleslet [first, , third] = list1; // from earlierconsole.log(first); // "1"console.log(third); // "3"
let [str, num] = tuple; // from earlierconsole.log(str); // "hello"console.log(num); // "10"
let numbers = [1, 2, 3, 4, 5];let [head, ...tail] = numbers;console.log(head); // "1"console.log(tail); // "[2, 3, 4, 5]"
SimpleCompoundTypes
Enumeratedtypes– representsboundsetofpossiblevalues– backedbynumericvalue
usuallystartingat0andincrementingifnotspecified– actualobjects/typesatruntime– "constenum"sarecompile-timecomputedforefficiency
SimpleCompoundTypes
Enumsenum Direction {
Up = 1,Down,Left,Right
}let dir = Direction.Down;
const enum GoodBeverages {DietCoke,VanillaShake,SingleMaltScotch
}let drink = GoodBeverages.DietCoke; // 0
FlowControl
Decision-makingandrepetition
FlowControl
Loopinganddecision-makingwithincode– looping:for,for-in,for-of,while,do-while– decision-making:if– branching:break,continue,return,throw– guardedcode:try/catch/finally
FlowControl
for– C-style"looping"construct– syntax
•initializationexpression•conditionalexpression•stepexpression
FlowControl
for-in– "looping"construct– operatesonlistofkeysonobject– servesasawaytoinspectpropertiesonanobject
FlowControl
for-of– "looping"construct– operatesonlistofvaluesonobject– mainlyinterestedinthevaluesofanobject
FlowControl
for, for-in and for-offor (let i=0; i<10; i++) {
console.log(i); // 0, 1, 2, 3, 4 ... 9}
let pets = new Set(["Cat", "Dog", "Hamster"]);pets["species"] = "mammals";
for (let pet in pets) {console.log(pet); // "species"
}for (let pet of pets) {
console.log(pet); // "Cat", "Dog", "Hamster"}
FlowControl
if– C-stylebooleanconditionalconstruct– conditionmustbeofbooleantype– optional"else"clause
FlowControl
break– terminateexecutionincurrentscope
continue– beginexecutionofnextloop
FlowControl
return– terminateexecutionofcurrentfunction– yieldavaluetocaller
throw– constructexceptionobject– terminateexecutionofcurrentscope– lookfor"catch"blocksincallers
FlowControl
try,catch,finally– trydenotesa"guardedblock"– catchdenotesablockenteredwhenanexceptionappearsinsideaguardedblock
– finallydenotesablockalwaysexecutedregardlessofhowtheguardedblockisexited
Functions
Doingstuff
Functions
Functionsstructure– "function"keyword– (optional)name– (optional)parameterlist
•parameterscanhavetypedeclarations•parameterscanhavedefaultvalues•parameterscanbedeclaredoptional•finalparametercanbedeclareda"rest"parameter
Functions
Functionsfunction add1(lhs : number, rhs : number) : number {
return lhs + rhs;}let add2 = function(lhs = 0, rhs = 0) {
return lhs + rhs; // return type inferred}let add3 = function(lhs: number, ...others : number[]) {
let total = lhs;for (let i of others) { total += i }return total;
}function add4(lhs : number, rhs? : number) : number {
if (rhs)return lhs + rhs;
return lhs;}
Functions
Lambdastructure– parameterlist
•typesoptional•parenthesesrequiredformorethanoneparameter
– "arrow"("=>")– lambdabody
•singleexpressionrequiresnobracesandnoreturn•multipleexpressionrequiresbracesandexplicitreturn
Functions
Lambdaslet add5 = function(lhs: number, ...others : number[]) {
return others.reduce( (prev,curr) => prev + curr);}let add6 = (lhs, rhs) => lhs + rhs;let add7 = (lhs, ...r) => r.reduce ( (prev, curr) => prev, lhs);
Functions
Functionshaveatypesignature– parameterlist
•types(required)•namesarehelpful,butnotpartofthesignature
– arrowseparator("=>")– returntype(required)– compilercanofteninfertypesfromusage
Functions
Functionslet add1t : (lhs : number, rhs : number) => number = add1;let add2t : (l : number, r : number) => number = add2;let add3t : (lhs : number, ...rest : number[]) => number = add3;let add4t : (l : number, r? : number) => number = add4;let add5t : (lhs : number, ...rest : number[]) => number = add5;
Classes
Entertheobject
Classes
Classes– TypeScriptbringsECMAScript2015classdeclarationsforward
– syntacticallyidenticalbutthenwecanaddtypedescriptors
– functionallyequivalentassumingthetype-checkingpasses
– "static"methods(nostaticfields)instead,useinstanceprototypeforstaticstorage
Classes
classclass Point {
x: number;y: number;constructor(x, y) {
this.x = x;this.y = y;
}add(other : Point) : Point {
this.x += other.x;this.y += other.y;return this;
}get distance () {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
}}let pt = new Point(5,12);console.log(pt.distance); // 13
Classes
Constructorscan"shorthand-declare"fields– parameterscanbedecoratedwithaccesscontrol– theseareeffectivelyfielddeclarations– automaticparameterassignmenttofieldimplied
Classes
classclass Person {
constructor (public firstName : string,public lastName : string,public age : number) {
// No body required}
}
Classes
NOTE:ThisisNOTC++/Java/C#-styleobjects– instancesholdaruntimereferencetothe"type"– "type"isbetterdescribedas"typeobject"– memberlookupfollowstheprototypelookupchain
Classes
Prototype chainlet origin = new Point(0,0);console.log(origin.toString());
console.log("Consulting origin...");for (let member in origin) {
console.log(member,"=",origin[member]);}
console.log("Consulting origin prototype...");let originP = Object.getPrototypeOf(origin);for (let member of Object.getOwnPropertyNames(originP)) {
console.log(member,"=",originP[member]);}
Classes
Inheritance– "BextendsA"– usesuper()toreferencebaseconstructor– usesuper.method()toreferencebasemethods
Classes
Inheritanceclass ThreeDPoint extends Point {
z: number;constructor(x, y, z) {
super(x,y);this.z = z;
}get distance () {
let dist = super.distance;return Math.sqrt(
(dist * dist) + (this.z * this.z)); }
}
let p : Point = new ThreeDPoint(1, 1, 1);console.log(p.distance);
Classes
Accesscontrol– memberscanbemarked
•public:accessibleanywhere•private:accessibleonlywithinthisclass•protected:accessibleonlywithinthisclassandsubclasses
– accessischeckedatTypeScript-compile-timeonlynoruntimeenforcement
Classes
Polymorphicthis– "this"normallyreferstothenominaltypeinwhichitisused
– asareturntype,"this"referstothetypewhenitisusedallowsforlate-boundtypingtothis
– extremelyusefulinfluentinterfaces
TypeCompatibility
Polymorphic thisclass BasicCalculator {
public constructor(protected value: number = 0) { }public currentValue(): number { return this.value; }public add(operand: number): this {
this.value += operand;return this;
}public multiply(operand: number): this {
this.value *= operand;return this;
}};let v1 = new BasicCalculator(2)
.multiply(5)
.add(1)
.currentValue();
TypeCompatibility
Polymorphic thisclass ScientificCalculator extends BasicCalculator {
public constructor(value = 0) {super(value);
}public sin() {
this.value = Math.sin(this.value);return this;
}}
let v2 = new ScientificCalculator(2).multiply(5).sin().add(1).currentValue();
Interfaces
Type-verifiedcontracts
Interfaces
Interfaces– declarationswithoutimplementation– essentiallya"contract"or"promise"ofbehavior– worksextremelywellwithTS'sstructuralsubtyping
Interfaces
Interfacesinterface LabelledValue {
label: string;}function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);}let myObj = {size: 10, label: "Size 10 Object"};printLabel(myObj);
Interfaces
OptionalpropertiesinInterfaces– propertiestype-suffixedwith"?"areoptional– optionalpropertiesdonotneedtobepresent– testforpresencewith"if"test
Interfaces
Optional propertiesinterface SquareConfig {
color?: string;width?: number;
}
function createSquare(config: SquareConfig) {let newSquare = {color: "white", area: 100};if (config.color) {
newSquare.color = config.color;}if (config.width) {
newSquare.area = config.width * config.width;}return newSquare;
}
let mySquare = createSquare({color: "black"});
Interfaces
Interfacescandescribefunctiontypes– sometimesmakesmorereadabletypes– goodtouseinsteadoftypealiases
Interfaces
Function interfaceinterface SearchFunc {
(source: string, subString: string): boolean;}
let mySearch : SearchFunc;mySearch = function(src: string, sub: string): boolean {
return true; // search in O(1) time}
Interfaces
Classescan"implement"interfaces– allinterface-declaredmembersmustbeonclass
•anymissingmemberswillbecaughtbycompiler•...orclassmustnotbeinstantiated
Interfaces
Interfacescandescribeindexabletypes– meaning,wecanuse"[]"toaccessthetype– parametercanbeeitherstringornumber
returntypeofnumber-indexermustbesameorsubtypeofstring-indexer
Lab1
DomainModels(30mins)
AngularJS(v2)
GettingStarted
GettingStarted
TouseAngularJS,youmusthave...– NodeJS– TypeScript
Installingtheseisusuallyprettystraightforward– InstallNodeJS(Homebrew,Chocolatey,apt-get,etc)– npminstall-gtypescript
GettingStarted
TouseAngularJS,youmust...– InstalltheAngularCLI
npminstall-g@angular/cli
AngularJSConcepts
TheBigPicture
Concepts
AngularJSdefinessomecorebuildingblocks– Modules– Components– Templates– Metadata– Databinding– Services– Directives– DependencyInjection
Concepts
Modules– Angularappsaremodularindesign
•everyappconsistsofatleastonemodulethe"rootmodule",normallycalledAppModule
Concepts
ComponentsAnAngularclassresponsibleforexposingdatatoaviewandhandlingmostoftheview’sdisplayanduser-interactionlogic.
Concepts
TemplatesAtemplateisachunkofHTMLthatAngularusestorenderaviewwiththesupportandcontinuingguidanceofanAngulardirective,mostnotablyacomponent.
Concepts
Metadata– alsoknownas"decorators"– amechanismfordescribingthe"surfacearea"ofacomponentormodule
Concepts
DatabindingApplicationsdisplaydatavaluestoauserandrespondtouseractions(clicks,touches,keystrokes)....usedatabindingbydeclaringtherelationshipbetweenanHTMLwidgetanddatasourceandlettheframeworkhandlethedetails.
Concepts
ServicesFordataorlogicthatisnotassociatedwithaspecificvieworthatyouwanttoshareacrosscomponents,buildservices....Aserviceisaclasswithafocusedpurpose.Youoftencreateaservicetoimplementfeaturesthatareindependentfromanyspecificview,provideshareddataorlogicacrosscomponents,orencapsulateexternalinteractions.
Concepts
DirectivesAnAngularclassresponsibleforcreating,reshaping,andinteractingwithHTMLelementsinthebrowserDOM
Concepts
DependencyInjectionDependencyinjectionisbothadesignpatternandamechanismforcreatinganddeliveringpartsofanapplicationtootherpartsofanapplicationthatrequestthem....Angulardevelopersprefertobuildapplicationsbydefiningmanysimplepartsthateachdoonethingwellandthenwiringthemtogetheratruntime.
Concepts
Resources– AngularJSArchitecture
https://angular.io/docs/ts/latest/guide/architecture.html– AngularJSGlossary
https://angular.io/docs/ts/latest/guide/glossary.html
Components
TheAngularWaytobuildaclassresponsibleforexposingdatatoaviewandhandlingmostoftheview’s
displayanduser-interactionlogic
Components
ComponentisaclassandHTMLview– componentshouldrepresentalogicalatomofUIorwork– classprovidescomponentstorageandlogic– HTMLprovidesviewUI/UX– classusesmetadatatoprovideadditionalinformation
@Componentdecorator
Components
Empty componentimport { Component } from '@angular/core';@Component({
selector: 'my-app',template: `<h1>Hello {{name}}</h1>`
})export class TitleComponent { name = 'Angular'; }
Components
@Componentdecorator– selector:thetagusedintheHTML– template:theHTMLfortheview– templateUrl:thefilecontainingtheHTMLview
onlyoneoftemplate/templateUrlisused– ...more
https://angular.io/docs/ts/latest/api/core/index/Component-decorator.html
Components
Lifecyclemethods– callbacksfromAngulartoinformcomponentofevents
methodscanbeimplementedviaTSinterfaces– ngOnInit/ngOnDestroy
preferinitializationinOnInit– ngOnChanges:firesonanypropertychange– ngDoCheck:detectandactuponchangesthatAngulardoesn'tcatchonitsown
– ngAfterViewInit,ngAfterViewCheckedcalledafterviewisinitializedandchecked
– ngAfterContentInit,ngAfterContentChecked
Modules
TheAngularWaytobuildacohesiveblockofcodededicatedtoasinglepurpose
Modules
Angularbreakseverythingintomodules– modulesformthemajorcomponentboundariesinAngular
•theseareES6modules•loadedviamoduleloaders(SystemJS,Webpack,etc)
– modulesprovidedefinitions•modulesexporttypes,functions,etc•othermodulesimportthedesiredbits
– Angularmodulesare"justmodules"•coreAngularbitsimportedviascopedpackages•@angular/core,@angular/common,@angular/forms,@angular/http
Modules
Angularmodules==ES6modules– use"export"topublicizeclasses– using"import"bringsmoduleintoscope– collectallcomponent-relatedmodulesintoonemodule
•callthisfile"index.ts"•(re-)exportthedeclaredelementsfromtheindividualfiles•thisisa"barrel"module
Modules
Angularmodules:asampling– Appcomponent(usuallycalledAppModule)
representsthe"rootcomponent"oftheapp– Directives
representsachunkoffunctionality– Components
adirectiveplusaview– Pipes
atooltotransforminputinsomeparticularmanner– Barrel
ameansto"rollup"declarationsintooneconvenientsyntax
Metadata
TheAngularWaytouseES6decoratorstoprovidedataabouttypes
Metadata
Angularmakesheavyuseofdecoratorstoprovidecomponentmetadata– theseprovideadditionalinformationtotheAngularenvironmentneverusedbythedeveloper/user
– decoratorsarealwaysES6functionsneverforgetthe()whenusingthem
Metadata
Listofcommonly-useddecorators– NgModule– Component
Metadata
Metadatacanalsobeappliedtofields– @Input():propertythatcanbeboundfromtheview– @Output():eventthatcanbeboundfromtheview
Templates
Layingouttheviewableparts
Templates
ViewsyntaxforAngular– templatescanappearinmetadataorstandalonefiles
•use"template"forinlinemetadatadeclarations•use"templateUrl"forstandalonefiles
– contentscontain"raw"HTMLplusAngularexpressions•someHTMLelementswon'tmakesenseinatemplate•somenon-HTMLconstructswillappear(components)•expressionsevaluatedinavarietyofways
– notethatsyntaxisalittleunusualinplacesmoreonthislater
Templates
Viewsyntax:Databinding– threeforms
•datasource->viewtarget•viewtarget->datasource•two-way/bidirectional
– eachhassomedifferentsyntax
Templates
Viewsyntax:Source-to-Viewdatabinding– {{}}(interpolation)syntax(data)– []propertybindingsyntax(targets)
thiswillre-evaluateasthevaluechanges– notethateithersyntaxcanoftenbeused(forstrings)– notethatfornon-strings,propertybindingsyntaxisrequired
Templates
Viewsyntax:Interpolation– {{}}surroundsavalidtemplateexpression
typicallyacomponentormodelproperty– evaluatedandresultdroppedinplace
Templates
Templateexpressions– expressionsproduceavalue– expressionshavesomerestrictions(nosideeffects)
•noassignments(=+=-=etc)•no"new"•nochainedexpressions(single-expressionsonly)•noincrement/decrementoperations(++--)
– expressionsarelimitedinscopetothecomponentinstanceand/ortemplate'scontext
– keepthesesimple!
Templates
Templatestatements– statementsarenotexpressions
•donothavetoproduceavalue•mayproducesideeffects(generallydesirable,infact)
– supportsexpressions,plus...•assignment•chainingexpressions(useof;or,)
– stillnotallowed:•no"new"•noincrement/decrement•nooperatorassignment(+=-=)•nobitwiseoperators(|&)
– keepthesesimple!
Templates
Tangent:HTMLattributevsDOMproperty– attributesaredefinedbyHTML;propertiesdefinedbytheDOM
– attributesinitializeDOMpropertiesonce– propertyvalueschangeovertime;attributesdon't– attributes!=properties,evenwhentheyhavethesamename
Templates
Viewsyntax:Propertybinding– taketheresultofanexpression,andbindittoaproperty– elementproperty,componentproperty,directiveproperty– square-bracketsusedtocapturethetarget– one-waybinding("bindingin")
Templates
Viewsyntax:Eventbinding– takeaneventsource(targetevent),invokeatemplatestatement
– eventsourcemustbesurroundedinround-brackets– one-waybinding("bindingout")– requiresanEventEmitter<T>inthecomponent– invokingemit()passestheeventouttoanyboundcode
•parametertoemit()ispassedtothetarget•parametertypeisthegenericized"T"parameter
Templates
Viewsyntax:Bidirectionalbinding– usesbothsquare- andround- bracketstosurroundthetarget
– establishesaround-tripcycleifcertainconventionsarefollowed•property"x"•eventEmitter"xChange"
– syntacticsugarequivalence:•<my-sizer[(size)]="fontSizePx"></my-sizer>•<my-sizer[size]="fontSizePx"(sizeChange)="fontSizePx=$event"></my-sizer>
Lab2
UpvoteComponent(30mins)
Lab3
JokeComponent(30mins)
Lab4
JokelistComponent(30mins)
Router
TheAngularWayofconfiguringandmanagingtheentireviewnavigationprocess
Router
Routingisthe"rearrangement"oftheview– formaster-detailscenarios...
•oneviewisthemasterlistofdataelements•anotheristhedetailedviewofanindividualelements
– theseusuallywanttobematchedupagainstURLpatternswhichstandardcomponentswouldn'tprovide
– ...andwedon'twanttowritestandaloneHTMLfileslossofscope,additionalroundtrips,etc
Router
Enter@angular/router– moduletoproviderouting/navigationsupport– entirelyoptional
Router
Routingconsistsofseveralkeyparts:– Routesconfiguration(typicallyinAppModule)
•establishingURLpatterns(paths)andcomponents•additionalelements(datatobepassed,etc)
– NgModuleconfigurationpassto"imports"metadataparameter
– "router-outlet"placeholderforview– "router-link"connectstotargetroutepath– routeparameterscanbeconsumedintargetcomponents
Router
Example Routes configurationconst appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },{ path: 'heroes', component: HeroListComponent },
];
@NgModule({imports: [
BrowserModule,FormsModule,RouterModule.forRoot(appRoutes)
],declarations: [
AppComponent,HeroListComponent,CrisisListComponent,
],bootstrap: [ AppComponent ]
})export class AppModule { }
Router
Example routing template (nav bar)template: `
<h1>Angular Router</h1><nav>
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a></nav><router-outlet></router-outlet>
`
Router
Routes are taken on first-match basis{ path: '**', component: PageNotFoundComponent }
PageNotFoundComponentimport { Component } from '@angular/core';@Component({
template: '<h2>Page not found</h2>'})export class PageNotFoundComponent {}
Router
Routes also can redirectconst appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },{ path: 'heroes', component: HeroListComponent },{ path: '', redirectTo: '/heroes', pathMatch: 'full' },{ path: '**', component: PageNotFoundComponent }
];
Lab5
Routing(30mins)
Services
TheAngularWayofprovidingdataorlogicthatisnotassociatedwithaspecificview
Services
ServicesinAngularprovidepurelogic– typicallyarounddataaccessofoneformoranother– essentially,functionalbehavior
Services
Servicesare"dependency-injected"– Angularwillpasstheserviceintothecomponent
thismakesserviceseasiertomockfortestingpurposes
Services
Serviceimplementation– standardTSclass– decoratedwith@Injectablemetadata– beyondthat,"just"aclass;providemethods,fields,etcasnormal
– typicallyserviceswillwanttousePromisesorRxJS
Services
Defining a serviceimport { Injectable } from '@angular/core';import { Hero } from './hero';import { HEROES } from './mock-heroes'; // const array@Injectable()export class HeroService {
getHeroes(): Promise<Hero[]> {return Promise.resolve(HEROES);
}}
Services
Serviceusage– componentdeclaresthedependencyviatwomechanisms:
•constructorparams•providersmetadataparameter
– Angularwillseetheprovidersdeclarationandmatchitagainsttheappropriateparameterintheconstructor
– notethatserviceswillnotbeavailablepriortongOnInit()
Services
Using a serviceimport { Component, OnInit } from '@angular/core';import { Hero } from './hero';import { HeroService } from './hero.service';@Component({
selector: 'my-app', template: `...`,providers: [HeroService]
})export class AppComponent implements OnInit {
heroes: Hero[];constructor(private heroService: HeroService) { }getHeroes(): void {
this.heroService.getHeroes().then(heroes => this.heroes = heroes);}ngOnInit(): void {
this.getHeroes();}
}
Lab6
Services(30mins)
Summary
Wrappingup(fornow)
Summary
Angularis...– ahighly-opinionatedframework– ahighly-productiveframework
onceyouagreetothe"AngularWay"ofdoingthings– growinginpopularity– averyreasonablechoiceforyourwebv.Nextapplications
Appendix
Somereferencematerial
ECMAScript6
AReallyFastIntro
ECMAScript6
ECMAScript6Syntax– (AsofMay9,2015)– Includes:
•Let+Const•Binary+OctalLiterals•Templatestrings•Unicode•Classes•Modules
ECMAScript6
ECMAScript6Syntax– (AsofMay9,2015)– Includes:
•EnhancedObjectLiterals•Defalt+Rest+Spread•Promises•IteratorsandForOf•Generators•Arrows•Comprehensions
ECMAScript6
ECMAScript6Syntax– (AsofMay9,2015)– Includes:
•DestructuringAssignment•ModulesandModuleLoaders•Map+Set+WeakMap+WeakSet•Proxies•Symbols•SubclassableBuilt-ins•Math+Number+String+ObjectAPIs•ReflectAPI•TailCalls
ECMAScript6
AllofthisisaccessibletoES5environments– ...throughtheES6->ES5transpiler,Traceur
•https://github.com/google/traceur-compiler•"npminstall-gtraceur"(asAdministrator)•"traceur{source.js}{output.js}"
– ...throughtheES6->ES5transpiler,Babel•https://babeljs.io•"npminstall-gbabel"(asAdministrator)•"babel{source.js}"•orrunBabelandthenNode:"babel-node{source.js}"
ECMAScript6
AllofthisisaccessibletoES5environments– ...throughTypeScript
•TSisactuallyveryclose(ifnotexact)toES6syntax•http://www.typescriptlang.org•"npminstall-gtypescript"•"tsc{source.js}"
ECMAScript6
NOTE:Transpilersusuallydependonaruntime– traceurrequires"traceur-runtime.js",forexample– thesewillbesupplantedbyECMAScriptstandardlibraries– ...butuntilyou'reonES6,makesuretoincludedependencies
ECMAScript6
LexicalandSyntaxchanges
ECMAScript6Lexical/Syntax
Lexicalandsyntacticstuff:Binary/OctalLiterals– Binaryliterals
•0b111110111(503decimal)– Octalliterals
•0o767(503decimal)
ECMAScript6Lexical/Syntax
Lexicalandsyntacticstuff:Unicode– AllECMAScript6codeisnowUnicode-based
•Unicodeliteralforminstrings•newAPIstoprocessstrings•extensionstoRegExp
ECMAScript6Lexical/Syntax
Lexicalandsyntacticstuff:TemplateStrings– "Backticked"strings
•backtickcharacterisnowanewstringliteraldelimiter•backticked-stringsaremultiline-aware
– Stringsnowsupportan"interpolation"form•similartoPython,Perl,Ruby,etc•use${name}-qualifiedidentifiers•combineswithbackticksverynicely
ECMAScript6Lexical/Syntax
Template Strings// String interpolationvar name = "Bob", time = Date.now();console.log(`Hello ${name}, how are you ${time}?`);
ECMAScript6Lexical/Syntax
Letandconst– Letisamutablevariabledeclaration– Constisanimmutablevariabledeclaration– Bothareblock-scoped– Bothpreventusebeforedeclaration
ECMAScript6Lexical/Syntax
Let and Constfunction f() {
{let x;{
// okay, block scoped nameconst x = "sneaky";// error, const//x = "foo";
}// error, already declared in block//let x = "inner";var y = "Fred";z = 12;
}}
ECMAScript6Lexical/Syntax
Lexicalandsyntacticstuff:Methodparameters– defaultparameters
methoddefinitionscannowhavedefaultvaluesforparameters
– "rest"parametersarraycanmapintoconsecutiveargumentsinafunctioncall
– "spread"parametersbindtrailingparametersintoanarray
ECMAScript6Lexical/Syntax
Method parameters: Default// Defaultsfunction slice(list, indexA = 0, indexB = list.length) {
// ...}
Method parameters: Rest// Rest paramsfunction push(array, ...items) {
items.forEach(function(item) {array.push(item);
});}var a = [];push(a, "1", "2", "3", "4", "5");console.log(a);
ECMAScript6Lexical/Syntax
Method parameters: Spreadfunction add(x, y) {
return x + y;}
var numbers = [4, 38];console.log(add(...numbers)); // 42
// Also works for array literalsvar a = [1];var b = [2, 3, 4];var c = [6, 7];var d = [0, ...a, ...b, 5, ...c];console.log(d);
ECMAScript6Lexical/Syntax
Lexicalandsyntacticstuff:Arrows– functionshorthand
•supportbothexpressionandstatementbodies•arrowssharethesamelexical"this"astheirsurroundingcode
ECMAScript6Lexical/Syntax
Arrows: Expression bodies// Expression bodiesvar evens = [2, 4, 6, 8];var odds = evens.map(v => v + 1);var nums = evens.map((v, idx) => v + idx);var pairs = evens.map(v => ({even: v, odd: v + 1}));console.log(odds);console.log(nums);console.log(pairs);
Arrows: Statement bodies// Statement bodiesvar fives = [];nums.forEach(v => {
if (v % 5 === 0)fives.push(v);
});console.log(fives);
ECMAScript6Lexical/Syntax
Arrows: Lexical this// Lexical thisvar bob = {
_name: "Bob",_friends: [],printFriends() {
this._friends.forEach(f =>console.log(this._name + " knows " + f));
}}bob._friends.push("Fred");bob.printFriends();
ECMAScript6
SemanticsChanges
ECMAScript6Semantics
Semantics:Symbols– Newprimitivetype(!)– Propertiescanbeenabledbynameorasymbol– Symbolsarenotvisibleoutsideoftheirdeclaredscope– Symbolisaclassthatholdswell-knownsymbols
•"@@iterator","@@match","@@hasInstance",etc•theseareallsymbolsthatareimportanttothelanguage
– Symbolsenableaccesscontrolforobjectstate
ECMAScript6
Symbolsvar MyClass = (function() {
var key = Symbol("key");
function MyClass(privateData) {this[key] = privateData;
}
MyClass.prototype = {doSomething: function() {
return this[key];}
};
return MyClass;})();
var c = new MyClass("hello");console.log(c.doSomething());console.log(c["key"]);
ECMAScript6Semantics
Semantics:DestructuringAssignment– "pickout"partsofanobjectandassigntovalues– commoninanumberoffunctionallanguages– usedwithbothobjectsandarrays(positionalassignment)– canalsobeusedinfunctionparameters
ECMAScript6
Destructuring Assignmentvar [a, b, c, d] = ['hello', ', ', 'world', 'ignored'];console.log(a + b + c);
// Some interesting objects we're working withvar pt = {x: 123, y: 444};var rect = {topLeft: {x: 1, y: 2}, bottomRight: {x: 3, y: 4}};
var {x, y} = pt; // unpack the pointvar {topLeft: {x: x1, y: y1}, bottomRight: {x: x2, y: y2}} = rect;
console.log(x, y);console.log(x1, y1, x2, y2); // 1,2,3,4
// Can be used in parameter positionfunction g({name: x}) {
console.log(x);}g({name: 5});
ECMAScript6Semantics
Semantics:IteratorsandFor-Of– CustomiterationalaCLRIEnumerableorJavaIterable– Use"for...of"similarto"for...in"– Noactualcollectionsrequired,justanobjectthatfollowstheIterableprotocol•objectmusthaveanext()method•returnfromthenext()methodmusthavea"done"and"value"field
ECMAScript6
Iterators and for-offor (let element of [1, 2, 3]) {
console.log(element);}
let fibonacci = {[Symbol.iterator]() {
let pre = 0, cur = 1;return {
next() {[pre, cur] = [cur, pre + cur];return { done: false, value: cur }
}}
}}
ECMAScript6
Iterators over generic arrayfunction iterateElements(array) {
return {[Symbol.iterator]: function() {
var index = 0;var current;return {
next: function() {if (index < array.length) {
current = array[index++];return { done:false, value: current };
}return { done:true, value: current };
}};
}};
}
let numbers = [1, 2, 3, 4, 5, 6];for (let n of iterateElements(numbers)) {
console.log(n);}
ECMAScript6Semantics
Semantics:Generators– generatorsare"thingsthatproduceavalue"– thinkofthemastheothersideofaniterable– producedwitheithera"yield"/"yield*"ora"function*"
ECMAScript6
Generators// A simple collection of namesfunction* createNames() {
yield "Ted";yield "Rocky";yield "Andrew";yield "Brian";
}
let names = createNames();console.log(names.next().value);console.log(names.next().value);console.log(names.next().value);console.log(names.next().value);
ECMAScript6
Generators: the ever-present Fibonacci examplevar fibonacci = {
[Symbol.iterator]: function*() {var pre = 0, cur = 1;for (;;) {
var temp = pre;pre = cur;cur += temp;yield cur;
}}
}
for (var n of fibonacci) {// truncate the sequence at 1000if (n > 1000)
break;console.log(n);
}
ECMAScript6Semantics
Semantics:TailCalls– withrecursion,comesinefficiency– runtimescanbeoptimizedtospotcertainkindsofrecursionandoptimize
– "tail-callrecursionoptimization"– givenhowrecursiveECMAScriptisbecoming,wewantithere,too
ECMAScript6
Classes
ECMAScript6Classes
Classes:Classconstruct– simplesugaroverprototype-basedOO
•stillprototype-basedinheritance•"super"callstoprototype•instanceandstatic•fields•methods•constructors
ECMAScript6Classes
Classesclass Monster extends Character {
constructor(x, y, name) {super(x, y);this.name = name;this.health_ = 100;
}
attack(character) {super.attack(character);
}
get isAlive() { return this.health_ > 0; }get health() { return this.health_; }set health(value) {
if (value < 0) throw new Error('Health must be non-negative.');this.health_ = value;
}}
ECMAScript6Classes
Classes:EnhancedObjectliterals– goal:bringclassdeclarationsandobjectliteralsclosertogether•settheprototypeatconstruction•shorthandsyntaxforsame-nameassignments•definingmethods•makingsupercalls•computepropertynameswith(runtime)expressions
ECMAScript6Classes
Object initializer shorthandvar handler = function() {
console.log("Handled!");};var theProtoObj = {
name: "Proto"};var obj = {
// __proto____proto__: theProtoObj,// Shorthand for 'handler: handler'handler,// MethodstoString() {
// Super callsreturn "d "; // + super.toString();
},// Computed (dynamic) property names[ 'prop_' + (() => 42)() ]: 42
};obj.handler();console.log(obj.toString());console.log(obj.prop_42);
ECMAScript6Classes
Proxies– meettheultimateDecorator– veryaspect-oriented-ish– NOTE:currentlyrequiresadditionalsupportoutsideoftranspilershttps://github.com/tvcutsem/harmony-reflect
ECMAScript6Classes
Proxy all the things// Object interceptionvar target = {};var handler = {
get: function(receiver, name) {return `Hello, ${name}!`;
}};var proxy = new Proxy(target, handler);console.log(proxy.world);
// Function interceptiontarget = function() { console.log("Hello, world!"); }handler = {
apply: function(receiver, ...args) {console.log("Before execution");receiver(args);console.log("After execution");
}}proxy = new Proxy(target, handler);proxy();
ECMAScript6
Libraries,modules,andothersupportstuff
ECMAScript6Libraries
Map/Set– Efficientdatastructuresforcommonalgorithms– Map:key/valuepairs– Set:"bag"allowingnoduplicates
WeakMap/WeakSet– MapsandSetswithweakreferences– usedforcachingandothermoresubtlepurposes
ECMAScript6Libraries
Mapvar m = new Map();m.set("hello", 42);m.set("goodbye", "world");console.log(m.get("hello") === 42);
ECMAScript6Libraries
Setvar s = new Set();s.add("hello");console.log(s.size);s.add("goodbye");console.log(s.size);s.add("hello");console.log(s.size);
ECMAScript6Libraries
Promises– nativeNodecodereliesheavilyoncallbacks
•"noblockingcalls"•thisgetsawkwardtodealwith
– promisesarelibrariesthathelpwrestlethisproblemdown
ECMAScript6Libraries
Promises– Promiseclasstakestwo-argcallback
•resolve:functiontoexecutiononresolution•reject:functiontoexecuteincaseoffailedpromise
– Promisescanbe"chained"•then()providesnextfunctiontoexecute•catch()providesfunctiontoexecuteincaseoferror
– Promiseobjectprovidesafewadditionalutilities•all()executeslistoffunctionsinparallel
ECMAScript6Libraries
Promises// Promisesfunction timeout(duration = 0) {
return new Promise((resolve, reject) => {console.log("Promise constructor");setTimeout(resolve, duration);
});}
var p = timeout(1000).then( () => {console.log("Promise then");return timeout(2000);
}).then( () => {console.log("Throwing Error");throw new Error("hmm");
}).catch(err => {return Promise.all([timeout(100), timeout(200)]);
});
ECMAScript6Libraries
Modules– require()isabitofahack– codeformalizesmodulesandmoduleloaders– seekingtobetterstructureJScodeforlarger-scaleprojects– mostlycodifyingconventionsinusebyJSprogrammersforyearsnow
ECMAScript6Libraries
Modules:Importing("import")– "import*from'module''":importsallmembersofmodule– "import{foo,bar}from'module'":importsfoo,barfrommodule
– "import*asmodfrom'module'":importsas"mod"-namedentity
– importtypostriggernoerrors– importedvariablesareread-only
however,objectmembersarenot
ECMAScript6Libraries
Modules:Creating– module==ECMAScriptfilethatexportsentities– moduleshavetheirownscope– modulesarenamedusingfilesystemconventions
•utils.js=="utils"or"utils.js"•utils/index.js=="utils","utils/index"or"utils/index.js"
ECMAScript6Libraries
Modules:Exporting("Export")– "exportdefaultthing":thingisthedefaultexport– eachdefault-exportedthingispartoftheobjectreturned– "export{thingasotherThing}":thingisexportedasotherThing
ECMAScript6Libraries
Modules// Profile.jsexport var firstName = 'Fred';export var lastName = 'Flintstone';export var year = -1000;
// ProfileView.jsimport {firstName, lastName, year} from './profile.js';
console.log(firstName + ' ' + lastName);