Javascript RXJS Observable 数组的简单过滤器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37991713/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:57:06  来源:igfitidea点击:

Simple filter on array of RXJS Observable

javascripttypescriptangularrxjsobservable

提问by Johannes

I am starting my project with Angular2 and the developers seem to recommend RXJS Observable instead of Promises.

我用 Angular2 开始我的项目,开发人员似乎推荐 RXJS Observable 而不是 Promises。

I have achieved to retrieve a list of elements (epics) from the server. But how can I filter the elments by using for example an id?

我已经实现了从服务器检索元素列表(史诗)。但是如何使用例如 id 过滤元素?

The following code is an extraction from my app and shows now the final working solution. Let's hope it helps someone.

以下代码是从我的应用程序中提取的,现在显示了最终的工作解决方案。让我们希望它可以帮助某人。

@Injectable()
export class EpicService {

  private url = CONFIG.SERVER + '/app/';  // URL to web API

  constructor(private http:Http) {}

  private extractData(res:Response) {
    let body = res.json();
    return body;
  }

  getEpics():Observable<Epic[]> {
    return this.http.get(this.url + "getEpics")
      .map(this.extractData)
      .catch(this.handleError);
  }

  getEpic(id:string): Observable<Epic> {
    return this.getEpics()
      .map(epics => epics.filter(epic => epic.id === id)[0]);
  }
}

export class EpicComponent {

  errorMessage:string;
  epics:Epic[];
  epic:Epic;

  constructor(
    private requirementService:EpicService) {
  }

  getEpics() {
    this.requirementService.getEpics()
      .subscribe(
        epics => this.epics = epics,
        error => this.errorMessage = <any>error);
  }

  // actually this should be eventually in another component
  getEpic(id:string) {
    this.requirementService.getEpic(id)
        .subscribe(
        epic => this.epic = epic,
        error => this.errorMessage = <any>error);
  }
}

export class Epic {
  id: string;
  name: string;
}

Thank you in advance for your help.

预先感谢您的帮助。

回答by Luka Jacobowitz

You'll want to filter the actual array and not the observable wrapped around it. So you'll map the content of the Observable (which is an Epic[]) to a filtered Epic.

您需要过滤实际的数组,而不是围绕它的可观察对象。因此,您需要将 Observable 的内容(即Epic[])映射到已过滤的Epic.

getEpic(id: string): Observable<Epic> {
  return this.getEpics()
     .map(epics => epics.filter(epic => epic.id === id)[0]);
}

Then afterwards you can subscribeto getEpicand do whatever you want with it.

然后之后,您可以subscribegetEpic,做任何你想用它。

回答by mtpultz

You can do this using the flatMapand filtermethods of Observableinstead of the JS array filter method in map. Something like:

您可以使用flatMapfilter方法来Observable代替 .js 中的 JS 数组过滤器方法map。就像是:

this.getEpics() 
    .flatMap((data) => data.epics) // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}]
    .filter((epic) => epic.id === id) // checks {id: 1}, then {id: 2}, etc
    .subscribe((result) => ...); // do something epic!!!

flatMapwill provide singular indices for filtering and then you can get on with whatever happens next with the results.

flatMap将提供用于过滤的单一索引,然后您可以继续处理接下来发生的结果。

If TypeScript throws a error indicating you can't compare a string and a number regardless of your use of ==in the filter just add a +before epic.idin the filter, per the Angular docs:

如果 TypeScript 抛出一个错误,表明无论您==在过滤器中使用什么,都无法比较字符串和数字,只需在过滤器中添加一个+before epic.id,根据 Angular 文档:

    .flatMap(...)
    .filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc
    .subscribe(...)

Example:

例子:

https://stackblitz.com/edit/angular-9ehje5?file=src%2Fapp%2Fapp.component.ts

https://stackblitz.com/edit/angular-9ehje5?file=src%2Fapp%2Fapp.component.ts

回答by Andrei Zhytkevich

original answer with a fix: Observablesare lazy. You have to call subscribeto tell an observableto send its request.

带有修复的原始答案: Observables懒惰。你必须打电话subscribe告诉一个observable发送它的请求。

  getEpic(id:number) {
    return this.getEpics()
           .filter(epic => epic.id === id)
           .subscribe(x=>...);
  }

Update to Rxjs 6:

更新到 Rxjs 6:

import {filter} from 'rxjs/operators';

getEpic(id:number) {
        return this.getEpics()
               .pipe(filter(epic => epic.id === id))
               .subscribe(x=>...);
      }

回答by rinukkusu

You have to subscribe on Observables to get the data, since http calls are async in JavaScript.

您必须订阅Observables 才能获取数据,因为 http 调用在 JavaScript 中是异步的。

getEpic(id: number, callback: (epic: Epic) => void) {
    this.getEpics().subscribe(
        epics: Array<Epic> => {
            let epic: Epic = epics.filter(epic => epic.id === id)[0];
            callback(epic);
        }
    );
}

You can call that method then like this:

您可以像这样调用该方法:

this.someService.getEpic(epicId, (epic: Epic) => {
    // do something with it
});