Angular Search & Pagination

with usage examples

In a real world application its really common to work with big amounts of data and to present the user with the possibility to search through it and present it paginated. Therefore, in this article, I’ll show one approach on how to create a search component that handles search inputs with debounce and a pagination component which will handle requesting different pages of data; both working together.

Search Component

Let’s start with our Search Component. Our goal here is to provide an input to the user so he can type a search string to filter the results on a big collection. However, we must notice that by using direct property binding we do not get a period of time between each character the user has typed (debounce time).

Most times that is an issue, since we might be doing requests to the server based on the provided input and you want to wait for the user to have finished typing; both for not doing many unnecessary requests but also to provide a better usability.

We can solve this problem quite simply through rxjs. Firstly, we need to create in our component a Subject of type string. This is what we are going to use to subscribe to changes on the inputted value and handle our debounce.

“Every Subject is an Observable and an Observer. You can subscribe to a Subject, and you can call next to feed values as well as error and complete.”

private _searchSubject: Subject<string> = new Subject();

Also, we are going to add to our component an Output that will emit an event with the inputted value after the debounce. Like that, it will be possible to make whichever request we need (or handle filter logic if the pagination is done in the frontend) bounded to that provided search string after the user has finished typing.

@Output() setValue: EventEmitter<string> = new EventEmitter();

Then, we need to create the subscription itself. We’ll do it using the pipe() function from rxjs.

“ You can use pipes to link operators together. Pipes let you combine multiple functions into a single function. The pipe() function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence.”

constructor() {

this._setSearchSubscription();

} private _setSearchSubscription() {

this._searchSubject.pipe(

debounceTime(500)

).subscribe((searchValue: string) => {

// Filter Function

});

}

We’ve also used debounceTime, an operator provided by the rxjs library; which receives a input of how many milliseconds it should wait before triggering the subscription. Here we are using 500ms, which I believe is a pretty decent period to wait “between key presses”.

Angular Docs has a nice simple page talking about the rxjs library, which you can check on the following link: https://angular.io/guide/rx-library

Explaining in-depth about RxJS is not the purpose of this article, but you can find out more in their documentation: https://rxjs-dev.firebaseapp.com/api

Then, we need to create the method we are going to bind to the HTML input, which is going to trigger our Subject when the user types on the search bar (the html input element).

public updateSearch(searchTextValue: string) {

this._searchSubject.next( searchTextValue );

}

And let’s not forget to unsubscribe it on onDestroy to avoid memory leaks; as I’ve previously written in Understanding Angular Life Cycle Hooks.

ngOnDestroy() {

this._searchSubject.unsubscribe();

}

Finally, we need our template markup, which in this example is going to be quite simple; but of course in a real application one would customize and style it accordingly. In order to bind with the updateSearch method, we are going to use the keyup method.

<input

type="text"

(keyup)="updateSearch($event.target.value)"

/>

Final Code

So, putting all of our pieces together, this would be the final code for a search input component with a debounce strategy implemented. When used, this component provides an input that will trigger an event indicating the the user has finished typing so we can add any logic we need to it.