Level 1
Our First Component
Section 1
What Is Angular?
Angular is a framework for dynamic web applications.
Provides a way to organize your HTML, JavaScript, and CSS
to keep your front-end code clean.
Released in 2011.
Mainly maintained by Google with the help of the opensource community.
Back-end Server
What Will We Be Building in This Course?
In the Challenges
What Will This Course Cover?
Level 1
Our First Component
Level 2
Structural Directives, Pipes & Methods
Level 3
Code Organization & Data Models
Level 4
Data Binding
Level 5
Services & HTTP
n
e
e
w
t
e
b
s
e
g
n
e
l
l
a
h
c
f
o
s
t
o
l
h
t
Wi
What Do You Need to Know to Take This Course?
Basic JavaScript
You dont
need any p
rior experie
nce with A
ngular 1
JavaScript Road Trip Parts 1, 2 & 3
Basic HTML & CSS
Front-end Foundations & Front-end Formations
(optional)
JavaScript: ES2015
ES2015: The Shape of JavaScript to Come
What Is the Dierence Between Angular 1 & 2?
Speed Angular 2 is faster.
Components Instead of controllers and scope, we use
components, which feel simpler.
Simpler Directives Creating custom directives is much
simpler.
Intuitive Data Binding When we need to link data to an
HTML element or listen for a button clicking on the page, we
have an intuitive syntax.
Services are now just a class.
Many more small improvements.
What Language to Use With Angular 2?
JavaScript
But all browsers dont support the newest version of JavaScript.
There are ways to access these features:
Transpile
Means it gets changed into JavaScript
: Our Language of Choice
TypeScript is Microsofts extension of JavaScript that allows the use of all ES2015 features
and adds powerful type checking and object-oriented features.
The Angular 2 source is programmed with TypeScript.
main.js
Instead, we will use
main.ts
Now we can use improved syntax!
http://www.typescrip
tlang.org
Transpiling Locations
Our browsers dont know how to read TypeScript out of the box, so we have two options
when it comes to changing our TypeScript code into JavaScript.
Transpile to JavaScript in the browser
Transpile to JavaScript before shipping to browser
This method is faster
and will be what you
want to do in production.
Building Our Index
index.html
HTML
<!DOCTYPE html>
<html>
<head>
<!-- All the Angular 2 libraries needed -->
</head>
</html>
When youre ready to start developing, we
suggest you go through the
5-minute QuickStart Guide.
http://go.codeschool.com/angular2start
We wont be covering all the libraries you
need to load up Angular 2.
Creating Our First Custom Element
index.html
HTML
This is where our Angular 2 application
will load.
<!DOCTYPE html>
<html>
<head>
<!-- All the Angular 2 libraries needed -->
</head>
This could be named anything,
even <racing-app>
<body>
<my-app>Loading App ...</my-app>
</body>
Until our app gets loaded in the browser,
we see:
</html>
Loading a JavaScript File Using SystemJS
index.html
HTML
<!DOCTYPE html>
<html>
<head>
<!-- All the Angular 2 libraries needed -->
<script>
...
System.import('app')
.catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading App ...</my-app>
</body>
</html>
SystemJS is a JavaScript library that
allows us to import other libraries.
app/main.ts
This loads our applications code.
Error messages should be printed
out to the browser console.
Writing Our First TypeScript File
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
import
bootstrap
Angular 2 library modules
ES2015 feature used to import functions, objects, or primitives.
A function used to instantiate an Angular 2 application.
Note: This has nothing to do with Bootstrap,
the front-end framework.
Component
A function we will use to create our rst component.
Components are the basic building blocks of Angular 2
applications. A component controls a portion of the screen.
Component Is a Decorator Function
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
Our component decorator code goes here.
class AppComponent { }
A decorator
adds more behavior to our class from outside the class.
It must be declared immediately before the class.
The decorator turns our plain old JavaScript class into a component.
Decorating Our First Component
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>Ultra Racing</h1>'
})
class AppComponent { }
@Component
index.html
<body>
<my-app>Loading App ...</my-app>
</body>
Often called metadata
Used to apply our component decorator to our class.
Decorators are a TypeScript feature.
selector
The CSS selector for the HTML element where we want the component to load.
template
The content we want to load inside our selector.
Bootstrapping Our First Component
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>Ultra Racing</h1>'
})
index.html
<body>
<my-app>Loading App ...</my-app>
</body>
class AppComponent { }
bootstrap(AppComponent)
We send our component into bootstrap to
instantiate an Angular 2 application.
Viewing the Source
Our App Is Full of Components
Components are the building blocks of Angular 2 applications.
And they easily nest one inside the other.
Each component may have its own:
class le
html le
css le
Sending Data Around
How do we send a property from our component class into our HTML?
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>???</h1>'
})
class AppComponent {
title = 'Ultra Racing';
}
bootstrap(AppComponent);
Inside a TypeScript class, we dont use the var or let
keywords to declare class properties.
Though we do in regular methods.
Using Interpolation to Print Properties
Curly braces allow us to load in component properties this is called interpolation.
app/main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<h1>{{title}} </h1>'
})
class AppComponent {
title = 'Ultra Racing';
}
bootstrap(AppComponent);
Loading an Object
What if we have an object we want to print out onto the screen?
app/main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: '<h1>{{title}} </h1>'
})
class AppComponent {
title = 'Ultra Racing';
carPart = {
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
};
}
bootstrap(AppComponent);
Template with Back Ticks
app/main.ts
TypeScript
Our template now uses back ticks
instead of single quotes.
...
@Component({
selector: 'my-app',
template: `<h1>{{title}} </h1>
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p> `
})
class AppComponent {
title = 'Ultra Racing';
carPart = {
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
};
}
bootstrap(AppComponent);
Single Quote
Back Tick
Using the back ticks allows us to
have template strings, which allows
us to be multiline.
This is another ES2015 feature.
Whatd We Learn?
Angular is a framework for dynamic web applications.
We are coding Angular using TypeScript, a language that transpiles into JavaScript.
Components are the basic building blocks of any Angular application.
We use a custom HTML tag (aka, selector) to show where we want our component to load
inside our HTML.
Our component decorator is what turns our plain TypeScript class into a component.
Level 2
Structural Directives
Section 1
Learning Angular Directives
A directive (within Angular) is how we add dynamic behavior to HTML.
There are three dierent kinds of directives:
Component
Has a template.
Structural
We will dene these later.
Attribute
We wont get to these.
Looking Back at Our Code
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p>
})
class AppComponent {
title = 'Ultra Racing';
carPart = {
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
};
}
bootstrap(AppComponent);
What if we had more than
one car part?
Adding an Array of Car Parts
main.ts
TypeScript
...
})
class AppComponent {
title = 'Ultra Racing';
carParts = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
},
{
"id": 2,
"name": "Reinforced Shocks",
"description": "Shocks made from kryptonite",
"inStock": 4
}, { ... }];
}
bootstrap(AppComponent);
Now that we have many car
parts, how do we loop through
each of these?
Adding an Array of Car Parts
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p>
</li>
</ul>`
})
class AppComponent {
title = 'Ultra Racing';
carParts = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
}, { ... }, { ... }];
*ngFor
is a structural directive.
carPart
carParts
is a local variable.
is the array to loop through.
The loop is run three times:
once for each carPart.
Learning Angular Directives
A directive (within Angular) is how we add dynamic behavior to HTML.
Component
Has a template.
Structural
Alters layout by adding, removing, or replacing HTML elements.
*ngFor
When Car Parts Are Out of Stock
When there are none in stock, how can we display Out of Stock?
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p>
</li>
</ul>`
})
class AppComponent {
...
Should read Out of Stock
Using ngIf With a Conditional
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
</li>
</ul>`
If true, display this.
})
class AppComponent {
...
*ngIf
is another structural directive. It allows us to evaluate conditionals.
Whatd We Learn?
A directive (within Angular) is how we add dynamic behavior to HTML.
A component directive has a template.
A structural directive alters layout by adding, removing, or replacing HTML elements.
*ngFor
*ngIf
Loops through an array.
Shows content conditionally.
Level 2
Pipes & Methods
Section 2
Using Pipes to Format Screen Data
A pipe takes in data as input and transforms it to a desired output.
How can we write out car part names in capital letters?
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
<h2>{{carPart.name | uppercase }}<h2>
<p>{{carPart.description}}<p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
</li>
</ul>`
})
class AppComponent {
...
Similar to Linux pipe,
if youre familiar with it.
Adding a Price to Our Data
main.ts
...
})
class AppComponent {
title = 'Ultra Racing';
carParts = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
},
{
"id": 2,
"name": "Reinforced Shocks",
"description": "Shocks made from kryptonite",
"inStock": 4,
"price": 9.99
}, ...
But how do we format this properly?
TypeScript
Using Documentation to Look Up Pipes
Using the Currency Pipe With One Parameter
To format our currency, we use the ISO 4217 currency code.
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts" >
<h2>{{carPart.name | uppercase }}</h2>
<p>{{carPart.description}}</p>
<p>{{carPart.price | currency:'EUR'}}</p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
<li>
<ul>`
})
class AppComponent {
...
But we want the EUR symbol how do we do that?
Ex.: USD, EUR, or CAD
Using the Currency Pipe With Two Parameters
The second parameter is a boolean indicating if we should use the currency symbol.
main.ts
TypeScript
...
@Component({
Notice the colon
selector: 'my-app',
template: `<h1>{{title}}</h1>
between parameters.
<ul>
<li *ngFor="let carPart of carParts" >
<h2>{{carPart.name | uppercase }}</h2>
<p>{{carPart.description}}</p>
<p>{{carPart.price | currency:'EUR':true }}</p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
<li>
<ul>`
})
class AppComponent {
...
Additional Pipes to Use
lowercase
date
Well, lowercase...
Formats dates how you like them.
You can
also crea
te custo
m pipes
!
number
Formats numbers.
decimal
Formats decimals.
replace
Creates a new string, replacing specied characters.
slice
json
Creates a new list or string containing a subset of the elements.
Transforms any input to a JSON-formatted string.
Great for debugging
Listing the Number of Car Parts in Stock
How could we display the total number of car parts in stock?
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
...
Modifying the Template
Well add new code to our HTML template and print the result of a method were about
to dene.
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<p>There are {{ totalCarParts() }} total parts in stock.</p>
<ul>
<li *ngFor="let carPart of carParts">
...
We dene this method inside of our component class.
Modifying the Template
Lets do the simplest thing and implement a class method that returns 10.
main.ts
TypeScript
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<p>There are {{ totalCarParts() }} total parts in stock.</p>
...
})
class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() {
return 10;
}
}
Inside a TypeScript class, we dont
use the word function, just like
we dont use let to declare the
properties.
ES2015 functionality enabled by
TypeScript!
Implementing the Sum of Car Parts
Lets use an ES2015 for of loop, like in our template.
main.ts
TypeScript
class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() {
let sum = 0;
ES2015
for (let carPart of this.carParts) {
sum += carPart.inStock;
}
return sum;
}
}
Whatd We Learn?
We can use pipes to transform our template output.
How to create and use methods in our components.
Our Current Application Structure
index.html
app
main.ts
Bonus: Simplifying a Sum
totalCarParts() {
let sum = 0;
Just for fun, lets go through a few
ways we could simplify this code.
for (let carPart of this.carParts) {
sum += carPart.inStock;
}
return sum;
}
totalCarParts() {
return this.carParts.reduce(function(prev, current) { return prev + current.inStock; }, 0 );
}
The fat arrow (ES2015)
totalCarParts() {
return this.carParts.reduce((prev, current) => prev + current.inStock, 0 );
}
Level 3
Splitting to Two Components
Section 1
Splitting Things Into Pieces
Weve been developing Angular 2 in one single le: main.ts. This isnt going to scale, so
lets split things up into pieces and get organized.
main.ts
We will take our single le and split it into three.
main.ts
Where well bootstrap our app, loading our rst component.
app.component.ts
This component contains our page header.
car-parts.component.ts
This contains our list of car parts.
o
w
t
e
v
a
h
l
l
i
w
e
w
,
s
i
h
t
.
After
e
n
o
f
o
d
a
e
t
s
n
i
s
t
n
e
n
compo
Trimming Down Our main.ts
This is where we bootstrap our app, loading our rst component.
main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
...`
})
class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}.
bootstrap(AppComponent)
Theres a bunch of code we need to move elsewhere.
Creating Our app.component.ts
We move most of our code into app.component.ts.
main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
bootstrap(AppComponent)
However, this code is broken. Were bootstrapping our
AppComponent, but we dont have access to this class.
How do we get access to a class from another le?
app.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
...`
})
class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}.
Exporting & Importing
We need to use the ES2015 feature of exporting and importing.
main.ts
TypeScript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent)
First, we export the class we want to import.
Then, we import this class into our main.ts.
The names must be the same in each le.
app.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
...`
})
export class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}.
One More File to Create
We need to create a car-parts.component.ts.
app
main.ts
Where well bootstrap our app, loading our rst component.
app.component.ts
This component contains our page header.
car-parts.component.ts
This contains our list of car parts.
t
n
e
n
o
p
m
o
C
p
p
A
r
u
o
t
li
p
s
We need to
.
s
t
n
e
n
o
p
m
o
c
o
w
t
o
t
in
Splitting Out Our Components
We need to remove the car parts-specic code from app.component.ts.
app.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<p>There are {{totalCarParts()}} total parts in stock.</p>
<ul>...</ul>`
})
export class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}
Splitting Out Our Car Parts Component
app.component.ts
TypeScript
TypeScript
car-parts.component.ts
import { Component } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1> `
})
export class AppComponent {
title = 'Ultra Racing';
}
@Component({
selector: 'car-parts',
template: `
Notice our new selector!
<p>There are {{totalCarParts()}} total parts in stock.</p>
<ul>...</ul> `
})
export class CarPartsComponent {
carParts = [...];
totalCarParts() { ... };
}
Three things we need to do inside our app.component.ts le to make it work:
Import our new component.
Use our new selector.
<car-parts>
Tell our AppComponent to explicitly use the CarPartsComponent.
Importing & Using Our New Component
app.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPartsComponent } from './car-parts.component'
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<car-parts></car-parts> `
})
export class AppComponent {
title = 'Ultra Racing';
}
Our new selector
Not working yet. Angular doesnt know to look for
our car-parts selector inside the template.
t
n
e
n
o
p
m
o
c
w
e
n
r
u
o
g
in
d
lu
Inc
e
h
t
n
e
e
w
t
e
b
g
in
h
t
o
N
car-parts tag
Specify Which Components We Use
We need to tell our AppComponent were using the CarPartsComponent in the template.
app.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPartsComponent } from './car-parts.component'
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>
<car-parts></car-parts> `,
directives: [CarPartsComponent]
})
export class AppComponent {
title = 'Ultra Racing';
}
Notice its an array.
List all the directives we use in the template.
Remember: A component is a type of directive.
Now it works!
Weve Separated Our Concerns!
app
main.ts
Where well bootstrap our app, loading our rst component.
app.component.ts
This component contains our page header.
car-parts.component.ts
This contains our list of car parts.
And weve created our rst reusable component.
Components are meant to be reusable, so we could use them
in dierent parts of our application.
Angular 2 Uses Component-based Architecture
Components can be all over the place in your application.
This isnt
what we
r
e
building
well k
eep it eve
n simpler
.
Our Two Components
AppComponent
CarPartsComponent
Whatd We Learn?
Our main.ts is where we import our rst component and bootstrap it.
In order to import a class, we must give it the export keyword.
We use the directives metadata to list the directives our component uses.
Components are the building blocks of our application.
index.html
app
main.ts
app.component.ts
car-parts.component.ts
Level 3
Component HTML & CSS
Section 2
How Do We Tie CSS to a Component?
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'car-parts',
template: `...
<p>{{carPart.description}}</p>
<p>{{carPart.price | currency:'EUR':true}}</p>
...`
})
export class CarPartsComponent {
...
We have an HTML template, and we can even include CSS.
Adding Styles Array Metadata
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'car-parts',
template: `...
New CSS classes
<p class="description" >{{carPart.description}}</p>
<p class="price" >{{carPart.price | currency:'EUR':true}}</p>
...`,
styles:[`
.description {
color: #444;
font-size: small;
}
.price {
font-weight: bold;
}
`]
Notice this is an array.
})
export class CarPartsComponent {
The CSS Is Scoped to the Component
The HTML Source
<p _ngcontent-dcy-2 class="description">These tires are the very best</p>
<p _ngcontent-dcy-2 class="price">4.99</p>
Notice the custom attribute.
The CSS Source
.description[_ngcontent-dcy-2] {
color: #444;
font-size: small;
}
.price[_ngcontent-dcy-2] {
font-weight: bold;
}
,
d
e
p
o
c
s
e
r
a
s
e
Angular 2 adds this custom attribute to scope
i
t
r
e
p
o
r
p
e
k
i
l
a
!
d
the CSS to only this component.
o
n
o
t
Ki
d
e
p
o
c
s
s
i
S
S
C
the
Mind Blown
Splitting Things Into More Pieces
Up until now, weve included the HTML and CSS alongside our code.
car-parts.component.ts
Lets split out our HTML and CSS into different les.
car-parts.component.html
Where our HTML for the component lives.
car-parts.component.css
Where our CSS for the component lives.
t
u
b
,
u
o
y
t
u
o
b
a
w
o
n
k
t
I don
.
e
m
o
t
y
s
s
e
m
s
l
e
e
f
s
i
th
Our Current Component
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'car-parts',
template: `
<p>There are {{totalCarParts()}} total parts in stock.</p>
<ul>...</ul> `,
styles:[`
.description {
color: #444;
font-size: small;
}
.price {
font-weight: bold;
}
`]
})
export class CarPartsComponent {
...
We need to move out the
HTML and CSS.
Moving Out the HTML & CSS
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
@Component({
selector: 'car-parts',
templateUrl: 'app/car-parts.component.html',
styleUrls:['app/car-parts.component.css']
})
export class CarPartsComponent {
...
car-parts.component.html
HTML
<p>There are {{totalCarParts()}} total parts in stock.</p>
<ul>...</ul>
car-parts.component.css
.description {
color: #444;
font-size: small;
}
.price {
font-weight: bold;
}
Once we create new les for our HTML and CSS, we can reference
them inside our component metadata.
d
e
p
o
c
s
s
t
e
g
l
l
i
t
s
S
S
C
The
.
e
r
o
f
e
b
e
k
i
l
t
s
u
j
CSS
Whatd We Learn?
We can include CSS just like we include our HTML template.
CSS automatically gets scoped to our component.
HTML and CSS can get split out into their own les.
index.html
app
main.ts
app.component.ts
car-parts.component.ts
car-parts.component.html
car-parts.component.css
Level 3
Mocks & Models
Section 3
Getting More Object Oriented
TypeScript gives us the ability to be more object oriented with our data, so lets create a
model.
.
t
p
i
r
c
S
a
v
a
J
n
i
s
s
a
l
c
a
y
l
l
a
Which is basic
car-part.ts
TypeScript
export class CarPart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
}/
Notice were declaring what type each of our properties are.
This is TypeScript.
d
n
a
e
d
o
c
r
u
o
k
c
e
h
c
o
t
r
e
l
i
p
m
o
c
r
u
o
This will allow
.
y
l
r
e
p
o
r
p
s
g
n
i
h
t
g
n
i
t
t
e
s
d
n
a
g
n
i
t
t
e
g
e
r
e
w
e
r
u
s
n
e
Our Previous Code
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
...
})
export class CarPartsComponent {
carParts = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
...
How do we use our new model?
car-part.ts
export class CarPart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
}/
TypeScript
Import the CarPart Model & Dene Type
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPart } from './car-part';
...
})
Tells TypeScript to
export class CarPartsComponent {
this
like
an
array
carParts: CarPart[] = [{
"id": 1,
of CarParts
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
...
Import the CarPart model
treat
car-part.ts
export class CarPart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
}/
TypeScript
Nothing Else Needs to Change
car-parts.component.ts
TypeScript
...
carParts: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
car-parts.component.html
car-part.ts
export class CarPart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
}/
HTML
<p>There are {{totalCarParts()}} total parts in stock.</p>
<ul>
<li *ngFor="let carPart of carParts" >
<h2>{{carPart.name | uppercase}}</h2>
<p class="description">{{carPart.description}}</p>
<p class="price">{{carPart.price | currency:'EUR':true }}</p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
</li>
</ul>
TypeScript
Cleaning Up Our Mock Data
Eventually we want to call out to a web service (API) to get the latest car parts, so its a
good practice to move our mock (fake) data out into its own le.
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPart } from './car-part';
...
})
export class CarPartsComponent {
carParts: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
...
mocks.ts
TypeScript
Lets create a new le and move our
mock data here.
Using Our Mock Data
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
...
})
export class CarPartsComponent {
carParts: CarPart[] ;
ngOnInit() {
this.carParts = CARPARTS;
}
...
mocks.ts
TypeScript
import { CarPart } from './car-part';
export const CARPARTS: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
Notice we use const instead of let this is an
ES2015 feature that makes sure CARPARTS can't
be reassigned.
ngOnInit is invoked after the component is constructed and is the best place to
initialize property values.
We could have initialized in the constructor, but thatd be harder to test.
Yay, It Still Works!
We didnt add any more functionality, but our
code became a lot easier to maintain and scale.
Our Component Architecture
index.html
Includes <my-app> and loads main.ts
app
main.ts
Imports and bootstraps our rst component
app.component.ts
Loads the header and our subcomponent
car-parts.component.ts
app/car-parts.component.ts
import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
car-part.ts
The data model
mocks.ts
The fake data
car-parts.component.html
car-parts.component.css
@Component({
selector: 'car-parts',
templateUrl: 'app/car-parts.component.html',
styleUrls:['app/car-parts.component.css']
})
export class CarPartsComponent {
carParts: CarPart[] ;
...
Whatd We Learn?
In TypeScript, we can use classes to model our data.
TypeScript helps us specify class property types that help our compiler ensure were
writing good code.
Its a good practice to keep your mock data separate from your model and your
components, in its own le.
Level 4
Property & Class Binding
Section 1
Lets Add Some Design
Not having to work with more complex HTML has been nice as weve learned Angular,
but now were going to implement a better design.
Raw HTML & CSS From Designer
index.html
style.css
s
e
g
a
m
i
e
h
t
g
Well be addin
.
l
e
v
e
l
s
i
h
t
r
e
t
a
l
y
t
i
t
n
a
u
q
d
an
Moving the CSS
Styles get put in a new CSS folder and the car-parts.component.css for styles specic to
that component.
Raw HTML & CSS From Designer
index.html
index.html
css
style.css
style.css
app
app.component.ts
car-parts.component.ts
car-parts.component.html
car-parts.component.css
Splitting Up the HTML
HTML gets split up into three les.
Raw HTML & CSS From Designer
index.html
index.html
css
style.css
style.css
app
app.component.ts
car-parts.component.ts
car-parts.component.html
car-parts.component.css
Our Current App
e
r
u
g
t
e
l
t
u
Much better, b
.
n
i
s
e
g
a
m
i
g
n
i
out how to br
The Ways Data Can Flow
When using a web framework like Angular that abstracts your code from HTML, there
are a few dierent ways that data can ow.
JavaScript to HTML
Like weve been doing with
properties from our components
HTML to JavaScript
Like a mouse click, hover, or key press
Both Ways
Like a text box, that should stay in sync
Note: Were saying JavaScript here because our TypeScript turns
into JavaScript.
JavaScript to HTML
In our application thus far, weve been sending all sorts of data from our components
into our HTML using interpolation.
car-parts.component.html
TypeScript
<li class="card" *ngFor="let carPart of carParts" >
<div class="panel-body">
<table class="product-info">
<tr>
<td>
<h2>{{carPart.name | uppercase}}</h2>
<p class="description">{{carPart.description}}</p>
<p class="inventory" *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p class="inventory" *ngIf="carPart.inStock === 0">Out of Stock</p>
</td>
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
</tr>
</table>
When code is interpolated, the properties are read from the
</div>
component
and
strings
are
printed.
</li>
So, how would we add an image tag with a dynamic image?
Adding Images to Our Model
We will add this property to our model, add new les, and add them to our mock data.
car-part.ts
TypeScript
export class CarPart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
image: string;
}
images
tire.jpg
shocks.jpg
seat.jpg
mocks.ts
TypeScript
import { CarPart } from './car-part';
export let CARPARTS: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99,
"image": "/images/tire.jpg"
},
{
"id": 2,
"name": "Reinforced Shocks",
"description": "Shocks made from kryptonite",
"inStock": 4,
"price": 9.99,
"image": "/images/shocks.jpg"
}, { ... } ];
Adding an Image to Our Template
We could try adding our image onto our page using interpolation.
car-parts.component.html
TypeScript
<li class="card" *ngFor="let carPart of carParts" >
<div class="panel-body">
<div class="photo">
<img src="{{ carPart.image}}">
</div>
<table class="product-info">
<tr>
<td>
<h2>{{carPart.name | uppercase}}</h2>
...
This would work just ne.
However, theres an alternative syntax we can use when we
want to set DOM element property values.
Introducing Property Binding
Property binding allows us to glue component properties to DOM element properties.
car-parts.component.html
TypeScript
<li class="card" *ngFor="let carPart of carParts" >
<div class="panel-body">
<div class="photo">
<img [ src ] =" carPart.image ">
</div>
<table class="product-info">
<tr>
<td>
<h2>{{carPart.name | uppercase}}</h2>
...
Notice the square brackets and no curly braces!
The square brackets tell Angular to set this DOM element
property to our component property.
And if the component property changes, update this.
Additional Property Binding Examples
We can bind to any DOM element property. How do you think we could bind to these?
<div hidden>secret</div>
<button disabled>Purchase</button>
<img alt=" Image Description">
Our previous solution
<img [ src ] ="carPart.image ">
Additional Property Binding Examples
All we need to do is add brackets and specify a component property.
<div [ hidden ] ="!user.isAdmin" >secret</div>
<button [ disabled ] ="isDisabled" >Purchase</button>
<img [ alt ] ="image.description">
Our previous solution
<img [ src ] ="carPart.image ">
Adding a Featured Car Part
If a car part is marked as featured, we want to add a class of featured to it.
car-parts.component.css
CSS
...
.featured {
background: #57595D;
-webkit-border-image: -webkit-linear-gradient(right, #818fd8 0%, #cbb4e2 50%, #a6f2f5 100%);
-o-border-image: linear-gradient(to left, #818fd8 0%, #cbb4e2 50%, #a6f2f5 100%);
border-image: linear-gradient(to left, #818fd8 0%, #cbb4e2 50%, #a6f2f5 100%);
border-image-slice: 1;
}
Here is the featured class, which adds a
lighter background and a gradient border.
How do we add functionality to sometimes
add this featured class?
Adding a Featured Property & Data
We need to add a new property to our car-part.ts model and add mock data for it.
car-part.ts
TypeScript
export class CarPart {
...
image: string;
featured: boolean;
}
Next, we need to conditionally add
a class if this property is true.
mocks.ts
TypeScript
export let CARPARTS: CarPart[] = [{
"id": 1,
...
"featured": false
},
{
"id": 2,
...
"featured": true
},
{
"id": 3,
...
"featured": false
}];
Using a Class Property Binding
Theres a unique syntax for binding to a class.
car-parts.component.html
TypeScript
<ul>
<li class="card" *ngFor="let carPart of carParts" [class.featured]="carPart.featured" >
<div class="panel-body">
...
</div>
</li>
</ul>
If carPart.featured is true, then the featured
class is added. If carPart.featured is false, then
the featured class is removed.
Looking Into the Web Page
[class.featured]="carPart.featured"
Looking at the source, we see that the
element and the class are properly scoped.
<li _ngcontent-opf-2 class="card featured">
.featured[_ngcontent-opf-2] {
background: #57595D;
...
}
How Not to Use Class Binding
You might be tempted to bind directly to the class element property:
<div [class]="property">
<div [class.name]="property">
Class names with dashes also work ne.
<div [class.my-name]="property">
This will overwrite all classes.
This will only add/remove the specic class.
Whatd We Learn?
Property binding allows us to bind component properties to any DOM element properties.
Any update to the component property value will update the DOM property, but not vice
versa thats why its one-way binding.
Class binding allows us to specify a CSS class to add to a DOM element if a component
property is true.
Level 4
Event Binding
Section 2
Types of Data Binding
Property Binding
Class Binding
JavaScript to HTML
HTML to JavaScript
Event Binding
Like a mouse click, hover, or key press
Adding Events to Our Page
Adding a Quantity Property & Data
We need to add a new property to our car-part.ts model and add mock data for it.
car-part.ts
export class CarPart {
...
image: string;
featured: boolean;
quantity: number;
}
TypeScript
mocks.ts
TypeScript
export let CARPARTS: CarPart[] = [{
"id": 1,
...
"featured": false,
"quantity": 0
}, { ... }, { ... }];
Adding a Simple Button
car-parts.component.ts
TypeScript
...
export class CarPartsComponent {
...
upQuantity() {
alert("You Called upQuantity");
}
...
To capture an event from our template, we wrap the name of the event we want to
listen to in parentheses and specify the method to call.
car-parts.component.html
HTML
...
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="increase" (click)="upQuantity()">+</button>
...
Making It Actually Work
Now lets use the carPart.quantity that we have on each car part.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
{{carPart.quantity}}
<button class="increase" (click)="upQuantity( carPart )">+</button>
We need to send in the current carPart.
car-parts.component.ts
TypeScript
export class CarPartsComponent {
...
upQuantity(carPart ) {
carPart.quantity++;
}
Uh-oh we can increase the quantity we
want beyond what we have in stock.
Limited Incrementing
We shouldnt be able to add more quantity than we have in stock.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
{{carPart.quantity}}
<button class="increase" (click)="upQuantity( carPart )">+</button>
car-parts.component.ts
TypeScript
export class CarPartsComponent {
...
upQuantity(carPart ) {
if (carPart.quantity < carPart.inStock) carPart.quantity++;
}
Only add quantity if current quantity is less than we have in stock.
Now With Proper Limits
Adding Our Decrease Button
We should be able to decrease the quantity, but not below zero.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="decrease" (click)="downQuantity(carPart)">-</button>
{{carPart.quantity}}
<button class="increase" (click)="upQuantity(carPart)">+</button>
car-parts.component.ts
TypeScript
export class CarPartsComponent {
...
downQuantity(carPart) {
if (carPart.quantity != 0) carPart.quantity--;
}
}
Only subtract quantity if current quantity is not zero.
Other Events to Listen For
Any standard DOM event can be listened for by wrapping it in parentheses and
removing the on at the beginning of the word.
<div (mouseover)="call()">
<input (blur)="call()">
<input (focus)="call()">
<input type="text" (keydown)="call()">
<form (submit)="call()">
Getting Additional Event Data
Sometimes you need additional event data, like which key is pressed or where the
mouse is on the screen. This is what the Angular event object is for.
<input type="text" (keydown)="showKey($event)">
We can send the $event object
showKey(event) {
alert(event.keyCode);
}
into our methods.
<h2 (mouseover)="getCoord($event)">Hover Me</h2>
getCoord(event) {
console.log(event.clientX + ", " + event.clientY);
}
We could also call event.preventDefault(); to prevent a clicked link from
being followed or a form from being submitted.
Whatd We Learn?
Event binding allows us to listen to any DOM event and call a component method when
its triggered.
To listen to any event, we need to remove the on in front of the word, wrap it in
parentheses, and specify a component method to call.
If we need to access the event object, we can pass it in to our component method with
$event.
Level 4
Two-way Binding
Section 3
Types of Data Binding
JavaScript to HTML
Property Binding
Class Binding
HTML to JavaScript
Event Binding
Both Ways
Like a text box, that should stay in sync
How can we bind properties from our component to our
HTML, but also listen for events and keep things in sync?
Adding an Input Field
How can we allow for the user input of the quantity?
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="decrease" (click)="downQuantity(carPart)">-</button>
<input class="number" type="text">
<button class="increase" (click)="upQuantity(carPart)">+</button>
We should be able to adjust the quantity by typing into
this eld or by using the buttons.
Using Property Binding
The rst thing we might try is to use property binding to bind the value to the quantity.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="decrease" (click)="downQuantity(carPart)">-</button>
<input class="number" type="text" [value]="carPart.quantity" >
<button class="increase" (click)="upQuantity(carPart)">+</button>
This gives us our quantity value in our input box, but only in one
direction: from our component property to our input value.
Using Event Binding
We need to listen for the input event on our input box.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="decrease" (click)="downQuantity(carPart)">-</button>
<input class="number" type="text" [value]="carPart.quantity"
(input)="carPart.quantity = $event.target.value" >
<button class="increase" (click)="upQuantity(carPart)">+</button>
Information is owing two ways.
This works, but theres another way.
Using ngModel
ngModel allows us to have one command to express two-way data binding.
car-parts.component.html
HTML
<td class="price">{{carPart.price | currency:'EUR':true }}</td>
<td>
<div class="select-quantity">
<button class="decrease" (click)="downQuantity(carPart)">-</button>
<input class="number" type="text" [(ngModel)]="carPart.quantity" >
<button class="increase" (click)="upQuantity(carPart)">+</button>
Notice that were using both brackets and parentheses.
[()]
This syntax is sometimes called banana in a box can you see why?
The ngModel Syntax
When we use the ngModel syntax, we can only set it equal to a data bound property.
[(ngModel)]="<must be data property>"
We will mostly use this for form elds.
These are component properties:
[(ngModel)]="user.age"
[(ngModel)]="firstName"
This will error out:
[(ngModel)]="fullName()"
Whatd We Learn?
The [(ngModel)] syntax allows us to specify a component property that will use
two-way binding.
Two-way binding means that if the component property is modied inside the
component (JavaScript) or inside our web page (HTML), it will stay in sync.
Level 5
Services
Section 1
Revisiting Our Mock Data
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
...
})
export class CarPartsComponent {
carParts: CarPart[] ;
mocks.ts
TypeScript
import { CarPart } from './car-part';
export const CARPARTS: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];
ngOnInit() {
this.carParts = CARPARTS;
}.
...
We are loading our CarParts by importing our mock le, but this isnt the best
solution for working with data.
Why This Isnt the Best Method
Wed need to import the mocks on every le
that needs the data. If the way we access
this data changes, wed have to change it
everywhere.
Its not easy to switch between real and
mock data.
This sort of data loading is best left to
service classes.
car-parts.component.ts
TypeScript
import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
...
})
export class CarPartsComponent {
carParts: CarPart[] ;
ngOnInit() {
this.carParts = CARPARTS;
}.
...
Introducing Services
Services are used to organize and share code across your app, and theyre usually where we
create our data access methods.
car-parts.component.ts
Asks the service for data
racing-data.service.ts
Fetches the appropriate data
mocks.ts
First, lets create the simplest service, and then well learn something
called dependency injection to make it even more powerful.
Writing Our First Service
racing-data.service.ts
TypeScript
import { CARPARTS } from './mocks';
export class RacingDataService {
getCarParts() {
return CARPARTS;
}
}
Weve decoupled our data.
car-parts.component.ts
TypeScript
import { RacingDataService } from './racing-data.service';
...
export class CarPartsComponent {
carParts: CarPart[];
ngOnInit() {
let racingDataService = new RacingDataService();
this.carParts = racingDataService.getCarParts();
}
}
Classes using this service must know how to create a RacingDataService.
Well be creating a new RacingDataService every time we need to fetch car parts.
Itll be harder to switch between a mock service and a real one.
Introducing Dependency Injection
When you run an Angular 2 application, it creates a dependency injector. An injector is in
charge of knowing how to create and send things.
Dependency Injector
Yup, I can create and
send that to you.
Could I have
RacingDataService?
racing-data.service.ts
car-parts.component.ts
The injector knows how to inject our dependencies.
Create (if needed) and send
Classes we depend on
Re-injecting Dependencies
If the injector already created a service, we can have it resend the same service.
Could I also have
RacingDataService?
car-cart.component.ts
Dependency Injector
I already created one
here it is.
car-parts.component.ts
racing-data.service.ts
How Does an Injector Know What It Can Inject?
We must tell the injector what it can inject by registering providers with it.
These are the providers I have they tell me what I can create and send.
Dependency Injector
racing-data.service.ts
another.service.ts
api.service.ts
There are three steps to make this all work with RacingDataService:
1. Add the injectable decorator to RacingDataService.
2. Let our injector know about our service by naming it as a provider.
3. Inject the dependency into our car-parts.component.ts.
Step 1: Add the Injectable Decorator
We need to turn our service into something that can be safely used by our dependency
injector.
racing-data.service.ts
TypeScript
import { CARPARTS } from './mocks';
import { Injectable } from '@angular/core';
@Injectable()
export class RacingDataService {
getCarParts() {
return CARPARTS;
}
}
Dont forget the parentheses!
Step 2: Let Our Injector Know About the Service
We want all our subcomponents to have access to RacingDataService. To do this, we
register it as a provider at the top level specically, AppComponent.
app.component.ts
TypeScript
...
import { RacingDataService } from './racing-data.service';
@Component({
selector: 'my-app',
template: `...`,
directives: [CarPartsComponent],
providers: [RacingDataService]
})
Now all subcomponents can ask for (inject) our RacingDataService
when they need it, and an instance of RacingDataService will either
be delivered if it exists, or it will be created and delivered.
Step 3: Injecting the Dependency
car-parts.component.ts
TypeScript
...
import { RacingDataService } from './racing-data.service';
@Component({ ... })
export class CarPartsComponent {
carParts: CarPart[];
We dont ne
ed to add R
acingData
Service
as a provide
r since its
a subcompo
nent.
constructor(private racingDataService: RacingDataService) { }
}
Means TypeScript automatically denes
component properties based on the
parameters. The generated JavaScript is:
function CarPartsComponent(racingDataService) {
this.racingDataService = racingDataService;
TypeScript syntax for setting the type of the
parameter. This is what identies that the
RacingDataService should be injected into
this component.
Using the Service to Fetch Our carParts
car-parts.component.ts
TypeScript
...
import { RacingDataService } from './racing-data.service';
@Component({ ... })
export class CarPartsComponent {
carParts: CarPart[];
constructor(private racingDataService: RacingDataService) { }
ngOnInit() {
this.carParts = this.racingDataService.getCarParts();
}
}
Now our app is more scalable and testable.
Scalable because our dependencies arent strongly tied to our classes.
Testable because itd be easy to mock services when we test the component.
Our App Still Works
Whatd We Learn?
Services are used to organize and share code across your app, and theyre usually where
you create your data access methods.
We use dependency injection to create and send services to the classes that need them.
We give our dependency injector providers so that it knows what classes it can create and
send for us.
We ask for dependencies by specifying them in our class constructor.
Level 5
Adding Http
Section 2
Lets Use the Internet!
Up until now, weve been seeding our car parts with mock data. How might we fetch this
from the internet instead?
car-parts.component.ts
Asks the service for data
racing-data.service.ts
Fetches the appropriate data from the internet
Internet
This will be JSON data
Welcome to the Real World
When a user visits our web page, the Angular app loads rst in our browser, and then it
fetches the needed data.
Browser
Server
Initial Browser Request
HTML/JavaScript/CSS Response
Angular Loads
Data Request (car parts)
JSON
Steps Needed to Use the HTTP Library
1. Create a JSON le with car parts data.
car-parts.json
2. Ensure our application includes the libraries it needs to do Http calls.
3. Tell our injector about the http provider.
app.component.ts
4. Inject the http dependency into our service and make the http get request.
racing-data.service.ts
5. Listen for data returned by this request.
car-parts.component.ts
Step 1: Creating a JSON File
We need to create a JSON data le to load from our service.
car-parts.json
{
JSON
We wrapped our array in an object to
"data": [
{
make it feel a little
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99,
"image": "/images/tire.jpg",
"featured": false,
"quantity": 0
},
{ ... },
{ ... }
]
}
more realistic.
Step 2: Including the HTTP and RxJS Libraries
The HTTP library provides the get call we will use to call across the internet.
The RxJS library stands for Reactive Extensions and provides some advance tooling for our
http calls.
If you used the 5-minute Quickstart, you have already included these libraries using SystemJS.
Step 3: Telling Our Injector It Can Inject HTTP
As you know, the rst step in dependency injection is to register providers.
app.component.ts
TypeScript
...
import { RacingDataService } from './racing-data.service';
import { HTTP_PROVIDERS } from '@angular/http';
@Component({
selector: 'my-app',
template: `...`
directives: [CarPartsComponent],
providers: [RacingDataService, HTTP_PROVIDERS]
})
Now well be able to inject the HTTP library when we need it.
Step 4: Injecting HTTP & Using It
Now lets inject http and call out to the internet.
TypeScript
racing-data.service.ts
import
import
import
import
{ Injectable } from '@angular/core';
{ CarPart } from './car-part';
{ Http } from '@angular/http';
'rxjs/add/operator/map';
@Injectable()
export class RacingDataService {
constructor(private http: Http) { }
Injecting HTTP as a dependency
e
c
i
v
r
e
s
r
u
o
e
s
u
a
c
e
b
s
i
h
We can do t
e
l
b
a
t
c
e
j
n
i
s
class i
getCarParts() {
return this.http.get('app/car-parts.json')
.map(response => <CarPart[]>response.json().data);
}
}
Theres a lot going on here lets break it out.
Stepping Through Our get Request
You might expect get to return a promise, but this returns an observable. Observables give us
additional functionality on our http calls one of which is to treat the return value like an array.
getCarParts() {
return this.http.get('app/car-parts.json')
.map(response =>
For the data returned,
do this to the response.
<CarPart[]>
Tells our TypeScript
compiler to treat this like
an array of CarParts.
response.json()
.data);
For each response, parse The array we want is
the string into JSON.
under the data keyword.
Step 5: Subscribing to the Stream
Since our service now returns an observable object, we need to subscribe to that data
stream and tell our component what to do when our data arrives.
car-parts.component.ts
TypeScript
...
export class CarPartsComponent {
constructor(private racingDataService: RacingDataService) { }
ngOnInit() {
this.racingDataService.getCarParts()
.subscribe(carParts => this.carParts = carParts);
}
...
When carParts arrive on our data stream, set it equal to our local carParts array.
Solving the Problem
In our browser, we get nothing:
TypeError: Cannot read property 'length' of undefined at
CarPartsComponent.totalCarParts
car-parts.component.ts
TypeScript
totalCarParts() {
let sum = 0;
Not an array yet
for (let carPart of this.carParts) {
sum += carPart.inStock;
}.
return sum;
}/
When our page initially loads, we havent yet
fetched any data, so our carParts is undened.
Checking for Undened carParts
Lets make sure we only calculate sum if carParts is an array.
car-parts.component.ts
totalCarParts() {
let sum = 0;
if (Array.isArray(this.carParts)) {
for (let carPart of this.carParts) {
sum += carPart.inStock;
}.
}
return sum;
}/
TypeScript
All Working Now Over the Internet!
Last Thoughts on Implementation
1. We didnt do any error handling. If you're writing a production app, youd want to do this.
2. Since we isolated our network calls as a service, we could easily write a RacingDataServiceMock
service and inject it when were testing or developing oine.
3. Observables can be quite powerful and are worth learning about if you are making lots of http calls.
Whatd We Learn?
Angular apps usually load data using service classes after the Angular app is initialized
and running.
We can use the HTTP library through dependency injection.
Our http calls return an observable, not a promise, which behaves more like an array.