Angular 2可以实现服务,它们只是可注入类的对应项,如下所述。在这种情况下,此类可以注入到其他元素中,例如组件。
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
import 'rxjs/add/operator/map';
@Injectable()
export class CompanyService {
constructor(http:Http) {
this.http = http;
}
}
在启动应用程序的主组件时,如果指定了HTTP_PROVIDERS
,则可以在其中注入一个Http
对象(使用其构造函数):
import {bootstrap} from 'angular2/platform/browser'
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component'
bootstrap(AppComponent, [
HTTP_PROVIDERS
]);
接下来可以将此服务注入到组件中,具体步骤如下。不要忘记在组件的providers
列表中指定它。
import { Component, View, Inject } from 'angular2/core';
import { CompanyService } from './company-service';
@Component({
selector: 'company-list',
providers: [ CompanyService ],
template: `
(...) `
})
export class CompanyList {
constructor(private service: CompanyService) {
this.service = service;
}
}
接下来您可以在服务中实现一个利用Http
对象的方法,并返回对应于您请求的Observable对象:
@Injectable()
export class CompanyService {
constructor(http:Http) {
this.http = http;
}
getCompanies() {
return this.http.get('https://angular2.apispark.net/v1/companies/')
.map(res => res.json());
}
}
getCompanies
方法并订阅Observable对象上的回调,在响应到达时通知更新组件的状态(就像在Angular1中使用Promise一样):export class CompanyList implements OnInit {
public companies: Company[];
constructor(private service: CompanyService) {
this.service = service;
}
ngOnInit() {
this.service.getCompanies().subscribe(
data => this.companies = data);
}
}
编辑
正如foxx在他的评论中建议的那样,async
管道也可以用于隐式订阅可观察对象。以下是使用它的方法。首先更新您的组件,将可观察对象放入要显示的属性中:
export class CompanyList implements OnInit {
public companies: Company[];
constructor(private service: CompanyService) {
this.service = service;
}
ngOnInit() {
this.companies = this.service.getCompanies();
}
}
在您的模板中使用 async 管道:
@Component({
selector: 'company-list',
providers: [ CompanyService ],
template: `
<ul>
<li *ngFor="#company of companies | async">{{company.name}}</li>
</ul>
`
})
export class CompanyList implements OnInit {
(...)
}
HTTP_PROVIDERS
,但注入的是ROUTER_PROVIDERS
。 这是一个笔误吗? - soroush gholamzadeh不需要将Http的get()方法返回的observable转换为promise。在大多数情况下,服务可以直接返回observable。
如果我们从服务器获取一个数组或原始类型(即字符串、数字、布尔值),我们可以通过在模板中使用返回的observable并使用asyncPipe来简化控制器逻辑。这个管道会自动订阅observable(它也适用于promise),并返回observable最近发出的值。当发出新值时,该管道会标记组件以检查更改,因此视图将自动更新为新值。
如果我们从服务器获取一个对象,我不知道如何使用asyncPipe,我们可以使用async管道,与安全导航运算符结合使用,如下所示:
{{(objectData$ | async)?.name}}
subscribe()
到可观察对象并将包含的对象存储到组件属性中。然后,在模板中使用安全导航运算符(?.)或(如@Evan Plaice在评论中提到的那样)NgIf。如果不使用安全导航运算符或NgIf,当模板首次尝试呈现对象尚未填充值时,将抛出错误。service.ts
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map'; // we need to import this now
@Injectable()
export class MyService {
constructor(private _http:Http) {}
getArrayDataObservable() {
return this._http.get('./data/array.json')
.map(data => data.json());
}
getPrimitiveDataObservable() {
return this._http.get('./data/primitive.txt')
.map(data => data.text()); // note .text() here
}
getObjectDataObservable() {
return this._http.get('./data/object.json')
.map(data => data.json());
}
}
app.ts
import {Component} from 'angular2/core';
import {MyService} from './my-service.service';
import {HTTP_PROVIDERS} from 'angular2/http';
@Component({
selector: 'my-app',
providers: [HTTP_PROVIDERS, MyService],
template: `
<div>array data using '| async':
<div *ngFor="#item of arrayData$ | async">{{item}}</div>
</div>
<div>primitive data using '| async': {{primitiveData$ | async}}</div>
<div>object data using ?.: {{objectData?.name}}</div>
<div *ngIf="objectData">object data using NgIf: {{objectData.name}}</div>`
})
export class AppComponent {
constructor(private _myService:MyService) { console.clear(); }
ngOnInit() {
this.arrayData$ = this._myService.getArrayDataObservable();
this.primitiveData$ = this._myService.getPrimitiveDataObservable();
this._myService.getObjectDataObservable()
.subscribe(data => this.objectData = data);
}
}
getArrayDataObervable()
- 只是为了突出这个方法返回一个Observable。通常你不会在名称中加入“Observable”。
data/array.json
[ 1,2,3 ]
data/primitive.json
Greetings SO friends!
data/object.json
{ "name": "Mark" }
输出:
array data using '| async':
1
2
3
primitive data using '| async': Greetings SO friends!
object data using .?: Mark
object data using NgIf: Mark
可以翻译为:{{链接1:Plunker}}
async
管道的一个缺点是在组件中没有处理服务器错误的机制。我回答了另一个问题,解释了如何在组件中捕获这样的错误,但在这种情况下我们总是需要使用subscribe()
。?
(Elvis)运算符的方法是在将使用数据的模板部分中添加一个*ngIf
条件。它提供了更粗粒度的控制,因此您不必担心在整个模板中随处添加Elvis运算符,也不必担心模板在没有数据的情况下的呈现方式。 - Evan Plaice
.then()
后添加.toPromise()
,将HTTP转换为Promise。但是,使用可观察对象是推荐的方法。 - Evan Plaice