Javascript 如何使用 rxjs 在 angular2 中实现输入 keyup 事件的去抖动服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41935424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:45:17  来源:igfitidea点击:

How to achieve a debounce service on input keyup event in angular2 with rxjs

javascriptangulartypescriptrxjsrxjs5

提问by varun

I am trying to call to a service on input key-up event.

我正在尝试在输入按键事件时调用服务。

The HTML

HTML

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

Below is the onKeyUp()function

下面是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
    });
}

It was found from the network tab of the browser that, it is calling the key-up function on every key-up event(as it is supposed to do), but what I am trying to achieve is a debounce time of 1sec between each service call. Also, the event is triggered if I move the arrow key move.

从浏览器的网络选项卡中发现,它在每个按键事件上调用按键功能(正如它应该做的那样),但我试图实现的是每个按键之间的去抖动时间为 1 秒服务电话。此外,如果我移动箭头键移动,则会触发该事件。

plunkr link

链接

回答by martin

So the chain is really correct but the problem is that you're creating an Observable and subscribe to it on every keyupevent. That's why it prints the same value multiple times. There're simply multiple subscriptions which is not what you want to do.

所以这个链确实是正确的,但问题是你正在创建一个 Observable 并在每个keyup事件上订阅它。这就是为什么它多次打印相同的值。只是有多个订阅,这不是您想要做的。

There're obviously more ways to do it correctly, for example:

显然有更多的方法可以正确地做到这一点,例如:

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

See your updated demo: http://plnkr.co/edit/mAMlgycTcvrYf7509DOP

查看您更新的演示:http: //plnkr.co/edit/mAMlgycTcvrYf7509DOP

Jan 2019: Updated for RxJS 6

2019 年 1 月:针对 RxJS 6 更新

回答by imal hasaranga perera

@marlin has given a great solution and it works fine in angular 2.x but with angular 6 they have started to use rxjs 6.0 version and that has some slight different syntax so here is the updated solution.

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

回答by Tim Consolazio

Well, here's a basic debouncer.

好吧,这是一个基本的去抖动器。

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

If you set up the two indicated view children (the input and the display), you'll see the debounce work. Not sure if this doesn't do anything your does, but this basic form is (as far as I know) the straightforward way to debounce, I use this starting point quite a bit, the set of the inner text is just a sample, it could make a service call or whatever else you need it to do.

如果您设置了两个指示的视图子项(输入和显示),您将看到去抖动工作。不确定这是否对您没有任何作用,但这种基本形式是(据我所知)去抖动的直接方法,我经常使用这个起点,内部文本集只是一个示例,它可以拨打服务电话或其他任何您需要它做的事情。

回答by Simon Dufour

I would suggest that you check the Angular2 Tutorial that show a clean and explained example of something similar to what you're asking.

我建议您查看 Angular2 教程,该教程显示了一个与您所要求的内容类似的干净且解释过的示例。

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

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