Jos*_*hik 126 observable angular
这更像是一个"最佳实践"问题.有三个球员:a Component,a Service和a Model.在Component被调用Service从数据库中获取数据.该Service方法是使用:
this.people = http.get('api/people.json').map(res => res.json());
Run Code Online (Sandbox Code Playgroud)
返回一个Observable.
在Component可以只订阅Observable:
peopleService.people
.subscribe(people => this.people = people);
}
Run Code Online (Sandbox Code Playgroud)
但是,我真正想要的是Service返回从数据库中检索Array of Model的数据创建的对象Service.我意识到Component可以在subscribe方法中创建这个数组,但我认为如果服务可以做到这一点并使其可用,那将会更清晰Component.
如何Service创建一个新的Observable,包含该数组,并返回?
Den*_*lek 157
更新: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
Run Code Online (Sandbox Code Playgroud)
因此,即使我迟到或需要加载以后我也可以随时获得最新的电话,而不用担心错过回调.
这也允许您使用相同的流向下推送到:
project.next(5678);
//output
//Subscription Streaming: 5678
Run Code Online (Sandbox Code Playgroud)
但是,如果你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
Run Code Online (Sandbox Code Playgroud)
真棒!即使我们关闭了主题,它仍然会回复它加载的最后一件事.
另一件事是我们如何订阅该http调用并处理响应.地图非常适合处理响应.
public call = http.get(whatever).map(res => res.json())
Run Code Online (Sandbox Code Playgroud)
但是,如果我们需要嵌套这些电话呢?是的,您可以使用具有特殊功能的主题:
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();
Run Code Online (Sandbox Code Playgroud)
但这很多,意味着你需要一个功能来完成它.输入FlatMap:
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Run Code Online (Sandbox Code Playgroud)
很好,这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);
}
}
Run Code Online (Sandbox Code Playgroud)
我是观察者和观察者的忠实粉丝,所以我希望这次更新有所帮助!
原始答案
我觉得这是一个使用的使用情况下可观察到主题或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);
}
}
Run Code Online (Sandbox Code Playgroud)
这种方式可以EventEmitter让您的不同服务功能现在可以推进.
如果您想直接从通话中返回一个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();
});
});
}
Run Code Online (Sandbox Code Playgroud)
这将允许您在组件中执行此操作:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
并搞乱你服务中的电话结果.
我喜欢EventEmitter自己创建流,以防我需要从其他组件访问它,但我可以看到两种方式都工作...
这是一个使用事件发射器显示基本服务的plunker:Plunkr
tib*_*bus 29
这是Angular2文档中有关如何创建和使用自己的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)
}
}
Run Code Online (Sandbox Code Playgroud)
组件
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');
}
}
Run Code Online (Sandbox Code Playgroud)
完整和有效的例子可以在这里找到:https: //angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
Mic*_*dis 18
我想补充说,如果创建的对象是静态的,而不是来自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());
}
}
Run Code Online (Sandbox Code Playgroud)
编辑: 对于Angular 7.xx映射需要使用pipe()完成,如此处所述(/sf/answers/3785975161/):
import {of, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
[...]
public fetchModel(uuid: string = undefined): Observable<string> {
if(!uuid) { //static data
return of(new TestModel());
}
else {
return this.http.get("http://localhost:8080/myapp/api/model/" + uuid)
.pipe(map((res:any) => res)) //already contains json
}
}
Run Code Online (Sandbox Code Playgroud)
从回答我关于观察者和静态数据的问题:https://stackoverflow.com/a/35219772/986160
Lar*_*und 15
我参加派对有点晚了,但我认为我的方法的优势在于它没有使用EventEmitters和Subjects.
所以,这是我的方法.我们无法摆脱subscribe(),我们也不愿意.在这种情况下,我们的服务将由一名Observable<T>拥有我们珍贵货物的观察员返回.从调用者,我们将初始化一个变量,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();
});
});
}
Run Code Online (Sandbox Code Playgroud)
好的,正如你所看到的,我们正在返回一个Observable"人"类型.方法的签名,甚至是这样说的!我们把_people对象塞进我们的观察者.接下来我们将从Component中的调用者访问此类型!
在组件中:
private _peopleObservable: Observable<people>;
constructor(private peopleService: PeopleService){}
getPeople(hairColor:string) {
this._peopleObservable = this.peopleService.people(hairColor);
this._peopleObservable.subscribe((data) => {
this.people = data;
});
}
Run Code Online (Sandbox Code Playgroud)
我们_peopleObservable通过Observable<people>从我们那里返回来初始化我们PeopleService.然后,我们订阅了这个属性.最后,我们设置this.people了data(people)响应.
以这种方式构建服务与典型服务相比具有一个主要优势:map(...)和component:"subscribe(...)"模式.在现实世界中,我们需要将json映射到我们类中的属性,有时候,我们会在那里做一些自定义的东西.所以这种映射可以在我们的服务中进行.而且,通常,因为我们的服务调用不会被使用一次,但是,可能在我们的代码中的其他地方,我们不必再次在某个组件中执行该映射.而且,如果我们为人们增加一个新领域怎么办?....
小智 7
请注意,您正在使用Observable #map将Response您的基本Observable发出的原始对象转换为JSON响应的已解析表示.
如果我理解正确,你想map再次.但这一次,将原始JSON转换为您的实例Model.所以你会做类似的事情:
http.get('api/people.json')
.map(res => res.json())
.map(peopleData => peopleData.map(personData => new Person(personData)))
Run Code Online (Sandbox Code Playgroud)
因此,您开始使用一个Observable发出一个Response对象,将其转换为一个observable,它发出该响应的已解析JSON的对象,然后将其转换为另一个将原始JSON转换为模型数组的observable.
小智 6
在service.ts文件中-
一种。从可观察到的/“的”进口
湾 创建一个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);
}
};
Run Code Online (Sandbox Code Playgroud)
在我们调用服务的get函数的组件中-
this.clientListService.getClientList().subscribe(res => this.clientList = res);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
183766 次 |
| 最近记录: |