角度点击反跳

时间:2018-11-15 12:32:12

标签: angular typescript rxjs debounce

在我的模板中,我有一个字段和两个按钮:

<div class="btn-plus" (click)="add(1)"> - </div>
<div class="txt"> {{ myValue }} </div>
<div class="btn-minus" (click)="add(-1)"> + </div>

在我的.ts组件文件中,我有:

add(num) {
    this.myValue +=num;
    this.update(); // async function which will send PUT request
}

this.update()函数将myValue放入大JSON对象中的适当字段,并将其发送到服务器。

问题:当用户在短时间内单击按钮正负10次后,请求将被发送10次。但我只想发送一次请求-最终点击后0.5秒。 如何做到

3 个答案:

答案 0 :(得分:3)

使用takeUntil运算符:

export class AppComponent  {
  name = 'Angular';

  calls = new Subject();

  service = {
    getData: () => of({ id: 1 }).pipe(delay(500)),
  };

  click() {
    this.calls.next(true);
    this.service.getData().pipe(
      takeUntil(this.calls),
    ).subscribe(res => console.log(res));
  }
}

Stackblitz(打开控制台以查看日志)

答案 1 :(得分:1)

这是我在互联网上找到的部分答案,但我愿意寻求更好的解决方案(或改进为低于解决方案(指令)):

在互联网上,我发现了appDebounceClick指令,该指令可以通过以下方式为我提供帮助:

我从.ts文件的update中删除了add

add(num) {
    this.myValue +=num;
}

并通过以下方式更改模板:

<div 
    appDebounceClick 
    (debounceClick)="update()" 
    (click)="add(1)" 
    class="btn-plus"
    > - 
</div>
<div class="txt"> {{ myValue }} </div>
<!-- similar for btn-minus -->

奖金

Cory Rylan编写的指令appDebounceClick(我在此处放置了代码,以防万一将来链接会停止工作):

import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { debounceTime } from 'rxjs/operators';

@Directive({
  selector: '[appDebounceClick]'
})
export class DebounceClickDirective implements OnInit, OnDestroy {
  @Input() debounceTime = 500;
  @Output() debounceClick = new EventEmitter();
  private clicks = new Subject();
  private subscription: Subscription;

  constructor() { }

  ngOnInit() {
    this.subscription = this.clicks.pipe(
      debounceTime(this.debounceTime)
    ).subscribe(e => this.debounceClick.emit(e));
  }

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

  @HostListener('click', ['$event'])
  clickEvent(event) {
    event.preventDefault();
    event.stopPropagation();
    this.clicks.next(event);
  }
}

答案 2 :(得分:1)

辅助功能-

export const debounced = (cb, time) => {
  const db = new Subject();
  const sub = db.pipe(debounceTime(time)).subscribe(cb);
  const func = v => db.next(v);

  func.unsubscribe = () => sub.unsubscribe();

  return func;
};

那么一个示例用法可能是:

import { Component, OnInit } from '@angular/core';
import { debounced } from 'src/helpers';

@Component({
  selector: 'app-example',
  // Click calls `debouncedClick` instead of `myClick` directly
  template: '<button (click)="debouncedClick($event)">Click This</button>'
})
export class Example implements OnDestroy {
  debouncedClick; // Subject.next function

  constructor() {
    // Done in constructor or ngOnInit for `this` to resolve
    this.debouncedClick = debounced($event => this.myClick($event), 800);
  }

  // Called after debounced resolves (800ms from last call)
  myClick($event) {
    console.log($event);
  }

  ngOnDestroy() {
    // Stay clean!
    this.debouncedFunc.unsubscribe();
  }
}

还可以颠倒用法,在点击时调用“ myClick”,并使debounced回调执行所需的操作。经销商的选择。

我个人也参加(keyup)事件。

不确定退订是否确实必要-比研究内存泄漏更快地实现:)