Reputation: 1085
I'm still learning RxJS. For a project of mine I wanted to implement this "save only once" functionality.
The code snippet from a video about RxJs is the following:
const clickToSave$ = saveClick$.pipe(
exhaustMap(() => http.post(saveURL, data) )
)
I have the following rewritten code in which I tried to implement a code snippet into my existing codebase.
const saveClick$ = new Observable();
// TODO: error handling
const clickToSave$ = saveClick$.pipe( exhaustMap(() => this.http.post(this.xmlendpointPdf, jsonType, this.httpOptions) )
).subscribe(
result => {
const docUrl = 'test';
console.log(docUrl); },
error => {
if (error['status'] === 0) {
this.openAlertDialog('Unknown error');
} else {
this.openAlertDialog('The following error has appeared:' + error['statusText']);
}
console.log('There was an error: ', error);
});
}
...but it apparently doesn't work. How am I supposed to bind to a (click)= ....
event in button's HTML like that?
To recap, what I want is that you can theoretically click on the button as much as you want but it will do the action (which is http.post
call in this case) only once for a time period so when the user spams the button with clicks. How can I successfully implement this code snippet for my own specific use case (which I imagine a lot of people in the future will look for too).
Upvotes: 0
Views: 193
Reputation: 121
Feel free to ask questions if you need more explanation!
Template
<button (click)="bntClicked($event)">Save Button</button>
<br />
<button #btn>Save Button 2</button>
Code
export class AppComponent implements OnInit {
//Solution 1 - Not a big fan of this one personally but it does work
//Manually make sure a subscription finishes before allowing a new one
activeSubscription: Subscription;
bntClicked($event) {
if (!this.activeSubscription) {
this.activeSubscription = this.saveMock().subscribe({
next: result => {
console.log(result);
this.resetSubscription();
}
});
}
}
resetSubscription() {
this.activeSubscription.unsubscribe();
this.activeSubscription = undefined;
}
//End solution 1;
//Solution 2 - I prefer this one
//We get a reference to the button using ViewChild
@ViewChild("btn", { static: true }) button: ElementRef;
ngOnInit(): void {
//Option 1
fromEvent(this.button.nativeElement, "click")
.pipe(
//Cancel previous observable and subscribe to new/last one
switchMap($event => this.saveMock())
)
.subscribe({
next: result => console.log("switchMap", result)
});
//Option 2
fromEvent(this.button.nativeElement, "click")
.pipe(
debounceTime(1000),
mergeMap($event => this.saveMock())
)
.subscribe({
next: result => console.log("debounceTime", result)
});
}
//End solution 2;
saveMock(): Observable<any> {
return of({ description: "Hello World!" }).pipe(delay(1000));
}
}
Resources
Upvotes: 1