web-dev-qa-db-ja.com

rxjsでangular2の入力キーアップイベントでデバウンスサービスを達成する方法

入力キーアップイベントでサービスを呼び出そうとしています。

HTML

_<input placeholder="enter name" (keyup)='onKeyUp($event)'>
_

以下はonKeyUp()関数です

_onKeyUp(event) {
    let observable = Observable.fromEvent(event.target, 'keyup')
        .map(value => event.target.value)
        .debounceTime(1000)
        .distinctUntilChanged()
        .flatMap((search) => {
            // call the service
        });
    observable.subscribe((data) => {
        // data
    });
}
_

ブラウザのネットワークタブから、すべてのキーアップイベントでキーアップ機能を呼び出していることがわかりました(想定どおり)が、私が達成しようとしているのは、各間の1秒のデバウンス時間ですサービスコール。また、矢印キーを動かすとイベントがトリガーされます。

plunkrリンク

28
varun

チェーンは本当に正しいのですが、問題はObservableを作成し、keyupイベントごとにサブスクライブすることです。それが同じ値を複数回印刷する理由です。単に複数のサブスクリプションがありますが、これはあなたがやりたいことではありません。

明らかにそれを正しく行うためのより多くの方法があります。例えば:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="text" (keyup)='keyUp.next($event)'>
    </div>
  `,
})
export class App implements OnDestroy {

  public keyUp = new Subject<KeyboardEvent>();

  private subscription: Subscription;

  constructor() {
    this.subscription = this.keyUp.pipe(
      map(event => event.target.value),
      debounceTime(1000),
      distinctUntilChanged(),
      mergeMap(search => of(search).pipe(
        delay(500),
      )),
    ).subscribe(console.log);
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

更新されたデモを参照してください: http://plnkr.co/edit/mAMlgycTcvrYf7509DOP

2019年1月:RxJS 6用に更新

53
martin

@marlinは素晴らしい解決策を与えており、angular 2.xでうまく動作しますが、angular 6ではrxjs 6.0バージョンを使用し始めており、わずかに異なる構文なので、ここに更新されたソリューションがあります。

import {Component} from '@angular/core';
import {Observable, of, Subject} from 'rxjs';
import {debounceTime, delay, distinctUntilChanged, flatMap, map, tap} from 'rxjs/operators';

@Component({
    selector: 'my-app',
    template: `
        <div>
            <input type="text" (keyup)='keyUp.next($event)'>
        </div>
     `,
})
export class AppComponent {
    name: string;

    public keyUp = new Subject<string>();

    constructor() {
        const subscription = this.keyUp.pipe(
            map(event => event.target.value),
            debounceTime(1000),
            distinctUntilChanged(),
            flatMap(search => of(search).pipe(delay(500)))
        ).subscribe(console.log);
    }
}

Angular2チュー​​トリアルを確認することをお勧めします。このチュートリアルでは、あなたが求めているものに似た、わかりやすく説明された例を示しています。

https://angular.io/docs/ts/latest/tutorial/toh-pt6.html#!#observables

2
Simon Dufour

さて、ここに基本的なデバウンサーがあります。

ngOnInit ( ) {
        let inputBox = this.myInput.nativeElement;
        let displayDiv = this.myDisplay.nativeElement;

        let source = Rx.Observable.fromEvent ( inputBox, 'keyup' )
            .map ( ( x ) => { return x.currentTarget.value; } )
            .debounce ( ( x ) => { return Rx.Observable.timer ( 1000 ); } );

        source.subscribe (
            ( x ) => { displayDiv.innerText = x; },
            ( err ) => { console.error ( 'Error: %s', err ) },
            () => {} );
    }
}

示された2つのビューの子(入力とディスプレイ)を設定すると、デバウンスが機能することがわかります。これがあなたのすることを何もしないかどうかはわかりませんが、この基本的な形式は(私が知る限り)デバウンスするための簡単な方法です、私はこの出発点をかなり使用しますサービスコールなど、必要なことを行うことができます。

0
Tim Consolazio