从Angular 2服务创build和返回Observable

这更像是一个“最佳实践”的问题。 有三个参与者:一个Component ,一个Service和一个ModelComponent正在调用Service以从数据库中获取数据。 该Service正在使用:

 this.people = http.get('api/people.json').map(res => res.json()); 

返回一个Observable

Component可以只订阅Observable

  peopleService.people .subscribe(people => this.people = people); } 

但是,我真正想要的是Service返回从数据库中检索的数据创buildArray of Model对象Array of Model 。 我意识到Component可以在订阅方法中创build这个数组,但我认为如果服务做到这一点,并使其可用于Component ,将是更清洁。

如何可以创build一个新的Observable ,包含该数组,并返回?

更新:9/24/16angular2.0稳定

这个问题仍然有很多stream量,所以我想更新它。 随着阿尔法,Beta和7个RC候选人的疯狂变化,我停止更新我的答案,直到他们稳定。

这是使用Subject和ReplaySubject的最佳例子

个人更喜欢使用ReplaySubject(1)因为它允许最后存储的值在新用户附加时传递,即使是迟到:

 let project = new ReplaySubject(1); //subscribe project.subscribe(result => console.log('Subscription Streaming:', result)); http.get('path/to/whatever/projects/1234').subscribe(result => { //push onto subject project.next(result)); //add delayed subscription AFTER loaded setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000); }); //Output //Subscription Streaming: 1234 //*After load and delay* //Delayed Stream: 1234 

所以,即使我迟到或需要加载后,我总是可以得到最新的电话,而不必担心错过callback。

这也可以让你使用相同的stream来推送到:

 project.next(5678); //output //Subscription Streaming: 5678 

但是,如果你100%确定,你只需要打一次电话呢? 留下开放的主题和可观察性并不好,但总是有“如果?

这就是AsyncSubject进来的地方

 let project = new AsyncSubject(); //subscribe project.subscribe(result => console.log('Subscription Streaming:', result), err => console.log(err), () => console.log('Completed')); http.get('path/to/whatever/projects/1234').subscribe(result => { //push onto subject and complete project.next(result)); project.complete(); //add a subscription even though completed setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000); }); //Output //Subscription Streaming: 1234 //Completed //*After delay and completed* //Delayed Sub: 1234 

真棒! 即使我们closures了这个主题,它仍然回答了最后一件事情。

另一件事是我们如何订阅该http调用并处理响应。 地图是伟大的处理响应

 public call = http.get(whatever).map(res => res.json()) 

但是如果我们需要嵌套这些电话呢? 是的,您可以使用具有特殊function的主题:

 getThing() { resultSubject = new ReplaySubject(1); http.get('path').subscribe(result1 => { http.get('other/path/' + result1).get.subscribe(response2 => { http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3)) }) }) return resultSubject; } var myThing = getThing(); 

但这很多,意味着你需要一个function来做到这一点。 inputFlatMap

 var myThing = http.get('path').flatMap(result1 => http.get('other/' + result1).flatMap(response2 => http.get('another/' + response2))); 

甜, var是一个可以从最终的http调用获取数据的可观察值。

那好,但我想要一个angular2服务!

我接到你了:

 import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { ReplaySubject } from 'rxjs'; @Injectable() export class ProjectService { public activeProject:ReplaySubject<any> = new ReplaySubject(1); constructor(private http: Http) {} //load the project public load(projectId) { console.log('Loading Project:' + projectId, Date.now()); this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res)); return this.activeProject; } } //component @Component({ selector: 'nav', template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>` }) export class navComponent implements OnInit { public project:any; constructor(private projectService:ProjectService) {} ngOnInit() { this.projectService.activeProject.subscribe(active => this.project = active); } public load(projectId:string) { this.projectService.load(projectId); } } 

我是观察者和观察者的忠实粉丝,所以我希望这个更新能够帮助你!

原始答复

我认为这是一个使用Observable主题的用例,或者在Angular2使用EventEmitter

在你的服务中,你创build一个EventEmitter ,允许你将值推送到它。 在Alpha 45中,你必须把它转换成toRx() ,但是我知道他们正在努力摆脱这个,所以在Alpha 46中,你可以简单地返回EvenEmitter

 class EventService { _emitter: EventEmitter = new EventEmitter(); rxEmitter: any; constructor() { this.rxEmitter = this._emitter.toRx(); } doSomething(data){ this.rxEmitter.next(data); } } 

这种方式有一个单一的EventEmitter ,你现在可以把不同的服务function推到上面。

如果你想直接从一个调用中返回一个observable,你可以这样做:

 myHttpCall(path) { return Observable.create(observer => { http.get(path).map(res => res.json()).subscribe((result) => { //do something with result. var newResultArray = mySpecialArrayFunction(result); observer.next(newResultArray); //call complete if you want to close this stream (like a promise) observer.complete(); }); }); } 

这将允许您在组件中执行此操作: peopleService.myHttpCall('path').subscribe(people => this.people = people);

并在您的服务中的电话结果搞乱。

我喜欢创buildEventEmitterstream自己的情况下,我需要从其他组件访问它,但我可以看到两种方式工作…

这是一个显示与事件发射器的基本服务: plunkr

这是Angular2文档中关于如何创build和使用自己的Observable的一个例子:

服务

 import {Injectable} from 'angular2/core' import {Subject} from 'rxjs/Subject'; @Injectable() export class MissionService { private _missionAnnouncedSource = new Subject<string>(); missionAnnounced$ = this._missionAnnouncedSource.asObservable(); announceMission(mission: string) { this._missionAnnouncedSource.next(mission) } } 

组件

  import {Component} from 'angular2/core'; import {MissionService} from './mission.service'; export class MissionControlComponent { mission: string; constructor(private missionService: MissionService) { missionService.missionAnnounced$.subscribe( mission => { this.mission = mission; }) } announce() { this.missionService.announceMission('some mission name'); } } 

完整的工作示例可以在这里find: https : //angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

我想补充说的是,如果创build的对象是静态的,而不是通过http来完成,那么可以这样做:

 public fetchModel(uuid: string = undefined): Observable<string> { if(!uuid) { //static data return Observable.of(new TestModel()).map(o => JSON.stringify(o)); } else { return this.http.get("http://localhost:8080/myapp/api/model/" + uuid) .map(res => res.text()); } } 

从答案我关于观察员和静态数据的问题: https : //stackoverflow.com/a/35219772/986160

我对派对有点迟,但是我觉得我的方法有缺点,就是没有使用EventEmitters和Subjects。

所以,这是我的方法。 我们不能脱离订阅(),我们不想。 在这种情况下,我们的服务将返回一个Observable<T>与一个观察员,我们珍贵的货物。 从调用者,我们将初始化一个variables, Observable<T> ,它将得到服务的Observable<T> 。 接下来,我们将订阅这个对象。 最后,你得到你的“T”! 从你的服务。

首先,我们的人员服务,但是你的不通过参数,这是更现实的:

 people(hairColor: string): Observable<People> { this.url = "api/" + hairColor + "/people.json"; return Observable.create(observer => { http.get(this.url) .map(res => res.json()) .subscribe((data) => { this._people = data observer.next(this._people); observer.complete(); }); }); } 

好的,正如你所看到的,我们正在返回一个types为“people”的Observable 。 方法的签名,甚至这样说! 我们把_people塞进我们的观察者。 接下来,我们将从组件中的调用者访问这个types。

在组件中:

 private _peopleObservable: Observable<people>; constructor(private peopleService: PeopleService){} getPeople(hairColor:string) { this._peopleObservable = this.peopleService.people(hairColor); this._peopleObservable.subscribe((data) => { this.people = data; }); } 

我们通过从PeopleService返回Observable<people>PeopleService 。 然后,我们订阅这个属性。 最后,我们this.people people设置为我们的数据( people )响应。

以这种方式构build服务与典型的服务有一个主要的优势:map(…)和component:“subscribe(…)”模式。 在现实世界中,我们需要将json映射到我们的类中的属性,有时我们在那里做一些自定义的东西。 所以这个映射可以发生在我们的服务中。 而且,通常,因为我们的服务调用不会被使用一次,而且可能在我们的代码的其他地方使用,所以我们不必在某个组件中再次执行该映射。 而且,如果我们给人们添加一个新的领域呢?

请注意,您正在使用Observable#map将base Observable发出的原始Response对象转换为JSON响应的parsing表示forms。

如果我正确地理解了你,你想再次map 。 但这一次,将原始JSON转换为您的Model实例。 所以你会做这样的事情:

 http.get('api/people.json') .map(res => res.json()) .map(peopleData => peopleData.map(personData => new Person(personData))) 

所以,你从一个发出Response对象的Observable开始,把它转换成一个observable,它发出了这个响应的parsingJSON对象,然后把它转换成另一个observable,将原始的JSON转换成你的模型数组。

在service.ts文件中 –

一个。 从…的可观察到的
湾 创build一个json列表
C。 使用Observable.of()返回json对象
防爆。 –

 import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; @Injectable() export class ClientListService { private clientList; constructor() { this.clientList = [ {name: 'abc', address: 'Railpar'}, {name: 'def', address: 'Railpar 2'}, {name: 'ghi', address: 'Panagarh'}, {name: 'jkl', address: 'Panagarh 2'}, ]; } getClientList () { return Observable.of(this.clientList); } }; 

在我们调用服务的get函数的组件中 –

 this.clientListService.getClientList().subscribe(res => this.clientList = res);