When your application has hundreds of records, fetching and displaying all of them at once is slow. The solution is Pagination—breaking the data into smaller, numbered pages. In this tutorial, we will add “Next” and “Previous” buttons to our blog post list and display the current page information.
Prerequisites
You must have a page that displays a list of posts from your database. For this tutorial to be effective, make sure you have at least 10-15 sample posts in yourPosts
table.
Part 1: Set Up the State for Pagination
We need new state variables to keep track of our pagination status.- Navigate to your post list page.
- Select the
Body
and go to the States tab. - Add or update the following state variables:
postList
(Data Type:Posts
Data Table, Is List?:true
)isLoading
(Data Type:Boolean
, Default Value:true
)currentPage
(Data Type:Number
, Default Value:1
)itemsPerPage
(Data Type:Number
, Default Value:5
)totalPosts
(Data Type:Number
, Default Value:0
)
Part 2: Build the ‘On Page Load’ Workflow
This workflow will run when the page first loads, fetching the initial page of data and the total number of posts.1
1. Fetch the First Page of Posts
- Open the “On Page Load” workflow from the Logic tab.
- Add a “Set data in state” action.
- Target State:
postList
. - New Value: In the expression editor, select “Get data from DB”.
- Table:
Posts
. - Limit: Bind this to your
itemsPerPage
state. - Offset: Build the expression
(currentPage - 1) * itemsPerPage
. This will correctly be0
on the first page load.
- Table:
2
2. Get the Total Number of Posts
- Add a second “Set data in state” action.
- Target State:
totalPosts
. - New Value: We will fetch the entire list and then get its
length.
- In the expression editor, select “Get data from DB”.
- Table:
Posts
. Do not set a Limit or Offset. - After the “Get data from DB” node, add an Operation and choose the
length
operation.
3
3. Update the Loading State
- Add a third “Set data in state” action at the very end.
- Target State:
isLoading
. - New Value: Set it to
false
.
Part 3: Build the Pagination Buttons (The Basic Way)
Now, let’s create the buttons to change pages.- Add the Buttons: On your page, add two Buttons: “Previous” and “Next”.
- “Next” Button Workflow:
- Create an “On Click” workflow.
- Action 1:
Set data in state
to updatecurrentPage
tocurrentPage + 1
. - Action 2:
Set data in state
to updatepostList
. You must copy and paste the entire data fetch expression from Part 2 here.
- “Previous” Button Workflow:
- Do the same, but set
currentPage
tocurrentPage - 1
, followed by the same copied data fetch expression.
- Do the same, but set
This works, but notice the repetition? You’ve used the exact same data fetch
logic in three different places (On Page Load, Next Button, Previous Button).
If you need to change how you fetch data, you’ll have to update it in all
three places. Let’s fix this with a Function.
Part 4: Refactor with a Reusable Function (The Better Way)
Instead of putting our data-fetching logic directly on the page, we will create a self-contained “recipe” for it.1
1. Create a New Function
- Go to Data → Functions.
- Create a new Client-side Function named
fetchPosts
.
2
2. Define the Function's Props (Its Inputs)
Our function needs to know which page to fetch and how many items to get per page. Add two Props:
pageToFetch
(Data Type:Number
)limit
(Data Type:Number
)
3
3. Build the Function's Workflow
The function’s job is to fetch the data and then return it.
- In the workflow editor for your
fetchPosts
function, add the “Return function result” action. This must be the only action. - In the
value
field of this action, build your data-fetching expression:- Select “Get data from DB”.
- Table:
Posts
. - Limit: Bind this to the
limit
Prop. - Offset: Build the expression
(pageToFetch - 1) * limit
. Crucially, use thepageToFetch
andlimit
Props from the function itself.
This function is now a perfect “black box”. It accepts two inputs (
pageToFetch
and limit
) and returns a list of posts. It has no knowledge of the page it’s being called from.1
1. Update the 'On Page Load' Workflow
- Open the “On Page Load” workflow for your post list page.
- Action 1: Trigger the Function to Fetch Posts
- Add the “Trigger Function” action.
- Function:
fetchPosts
. - Props:
pageToFetch
: Pass thecurrentPage
state (which is1
).limit
: Pass theitemsPerPage
state.
- Result: In the
Result
tab of the action, save the returned list of posts into yourpostList
state variable.
- Action 2: Get the Total Count
- Add a
Set data in state
action to set thetotalPosts
state by fetching all posts and applying alength
operation.
- Add a
- Action 3: Update Loading State
- Add a
Set data in state
action to setisLoading
tofalse
.
- Add a
2
2. Build the 'Next' Button Workflow
- Select the “Next” button and create an “On Click” workflow.
- Action 1: Increment the Page Number
- Add a
Set data in state
action to updatecurrentPage
tocurrentPage + 1
.
- Add a
- Action 2: Trigger the Function Again
- Add a “Trigger Function” action.
- Function:
fetchPosts
. - Props: Pass the
currentPage
anditemsPerPage
states. This will use the newly updated page number. - Result: Save the returned value into the
postList
state. This will update the UI.
3
3. Build the 'Previous' Button Workflow
- Create the workflow for the “Previous” button. It will be the same as the “Next” button, but you will decrement the
currentPage
state in the first action.
Part 4: Add Conditional Logic for a Professional UI
Finally, let’s disable the buttons when they can’t be used and show the user where they are.- Disable the “Previous” Button:
- Select the “Previous” button. In its Properties Panel, bind the
Disabled
property to the expression:currentPage <= 1
.
- Select the “Previous” button. In its Properties Panel, bind the
- Disable the “Next” Button:
- Select the “Next” button. Bind its
Disabled
property to the expression:currentPage * itemsPerPage >= totalPosts
.
- Select the “Next” button. Bind its
- Display Page Info:
- Add a Text element and bind its content to a dynamic expression to show something like:
Page [currentPage] of [ceil(totalPosts / itemsPerPage)]
.
- Add a Text element and bind its content to a dynamic expression to show something like: