Подтвердить что ты не робот

Как получить службу debounce при событии ввода keyup в angular2 с помощью rxjs

Я пытаюсь вызвать службу при вводе событий ввода.

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

На вкладке "Сеть" браузера было обнаружено, что он вызывает функцию "key-up" в каждом событии с ключом (как это и предполагалось), но то, что я пытаюсь достичь, - это время отладки 1сек между каждым сервисным вызовом. Кроме того, событие срабатывает, если я перемещаю стрелку.

ссылка plunkr

4b9b3361

Ответ 1

Таким образом, цепочка действительно правильная, но проблема в том, что вы создаете 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: обновлено для RxJS 6

Ответ 2

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

Ответ 4

Ну, вот базовый дебютант.

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 ) },
            () => {} );
    }
}

Если вы настроите два указанных дочерних представления (ввод и отображение), вы увидите, что работа над debounce. Не уверен, что это не делает ничего, что вы делаете, но эта базовая форма (насколько мне известно) является простым способом отладки, я использую эту начальную точку совсем немного, набор внутреннего текста - это всего лишь образец, он может сделать служебный вызов или что-то еще, что вам нужно для этого.