Getting the Most out of the XPages View Panel Control Part 4: Use Dojo to Fix Category Indenting

If you’ve ever created a view panel for a categorized view that includes a Totals column, you’ve probably noticed that the view is not indented properly. This is pretty common to find on modernization projects where views from an existing Notes client application are being surfaced in XPages. In this article, I’ll show how you can fix that with client side JavaScript and dojo.

Standard Categorized View Indentation

I created a categorized view with a long category value for my database of NFL football teams. When I create a view that just includes that category column, along with the location and team name fields, it indents the way I would expect.


Categorized View with a Totals Column

However, if I add a totals column to the view and create a view panel for the view, the formatting is pretty awful — especially if I have a long category value.


Since it has to display something else (the totals column) in the category row, it breaks the whole row up into cells that correspond to each column.

<td class="xspColumnViewStart">
<div class="xspColumnViewStart">

{Source for expand/collaps button removed}

<a id="view:_id1:viewPanel1:0:viewColumn1__shrink:1link" style="cursor:pointer;" class="xspColumnViewStart">
American Football Conference - East Division</a>
<td class="xspColumnViewMiddle"></td>
<td class="xspColumnViewMiddle"></td>
<td class="xspColumnViewEnd">
	<span id="view:_id1:viewPanel1:0:viewColumn4:_internalViewText" class="xspTextViewColumn">4</span>

Compare this with the source of the category row in the first screen shot above, where you can see that it sets the colspan attribute to cover all cells in the row, with provides proper indentation.

<td colspan="3" class="xspColumnViewStart">
<div class="xspColumnViewStart">

{Source for expand/collapse button removed}

<a id="view:_id1:viewPanel1:0:viewColumn1__shrink:1link" style="cursor:pointer;" class="xspColumnViewStart">
American Football Conference - East Division</a>

Dojo to the Rescue

So, what we need is a way to get the category column to span across multiple cells so that the values below it can be indented properly. Fortunately, with no extra configuration, we have dojo libraries available.

Stay Classy

The cleanest way I’ve found to help the necessary code identify the category cells easily is to apply a class to the category column in the view.

However, we need to apply it conditionally, because the class will be applied to the first table cell in every row in the view — even the ones that aren’t categories.

On the category column, I set the style class’s computed value to this:

if (rowHandle.isCategory()) {
	return 'category';
} else {
	return '';

This assumes that I have set my view panel’s var to rowHandle.

Code to Fix the Indentation

XPages and Custom Controls have an onClientLoad event that we can use to run code to process the view after its loaded.

This code will work on each categorized row. It will remove the blank cells between the category value and the totals column and add a colspan attribute to the category cell to use up the blank space, thereby indenting the rows below more naturally.

// Get a list of all rows in the view panel.
dojo.query('.xspDataTableViewPanel table tr').forEach(function(nodeRow, indexRow) {

  // Locate the category cells within the context of the view rows
  dojo.query('td.category', nodeRow).forEach(function(nodeCat){

    // Execute a search on the parent node (row) and remove all cells until data is found
    var emptyCells = 0;
    var keepCounting = true;
    dojo.query('td', nodeRow).forEach(function(nodeTD, indexTD){

      // Check all non-category cells until a non-empty cell is found
      if ((keepCounting) && !dojo.hasClass(nodeTD, 'category')){
        if (nodeTD.innerHTML == '') {
          emptyCells +=1;
        } else {
          keepCounting = false;

    // Add a colspan attribute to the category cell (1 + [# of empty cells])
    dojo.attr(nodeCat, 'colspan', 1+emptyCells);


Here is the result:


Handle View Paging

The onClientLoad code works great when the view first loads, but the problem is that views are generally updated with partial refreshes as the user pages through, so we need to run the code on that event as well.

One option is to trigger a full refresh when the view is paged through, by selecting the view pager and disabling the partial refresh option, but there’s a better way.

Using the technique I demonstrated in my last post, all I need to do is move the onClientLoad event handler into the view panel and then this code will run when the page is loaded and when the user pages through the view.

Have you tackled this problem in a different way? If so, I’d love to hear how you did it.


18 responses to “Getting the Most out of the XPages View Panel Control Part 4: Use Dojo to Fix Category Indenting”

  1. Sven Hasselbach says :

    Thanks a lot for your very impressive series about the viewpanel.

    You can use the “additional” facets for adding CSJS code. Here is a list:

    The main advantage of using a facet is that you can add more then just CSJS. It allows to add every component you want with a reload / refresh of the viewPanel.
    A working example can be found here:

  2. PV says :

    See the below link. This is another way of fixing the category issue.

    • Brad Balassaitis says :

      I haven’t tried that code, but it looks like it’s meant to fix column widths in general so the page doesn’t “jump” when categories are expanded and collapsed. It doesn’t look like it would fix the issue with totals columns (which someone mentioned in comments), because that requires removing empty cells and setting a colspan attribute on the category cell.

  3. Ronda Brewer says :

    I am trying to use this code snippet and am getting the following error:

    Error while executing JavaScript action expression
    Script interpreter error, line=2, col=6: [ReferenceError] ‘dojo’ not found
    JavaScript code

    Can you provide me with further instruction?

  4. Brad Balassaitis says :

    Great! Can you tell me exactly what you had to change? (I’ve seen many people post a similar problem, but no one post a specific solution.)

  5. Brad Balassaitis says :

    I’ve seen some instability at times with that, too, hence this blog post: 🙂

    There’s a great alternative, though. The post that Sven Hasselbach refers to above ( talks about how you can add a facet to the view. Create a custom control with the code to fix the column sorting in the onClientLoad event and include the custom control as a facet of the view panel. This way, it will execute every time you page through the view.

  6. serviced offices says :

    Pretty nice post. I just stumbled upon your blog and wished to say that I have really enjoyed browsing your blog posts.
    After all I’ll be subscribing to your rss feed and I hope you write again very soon!

  7. Baxter Jimuk says :

    Hi, does this work with 2 categorized column? I tested it and everything in the second categorized column moved to the column just before the total column while the rest of the column starts at 2nd column. Any workaround?

  8. finley says :

    You did your a great operate writing and also revealing your hidden beneficial features of

Leave a Reply

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

You are commenting using your 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: