In this post we’re going to take a look at how to page data in Phoenix with scrivener_ecto.
These days infinite scrolling is a popular way to achieve paging but isn’t always appropriate for every situation. Infinite scrolling works great for a news feed or user posts, but not so much for something like a product list. So we’ll be looking at how we can go about implementing traditional style paging.
What we’ll build
To demonstrate paging we’re going to build a simple list of products.
So let’s get started!
Create the app
We’ll start from scratch with a new Phoenix application and add some simple scaffolding for the purposes of demonstrating paging.
Terminal
Choose Y
when asked to fetch and install dependencies. Now we’ll change into the application directory and create the database.
Terminal
Ok, our basic application is good to go, now let’s add some simple scaffolding.
Adding some scaffolding
Terminal
As per the mix
output, let’s update the routes…
/lib/paging_web/router.ex …line 16
… and run the migrations.
Terminal
And with that our initial application is complete, but we don’t have any data to page. We could enter some data manually; instead let’s use a seed file.
Seeding some data
Phoenix already creates a seeds.exs
file for us when we create a new project, so all we need to do is add the appropriate code.
/priv/repo/seeds.exs
Pretty simple! We only want to create our seed data when running in development so we’ve wrapped our code in Mix.env == :dev
. We then use Enum.map
to create 100 products. We use Widget <index value>
for the name of the product, and a random number between 10 and 200 for the quantity.
Now we can seed our data.
Terminal
Let’s have a quick look at our application prior to adding paging.
Terminal
If you navigate to http://localhost:4000/products you’ll see the products we created.
We’re now ready to move onto adding paging.
Paging
We’ll split the paging implementation into a couple of parts. First we’ll deal with the back-end code and then address the front-end.
Adding paging on the back-end
As mentionned earlier we’ll be using the scrivener_ecto
package to accomplish our paging, so let’s start by adding the package.
/mix.exs …line 34
We’ve added scrivener_ecto
to our mix.exs
file and now need to get our new dependency.
Terminal
We’ll see that both the scrivener
and scrivener_ecto
packages are added.
Next we need to update our Repo
module so that we can make use of the paging functionality. We do this by adding a use Scrivener
statement in repo.ex
. This makes the scrivener_ecto
functions available thru the Repo
module.
/lib/paging/repo.ex
We’ve also set a default page size of 10 via the page_size
option.
To make use of the paging functionality in our products page we will update the list_products
context method. It needs to take in a parameter which we’ll simply call params
; and it also needs to call into the paginate
function instead of the all
function, i.e. Repo.all
becomes Repo.paginate
.
/lib/paging/inventory.ex
Now we need to add a parameter to the controller method as well which we pass thru to the list_products
context method.
/lib/paging_web/controllers/product_controller.ex
And that’s it! Let’s restart the server.
Terminal
And we can test out our paging in the browser; we see by default the page size is 10 items.
By changing the URL we can control both the currently displayed page and the page size via the page
and page_size
parameters. For instance http://localhost:4000/products?page=5&page_size=3 yields:
We probably don’t want to make our users update the URL
manually when they want to switch pages thou! So let’s add some controls in the UI.
Adding paging on the front-end
We’ll take two approaches to adding some UI controls on the front-end. First we’ll take a custom approach and directly add Previous
and Next
buttons. Then we’ll look at a package that provides us with an easy way to create a standard pagination navigation bar.
Adding paging buttons
The first step with either approach is to update our controller method to push the current page
parameter to our template.
/lib/paging_web/controllers/product_controller.ex
Above we’ve renamed the variable returned from list_products
to page
as this is what is being returned, a single page of products. We then assign page.entries
to the products
template variable and pass the page
parameter to the template.
We then need to make some minor changes to the template.
/lib/paging_web/templates/product/index.html.eex
We’ve added two buttons for our paging controls, along with some simple logic to disable the Previous
button when we are on the first page; and the Next
button when we are on the last.
We now have the ability to change our page without having to manually update the URL!
This works pretty good, but let’s have a look at an alternative approach via the scrivener_html package.
Adding paging buttons via the scrivener_html package
Another option for adding UI paging elements is to use the scrivener_html
package.
The first step is to install the package
/mix.exs …line 34
Terminal
With scrivener_html
added to our application, we now need to add a configuration entry for the package.
/config/config.exs …line 25
We’ll add the configuration right after the JSON
configuration. There are a number of view style options availble that correspond to different CSS frameworks. There isn’t one for Milligram (the default CSS framework for Phoenix) so we’ll just stick with the Bootstrap view style.
Next we need to import Scrivener.HTML
in any views in which we want to make use of the package. So we’ll update product_view.ex
.
/lib/paging_web/views/product_view.ex
Now we just need to update our template. We’ll keep our existing paging buttons in the template as a comparison, but you’d obviously want to use a single paging control if building out a real application!
/lib/paging_web/templates/product/index.html.eex
All we need for the pagination links is a single line: <%= pagination_links @page %>
… sweet!
Now with a server restart we’ll see some new paging links show up.
Terminal
The links work, but they are not looking so great! We can add some basic styles to make them look a little better.
/assets/css/app.css
We’ve added some pretty simple styling, you might want to add hover effects and other elements in a real implementation, but at least things are horizontal now and the active page is highlighted.
If using one of the many CSS frameworks scrivener_html
supports you’d get attractive paging links styled as per your chosen framework, i.e. with Bootstrap
installed you’d see.
Fantastic!
Summary
So with the help of the scrivener_ecto
package we can see that paging in Phoenix is a snap! And the scrivener_html
package makes it easy to add paging navigation to our UI, heck, what more could you ask for?
Thanks for reading and I hope you enjoyed the post!