typescript - Angular klick debounce
I min mall har jag ett fält och två knappar:
<div class="btn-plus" (click)="add(1)"> - </div>
<div class="txt"> {{ myValue }} </div>
<div class="btn-minus" (click)="add(-1)"> + </div>
I min komponent .ts-fil har jag:
add(num) {
this.myValue +=num;
this.update(); // async function which will send PUT request
}
Funktionen this.update() placerar myValue i rätt fält i ett stort JSON-objekt och skickar det till en server.
Problem: När en användare klickar 10 gånger på kort tid på knappen plus/minus, skickas då en förfrågan 10 gånger. Men jag vill bara skicka en förfrågan - 0,5 sekunder efter sista klicket. Hur gör man det?
Svar #1
Använd takeUntil-operatorn:
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 (öppna din konsol för att kontrollera loggarna)
Svar #2
Detta är ett svar jag delvis hittade på internet, men jag är öppen för bättre lösningar (eller förbättringar av nedanstående lösning (direktiv)):
På internet hittade jag appDebounceClick-direktivet som hjälper mig på följande sätt:
Jag tar bort update från add i .ts-filen:
add(num) {
this.myValue +=num;
}
Och ändra mallen på följande sätt:
<div
appDebounceClick
(debounceClick)="update()"
(click)="add(1)"
class="btn-plus"
> -
</div>
<div class="txt"> {{ myValue }} </div>
<!-- similar for btn-minus -->
BONUS
Direktiv appDebounceClick skrivet av Cory Rylan (jag satte koden här ifall länken slutar fungera i framtiden):
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);
}
}
