Flexible View Control for XPages – Adding Subcategories To Categorized Views

With the last post in the Flexible View Control Series introducing categorized Views, this post is picking right up where that left off and demonstrating how easy it can be to add multiple levels of categorization to a View.

The View Definition

Jumping right in, I’ve created a copy of the ferraris-categorized View Definition used in the previous demo and named the copy ferraris-subcategorized. Since this View Definition is already categorized by MODEL, I want to subcategorize the YEAR column. All I need to do is make a couple of small changes:

  1. Sort the subcategory column
  2. Tell the YEAR column to categorize in addition to the MODEL category
  3. Hide the YEAR column for the detail rows

Displaying the View

For displaying the View I can reuse my viewCategories XPage created for the category demo in the last blog post since it’s configured to dynamically read the View Definition and query from the url QueryString.

Keep in mind … I haven’t altered the back-end View at all. The power is in the View Definition, allowing me to use the same data source to create multiple Views.

See the demo for yourself


Adding a subcategory to a categorized View

Expanding, collapsing, and filtering all still work as you would expect.

How About More than Two Levels of Categorization?

The Flexible View Control will support as many levels of categorization as you need. The caveat, of course, is all of the categorized columns need to be sorted in the order of categorization.

Demo: Three levels of categorization

View Definitions currently support four levels of client-side sorting. Alternatively, if the data being sent from the server is already sorted, then theoretically the FVC will support as many levels of categorization as needed.

Note: It’s important to understand the performance implications of using multiple levels of categorization. Every additional level adds an nth degree of speed reduction in rendering the View since categorization is accomplished by traversing the dataset. The more data in the View, the more impact on performance.

Note: For any categorized View, whether the data is sorted sever-side or client side, the first category column needs to be listed in the first client-side sort field of the View Definition. This is an unintended byproduct of the categorization functionality and I will look to remove this requirement in the future

To demonstrate the server-sort, I created a View in the used car database of all Ferraris and sorted the first four columns, By MODEL, By STATE, By YEAR, and By CITY.

Click to open the View Definition
Click to open this View

Note: The category CSS for the Flexible View Control that handles category indentation only accommodates three levels of categories but its easy enough to add custom CSS for four levels and beyond:

/* level-3 refers to the 4th level since it's
 zero based indexing */
tr.group-level-3 td:nth-child(1) {
    padding-left: 75px;

tr[data-category-level="3"] td:nth-child(1) {


Again, not to beat a dead horse … but flexibility, reusability, and low-code-ability (I think I just made that word up) are qualities that make the Flexible View Control a game-changer for XPage development. The next post will talk about “Category Renderers”, a killer feature to enhance the UI and UX of categorized views.

Flexible View Control for XPages – Categorized Views

HCL Digital Week made very clear the emphasis in the application development space is on “low-code”. That got me thinking about the Flexible View Control and how, at the end of the day, it really is a low-code tool to add View data to XPage applications. Just like with Domino Volt, many aspects of configuring a View with the Flexible View Control are as simple as drag, drop, and configure.

Creating a categorized View is no different. Let’s take a look at just how easy it is by creating a View of all the Ferraris listed in the used car database. Naturally, we start by creating the View Definition:

The View Definition

The View Definition being used for the demos shown in this post can be found here.

I want to categorize this View by the MODEL column. Just like we do for a Notes View, I make that the first column. Next, check off the “category” checkbox in the last column of the MODEL column row.

A couple of important notes in the above sceenshot:

  1. The column to be categorized MUST be sorted.
  2. In the image above the MODEL column is being hidden. That might seem counter-intuitive since this is the column we are categorizing, but it will make sense in a moment.

The View XPage

Link to the demo used in this post.

BEFORE adding categorization

The image above shows what the Ferraris View looks like before adding the categorization.

The image below shows what the View looks like after adding the categorization and hiding the MODEL column.

AFTER adding categorization and hiding the MODEL column

How does it work?

To create the categorization the Flexible View Control traverses the DataTable during the drawCallback phase and when a row contains a different MODEL value, a new tr node is inserted before that row to represent the category. The reason why we can hide the MODEL column is the traversal is done on the DataTable dataset, not the actual HTML of the table. After inserting the tr node a click event is applied to provide expand/collapse functionality for the category.

Let’s break down the tr node that gets added for each category:

category tr element insert for each category
  • The data-category attribute is the unique identifier for this category. This value also gets applied to all of the child rows for this category.
  • “group” classes are added to aid in referencing the category rows.
  • The data-hide attribute is used to handle expansion/collapse of the category.
  • The table cell created inside the tr node is automatically given a colspan equal to the number of cells in a non-category row.

Doing the Twist(ie)

You probably noticed in the image above that there is a “twistie” node in the tr HTML. By default this is simply a “-” to denote expansion and a “+” to denote a collapsed category. This is handled with some simple CSS:

.twistie {margin-right:5px}
.twistie-collapse::before {

Adding a little more “flair” to the twistie is easy by simply overriding the CSS. For example, I’m a big fan of Font Awesome and use that for my twistie icons:

Using Font Awesome icons for twisities
	font-family: FontAwesome;
	content: "\f056";
	font-size: inherit;
.twistie-collapse::before {
	font-family: FontAwesome;
	content: "\f055";
	font-size: inherit;

Expand/Collapse All

Just as in a Notes View that contains categorization, the Flexible View Control provides the ability to expand or collapse the entire View. In our demo there are two buttons at the top that are wired with this functionality:

When the control is rendered functions are created dynamically that call functions contained in the csjsCCRestView.js script library:

collapseAll : function() {
expandAll : function() {

The code behind the buttons can then refer directly to a specific View, which we’ve named ViewBasic in the thisView property of the control for this demo:



One of the great features of DataTables is being able to enter a query in the search box and having the contents of the DataTable reduce to the records that match that query. This functionality still works when the View is categorized!

The next post will expand on the categorization functionality by introducing subcategories and a feature called “category renderers”.

Flexible View Control for XPages Updates

On the heels of the OpenNTF Webinar where I presented the Flexible View Control for XPages, I was able to make some long-overdue updates that improve the functionality and performance of the control.

Get the code from GitHub:

Release v2020-11-17

Updates in this release:

  • Improved the setup and configuration process to make it more intuitive, including adding an option to create the default (view-definitions) View Definition automatically.
  • Fixed and improved category/sub-category creation and expansion/collapse.
  • Cleaned up the View Definition UI.
  • Added additional client sorting fields in the View Definition. There is now a total of 4 levels of client-side sorting available.
  • Fixed totals options including totaling up for each category/subcategory and showing totals in the footer.
  • Added ability to total # of rows or total the values for a column in each row.
  • Added a category renderer option to the View Definition.
  • Added a footer callback option.
  • Reduced expression language evaluations on the ccRestView custom control.
  • Added a stats component to the View object to track the performance of different aspects of the control.

The demo site has been updated with the most recent version of the control. Blog posts expanding on/demonstrating the items listed above to follow soon!