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
Angular 2 way to get item from Observable<Xyz[]>
提问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 filter
expects 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 Observable
result 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 mergeMap
instead of map
to 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 getLanguages
will be an Observable<Language>
现在的返回值getLanguages
将是一个Observable<Language>
回答by MatthewScarpino
If you follow the map
method with subscribe
, you can access members of the Language
array when the array is available:
如果按照map
with的方法操作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.
我很好奇这是否适合你。