angular2-workshop
angular2-workshop copied to clipboard
Egghead.io - Angular 2 Workshop
{% raw %}
Angular 2 StarWars Party
Workshop Resources
Completed Exercises
The numbers folders 01-10 can be renamed at any time to catch up.
For example, rename 07
to src
then restart your npm start
to catch up to Exercise 7.
Exercise 00 - Setup
- Clone or fork this repository
- Make sure you have node.js installed
- Run
npm install -g webpack webpack-dev-server typings typescript
to install global dependencies - Navigate to your project folder from the command line
- Run
npm install
to install dependencies - Run
npm start
to fire up dev server - Open browser to
http://localhost:3000
Set up the StarWars server
- Install and run https://github.com/johnlindquist/swapi-json-server
- Open browser to
http://localhost:4000
Exercise 01 - Hello World
- Notice the
<app>
tag inindex.html
- Delete everything in
app.ts
- Write a
@Component
with a selector of'app'
- Create a basic
template
- Remember to
export
yourclass
Exercise 02 - Create a Component
- Create a
components
directory - Add a file called
home.ts
- Create a
@Component
andexport
it - Import your component into
app.ts
- Include the component with
directives:[Home]
- Add the component to your
template
with<home>
Exercise 03 - Handling Clicks and Refs
Logging an event
- Create a button in your
Home
component - Handle the click with a
(click)="onClick($event)"
- Log out the event
Logging an Input
- Create an
input
- Reference the
input
with a#i
- Pass the value with
#i.value
of the input to theonClick
- Log out the value
Exercise 04 - Smart and Dumb Components
Inputs
- Add a
people = [{name:"John"}];
to yourHome
component - Create a
PersonList
component - Add the
PersonList
to yourHome
component - Create an
@Input
calledpeople
(remember to import it) - Push
people
fromHome
intoPersonList
with[people]=people
- Render the first person from the
@Input
with{{people[0].name}}
Outputs
- Move the
input
and thebutton
to thePersonList
- Create an
@Output()
calledselect
- Call
select.emit(value)
in the button'sonClick
handler - Handle the
select
event inHome
with(select)=onSelect($event)
- Log out the input
Exercise 05 - Templates, Styles, and Built-in Directives
NgModel
- Add an
[(ngModel)]="name"
to theinput
- Add a
<span>{{name}}</span>
- Type in the
input
to see the name appear in the<span>
<style>
- Add a
<style></style>
tag to the template - Add a
.person { cursor: pointer; cursor: hand; }
style - Add the
class=person
to your span - Roll over your
<span>
to see the hand cursor
*ngIf
- Add a
<i class="fa fa-star"></i>
- Add an
*ngIf="name"
to the<i>
- Type in the input to see the
<i>
appear
[ngClass]
- Add
(mouseover)="isOver = true" (mouseout)="isOver = false"
tospan
- Change the
class
attribute toclass="fa"
on the<i>
element - Add
[ngClass]="{'fa-star':isOver, 'fa-star-o':!isOver}"
to the<i>
- Roll over the span to see the icon toggle
Exercise 06 - Repeating Elements with *ngFor
*ngFor
- Add more
people
to theHome
people = [
{
name:"Luke Skywalker",
image: "http://localhost:4000/luke_skywalker.jpg"
},
{
name:"Darth Vader",
image: "http://localhost:4000/darth_vader.jpg"
},
{
name:"Leia Organa",
image: "http://localhost:4000/leia_organa.jpg"
}
];
Loop through each person using *ngFor
on a simple element
- Create a
p
element inPersonList
that binds toperson.name
- Add
*ngFor="let person of people"
to thep
tag
Loop through each person using *ngFor
on a custom component
- Create a
Card
component using the code below as a reference - Give the
Card
an@Input()
ofperson
- Add the
Card
to thePersonList
- Add
*ngFor="let person of people"
to thecard
- Update the
src
to[src]="person.image"
- Show the
person.name
in theh5
with{{person.name}}
import {Component, Input} from '@angular/core';
@Component({
selector: 'card',
template: `<style>
.card{
display: flex;
flex-direction: column;
align-items: center;
}
.info{
display: flex;
flex-basis: 100px;
justify-content: center;
align-items: center;
flex-direction: column;
}
</style>
<div class="card">
<img [src]="person.image">
<div class="info">
<h5>{{person.name}}</h5>
<a class="btn btn-primary"><i class="fa fa-plus"></i> Add to Party</a>
</div>
</div>
`
})
export class Card{
@Input() person;
}
Exercise 07 - Move the Data to a Service
- Create
services
directory - Create a
StarWars.ts
file - Use the
@Inject()
decorator on aStarWars
class - Move the
people
from theHome
to the service - Include the service in the
Home
providers:[]
- Inject the service
constructor(public starWars:StarWars){}
- Use the service in the template
[people]="starWars.people"
Exercise 08 - Loading Data with Http
- Add
providers: [HTTP_PROVIDERS],
to yourapp.ts
- Import
import {Http} from '@angular/http';
in your service - Inject
Http
in your serviceconstructor(private _http:Http){}
- Delete the
people
array - In the constructor, assign the people to an
http
request - Use
http.get()
thenmap
then response usingres => res.json()
-
map
the images:luke_skywalker.jpg
tohttp://locahost:4000/luke_skywalker.jpg
import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';
const API = 'http://localhost:4000';
@Injectable()
export class StarWars{
people;
constructor(private _http:Http){
this.people = _http.get(`${API}/people`)
.map(res => res.json() //get the response as json
.map(person =>
Object.assign(person, {image: `${API}/${person.image}`})
)
)
}
}
Use an | async
pipe to load the data in the template
[people]="starWars.people | async"
Exercise 09 - Searching Data with a Pipe
Housekeeping
- Clean up
PersonList
template so onlyinput
andcard
s remain
<input [(ngModel)]="name" type="text">
<div class="card-container">
<card
*ngFor="let person of people"
[person]="person">
</card>
</div>
Creating a Pipe
- Create a
pipes
directory - Create a
search.ts
file - Create a
@Pipe()
calledSearch
- Create your own searching logic
import {Pipe} from '@angular/core';
@Pipe({
name: 'search'
})
export class Search{
transform(data, key, term = ""){
if(!data) return null;
return data.filter(item => {
return item[key]
.toLowerCase()
.includes(term.toLowerCase());
})
}
}
Using the Pipe
Add the Search
to your PersonList
pipes:[Search],
- Add the
name
("search") of theSearch
pipe to the template - Use
'name'
as thekey
to search on - Use the
name
from the[(ngModel)]="name"
as the term
let person of people | search:'name':name"
Exercise 10 - Adding Routes
- Add a
<base href="/">
to yourindex.html
<head>
- Create a simple
Party
component with ahello world
template - Import all the required Router classes into
app.ts
import {ROUTER_PROVIDERS, RouteConfig, RouterOutlet, RouterLink} from '@angular/router';
- Include
RouterOutlet
andRouterLink
in yourdirectives:[]
directives: [RouterOutlet, RouterLink],
- Replace
<home>
the<router-outlet>
- Decorate your
App
with your routes
@RouteConfig([
{path: '/home', name: 'Home', component: Home, useAsDefault: true},
{path: '/party', name: 'Party', component: Party},
{path: '/**', redirectTo: ['Home'] }
])
- Create a nav with
[routerLink]
<ul class="nav nav-tabs">
<li class="nav-item">
<a [routerLink]="['Home']" class="nav-link">Home</a>
</li>
<li class="nav-item">
<a [routerLink]="['Party']" class="nav-link">Party</a>
</li>
</ul>
- Stylize the active route with a
.router-link-active
style:
.router-link-active{
color: #55595c;
background-color: #fff;
border-color: #ddd #ddd transparent;
}
Challenges (Solutions Not Included!)
The following are for people who enjoy a challenge and working ahead.
Challenge
Create a second service with a route to manage who you "Add" to the Party.
Moderate Challenge
Add create, read, update, delete to the "Party" service so you can add, remove, edit people to the party. Also make sure you can't add the same Person to the party twice.
Difficult Challenge
Create a "PersonDetail" component and route so that when you click on the Person image, it navigates to a route displaying Person's detail including all the images of starships they've flown :wink:
Difficult Challenge
Build an "Autocomplete" search box from the Star Wars api. Prior RxJS knowledge is recommended.
Super Duper Tough Challenge
Build a full Create, Read, Update, Delete app (the api supports it!) with the people from Star Wars including all of the features above! {% endraw %}