{% raw %}
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.
- 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
- Install and run https://github.com/johnlindquist/swapi-json-server
- Open browser to
http://localhost:4000
- 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
- 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>
- Create a button in your
Home
component - Handle the click with a
(click)="onClick($event)"
- Log out the event
- Create an
input
- Reference the
input
with a#i
- Pass the value with
#i.value
of the input to theonClick
- Log out the value
- 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}}
- 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
- Add an
[(ngModel)]="name"
to theinput
- Add a
<span>{{name}}</span>
- Type in the
input
to see the name appear in the<span>
- 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
- Add a
<i class="fa fa-star"></i>
- Add an
*ngIf="name"
to the<i>
- Type in the input to see the
<i>
appear
- 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
- 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"
}
];
- Create a
p
element inPersonList
that binds toperson.name
- Add
*ngFor="let person of people"
to thep
tag
- 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;
}
- 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"
- 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"
- 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>
- 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());
})
}
}
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"
- 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;
}
The following are for people who enjoy a challenge and working ahead.
Create a second service with a route to manage who you "Add" to the Party.
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.
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 😉
Build an "Autocomplete" search box from the Star Wars api. Prior RxJS knowledge is recommended.
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 %}