typescript 从 Observable<Xyz[]> 获取项目的 Angular 2 方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35351922/
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-10-21 03:16:44  来源:igfitidea点击:

Angular 2 way to get item from Observable<Xyz[]>

typescriptangularrxjs

提问by gxclarke

Given the following Typescript in an Angular 2 service:

给定 Angular 2 服务中的以下打字稿:

getLanguages () {
    return this.http.get(this._languagesUrl)
        .map(res => <Language[]> res.json().data)
        .catch(this.handleError);

I'm having difficulty using this in circumstances where I need to lookup a specific item from the array. For example, I can't do the following because filterexpects an Observable<Language>rather than an the Observable<Language[]>that is being returned.

在需要从数组中查找特定项目的情况下,我很难使用它。例如,我不能执行以下操作,因为filter期望返回的是一个Observable<Language>而不是一个Observable<Language[]>

getLanguages().filter(language => language.id == 3) // Error

I appreciate that my issue may be that I'm mixing synchronous and asynchronous behavior, so Ill provide my use case: User can enter a language id and I want to display the associated language name. I want to leverage getLanguages()with the Observableresult because it is already being used elsewhere in the project. I also want implement some caching so the HTTP request doesn't get made each time I do a lookup.

我很欣赏我的问题可能是我混合了同步和异步行为,所以我将提供我的用例:用户可以输入语言 ID,我想显示关联的语言名称。我想利用getLanguages()Observable结果,因为它已经被其他地方的项目中使用。我还想实现一些缓存,以便每次查找时都不会发出 HTTP 请求。

Any thoughts?

有什么想法吗?

采纳答案by Langley

Here's an example working of what you want to do:

这是您想要执行的操作的示例:

https://plnkr.co/edit/lK47pVaW8b0CEez0mum4?p=preview

https://plnkr.co/edit/lK47pVaW8b0CEez0mum4?p=preview

Press F12 in chrome to see the logs to give you a more clear idea of what's going on and why it doesn't work in your example.

在 chrome 中按 F12 以查看日志,让您更清楚地了解发生了什么以及为什么它在您的示例中不起作用。

Take a special atention to:

要特别注意:

constructor(private _langService: LanguagesService) {
    _langService.getLanguages() //We get an Observable<Array> object returned.
        //So this is the observable's filter function:
        .filter( this._filter3rdLanguage )
        //The filter gets called only once and its comparing an observable object, not a language object.
        //that's why nothing gets filtered:
        .do( o => console.log(o) )
        //If you filter the actual list instead of the observable object, you'll get it called several times.
        //This is the Array's filter function.
        .subscribe( list => this.languages = list.filter( this._filter3rdLanguage ) );
}

This is another, maybe better, way to do it:

这是另一种可能更好的方法:

  _langService.getLanguages()
    .map( list => list.filter(this._filter3rdLanguage) )
    //see that this one IS filtered.
    .do( list => console.log(list) )
    .subscribe( list => this.languages = list );

回答by hadi

finding item in Observable<Type>

在 Observable<Type> 中查找项目

    let item: Language;
    langugages. // observable cached data
        .subscribe((items: Language[]) => item = items.find(p => p.id == 3));

回答by paulpdaniels

You can use mergeMapinstead of mapto flatten out the array:

您可以使用mergeMap代替map来展平数组:

getLanguages () {
    return this.http.get(this._languagesUrl)
        .flatMap(res => Rx.Observable.fromArray(<Language[]> res.json().data))
        .catch(this.handleError);

}

Now the return value from getLanguageswill be an Observable<Language>

现在的返回值getLanguages将是一个Observable<Language>

回答by MatthewScarpino

If you follow the mapmethod with subscribe, you can access members of the Languagearray when the array is available:

如果按照mapwith的方法操作subscribe,则可以Language在数组可用时访问数组成员:

return this.http.get(this._languagesUrl)
  .map(res => <Language[]> res.json().data)
  .subscribe((languages: Language[]) => alert(languages[3]); );

回答by David Spenard

For a customer service app I'm supporting, I needed a way to hide or show buttons depending on whether or not a user account had a particular line of business, and I needed to act upon the async data being loaded on the page, and not necessarily use the data as-is. So I'm calling a method from the template and using map with find then subscribe.

对于我支持的客户服务应用程序,我需要一种根据用户帐户是否具有特定业务线来隐藏或显示按钮的方法,并且我需要根据页面上加载的异步数据采取行动,并且不一定按原样使用数据。所以我从模板中调用一个方法并使用 map 和 find 然后订阅。

      <button *ngIf="(lobs$ | async) ? getButtonVisibility('internet') : false" class="eing-account-header-drawers-button" (click)="openDrawer(drawers[drawers.internet],$event)">


public getButtonVisibility(lobName: string) {
  let isVisible;
  this.lobs$.map(x =>
    x.findIndex(y =>
      y.lobName.toLowerCase() == lobName.toLowerCase() && y.hasLob))
        .subscribe(x => { isVisible = x != -1});
  return isVisible;      
}

回答by GregL

This is something of a guess, since I haven't used RxJS personally, though I am interested in it. Perusing the docs, I wonder if the following would work:

这是一个猜测,因为我个人没有使用过 RxJS,尽管我对它很感兴趣。仔细阅读文档,我想知道以下是否可行:

function getLanguageName(id: number): Observable<string> {
    return getLanguages()
              .map((langs: Language[]) => _.find(langs, { id: id }))
              .pluck('name');
}

I used Lodash's _.find()to find the matching record in the array, but if you don't have it, you can always do the search manually or use .filter(langs, ...)[0].

我使用 Lodash's_.find()在数组中查找匹配的记录,但如果你没有它,你总是可以手动进行搜索或使用.filter(langs, ...)[0].

If you want to do caching, and you know that the name of a language for a given id will never change, you could use Lodash's _.memoize()function to reuse the output for a given input.

如果你想做缓存,并且你知道给定 id 的语言名称永远不会改变,你可以使用 Lodash 的_.memoize()函数来重用给定输入的输出。

I'm curious to see if this works for you.

我很好奇这是否适合你。