当前位置: 首页 > 知识库问答 >
问题:

从Angular 2服务创建和返回可观测数据

龚浩宕
2023-03-14

这更像是一个“最佳实践”问题。有三个参与者:一个组件、一个服务和一个模型组件正在调用服务从数据库获取数据。服务正在使用:

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

返回可观察的

组件只能订阅可观察的

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

然而,我真正想要的是Service返回一个Array of Model对象,该对象是从Service从数据库中检索的数据创建的。我意识到Component可以在订阅方法中创建这个数组,但是我认为如果服务这样做并使它对Component可用,它会更干净。

服务如何创建包含该数组的新的可观察的,并返回该数组?


共有3个答案

艾嘉石
2023-03-14

我想补充一点,如果创建的对象是静态的,并且不通过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());
      }
    }

编辑:对于Angular 7. x. x映射需要使用管道()来完成,如下所述(https://stackoverflow.com/a/54085359/986160):

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
      }
    }

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

谢英光
2023-03-14

这是Angular2文档中的一个示例,说明了如何创建和使用自己的观测值:

服务

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');
      }
    }

可在此处找到完整的工作示例:https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#双向服务

龙欣德
2023-03-14
匿名用户

更新:2016年9月24日Angular 2.0稳定

这个问题仍然有很多流量,所以,我想更新它。随着Alpha、Beta和7个RC候选者的疯狂变化,我停止更新SO答案,直到它们稳定下来。

这是使用主题和重放主题的完美案例

我个人更喜欢使用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

令人惊叹的即使我们关闭了主题,它仍然用最后加载的内容进行了回复。

另一件事是我们如何订阅超文本传输协议调用并处理响应。地图是伟大的处理响应。

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)));

Sweet,var是一个可观察的对象,它从最后的http调用中获取数据。

好的,那很好,但是我想要一个角服务!

我明白了:

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);
    }

 }

我是观察者和观察者的超级粉丝,所以我希望这次更新有所帮助!

原始答案

我认为这是一个使用可观察主题或Angular2EventEmitter的用例。

在您的服务中,您创建了一个EventEmitter,允许您将值推送到它上面。在Alpha 45中,您必须使用toRx()对其进行转换,但我知道他们正在努力消除该问题,因此在Alpha 46中,您可以简单地返回值。

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=

然后在你的服务中弄乱通话结果。

我喜欢自己创建EventEmitter流,以防我需要从其他组件访问它,但我可以看到这两种方法都是有效的。。。

下面是一个plunker,它显示了一个带有事件发射器的基本服务:Plunkr

 类似资料:
  • 我正在为我的全堆栈应用程序构建一个angular2前端。我正在进行用户登录,我有这个功能,当提交登录表单时调用: 我的userService中的登录功能如下: 最后,handleError函数: 当我提交错误的密码时,我会收到错误信息: 401-未经授权的响应,状态为:401未经授权的URL:http://localhost:3000/api/login 从我的错误处理程序中的变量打印。这很好,但

  • 问题内容: 我目前有一种方法可以检查3x3网格中中心项周围的内容,如果8个相邻位置中的内容包含我要检查的内容,我想在长度为7的数组上将该正方形标记为1。 为此,我需要在我的方法中创建并返回一个数组,这可能吗? 问题答案: 不知道是什么问题。你是这个意思?

  • 我正在尝试使用 考虑以下代码 每当我试图打印出的结果时,它总是返回 即使我返回一个json对象。 如何打印的结果?

  • 我有一个返回用户对象的角度服务。用户对象有自己的属性和一组墙。服务向调用组件返回一个可观察的。在该服务中,我能够从http服务返回的json创建用户对象。但是,当我订阅组件中的服务时,返回的对象为null。我做错了什么?

  • 我需要从现有的WSDL文件为使用OCPP协议的系统创建一个中心系统(SOAP服务器)。(开放充电桩协议) 我已经成功地在非wsdl模式和wsdl模式下编写了测试SOAP服务器和客户机,但是当我尝试使用现有的wsdl时,我得到的只是一堆错误(这并不能告诉我太多) 可以在此处找到WSDL文件(中央系统和chargepoint。抱歉,无法发布更多链接..) 我已经修复了一些错误,但是不能越过这个。 我想