bsgriggs / mendix-advanced-pagination

Reusable widget to encapsulate the math required to manually do pagination. Most useful when getting data from an API that allows pagination (e.g. https://facebook.com/me/feed?limit=25&offset=50).
MIT License
3 stars 3 forks source link

Advanced Pagination

A reusable widget to encapsulate the math required to manually do server-side pagination. It's useful for the following scenarios:

  1. Getting data from an API (e.g. an OData API - https://facebook.com/feed?$top=2$skip=18).
  2. Building a list view, template grid, or gallery that resembles a data grid with custom search criteria and/or aggregates that change with the search criteria.

Tip: Need sorting too? Check out Advanced Sorting. (GitHub) (Mendix Marketplace)
Need row selection too? Check out Listview Selection. (GitHub) (Mendix Marketplace)

Overview

Features

Limitations

Usage

The following steps will create a list view with server-side pagination that looks like the image below.
demoBrowser

Create the Pagination Module

I usually make a separate, small module for some of the core functionality. This serves 2 purposes:

  1. The module can easily be exported and imported into other projects
  2. The core logic is stored in a common place if you need to make multiple Custom Grids in your app

Follow these steps to make the Pagination Module:

  1. Download the latest version of the Nanoflow Commons module
  2. Right-click on your app name in Studio Pro, click 'Add module ...', and name the module "Pagination"
  3. In the domain model, create a non-persistent entity called Pagination with Page (default to 1), PageSize, and ResultTotal.
    pagination entity
    _Note: The SortAscending and SortAttribute are not used for this example, but you'll need them if you want to use the Advanced Sorting widget. (GitHub) (Mendix Marketplace)_
  4. Create a Nanoflow called ACT_Pagination_Refresh with a Pagination parameter. Add a refresh object activity from the Nanoflow Commons module.
    ACT Pagination_Refresh
  5. Create a Nanoflow called ACT_Pagination_Search with a Pagination parameter. Add a change object activity and set the Page attribute to 1. Then call the ACT_Pagination_Refresh Nanoflow.
    ACT Pagination_Refresh
  6. Create a module role called User and grant that module role full access to the Pagination entity and the Microflows from steps 3 and 4.
  7. In your project security settings, grant all user roles the Pagination module's User user role.

_What are the two Nanoflows for? ~ ACT_Pagination_Refresh should be used when you just want to refresh the results (e.g. changing pages or sorting). ACT_PaginationSearch should be used when the user may have changed the search criteria (e.g. on-change action for a text box or a search button)

Main Domain Model

Inside the domain model of the entity you need to retrieve, create a non-persistent entity specific to your grid. I usually put this right next to the entity it retrieves in the domain model

Page and Widget Setup

  1. Create a Microflow called DS_Search{Entity} that retrieves the list from $currentSession for an existing Search{Entity} object. If the list is not empty, head the list and return the object. Otherwise, create a new object with the association to System.Session as $currentSession and PageSize as whatever default page size you want.
    DS_SearchEmployees
  2. Wrap your list view with a data view that calls DS_Search{Entity}. Add input widgets for your search criteria and the Advanced Pagination widget where you would like the buttons.
    page_mendix
  3. In the Advanced Pagination widget(s), set the Page, Result Count, Page Size, and the refresh action as the following:
    required configuration
  4. In your listview's data source Microflow, you can calculate the Offset and Amount/Limit using the Pagination object. In my example, I'm using a custom retrieve from database action, but you could use the same expressions for your retrieve or API call.
    calcLimitOffset
  5. Also in your listview's data source Microflow, set the Pagination's ResultTotal attribute as the total count of objects.
    a. For standard database retrieves, it should be from a second database retrieve that has range set to all. Directly after the second retrieve, add an Aggregate List action set to Count.
    calcResultTotal
    b. For API Calls, you will need to get this number from the API itself. ResultTotal should be the total number of records that match the search criteria without the limit or offset.
  6. Run the project and see how the widget looks.

Auto Correct

required configuration
When enabled, the widget will update the page number if it is outside the range of valid pages. It can set the page to either the first or last page.

This is helpful when the user to looking at data that is changing. For example, think of a page listing Orders in the open status. User1 is looking at the last page while User2 is changing the status of the Orders to closed. User1's current page would become invalid on a refresh if too many Orders changed status (i.e. Page 4 of 3).

By default, this setting is enabled and set to the first page. You should only have 1 advanced pagination widget per page with this setting enabled to avoid extra refreshes.

Customization Settings

See the documentation here to learn how each setting in the Customization, Text, and Buttons tabs changes the widget.

Demo project

https://widgettesting105-sandbox.mxapps.io/p/advanced-listview-controls

Issues, suggestions, and feature requests

Got any ideas for different styles of pagination? Submit an issue below!
https://github.com/bsgriggs/mendix-advanced-pagination/issues

Development and contribution

Benjamin Griggs