把服务和组件改为用 Angular 的 HTTP 服务实现
1、app.module.ts中导入HttpModule模块
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import {HeroService} from './hero.service';
import { HeroesComponent } from './heroes/heroes.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import {AppRoutingModule} from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
HeroDetailComponent,
HeroesComponent,
DashboardComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AppRoutingModule
],
providers: [HeroService],
bootstrap: [AppComponent]
})
export class AppModule { }
2、模拟WebAPI
要使用 angular-in-memory-web-api 首先要 npm install
app.module.ts被修改成如下:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import {HeroService} from './hero.service';
import { HeroesComponent } from './heroes/heroes.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import {AppRoutingModule} from './app-routing.module';
// Imports for loading & configuring the in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
@NgModule({
declarations: [
AppComponent,
HeroDetailComponent,
HeroesComponent,
DashboardComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
//InMemoryWebApiModule将Http客户端默认的后端服务 — 这是一个辅助服务,负责与远程服务器对话 — 替换成了内存 Web API服务
InMemoryWebApiModule.forRoot(InMemoryDataService),
AppRoutingModule
],
providers: [HeroService],
bootstrap: [AppComponent]
})
export class AppModule { }
in-memory-data.service.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
let heroes = [
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];
return {heroes};
}
}
修改hero.service.ts服务
import { Injectable } from '@angular/core';
import {Headers,Http} from '@angular/http';
import 'rxjs/add/operator/toPromise';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
@Injectable()
export class HeroService {
private heroesUrl:string='api/heroes'; //URL to web api
constructor(private http:Http){
}
getHero(id: number): Promise {
//return this.getHeroes().then(heroes => heroes.find(hero => hero.id === id));
const url = `${this.heroesUrl}/${id}`;
return this.http.get(url)
.toPromise()
.then(response => response.json().data as Hero)
.catch(this.handleError);
}
getHeroes():Promise{
//return Promise.resolve(HEROES);
return this.http.get(this.heroesUrl)
.toPromise()
.then(response=>response.json().data as Hero[])
.catch(this.handleError);
}
getHeroesSlowly(): Promise {
return new Promise(resolve => {
// Simulate server latency with 2 second delay
setTimeout(() => resolve(this.getHeroes()), 2000);
});
}
private handleError(error:any):Promise{
console.error('An error occurred',error);
return Promise.reject(error.message||error);
}
}
3、更新英雄详情
先在英雄详情模板的底部添加一个保存按钮,它绑定了一个click事件,事件绑定会调用组件中一个名叫save()的新方法:
//hero-detail.component.ts中添加保存方法
save(): void {
this.heroService.update(this.hero)
.then(() => this.goBack());
}
hero.service.ts修改
import { Injectable } from '@angular/core';
import {Headers,Http} from '@angular/http';
import 'rxjs/add/operator/toPromise';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
@Injectable()
export class HeroService {
private heroesUrl:string='api/heroes'; //URL to web api
private headers=new Headers({'Content-Type':'application/json'});
constructor(private http:Http){
}
getHero(id: number): Promise {
//return this.getHeroes().then(heroes => heroes.find(hero => hero.id === id));
const url = `${this.heroesUrl}/${id}`;
return this.http.get(url)
.toPromise()
.then(response => response.json().data as Hero)
.catch(this.handleError);
}
getHeroes():Promise{
//return Promise.resolve(HEROES);
return this.http.get(this.heroesUrl)
.toPromise()
.then(response=>response.json().data as Hero[])
.catch(this.handleError);
}
getHeroesSlowly(): Promise {
return new Promise(resolve => {
// Simulate server latency with 2 second delay
setTimeout(() => resolve(this.getHeroes()), 2000);
});
}
private handleError(error:any):Promise{
console.error('An error occurred',error);
return Promise.reject(error.message||error);
}
update(hero:Hero):Promise{
const url=`${this.heroesUrl}/${hero.id}`;
return this.http.put(url,JSON.stringify(hero),{headers:this.headers})
.toPromise()
.then(()=>hero)
.catch(this.handleError);
}
create(name:string):Promise{
return this.http
.post(this.heroesUrl,JSON.stringify({name: name}), {headers: this.headers})
.toPromise()
.then(res=>res.json().data as Hero)
.catch(this.handleError);
}
delete(id: number): Promise {
const url = `${this.heroesUrl}/${id}`;
return this.http.delete(url, {headers: this.headers})
.toPromise()
.then(() => null)
.catch(this.handleError);
}
}
heroes.component.ts修改
import { Component,OnInit } from '@angular/core';
import {Router} from '@angular/router';
import {Hero} from '../hero';
import {HeroDetailComponent} from '../hero-detail/hero-detail.component';
import {HeroService} from '../hero.service';
@Component({
selector: 'my-heroes',
template:`
-
{{hero.id}} {{hero.name}}
{{selectedHero.name | uppercase}} is my hero
`,
styleUrls:['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes:Hero[];
selectedHero:Hero;
constructor(private heroService:HeroService,private router:Router){
}
onSelect(hero:Hero):void{
this.selectedHero=hero;
}
getHeroes():void{
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}
ngOnInit(){
this.getHeroes();
}
gotoDetail(): void {
this.router.navigate(['/detail', this.selectedHero.id]);
}
add(name:string):void{
name=name.trim();
if(!name) return;
this.heroService.create(name)
.then(hero=>{
this.heroes.push(hero);
this.selectedHero=null;
});
}
delete(hero:Hero):void{
this.heroService
.delete(hero.id)
.then(() => {
this.heroes = this.heroes.filter(h => h !== hero);
if (this.selectedHero === hero) { this.selectedHero = null; }
});
}
}
4、为英雄指南添加英雄搜索
创建hero-search.service.ts服务 ng g service hero-search
import { Injectable } from '@angular/core';
import {Http} from '@angular/http';
import {Observable} from 'rxjs/observable';
import 'rxjs/add/operator/map';
import {Hero} from './hero';
@Injectable()
export class HeroSearchService {
constructor(private http:Http) { }
search(term:string):Observable{
return this.http.get(`app/heroes/?name=${term}`)
.map(response=>response.json().data as Hero[]);
}
}
再创建一个新的hero-search.component.ts组件
ng g component hero-search
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// Observable class extensions
import 'rxjs/add/observable/of';
// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import { HeroSearchService } from '../hero-search.service';
import { Hero } from '../hero';
@Component({
selector: 'hero-search',
templateUrl: './hero-search.component.html',
styleUrls: [ './hero-search.component.css' ],
providers: [HeroSearchService]
})
export class HeroSearchComponent implements OnInit {
heroes: Observable;
private searchTerms = new Subject();
constructor(
private heroSearchService: HeroSearchService,
private router: Router) {}
// Push a search term into the observable stream.
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit(): void {
this.heroes = this.searchTerms
.debounceTime(300) // wait 300ms after each keystroke before considering the term
.distinctUntilChanged() // ignore if next search term is same as previous
.switchMap(term => term // switch to new observable each time the term changes
// return the http search observable
? this.heroSearchService.search(term)
// or the observable of empty heroes if there was no search term
: Observable.of([]))
.catch(error => {
// TODO: add real error handling
console.log(error);
return Observable.of([]);
});
}
gotoDetail(hero: Hero): void {
let link = ['/detail', hero.id];
this.router.navigate(link);
}
}
hero-search.component.html
Hero Search
{{hero.name}}
hero-search.component.css
.search-result{
border-bottom: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
width:195px;
height: 16px;
padding: 5px;
background-color: white;
cursor: pointer;
}
.search-result:hover {
color: #eee;
background-color: #607D8B;
}
#search-box{
width: 200px;
height: 20px;
}
为仪表盘添加搜索组件
dashboard.component.html
Top Heroes
运行结果: