How To Paginate Filtered Query Results
In this lesson, we'll learn about AdonisJS Model Query Builder pagination and walk through an example of how we can easily paginate the results of our filtered movies.
- Author
- Tom Gobich
- Published
- May 06
- Duration
- 9m 15s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
How To Paginate Filtered Query Results
-
(upbeat music)
-
So currently on our movies list,
-
we just have our static list of 15.
-
We can't go beyond the initial 15 results that we get back.
-
Well, that's where pagination comes into play.
-
So let's hide our browser back away
-
and let's get that added into our query.
-
So the first thing that we're gonna wanna do
-
is be able to accept in a page for our getFiltered method.
-
So we'll do page and that type will be number.
-
If we don't have a page,
-
we'll just default that to one
-
because we'll always want a value for it.
-
Then we can scroll down and this will replace our limit.
-
The pagination method is available
-
on both the model query builder
-
as well as the database query builder.
-
We just call it via paginate like so.
-
It accepts in the page number that we want,
-
which is our page parameter.
-
And then the number of items that we want per page
-
and we're using 15 for that.
-
This does alter the type that we're returning back
-
from a model query builder
-
to now a model paginator contract of type movie.
-
And if we jump into the documentation,
-
there's a pagination page
-
and we can see that this adds some additional information
-
specifically for paginating our results.
-
Now, what we're taking a look at here
-
is the simple paginator class,
-
but these same properties
-
are also on the model paginator result.
-
And if we scroll down a little bit further,
-
real quick, they do note that you do wanna order your results
-
to keep the results per page consistent,
-
but they also show that you can display a list
-
of pagination links using this paginator as well.
-
So you define the base URL on the results
-
that you get back from the paginate method.
-
And this URL you're going to want to be query stringless.
-
So you don't want query strings to be on it
-
because this will apply the query string for the page to it.
-
Then if we scroll down a little bit further,
-
they'll see that there's another method,
-
get URLs and range,
-
where you pass in the start of the range
-
and the end of the range,
-
and it will give you back an object like so with the URL.
-
And this is that base URL
-
that we defined via the base URL method,
-
and then a query string for the current items page.
-
And then that current items page as an accessible property,
-
whether or not that current item is active
-
and whether or not that current item is a separator.
-
So if we hide that back away,
-
jump out of our browser
-
and give our movie service here a save,
-
jump back into our movies controller.
-
Let's scroll up to our index method here.
-
First and foremost,
-
we need to provide a page into our get filtered.
-
We could add that into our filter validator,
-
but there's instances where we're going to want
-
the filter data without the page on it.
-
So it's just easier to keep these separate as a whole.
-
So we'll do const page equals request,
-
and we'll use the input method to reach specifically
-
for the page on the query string.
-
Our get filtered is going to apply a default to that
-
if there isn't one.
-
So we'll just provide it straight in like so.
-
As for that base URL,
-
we can either add that in as an option
-
to our get filtered call,
-
or we can add that out here within our controller.
-
Since we're not actually awaiting the query within here,
-
but we're returning back the model paginator
-
and not actually executing the query
-
until we await it right here,
-
let's go ahead and apply our base URL
-
out here inside of our control.
-
So we can do movies.baseURL.
-
Let's import our router from a.sjs core services router,
-
hit tab to auto import that,
-
and use a method called makeURL.
-
This method is actually the same one
-
that's provided via route within EdgeJS.
-
So we just need to provide it the route identifier.
-
In our case, that's movies.index.
-
You can also get at that information
-
via the route property off of your HTTP context.
-
It'll be available via route.name.
-
However, a value for that may or may not be provided
-
depending on how you have your route defined,
-
but do note it's available there.
-
Cool.
-
So if we give that a save,
-
let's jump back into our index page
-
and let's get our pagination added.
-
So before our end call there,
-
that ends out our layout,
-
let's do a div class flex items center,
-
and maybe a gap of two.
-
Then we'll want our at each item in movies.getURLsFrom.
-
Range, specify one as the start
-
and movies.lastPage as the end.
-
We'll go ahead and end our each there as well,
-
and just do a quick anchor, href item.url,
-
and then item.page to list out the actual page
-
for the URL there.
-
We'll do class with four, h4, flex items center,
-
justify center, border, and border,
-
slate maybe 200, and make that rounded as well.
-
Okay, give that a save.
-
Let's jump back into our browser,
-
and whoop, let's get URLs for range.
-
My bad, for range right there.
-
Jump back into our browser now,
-
give that a refresh.
-
There we go, okay.
-
So let's scroll down and see what we have for pagination.
-
All right, forgot to add a padding to those,
-
but we do see one, two, three, four,
-
all the way up through our last page of 28.
-
So if we were to click on 28 here,
-
note that we're sorting by default by title ascending,
-
so we just jumped down to the end of our alphabetical list.
-
Cool, if we jumped somewhere in the middle,
-
we'll be somewhere in the middle of our alphabetical list,
-
and then if we jump back to one,
-
we'll be at the start of our alphabetical list.
-
All right, so that seems to be working A-okay.
-
Ideally though, we don't wanna show all 28 pages
-
that we have available,
-
because at some point that's gonna start wrapping.
-
So let's hide our browser back away,
-
and let's define what our range actually is.
-
So let's move this out into our controller.
-
So let's give that a cut, jump up to our controller,
-
and after we've added in that base URL,
-
let's do const, and we'll just call this our pagination,
-
equals, and we'll paste that in.
-
Then we'll also filter it down
-
to just the items that we care about.
-
So let's filter item, just like so.
-
So there's a ton of different ways
-
that we can go about discerning what items
-
we want to include within our pagination.
-
I think the most straightforward approach
-
for us here today to keep us on time
-
is to go minus three and plus three from the current index,
-
and then just remove out those
-
that aren't applicable to our range.
-
So do const range min equals movies dot,
-
and there is a current page option that we have available
-
to get the current pagination page,
-
and we could do minus three there,
-
and then const range max equals
-
movies dot current page plus three.
-
So from our filter, we can return,
-
if item dot page is greater than or equal to our range min,
-
and item dot page is less than or equal to our range max,
-
then we'll go ahead and use the range item.
-
It would also be great to go ahead
-
and just keep one and 28 inside of that range as well.
-
So we'll do if item dot page equals one,
-
or item dot page equals our movies dot last page,
-
then we'll just go ahead and return true
-
to always include those.
-
Give it a save to fix our formatting,
-
and let's go ahead and apply our pagination
-
into our page state.
-
So pagination there, give it a save,
-
jump back into our page,
-
and now let's loop over our pagination items.
-
Give that a save.
-
While we're here, maybe we'll switch this to eight
-
because that looked pretty tight,
-
and let's add a padding of two, and give that a save.
-
All right, let's jump back into our browser.
-
Let's see what we got.
-
So we got one, two, three, four, and 28.
-
So since we're currently on page one, we see one.
-
We've removed one minus three
-
because that's out of our range,
-
but we do have one plus three up to four,
-
and then we've auto-included 28.
-
If we jump to four, scroll down,
-
then we start to see our current page of four minus three,
-
which takes us back to one, as well as plus three
-
plus our last page there as well.
-
Then if we jump to 28,
-
we should see the opposite of what we saw with one.
-
We can go minus three,
-
but we don't go plus three out of our range.
-
And keeping one and 28 there allows us
-
to always be able to jump to the front
-
and the back of the pack.
-
Okay, so one thing that we do need to take care of is,
-
let's say we're filtering our list down
-
to just those that contain T in the title.
-
All right, so within our pagination list,
-
that takes us down from 28, I think we were at,
-
down to just 20 pages.
-
And we have some query strings here applied for our filters.
-
So if we take a look at what we have down here
-
in the bottom left-hand corner,
-
you can see it's just going to reapply with page.
-
So it's gonna get rid of our filter
-
if we then click on the pagination.
-
What we want is for this to maintain our filters.
-
So let's hide our browser back away
-
and jump into our movies controller.
-
And essentially what we wanna do is take our filters
-
and convert that into a query string.
-
So for that, we can use a Node.js module
-
called query string.
-
So let's import query string from node query string.
-
Let's jump down here.
-
We could do const qs equals query string dot,
-
and there's a stringify method that we can use,
-
pass our filters into it,
-
and it will provide us back a query string safe version
-
of our filters.
-
Again, we don't want to apply that here to the base URL
-
because the base URL needs a path
-
without a query string in it
-
because it will add the query string to it.
-
So let's switch our pagination here to a let
-
and do an if we have a query string
-
because we don't need to apply any of this
-
if we don't have a query string
-
to append onto our pagination items.
Join The Discussion! (1 Comments)
Please sign in or sign up for free to join in on the dicussion.
tomgobich
Hey all! Somehow, I completely missed that there's a
queryString
method available on the paginator that allows us to define additional query string key/values. We'll patch this in down the road, but wanted to make a note here that it is available!Please sign in or sign up for free to reply