简体   繁体   English

如何在Angular2中的observable中创建一个observable

[英]How to create an observable within an observable in Angular2

I might be off on the process, but here goes: 我可能会关注这个过程,但是这里有:

I have an angular2 service. 我有一个angular2服务。 The source for the data of this service is going to be localstorage... later optionally updated when a DB call using http returns. 此服务的数据源将是localstorage ...稍后可选择在使用http返回DB调用时更新。 Because I'll be wanting to update the data returned as the various sources come back, it appears I want to use an observables. 因为我想要更新返回的数据,因为各种来源都会回来,看来我想要使用一个observables。 For now, I'm just trying to get the concept down, so I've skipped the localstorage aspect... but I'm including the 'backstory' so it makes (some) sense as to why I'm wanting to do this in multiple methods. 就目前而言,我只是试图让这个概念失效,所以我已经跳过了本地存储方面......但我包括了“背景故事”,所以它让(某些)感觉到我为什么要做这在多种方法中。

My thought was I would have a "getHTTPEvents()" method that would return an observable with the payload being the events from the DB. 我的想法是我会有一个“getHTTPEvents()”方法,它将返回一个observable,其中有效负载是来自DB的事件。 (the theory being that at some point in the future I'd also have a 'getLSEvents()' method that would piggy back in there) (理论是,在未来的某个时候,我也会有一个'getLSEvents()'方法,可以在那里捎带)

To mock that up, I have this code: 为了模拟它,我有这个代码:

private eventsUrl = 'app/mock-events.json';
getHTTPEvents() : Observable<Array<any>> { 
    return this._http.get(this.eventsUrl)
        .map(response => response.json()['events'])
        .catch(this.handleError); // handle error is a logging method
}

My goal would be to create a method that allows filtering on the returned events yet still returns an observable to users of the service. 我的目标是创建一个方法,允许过滤返回的事件,但仍然向服务的用户返回一个observable。 That is where my problem is. 这就是我的问题所在。 With that goal, I have a public method which will be called by users of the service. 有了这个目标,我有一个公共方法,将由服务的用户调用。 (attempted to use pattern from here https://coryrylan.com/blog/angular-2-observable-data-services ) (试图从这里使用模式https://coryrylan.com/blog/angular-2-observable-data-services

public getEvents(key:string,value:string) : Observable<Array<any>> {
    var allEventsObserve : Observable<Array<any>> = this.getHTTPEvents();
    var filteredEventsObserve : Observable<Array<any>>;


    allEventsObserve 
    .subscribe(
        events => {
            for(var i=0;i<events.length;i++) {
                if(events[i][key]==value) {
                    console.log('MATCH!!!' + events[i][key]); // THIS WORKS!
                    return new Observable(observer => filteredEventsObserve = observer);  // what do I need to return here?  I want to return an observable so the service consumer can get updates
                }
            }
            return allEventsObserve
        },
        error =>  console.error("Error retrieving all events for filtering: " + error));

} }

The above doesn't work. 以上不起作用。 I've watch lots of videos and read lots of tutorials about observables, but nothing I can find seems to go more indepth other than creating and using the http observable. 我看了很多视频,并阅读了很多关于可观察对象的教程,但除了创建和使用http observable之外,我找不到的东西似乎更加深入。

I further tried this method of making the new observable: 我进一步尝试了这种制作新观察的方法:

var newObs = Observable.create(function (observer) {
                    observer.next(events[i]);
                    observer.complete(events[i]);
                });

And while at least that compiles, I'm not sure how to 'return' it at the right time... as I can't "Create" it outside the allEventsObserve.subscribe method (because 'events' doesn't exist) and can't (seem) to "return" it from within the subscribe. 虽然至少编译,我不知道如何在正确的时间'返回'它...因为我不能在allEventsObserve.subscribe方法之外“创建”它(因为'事件'不存在)并且不能(似乎)从订阅中“返回”它。 I'm also not entirely sure how I'd then "trigger" the 'next'...? 我也不完全确定我是如何“触发”'下一个'......?

Do I need to modify the data within allEventsObserve and somehow simply still return that? 我是否需要修改allEventsObserve中的数据并以某种方式仍然返回? Do I make a new observable (as attempted above) with the right payload - and if so, how do I trigger it? 我是否使用正确的有效负载创建了一个新的可观察对象(如上所述) - 如果是这样,我该如何触发它? etc... I've checked here: How to declare an observable on angular2 but can't seem to follow how the 'second' observable gets triggered. 等等......我在这里检查过: 如何在angular2上声明一个observable,但似乎无法跟踪“第二个”observable如何被触发。 Perhaps I have the entire paradigm wrong? 也许我的整个范式都错了?

It appears that you're misunderstanding what an RxJS operator (like map , filter , etc) actually returns, and I think correcting that will make the solution clear. 你似乎误解了RxJS操作符(如mapfilter等)实际返回的内容,我认为纠正这一点会使解决方案变得清晰。

Consider this short example: 考虑这个简短的例子:

allEventsObserve
  .map(events => {
    return 'this was an event';
  })

Granted, it's a pretty useless example since all of the data from events is lost, but let's ignore that for now. 当然,这是一个非常无用的例子,因为来自events所有数据都丢失了,但是现在让我们忽略它。 The result of the code above is not an array of strings or anything else, it's actually another Observable . 上面代码的结果不是字符串数组或其他任何东西,它实际上是另一个Observable This Observable will just emit the string 'this was an event' for each array of events emitted by allEventsObserve This is what allows us to chain operators on observables -- each operator in the chain returns a new Observable that emits items that have been modified in some way be the previous operator. 这个Observable将为allEventsObserve发出的每个事件数组发出字符串'this was an event' allEventsObserve 'this was an event'这是允许我们在observables上链接运算符的东西 - 链中的每个运算符都返回一个新的Observable ,它发出已修改的项目。某种方式是以前的运营商。

allEventsObserve 
  .map(events => {
    return 'this was an event';
  }) 
  .filter(events => typeof events !== 'undefined') 

allEventsObserve is obviously an Observable , allEventsObserve.map() evaluates to an Observable , and so does allEventsObserve.map().filter() . allEventsObserve显然是一个ObservableallEventsObserve.map()求值为ObservableallEventsObserve.map().filter()

So, since you're expecting your function to return an Observable , you don't want to call subscribe just yet, as doing so would return something that isn't really an Observable . 所以,既然你期望你的函数返回一个Observable ,你不想再调用subscribe,因为这样做会返回一些不是Observable东西。

With that in mind, your code can be rewritten in the following way: 考虑到这一点,您的代码可以通过以下方式重写:

public getEvents(key:string,value:string) : Observable<Array<any>> {
    var allEventsObserve : Observable<Array<any>> = this.getHTTPEvents();

    return allEventsObserve 
      .map(events => {
          var match = events.filter(event => event[key] == value);
          if (match.length == 0) {
            throw 'no matching event found';
          } else {
            return match[0];
          }
      })
      .catch(e => {
        console.log(e);
        return e;
      });

}

Since getEvents returns an Observable , somewhere else in your code you would do something like getEvents().subscribe(events => processEvents()) to interact with them. 由于getEvents返回一个Observable ,在代码中的其他地方,你会做一些像getEvents().subscribe(events => processEvents())来与它们进行交互。 This code also assumes that this.getHTTPEvents() returns an Observable . 此代码还假定this.getHTTPEvents()返回一个Observable

Also, notice that I changed your for loop to a call to filter , which operates on arrays. 另外,请注意我将for循环更改为对filter的调用,该filter对数组进行操作。 events in this case is a plain-old JavaScript Array , so the filter that is getting called is not the same filter as the RxJS operator filter . events在这种情况下是一个普通老式的JavaScript Array ,所以filter ,这是获得所谓的是不一样的filter作为RxJS运营商filter

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM