我尝试使用 Angular 2-beta ,我想使用 Http 组件。但这里有一个严重的问题:
我读过this和 我知道在Angular 2中(与Angular 1不同), Http 组件不是返回 Promise 的服务。它返回一个名为 Observable 的东西。我们知道组件最好不要直接使用 Http 。有效的方法是制作一个负责消费 Http 的服务。但是如何?!在完成请求后,是否应该返回承诺? (看here)
它有意义吗?!
答案 0 :(得分:25)
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
的条件下在其中注入HTTP_PROVIDERS
对象(使用其构造函数):
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();
}
}
然后在模板中使用异步管道:
@Component({
selector: 'company-list',
providers: [ CompanyService ],
template: `
<ul>
<li *ngFor="#company of companies | async">{{company.name}}</li>
</ul>
`
})
export class CompanyList implements OnInit {
(...)
}
本文分两部分也可以提供更多细节:
希望它可以帮到你, 亨利
答案 1 :(得分:7)
无需将Http的get()方法返回的observable转换为promise。在大多数情况下,服务可以简单地返回observable。
如果我们从服务器获取数组或基本类型(即字符串,数字,布尔值),我们可以使用返回来简化控制器逻辑可以直接在我们的模板中使用asyncPipe进行观察。此管道将自动订阅observable(它也可以使用promise),它将返回observable发出的最新值。当发出新值时,管道标记要检查更改的组件,因此视图将自动使用新值更新。
如果我们从服务器获取对象,我不知道有什么方法可以使用asyncPipe,我们可以结合使用异步管道使用安全导航操作符如下:
{{(objectData$ | async)?.name}}
但这看起来很复杂,我们必须为我们想要显示的每个对象属性重复这一点。
相反,我建议我们subscribe()
到组件中的observable并将包含的对象存储到组件属性中。然后我们在模板中使用safe navigation operator(?。)或(在注释中提到的@Evan Plaice)NgIf。如果我们不使用安全导航操作符或NgIf,则在模板首次尝试渲染时将抛出错误,因为该对象尚未填充值。
请注意以下服务如何为每个get方法返回一个observable。
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);
}
}
注意:我把&#34; Observable&#34;在服务方法名称中 - 例如,getArrayDataObervable()
- 只是为了突出显示该方法返回一个Observable。通常你不会放弃&#34; Observable&#34;在名称中。
数据/ array.json
[ 1,2,3 ]
数据/ primitive.json
Greetings SO friends!
数据/ 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
使用async
管道的一个缺点是没有机制来处理组件中的服务器错误。我answered another question解释了如何在组件中捕获此类错误,但在这种情况下我们总是需要使用subscribe()
。