(六)Angular4 英雄征途HeroConquest-服务service

(六)Angular4 英雄征途HeroConquest-服务

为了不再把相同的代码复制一遍又一遍,我们要创建一个单一的可复用的数据服务,并且把它注入到需要它的那些组件中。 使用单独的服务可以保持组件精简,使其集中精力为视图提供支持,并且,借助模拟(Mock)服务,可以更容易的对组件进行单元测试,在本节中将实现一个异步的数据请求机制Promise。承接上一节,在这一节中, 从组件中移除数据访问逻辑意味着你可以随时更改这些实现方式,而不影响需要这些英雄数据的组件。


创建服务hero-get.service.ts

文件命名约定规则:服务名称的小写形式(基本名),加上.service后缀。 如果服务名称包含多个单词,我们就把基本名部分写成中线形式 (dash-case)。 例如,本节要创建的HeroGetService服务应该被定义在hero-get.service.ts文件中。

// 导入了 Angular 的Injectable函数
import { Injectable } from '@angular/core';
// 导入属性HeroProperty
import { HeroProperty } from './heroproperty';
// 导入数据HeroArray
import { HeroArray } from './mock-hero-data';
//作为@Injectable()装饰器使用这个函数,当 TypeScript //看到@Injectable()装饰器时,就会记下本服务的元数据。 
//如果 Angular 需要往这个服务中注入其它依赖,就会使用//这些元数据。虽然此时HeroService还没有任何依赖,但
//我们还是得加上这个装饰器。 作为一项最佳实践,无论是
//出于提高统一性还是减少变更的目的, 都应该从一开始就
//加上@Injectable()装饰器。
@Injectable()
export class HeroGetService {
//定义一个获取HeroArray数据的方法,这个HeroArray数据
//可以来自Web服务、本地存储或模拟数据源,本节就是模拟
//数据源来自mock-hero-data模块。 我们请求一个异步服务
//去做点什么,并且给它一个回调函数。 它此时它去获取数据
//,一旦完成,它就会调用我们的回调函数,并通过参
//数把工作结果或者错误信息传给我们。通过返回一个立即解
//决的承诺的方式,模拟了一个超快、零延迟的超级服务器。
  getHeros(): Promise<HeroProperty[]> {
    return Promise.resolve(HeroArray);
  }
}

app.component.ts文件

import { Component, OnInit } from '@angular/core';
import { HeroDetailComponent} from './hero-detail.component';
import { HeroArray } from './mock-hero-data';
import { HeroProperty} from './heroproperty';
//在app.component.ts这个组件中导入HeroGetService
//以便使用该服务
import { HeroGetService} from './hero-get.service';


@Component({

AppComponent的模板中。
// 这就是所谓的自定义标签
  selector: 'app-root',
  template: `<h1>{{title}}</h1>
<!--上一节代码begin-->
  <br>
  <h2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -------{{from}}</h2>
  <ul>
  <li>
  <div><label>ID:</label>{{hero.id}}&nbsp;<label> name:</label>{{hero.name}}</div>
  </li>
  </ul>
  <div>
  <label>name: </label>
  <input [(ngModel)]="hero.name" >
  <label>ID: </label>
  <input  [ngModel]="hero.id" (ngModelChange)="hero.id=$event">
</div>
<div>
<ul class="heroes">
<li *ngFor="let onehero of Heroes" (click)="onSelect(onehero)" [class.selected]="onehero===selectedHero">
<span class="badge">ID:{{onehero.id}}</span>&nbsp;{{onehero.name}}
</li>
</ul>
</div >
<app-hero-detail [DetailHero]="selectedHero"></app-hero-detail>
<!--上一节代码end-->
  `
  ,
  styleUrls: ['./app.component.css'],
  //注册一个HeroGetService提供商,来告诉注入器如何创
  //建HeroGetService。 因此在@Component组件的元数据
  //底部添加providers数组属性
  providers: [HeroGetService]
})

export class AppComponent implements OnInit {
//如下:添加一个构造函数,并定义一个私有属性。
//我们修改了HeroService的构造函数,我们不得不找出创
//建过此服务的每一处代码,并修改它。 围着补丁代码转圈
//很容易导致错误,还会增加测试负担。我们每次使用new都
//会创建一个新的服务实例(herogetService = new HeroGetService();)。 如果这个服务需要缓存英雄列
//表,并把这个缓存共享给别人呢?怎么办? 没办法,做不
//到。我们把AppComponent锁定到HeroGetService的一个
//特定实现。 我们很难在不同的场景中切换实现。 例如,能离
//线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。
//构造函数自己什么也不用做,它在参数中定义了一个私有
//的herogetService属性,并把它标记为注入HeroGetService的实例。
  constructor(private herogetSevice: HeroGetService) {}
  title = 'My conquest is the sea of stars.';
  from = 'Reinhard von Lohengramm';
  hero: HeroProperty = {
    id: 9527,
    name: 'Lee',
  };
//  Heros = HeroArray;
// 将以上改为如下,添加一个尚未初始化的Heros属性
  Heroes: HeroProperty[];
  selectedHero: HeroProperty;
  onSelect(each: HeroProperty): void {
    this.selectedHero = each;
  }
  getHerosData(): void {
   this.herogetSevice.getHeros().then(heroesdata => this.Heroes = heroesdata);
   //this.heroes = this.heroService.getHeroes();并不能做到异步获取数据
   //HeroService立即返回一个模拟的英雄列表,它的
//远端服务器获取。当使用远端服务器时,用户不会等待服务
//器的响应。换句话说,用户没法在等待期间阻塞浏览器界
//面。为了协调视图与响应,我们可以使用(Promise),它是一
//种异步技术,它会改变getHeroes()方法的签名。它就是
//一个承诺,在有了结果时,它承诺会回调我们。 英雌调用
//一个异步服务去执行数据请求,并且给它一个回调函数。 
//请求一旦完成,它就会调用我们的回调函数,并通过参数把工
//作结果或者错误信息传给我们。把回调函数作为参数传给承
//诺实例对象的then方法。在回调函数中,我们把服务返回的英
//雄数组赋值给组件的Heroes属性。
  }
  ngOnInit(): void {
    this.getHerosData();
  }
}

heroproperty.ts文件

export class HeroProperty {
  id: number;
  name: string;
}

mock-hero-data.ts文件

import { HeroProperty} from './heroproperty';
export const HeroArray: HeroProperty[] = [
  { id: 1, name: 'Asimov' },
  { id: 2, name: 'IronMan' },
  { id: 3, name: 'Gen' },
  { id: 4, name: 'AnglovLee' }
];

hero-detail.component.ts文件

import { Component, Input } from '@angular/core';
import { HeroProperty} from './heroproperty';


@Component({
  selector: 'app-hero-detail',
  template: `
  <!--herodetail-->
<div *ngIf="DetailHero">
<h2>{{DetailHero.name}} details!</h2>
<label>id: </label>{{DetailHero.id}}
<div>
    <label>name: </label>
    <input [(ngModel)]="DetailHero.name" placeholder="name"/>
</div>
</div>
<!--herodetail-->
  `,
})
export class HeroDetailComponent {
  @Input() DetailHero: HeroProperty;
}

app.module.ts文件

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroDetailComponent} from './hero-detail.component';
@NgModule({
  declarations: [
    AppComponent,
    HeroDetailComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

猜你喜欢

转载自blog.csdn.net/changerjjlee/article/details/76735697