rxjs使おうとすると毎度ドキュメント見ながら使えそうなオペレータ調べてやるのがつらいですね
後の自分用のメモにサンプル実装を残します
今回は「検索ボックスなどの入力で必要な部分だけ取り出す」です
- 実行環境
angular: 5.1.2 rxjs: 5.5.6
やりたいこと
インクリメンタルサーチで検索かけてくれるボックスなど文字列が変わるたび(keyup)にイベントが発生する場合
keyupイベントでinputに入力された値を取ると下記のような感じになります
h ho hog hoge #この部分だけ取ってきたい
最後の部分だけを取ってきたいというのが今回の内容となります
途中経過ではなく検索対象としての文言のみ取得したいって感じですね
まずそれぞれ使うオペレータを見ていきます
interval
一定間隔でストリームに値を流すやつですね
Observable | RxJS API Document
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-intervalreactivex.io
withLatestFrom
二つのストリームの一番最新のものを取ってくる感じですね
Observable | RxJS API Document
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-withLatestFromreactivex.io
pairwise
ひとつ前の値とセットにして次のストリームへ流すやつですね
Observable | RxJS API Document
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwisereactivex.io
filter
フィルターです、これは特に説明はいらないですね
Observable | RxJS API Document
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-filterreactivex.io
distinctUntilChanged
流れてくるストリームに対してdistinctをかけるやつですね
オブジェクトのデータが渡ってくる場合はcallbackに何を同一と判断するかの式を渡してあげる必要があります
Observable | RxJS API Document
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-distinctUntilChangedreactivex.io
検索機能などで入力された文字列を取得する
ここまで見てきたオペレータを使ってサンプルを実装してみます
入力が完了したという条件を仮に「5秒以上inputに変化がない」とすると
まず下記二つのストリームを用意します
- 5秒ごとに値を流すストリーム
- keyupイベントを流すストリーム
5秒ごとに値を流しwithlatestfrom
でkeyupストリームの最後の値を取得してきます
さらにストリームの前後のデータが欲しいのでpairwise
で前後のデータをくっつけてストリームに流します
filter
でkeyupイベントのデータに変化が無い(5秒)状態になったものだけをフィルタします
この場合だとintervalが5秒に設定しているため入力が落ち着いたあともずっと値が流れてしまうが欲しくない
最後にdistinctUntilChanged
で変化がないけど5秒毎に流れてくる同じ値をカットします
コードにするとこんな感じ
- component.ts
export interface IInputText { value: string; } @Component({ selector: 'app-rxjs', templateUrl: './rxjs.component.html', styleUrls: ['./rxjs.component.scss'] }) export class RxjsComponent implements OnInit { private inputTexts$: Subject<IInputText>; private interval$: Observable<any>; constructor( ) { } ngOnInit(){ this.inputTexts$ = new Subject<IInputText>(); this.interval$ = interval(5000); this.interval$.pipe( withLatestFrom(this.inputTexts$), pairwise(), filter(this.silinceValue), distinctUntilChanged(this.distinct) ).subscribe(p => { console.log(p); }); } silinceValue(v){ // 入力が落ち着いたかどうかをチェック // このフィルタを通る = 入力がintervalの分だけないということ return v[0][1].value == v[1][1].value; } // 落ち着いてからずっと同じものが流れないようにする distinct(a, b) { return a[1][1].value === b[1][1].value; } onInputEvent(e) { this.inputTexts$.next({value: e.target.value}); }
- component.html
div> <h5>入力されたテキストを(入力途中の値を除く)何とかして取り出す</h5> <input (keyup)="onInputEvent($event)"> </div>
書いててめっちゃわかりずらい。。。。
整形とかしてないのでいろいろ微妙な部分もありますが目的の動作は達成できました。
図にするとこんな感じの流れですね
まとめ
なんとなくわかるしドキュメント見ながら使えるようにはなってきたけどやっぱり難しいです
感覚的にはパズルみたいでオペレータを調べて組み合わせて目的の挙動にできるとおぉぉぉ!!!!ってなりますねw
もっとたくさんケースをこなして魔術師になりたいものです