Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debouncing HTTP requests in Angular

Tags:

angular

I've built a loading spinner component in Angular 2 that I'd like to trigger before http requests are made and disable when they're done. The problem is that each time the user changes an input (checks of of a box, types into the input box), the http request fires. This means a lot of requests, and the overlay is coming up constantly. I'd like to wait a set period of time (half a second?) after an input is triggered before triggering the http request, giving the user time to put in other inputs. I've read up a bit on debounce, but as far as I can see, that's for time waiting before making another request? And as far as I can see, that's just a buffer time between requests.

Basically, right now, I have a component that handles my inputs. When an input is changed (checkboxes right now), the following code is triggered:

@Output() filtersChanged = new EventEmitter();
emitFilters(): void {
    this.filtersChanged.emit(this.filters);
}

Which through an intermediary step, sets off my http request:

getEvents(filters): Observable<Event[]> {
    this.loadingSpinnerService.showLoadingSpinner();
    let params: URLSearchParams = new URLSearchParams();
    params.set('types', filters.types.join(','));
    params.set('dates', filters.dates.join(','));
    return this.http
        .get('//api.dexcon.local/getEvents.php', { search: params })
        .map((response: Response) => {
            return response.json().events;
        });
}

In Angular 1, I would have put it in a timeout which refreshed each time a user affected an input, so it'd trigger a set time after the final input was touched. Is this the best way to do it in Angular 2 as well? From my reading, debounce locks out a request from happening too close to a second request, but I'm wondering how to best prevent a request from happening after an action is taken for a given period of time.

like image 549
Rohit Avatar asked Feb 04 '17 15:02

Rohit


1 Answers

The easiest way to accomplish what you're after is to set up a Subject (I'm assuming you have access to Rxjs here). Initialize one in your component:

inputSubject: Subject<string> = new Subject<string>();

Since a Subject is both an observer and an observable, you're going to want to set up a subscription to listen for changes. Here's where you can apply your debounce.

this.subscription = this.inputSubject.asObservable()
    .debounceTime(1000)
    .subscribe(x => this.filtersChanged.emit(this.filters));

Now, in your emitFilters() function instead of directly emitting, push the value onto the Subject.

this.inputSubject.next(newValue);

Don't forget to store your subscription as a member of your component class and dispose of it properly in your OnDestroy().

ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
}
like image 113
Jesse Carter Avatar answered Oct 02 '22 20:10

Jesse Carter