Archive | View Panel RSS for this section

XPages Tip: Displaying View Panel Sort Icons on a Separate Line

If there isn’t enough room to display both the column title and sort icons in all column headers in a view panel, you can end up with an uneven look. In this post, I’ll show how to use CSS to move the sort icons down to a new line.

Column Header Layout

If you’re using a view panel with sortable columns, you will ideally not have too many columns and instead have enough screen real estate that the sort icons don’t make a difference.

View Panel Sort Icons - 1

However, a common scenario is that there are a lot more columns crammed in and some (but not all) sort icons wrap to a new line. This ends up causing an uneven look.

View Panel Sort Icons - 2

In addition, the icons take up space, so you may have columns that have a 1- or 2-letter code, but the sort icon makes the column 2-3 times wider than it needs to be, so you lose precious real estate.

If that happens and you’d like to make them consistent, you can use CSS to always move the sort icons to the next line.

Column Header Source

In order to apply CSS to adjust the layout, we need to view the page source to see what’s being generated.

This snippet contains the tags that start the view panel (line 1), start the column header row (lines 2-3), and display the first column header (lines 4-16).

<table id="view:_id1:viewPanel1" class="xspDataTable">
  <thead>
    <tr>
      <th scope="col">
        <div class="xspPanelViewColumnHeader">
          <span>
            <a id="view:_id1:viewPanel1:viewColumn1:__internal_header_title_id" href="#" class="xspPanelViewColumnHeader">
              <span class="xspPanelViewColumnHeader">Group</span>
            </a>
          </span>
          <span>
            <img id="view:_id1:viewPanel1:viewColumn1:__internal_header_sort_icon" src="/domjava/xsp/theme/common/images/sort_none.gif" 
alt="Sort Toggle" title="Sort Toggle" class="xspImageViewColumnHeaderSort">
          </span>
        </div>
      </th>

This shows that a column header div contains a span with the column title and another span with the sort icon.

Adding a New Line with CSS

This gives us enough information to know how to target the proper element with CSS. There are several ways to go about it. My example will target the table (with class name), div (with class name), and then get the first span tag. It will add the new line after the first span.

table.xspDataTable div.xspPanelViewColumnHeader span:first-of-type:after {
  content: '\A';
  white-space: pre;
}

The '\A' in the content attribute denotes a new line with CSS. It does not work to put a <br> tag there. The white-space attribute is also required or you may not see any difference.

Now, all of the sort icons appear on a separate line.

View Panel Sort Icons - 3

You can tweak it by adjusting the space between the lines or centering, etc, but this gets the ball rolling.

Also, if you want to modify the images themselves, you can target .xspImageViewColumnHeaderSort with CSS.

Improving the Responsivness of an XPage/Custom Control with a View Panel in Domino Designer

In his presentation during the recent TLCC webinar, Mark Roden had some great tips on speeding up Domino Designer. During the open Q&A period, a question about improving the responsivness of DDE with a page containing a view panel was raised. In this post, I’ll provide a few tips to help.

The Problem

There are times when there is a significant delay in Domino Designer (DDE) when attempting to view or modify properties of a View Panel control. Even in the source view, you may change a property and wait several seconds (or more) between each keystroke. Just clicking on the panel or a column or a subtab in the properties view can be very slow. With every click or keystroke DDE appears to be resolving the data source. The lag can become extremely frustrating, based on machine, server, and network performance. The constant delays can be a significant detriment to your ability to be productive.

Fortunately, there are a few things you can do to improve the situation.

Ensure that DDE Memory Settings are Correct

This tip isn’t view-specific, but for DDE performance in general.

When you install Domino Designer, the default memory settings are far too low. See this TLCC tip for information on how to provide more memory to Domino Designer, thus dramatically speeding up its performance.

Even if you fix the settings, they will be reverted when you upgrade to a newer version of Domino Designer.

Work Locally

The lag in working with a view panel is usually far, far, far (did I say “far”?) worse when working over a network on the server. If you can replicate the application locally for your development and replicate frequently to the server for testing, you will generally see a significant improvement in the responsiveness of Domino Designer when working with the view panel.

Compute the Data Source

If you cannot work on a local replica (or if that doesn’t speed up performance enough), you can compute the view’s data source.

When the data source is computed, Domino Designer no longer attempts to resolve it and read information every time you click on any part of the panel or use any keystroke to modify a property.

Originally, the view data source will look something like this:

<xp:this.data>
  <xp:dominoView var="view1" viewName="myViewName>
  </xp:dominoView>
</xp:this.data>

When you compute the source, it looks more like this:

<xp:this.data>
  <xp:dominoView var="view1"> 
    <xp:this.viewName>
      <![CDATA[#{javascript:return "myViewName";}]]>
    </xp:this.viewName>
  </xp:dominoView>
</xp:this.data>

This provides a massive improvement in responsiveness — even when working on a remote server.

However, since the data source is not being resolved by Domino Designer, you will lose column selection drop-downs.

My recommendation is to implement the view panel and drag-and-drop the columns that you’d like in the view, then change the data source to be computed and modify formatting or other view properties after that.

Note: If you’re pointing to a different server or different database name, compute both of those properties as well to gain this performance benefit.

Article Published in The VIEW: Streamline Deployment and Improve Usability of Editable View Columns in XPages with a Flexible Custom Control

My article on enhancing editable view columns has been published in The VIEW (subscription required). This article builds on the concepts introduced in the first part and shows how to create a reusable custom control that handles several data types and also provides an ‘undo’ feature for each edited value. These enhancements make it much easier to deploy editable columns in multiple places while only requiring one implementation of the logic.

Abstract

The first article of this series showed how to build editable columns, a feature that makes application usage more efficient for your users. This article will show not only how to enhance that functionality, but also to make the deployment and usage of editable columns much more efficient for you as the developer.

The following enhancements will be added:

  • Improve usability by providing a failsafe and giving the user the option to revert
  • Trigger the field update automatically when the user leaves the field
  • Create an editable column custom control to provide easy implementation and reuse
  • Handle multiple data types in order to further facilitate reuse

Fix Indenting on Multiple Categories in a View Panel

I previously demonstrated a solution for fixing category indenting in a view panel that contains a totals column. In this post, I’ll provide an updated version of the code that handles indenting multiple columns properly.

For more insight into the logic, please take a look at that previous post.

Code

Here is the code that fixes the category indentation:

function fixViewIndentation(categoryClass) {
  // 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.' + categoryClass, nodeRow).forEach(function(nodeCat){
    // Execute a search on the parent node (row) and remove all cells until data is found   
    var emptyCells = 0;
    var countCells = false;
    dojo.query('td', nodeRow).forEach(function(nodeTD, indexTD){
      // Start counting when the first category cell is found (this is more for levels after the top-level categorization)
      // Check all non-category cells until a non-empty cell is found
      if (dojo.hasClass(nodeTD, categoryClass)) {
        countCells = true;
      } else if (countCells){          
        if (nodeTD.innerHTML == '') {          
          emptyCells +=1;
          dojo.destroy(nodeTD);
        } else {
          countCells = false;
        }
      }    
    });
    // Add a colspan attribute to the category cell (1 + [# of empty cells])  
    // dojo.attr(nodeCat, 'colspan', 1+emptyCells);
    nodeCat.colSpan = 1+emptyCells;
  });
  });	
}

Custom Control for Easy Reuse

In order to reuse this feature easily, I put the above function in a client JavaScript library called viewPanel.js and I created this custom control (named ccViewIndentationFixer) that will execute the code onClientLoad.

Here’s the full source of the custom control:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
  <xp:this.resources>
    <xp:script src="/viewPanel.js" clientSide="true">
    </xp:script>
  </xp:this.resources>
  <xp:eventHandler event="onClientLoad" submit="false">
    <xp:this.script><![CDATA[fixViewIndentation("CATEGORY_CLASS_NAME");]]></xp:this.script>
  </xp:eventHandler>
</xp:view>

The call to the fixViewIndentation() function must pass the name of the class used on the category columns that need to be indented. (I showed how I set the category column class in the previous post.)

Per a great tip from Sven Hasselbach, I’ve learned that the best way to use it is to include it within a view panel facet by putting this in the page source:

<xp:viewPanel ...>
  <xp:this.facets>
    <xp:pager...></xp:pager>
    <xc:ccViewIndentationFixer xp:key="south" />
  </xp:this.facets>
</xp:viewPanel>

XPages Tip: Alternating Row Colors along with Dynamically Setting Row Colors

In my last past, I showed how you can dynamically set row colors in views and repeats based on data in each entry. In this post, I’ll show how you can take it a step further and use that technique along with providing default alternating row colors.

In my task list, I want to alternate the rows between white and light gray to provide visual separation of the data. But I want to override those defaults and display the row with a yellow background if the task is expiring and a red background if the task is late.

Here’s an example of a repeat control using this combined technique:

Dynamic Row Styling Part 2

Here’s the updated css:

.repeatRow {
background-color: #EEEEEE;
}

.repeatRowAlt {
background-color: #FFFFFF;
}

.yellowRow {
background-color: #FFFF00;
}

.redRow {
background-color: #FF0000;
}

NOTE: It is important to define the red and yellow classes after the default row classes. Whichever ones are defined later will take precedence when multiple classes are assigned to a row.

Here’s the computed style class code to make it work:

var status = varTask.getColumnValue('Status');
var cssClass;

if (rowIndex % 2 == 0) {
cssClass = 'repeatRow';
} else {
cssClass = 'repeatRowAlt';
}

if (status == 'Expiring') {
cssClass += ' yellowRow';
} else if (status == 'Late') {
cssClass += ' redRow';
}

return cssClass;

The code checks the row number and starts with a class of repeatRow or repeatRowAlt. If the status is Expiring or Late, it adds another class to the list. Note that there’s a space before the class name in lines 11 and 13. This is because I’m retaining the first class name and adding a second class to it.

I’m doing it this way because I tend to define font and spacing settings in the repeatRow and repeatRowAlt classes. By assigning two classes to rows as needed, I can retain those settings while overriding the background color when required.

XPages Tip: Dynamically Set Row Colors in a View or Repeat Control Based on Data

In a recent post, Kathy Brown showed how to alternate row colors, in XPages. In this post, I’ll show how to take that a step further and dynamically set the row color based on data in the row.

You can compute the style class of each row in a view panel or repeat control (or data table or data view, etc), so you have the ability to check the data in each view entry and set a style class accordingly. Let’s start with the view panel.

In my example, I have a list of tasks. When a task is about to expire, I want the row to appear with a yellow background. When the task has expired, I want the row to appear with a red background.

Here’s a View Panel using this technique:

Dynamic Row Styling Part 1 - View

Here’s a Repeat Control:
Dynamic Row Styling Part 1

This requires 3 steps:

  1. Create CSS style classes for the row colors (and include the style sheet on the page)
  2. Set the var property of the view panel
  3. Compute the style class to use for the row, based on the data

1. Create CSS Style Classes for the Row Colors

I have defined these styles in a style sheet that is included on my page:

.yellowRow {
background-color: #FFFF00;
}

.redRow {
background-color: #FF0000;
}

2. Set the var property of the view panel

In order to compute the class based on data in each view entry, we need to have the ability to read data from the view entry. The var property of the view panel gives us that handle.

Dynamic Row Styling Part 1 - View Var Property

3. Compute the style class to use for the row, based on the data

Now that I have styles defined and a handle to the view entry, I can compute the style class for each row. To do so, select the view panel properties, select the Style subtab, and select the rowClasses property. Next to the Class property, click on the diamond to open up an SSJS window and add the code to compute the style class.

Dynamic Row Styling Part 1 - View Property

This code will read the value of the ‘status’ column and return a class name to use for the row accordingly.

var status = varTask.getColumnValue('Status');
var cssClass = '';

if (status == 'Expiring') {
  cssClass = 'yellowRow';
} else if (status == 'Late') {
  cssClass = 'redRow';
}

return cssClass;

Working with a Repeat Control

All of the same concepts apply. The difference is that you don’t have a built-in styleClass property to use. Assuming your repeat control contains a table, you can compute the style class on the xp:tr tag within the xp:repeat tag.

It can be difficult to try to select the xp:tr tag directly, but you can click on the first cell in the row and then locate the xp:tr tag either via the Outline view or in the page source. Once you have the xp:tr tag selected, you can compute its styleClass property and use the same code as shown above, provided you have defined the same var name for the repeat control.

Dynamic Row Styling Part 1 - Repeat

Article Published in The View: Implementing Editable View Columns in XPages

If you have a subscription to The View, please check out my first article, which was just published today:

http://www.eview.com/eview/volr6.nsf/articleURL/2013-04-decrease-server-load-and-improve-application-performance-with-editable-view-columns-in-xpages

The article is about how to add editable columns to your XPages view panels, similar to the InViewEdit event in the Notes client.