web-dev-qa-db-ja.com

Angularでダブルクリックを防ぐ方法は?

clickのコンポーネントがあります。

<my-box (click)="openModal()"></my-box>

この要素をクリックすると、openModal関数が実行されます。そして、複数のモーダルを開くのを防ぐために、1000msのスロットル時間を与えたいと思います。

私の最初のアプローチはSubjectを使用することでした(rxJsから)

//html
<my-box (click)="someSubject$.next()"></my-box>
//ts
public someSubject$:Subject<any> = new Subject();
...etc subscribe

しかし、それは少し冗長だと感じています。

次のアプローチではdirectiveを使用していました。グーグルで見つけたコードを少し修正しました。

//ts
import {Directive, HostListener} from '@angular/core';

@Directive({
    selector: '[noDoubleClick]'
})
export class PreventDoubleClickDirective {

    constructor() {
    }

    @HostListener('click', ['$event'])
    clickEvent(event) {
        event.stopPropagation();    // not working as I expected.
        event.preventDefault();     // not working as I expected.

        event.srcElement.setAttribute('disabled', true);    // it won't be working unless the element is input.
        event.srcElement.setAttribute('style', 'pointer-events: none;');   // test if 'pointer-events: none' is working but seems not. 

        setTimeout(function () {
            event.srcElement.removeAttribute('disabled');
        }, 500);
    }
}

//html
<my-box noDoubleClick (click)="openModal()"></my-box>

しかし、私が何をしようとも、常にopenModalが実行されました。ディレクティブでopenModalの実行を停止する方法が見つかりませんでした。

私はちょうど作ることができます

//ts
//In the openModal method.
openModal() {
    public isClickable = true

    setTimeout(() => {
        this.newsClickable = true;
    }, 1000);
    ...
}

しかし、再利用可能なコードについては、ディレクティブの使用が理想的だと思います。

どうすれば作成できますか?

8
Téwa

RxJの debounce または debounceTime 演算子を使用して、ダブルクリックを防ぐことができます。 ここ は、カスタムのデバウンスクリックディレクティブを作成する方法に関する投稿でもあります。

投稿が将来削除される場合の最終的なコードは次のとおりです。

指令:

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

使用例:

<button appDebounceClick (debounceClick)="log()" [debounceTime]="700">Debounced Click</button>
21
Sam Herrmann

私の場合、デバウンスの代わりにthrottleTimeがより良い解決策でした(イベントをすぐに起動し、時間が経過するまでブロックします)

8
repo

一部の人々はthrottleTimeディレクティブを要求したので、以下に追加します。 debounceTimeがラストクリックを待ってから実際のクリックイベントを発生させるため、このルートを選択しました。 throttleTimeは、その時間になるまでクリッカーがボタンを再度クリックすることを許可せず、代わりにクリックイベントをすぐに発生させます。

指令

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

@Directive({
  selector: '[appPreventDoubleClick]'
})
export class PreventDoubleClickDirective implements OnInit, OnDestroy {
  @Input()
  throttleTime = 500;

  @Output()
  throttledClick = new EventEmitter();

  private clicks = new Subject();
  private subscription: Subscription;

  constructor() { }

  ngOnInit() {
    this.subscription = this.clicks.pipe(
      throttleTime(this.throttleTime)
    ).subscribe(e => this.emitThrottledClick(e));
  }

  emitThrottledClick(e) {
    this.throttledClick.emit(e);
  }

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

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

使用例

throttleTimeはディレクティブにデフォルトの500があるためオプションです

<button appPreventDoubleClick (throttledClick)="log()" [throttleTime]="700">Throttled Click</button>

1msごとに要素をクリックしているボットがある場合、throttleTimeが起動するまでイベントが1回だけ発生することがわかります。

7
Jon La Marr