更新:9/24/16 Angular 2.0稳定
这个问题仍然吸引了大量流量,因此,我想对其进行更新。由于Alpha,Beta和7个RC候选人的变化而导致的疯狂,我停止更新我的SO答案,直到它们变得稳定为止。
这是使用Subjects和ReplaySubjects的完美案例
我个人更喜欢使用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
因此,即使我延迟连接或需要稍后加载,我也总是可以得到最新的呼叫,而不必担心缺少回调。
这也使您可以使用相同的流向下推送到:
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
太棒了!即使我们关闭了主题,它仍然会回复它加载的最后一件事。
另一件事是我们如何订阅该http调用并处理响应。Map非常适合处理响应。
public call = http.get(whatever).map(res => res.json())
但是,如果我们需要嵌套这些调用怎么办?是的,您可以使用具有特殊功能的主题:
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();
但这很多,这意味着您需要一个函数来执行此操作。输入FlatMap:
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 Subject或在中Angular2
的用例EventEmitter
。
在您的服务中,您将创建一个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
,您的不同服务功能便可以轻松执行。
如果您想直接从通话中返回可观察对象,则可以执行以下操作:
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);
并弄乱您的服务中的通话结果。
我喜欢EventEmitter
自己创建流,以防需要从其他组件访问它,但是我可以看到两种方法都可以工作...
这是一个通过事件发射器显示基本服务的插件:Plunkr