Gridx in XPages – 9: More Sorting Features

In the last two posts, we looked at implementing column sorting on remote and local data stores. In this post, we’ll look at more available sorting functionality: setting the initial sort order, sorting the grid programmatically, preventing column sorting, and creating your own custom sorting function.

Gridx Series

Gridx in XPages — Entire Series

Setting the Initial Sort Order

By default, the data will be displayed in whatever order it is sent by the REST service, but when you implement the SingleSort module, you can add the sortInitialOrder property to the grid to set the default sort order.

All you have to do is add the attribute when setting up the grid object. It takes two parameters: colId and descending. The column ID will match the id property of the column definition — not necessarily the name of the column in the underlying view (unless you define it that way).

grid = new Grid({
  id: "my_gridX",
  ...
  sortInitialOrder: {colId: 'last', descending: false},
  ...

Programmatic Column Sorting

Another nice feature that the SingleSort module provides is the ability to programmatically sort (or un-sort) the grid.

Here are a few examples…

You can sort a column based on its ID. This line will sort the state column ascending. The parameter to the sort() function is true for descending order and false for ascending.)

grid.column('state').sort(false);

You can also sort a column by its (zero-based) position in the grid. This line will sort the second column in the grid descending.

grid.column(1).sort(true);

The API also provides the ability to clear the current sort — something you cannot do by clicking on the grid.

grid.sort.clear();

Note: In all these cases, grid is the name of the variable that references the grid object.

Live Demo

This demo page includes buttons to programmatically sort (and un-sort) the grid as well as a property to set the initial grid sort by last name.

Preventing Column Sorting

If you want to enable column sorting but selectively prevent it from one or more columns, you can simply do so by setting the column’s sortable attribute to false.

You definitely want to do this if you’re using a remote data store and the underlying view does not support resorting by a given column, because it would make the request, reload the data (in the same order as before) and indicate that it’s sorted, even though it’s not.

This line prevents the firstname column from being sorted:

var columns = [
  {id: 'first', field: 'firstname', name: 'First', width: '65px', sortable: false}
]

Defining a Custom Sort Algorithm

Sorting will be performed with string comparisons by default. If you want to define your own custom sorting logic, you need to do two things:

  1. Add the FormatSort module extension to the grid
  2. Define a comparator function for that column

Here is the full source code for my test page, which includes buttons to sort the grid programmatically as well as a custom sort order (comparator) function for the firstname column.

Lines 6-8 are buttons that programmatically sort (or un-sort) the grid.

Line 19 includes the FormatSort model extension that the grid requires for custom sorting and lines 66-68 add it to the grid. (It’s a model extension, so does not get included via the modules attribute.)

Lines 25-36 define the custom sorting function for the firstname column. In a comparator function, return a positive value when the first value is greater than the second value, a negative value when the first value is less than the second value, or 0 if they are equal.

In this case, I’m demonstrating a handy function that will sort all people with the first name Brad to the top of the list and all people named Marky to the bottom of the list. (It could be written more concisely, but I wanted to make sure the logic is clear.)

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">

<xc:ccGridxResources></xc:ccGridxResources>

<input type="button" value="Sort by State Asc" onClick="grid.column('state').sort(false);"></input>
<input type="button" value="Sort by column(1) [Last Name] Desc" onClick="grid.column(1).sort(true);"></input>
<input type="button" value="Clear Sort" onClick="grid.sort.clear();"></input>

<div id="gridX_Here" style="height:300px; width:430px;"></div>
          
<script>
require([
  "gridx/Grid",
  "dojo/store/Memory",
  "gridx/core/model/cache/Sync",
  "gridx/modules/ColumnResizer",
  "gridx/modules/SingleSort",
  "gridx/core/model/extensions/FormatSort",
  "dojo/domReady!"
], function(Grid, MemoryStore, Cache, Resizer, SingleSort, FormatSort) {

  var columns = [
    {id: 'first', field: 'firstname', name: 'First', width: '65px', sortable: true,
      comparator: function(name1, name2) {
        if (name1 == 'Brad') {
          return -1;
        } else if (name2 == 'Brad') {
          return 1;
        } else if (name1 == 'Marky') {
          return 1
        } else if (name2 == 'Marky') {
          return -1;
        } else {
          return name1 > name2;
        }
      }  
    },
    {id: 'last', field: 'lastname', name: 'Last', width:'150px'},
    {id: 'state', field: 'state', name: 'State', width: '35px'}
  ];


  // Make an AJAX call to look up the full data set and store it locally for fast access
  dojo.xhr.get({
    url:"X_REST.xsp/gridData_LocalStore",
    handleAs:"json",
    load: function(restData){
    
      // Load the data into a local memory store
      var store = new MemoryStore({
        data: restData,
        idProperty: '@noteid'
      });
    
      grid = new Grid({
        id: "my_gridX",
        cacheClass: Cache,
        store: store,
        structure: columns,
        sortInitialOrder: {colId: 'last', descending: false},
        modules: [
        	Resizer,
        	SingleSort
        ],
        modelExtensions: [
          FormatSort
        ]
      });

      //Put it into the DOM tree.
      grid.placeAt('gridX_Here');
      grid.startup();
    
    },
    error: function(msg, args) {
      console.error('Error loading grid data');
      alert('There was an error loading the data'); 
    }
  });

  });
</script>
</xp:view>

Another use case for a custom sort would be if you have dates stored as strings and need to sort them. You can write a function to turn them into Date objects and then compare them. If you’re using a REST service providing a NotesDateTime object, it will be provided in a format that will automatically sort properly without the custom comparator.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: