2017-12-16 25 views
1

私のシナリオは、検索フォームと結果リストを持つ古典的なWebページです。 Observableに結果をロードする動作をカプセル化したいと思います。RxJs:観測可能な検索結果のパターン

は、ここで私は現在、活字体でやっているものだ:pendingpresentfailed次のいずれか

function loadResults(query): Observable<T[]> {} 

const results = new Subject<ResultEvent<T[]>>(); 

const results: Observable<ResultEvent<T[]>> = 
    form.valueChanges 
    .distinctUntilChanged() 
    .do(() => results.next(ResultEvent.pending())) 
    .switchMap(query => loadResults(query)) 
    .subscribe({ 
     next: (data: T[]) => results.next(ResultEvent.present(data)), 
     error: err => results.next(ResultEvent.failed(err)), 
    }); 

アイデアはresultsは常に検索の現在の状態が含まれていることです。クエリが変更されると、結果はpendingに設定され、サービスがデータを返すと結果はpresentに設定されます。

この解決方法について私が気に入らないのは、subscribe()への明示的な呼び出しです。私はむしろ明示的サブスクリプションを作成せずに、サブスクライブされていない単純なObservableを(例えば、asyncパイプのAngularで)購読することができます。 doの副作用もややハッキリなようです。

const results: Obserbable<ResultEvent<T[]>> = 
    form.valueChanges.distinctUntilChanged() 
    . /* here be dragons */; 

アドバイスやアイデアをお寄せいただきありがとうございます。

答えて

2

私はあなたがこれらの線に沿って何かをしたいと思う:

const results$ = form.valueChanges 
    // This is up to you, but with user input it might make sense to 
    // give it just a little bit of time before we hit the server since 
    // most user input will be more than a single character. 
    //.debounceTime(100) 

    .distinctUntilChanged() 

    // Using switchMap guarantees that the inner observable will be 
    // cancelled if the input changed while we are still waiting for 
    // a result. Newer is always better! 
    .switchMap(query => loadResults(query) 
    // If we get data, we use it. 
    .map(results => ResultEvent.present(results)) 

    // We catch errors and turn them into a failure event. 
    .catch(err => Observable.of(ResultEvent.failed(err))) 

    // Whatever happens, first things first. 
    .startWith(ResultEvent.pending()) 
); 

私も仕方によって、そこにdebounceTimeを追加することを考えるでしょう。

https://rxviz.comにコピーして貼り付けることができます(残念ながら、共有リンク機能はもう機能しません)。時間ウィンドウを10秒に設定してください。

const ResultEvent = { 
    pending:() => 'Pending', 
    failed: err => 'Error: ' + err, 
    present: data => 'Data: ' + data, 
}; 

const loadResults = query => query === 2 
    ? Rx.Observable.of(null).delay(500).switchMap(() => Rx.Observable.throw('Oops')) 
    : Rx.Observable.of(42).delay(500) 

const input$ = Rx.Observable.timer(0, 2000).take(4); 

input$.switchMap(query => loadResults(query) 
    .map(data => ResultEvent.present(data)) 
    .catch(err => Rx.Observable.of(ResultEvent.failed(err))) 
    .startWith(ResultEvent.pending()) 
) 
+0

いいね、ありがとう。この方法でもっときれいに見えます。デバウンスについての良い点は、私は例を単純にすることを意図的にやめました。 –

+0

@PhilippJardas質問に答えた場合は、それを受け入れたものとしてマークしてください。 :-) –

+1

確かです。 :-) –

関連する問題