web-dev-qa-db-ja.com

Angular Observable <Xyz []>からアイテムを取得する2つの方法

Angular 2サービスで次のTypeScriptがある場合:

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

配列から特定のアイテムを検索する必要がある状況で、これを使用するのに問題があります。たとえば、filterは、返される_Observable<Language>_ではなく_Observable<Language[]>_を予期しているため、次のことはできません。

_getLanguages().filter(language => language.id == 3) // Error
_

私の問題は、同期動作と非同期動作が混在している可能性があることを理解しているので、ユースケースを提供します。ユーザーは言語IDを入力でき、関連する言語名を表示したい。プロジェクトの他の場所ですでに使用されているため、getLanguages()Observableの結果で活用したいと思います。また、ルックアップを実行するたびにHTTPリクエストが作成されないように、キャッシュを実装したいと思います。

何かご意見は?

8
gxclarke

これがあなたがやりたいことの動作例です:

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

chromeでF12を押すと、ログが表示され、何が起こっているのか、例で機能しない理由がより明確になります。

以下に特別な注意を払ってください。

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

これは別の、おそらくより良い方法です:

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

observable <Type>でアイテムを検索する

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

mergeMapの代わりにmapを使用して、配列をフラット化できます。

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

}

これで、getLanguagesからの戻り値はObservable<Language>になります。

2
paulpdaniels

mapメソッドをsubscribeで実行すると、配列が使用可能なときにLanguage配列のメンバーにアクセスできます。

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

私はRxJSを個人的に使用したことがないので、興味はありますが、これは推測のようなものです。ドキュメントをよく読んで、次のことがうまくいくかどうか疑問に思います。

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

Lodashの_.find()を使用して配列内の一致するレコードを検索しましたが、レコードがない場合は、いつでも手動で検索するか、.filter(langs, ...)[0]を使用できます。

キャッシュを実行する必要があり、特定のIDの言語の名前が変更されないことがわかっている場合は、Lodashの_.memoize()関数を使用して、特定の入力の出力を再利用できます。

これがあなたのために働くかどうか私は興味があります。

0
GregL

私がサポートしているカスタマーサービスアプリの場合、ユーザーアカウントに特定の業種があるかどうかに応じてボタンを表示または非表示にする方法が必要であり、ページに読み込まれている非同期データに基づいて操作する必要がありました。必ずしもデータをそのまま使用する必要はありません。そのため、テンプレートからメソッドを呼び出し、マップを使用して検索してからサブスクライブします。

      <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;      
}
0
David Spenard