Archive | November 2013

XPages Tip: Setting a Date Field with @Now

I came across an interesting quirk recently when using @Now() to set date fields in an XPages workflow application — it works on the front-end (XSP) document but not on a back-end NotesDocument.

Assuming I have a document data source named document1, this code will work in SSJS to set a date field to @Now() via the XSP document:

document1.replaceItemValue('DateField', @Now());

However, if I get the back end document and try to do the same thing, it throws an error. (The same is true if working with the back-end document even without getting a handle to it through the front-end document.)

document1.getDocument().replaceItemValue('DateField', @Now());

AtNowError

Looking through the stack trace, this is the real error: “NotesException: Unknown or unsupported object type in Vector”

So it appears that the NotesDocument version of replaceItemValue() doesn’t handle that type of date.

Fortunately, there’s an easy workaround. You can use session.createDateTime() to get a date in a format that replaceItemValue can handle.

This line of code works:

document1.getDocument().replaceItemValue('DateField', session.createDateTime(@Now()));

Dojo Data Grid – Part 32: Setting Row Color Based on Row Data

In this post, I’ll show how dynamically change the row color in an XPages Dojo Data Grid based on data in the row.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

Conditional Row Styling

A common use case for setting the row color is to draw attention to certain rows based on the status. If an item is being shipped and it’s late, you might want to highlight it in red to make sure that it’s obvious that there’s a problem.

The client-side onStyleRow event of the grid is the key to this technique. It executes as each row is drawn in the grid, which is the timing we need in order to dynamically set the row styling. See my previous post on the onStyleRow event for more information.

CSS

In the method I’ll demonstrate, it appends a class to each row that is styled. For this to work, the class names have to correspond to CSS classes that define the row style.

Here is the CSS used in my sample:

.redRow {
  background-color:red !important;
}
.yellowRow {
  background-color:yellow !important;
}
.greenRow {
  background-color:green !important;
}
.blueRow {
  background-color:blue !important;
}
.grayRow {
  background-color:gray !important;
}

The Code

Below is the source code for a working example. Since the data I have in my test database is about people, I set it up to display different row colors if the first name starts with A, B, C, or D.

var columnNumber = 0;  // 0-based column number of the grid data to read

// This event automatically receives an object with information about the current row. It's not named, so we refer to it by arguments[0]
var row = arguments[0];

// Read the data from the specified cell in the row
var firstName = dojo.query('TD', row.node)[columnNumber].innerHTML;
if (firstName == '...') {
  return;
}

// Assign the style class based on the first letter of the first name
var rowClass = 'grayRow';
switch(firstName.substr(0,1).toUpperCase()) {
  case 'A':
    rowClass = 'redRow';
    break;
  case 'B':
    rowClass = 'yellowRow';
    break;
  case 'C':
    rowClass = 'greenRow';
    break;
  case 'D':
    rowClass = 'blueRow';
    break;
}

row.customClasses += ' ' + rowClass;

Understanding the Code

The main thing that the code needs to do is to read the row data and set the class accordingly. Now that we understand what information is available in the onStyleRow even, the code is pretty simple.

Line 1 defines the column number from which data should be read. It’s 0-based (because I’ll end up getting an array of table cells to read from and that will be 0-based). In this example, I want to read the firstname column, so it’s set to column #0.

Line 4 gets a handle to the object that is automatically passed into the onStyleRow event. It’s not named, so we refer to it by arguments[0].

Line 7 does the heavy lifting. It uses dojo.query to get all of the cells (TD) in the table for the current row. It gets the nth cell based on the column number defined in line 1; this determines which column it’s reading. It then returns the innerHTML of that cell in order to return the cell content.

Lines 8-10 account for the grid behavior that defaults each cell to ‘…’. The onStyleRow event will run twice as rows are loaded. The first time, the data will be ‘…’ and thereafter, it will be populated with the real data. So, if this is the initial pass, just exit the function for the time being and it will re-execute as the data is filled in.

The rest of the code reads the first character of the first name and determines which style class to add to the row.

The last line uses the customClasses property of the row in order to add the style class that sets the row color.

The Result

That’s it — we now have code that dynamically styles the row colors based on the data within the row!

Grid 30 - B

Working around a SourceTree Error with Hg Flow

While testing out SourceTree with a current project after watching David Leedy’s great NotesIn9 episode on the subject I came across an error when I first tried to start Hg Flow, so I want to document how to fix it in case anyone else runs into the same problem.

The error I received was, “abort: No module named ConfigParser!”.

SourceTree_ErrorOnHgFlow_1

Fortunately, someone has already documented a fix for this error:

http://blog.omarmohamed.com/fixing-mercurial-problem-abort-no-module-named-configparser/

I followed the steps in that blog post and it worked.

FWIW – When I installed SourceTree, I selected the options to install both Git and Mercurial within it. However, it is important to note that I previously installed Mercurial binaries and have been using that plugin in DDE, so I’m not sure whether that is related.

Dojo Data Grid – Part 31: Setting Row Styles on Hover, Selection, and Alternate Rows

In this post, I’ll show how change the row color in an XPages Dojo Data Grid based on whether the row is hovered over, selected, or is an odd-numbered row.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

Row Styling

By default, the grid will provide alternate row coloring and different styles when you select or hover over a row. This image shows all three of those styles in effect.
Grid 30A

However, as soon as you add any code into the event handler, you lose the hover, selected, and alternate row styles.

The client-side onStyleRow allows us to re-apply this styling or change it. The event executes as each row is drawn in the grid, which is the timing we need in order to dynamically set the row styling. See my previous post on the onStyleRow event for more information.

Restoring the Default Styles

To restore the default styles, you can use the same class names that the grid uses to apply the styles.

  • Alternate Rows – dojoxGridRowOdd
  • Row Hover – dojoxGridRowOver
  • Row Selection – dojoxGridRowSelected
// This event automatically receives an object with information about the current row. It's not named, so we refer to it by arguments[0]
var row = arguments[0];

if (row.over) {
  row.customClasses = 'dojoxGridRowOver';
} else if (row.selected) {
  row.customClasses = 'dojoxGridRowSelected';
} else if (row.odd) {
  row.customClasses = 'dojoxGridRowOdd';
}

Customizing the Styles

Now that you understand how this works, it is just as easy to change the styles completely in these three cases.

Just define classes in CSS and include the style sheet on the page and you use the same technique to append classes to rows as needed.

In this hideous example, alternate rows are set to blue, selected rows are set to yellow, and the hovered row is set to red.

Grid 31

var row = arguments[0];

if (row.over) {
  row.customClasses = 'redRow';
} else if (row.selected) {
  row.customClasses = 'yellowRow';
} else if (row.odd) {
  row.customClasses = 'blueRow';
}

Getting Awesome Category Icons in Data Views – A jQuery Variation

In a Twitter exchange with Paul Withers regarding his great post on replacing category expand/collapse icons in a Data View with Font Awesome icons, he mentioned that it would be interesting to see a jQuery alternative. Since I’m working on improving my proficiency with jQuery, I thought it would be an interesting challenge. In this post, I’ll show how I implemented it and describe the main challenge that I faced.

This code will use jQuery to replace the expand/collapse icons with related font awesome icons.

As in Paul’s post, this code depends on the category columns having a class of catColumn (although it can be done without it).

The expand and collapse icons are within an <h4> tag and an <a> link. The image source name will be collapse.gif or expand.gif, so this code reads the source to determine which type of image to replace. Since Font Awesome uses <i> tags, it adds the new icon tag and then removes the <img> tag.

This code has been placed in a client-side JavaScript library so I can call it from two different places.

Note: The application I’m testing on has Font Awesome v3, so the icon tags look different than the one in Paul’s post, where he’s using version 4.

// Replace the standard Data View expand/collapse icons with font-awesome icons (v3) using jQuery
function replaceCategoryIcons() {
  $('.catColumn a img').each(function(){
    var src=$(this).attr('src');
    if (src.indexOf('collapse') > -1) {
      $(this).after('<i class="icon-collapse"></i>&nbsp');
    } else {
      $(this).after('<i class="icon-expand"></i>&nbsp');
    }
    $(this).remove();
  });
}

This code was pretty straightforward to create; the real trick is firing it as the data view is refreshed when categories are expanded and collapsed. There’s no pure DOM event that I’m aware of that I can listen to with jQuery in order to re-execute after each partial refresh. jQuery cannot subscribe to a stream that’s published by dojo, so I can’t use code similar to Paul’s post.

I tried to use event delegation (check out Marky’s great explanation here) on the click event of the images (since that’s what triggers the update). This kind of worked, but the problem was that it replaced the icons and then, when the page refreshed, the old icons were right back in place.

So, it all came back to Tommy Valand’s great post about hijacking partial refresh events to solve this problem.

I trimmed down original code and updated the onComplete event to trigger my jQuery function to replace the icons (line 18).

function hijackPartialRefresh() {
  // Hijack the partial refresh
  XSP._inheritedPartialRefresh = XSP._partialRefresh;
  XSP._partialRefresh = function( method, form, refreshId, options ){
    // Publish init
    dojo.publish( 'partialrefresh-init', [ method, form, refreshId, options ]);
    this._inheritedPartialRefresh( method, form, refreshId, options );
  }

  // Publish start, complete and error states
   dojo.subscribe( 'partialrefresh-init', function( method, form, refreshId, options ){
    if( options ){ // Store original event handlers
      var eventOnComplete = options.onComplete;
    }

    options = options || {};
    options.onComplete = function(){
      replaceCategoryIcons();
      if( eventOnComplete ){
        if( typeof eventOnComplete === 'string' ){
          eval( eventOnComplete );
        } else {
          eventOnComplete();
        }
      }
    };
  });
}

Now, to run the code both when the page loads and then again on each partial refresh, I added this code to the onClientLoad event of the page:

// Replace the category icons with font-awesome icons
replaceCategoryIcons();

// Set up ongoing replacement of icons
hijackPartialRefresh();

Now, it replaces the default icons…

DataViewExpandCollapseIcons_Before

… with Font Awesome icons…

DataViewExpandCollapseIcons_After

Dojo Data Grid – Part 30: The onStyleRow Event

In this post, I’ll dig into the onStyleRow event of the XPages Dojo Data Grid in order to show how it can be used to modify the display of grid rows. This will lay the foundation for the next few posts.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

The onStyleRow Event

The onStyleRow event runs on each row in the grid as it is rendered. The event handler automatically receives one argument that has a number of properties that can be used to conditionally customize the display of the row.

By default, the grid will provide alternate row coloring and different styles when you select or hover over a row. This image shows all three of those styles in effect.
Grid 30A

However, as soon as you add any code into the event handler, you lose the hover, selected, and alternate row styles. (In this case, I added a single comment to the event handler and it was still enough to cause other styles to be dropped.)
Grid 30B

onStyleRow Argument Properties

The onStyleRow event automatically receives an object with information about the current row. It’s not a named argument, so we refer to it by arguments[0]. The properties of the row object are as follows:

  • index (row index)
  • node (DOM node)
  • odd (boolean — whether the row is an odd-numbered row)
  • selected (boolean — whether the row is currently selected)
  • over (boolean — whether the row is currently hovered over)
  • customStyles (used to add style information to the row)
  • customClasses (used to add classes to the row)

The index property is the 0-based number of the row in the grid.

odd, selected, and over are boolean properties that are handy for changing styles for alternate rows and whether the row is selected or hovered over.

The customStyles property is used to add custom style information to the row. The customClasses property is used to add additional classes to the grid row.

The node provides a handle to the DOM node of the grid row.

Here’s an example of what it returns:

</pre>
<table class="dojoxGridRowTable" role="presentation" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
</tr>
</tbody>
</table>
<pre>

There are two interesting things to note. First of all, each row in the grid is actually its own table. Secondly, each cell in the row is initially populated with ‘…’. It then fills in the data from the REST service on a second pass.

This is important to understand — the onStyleRow event will generally run more than once on each row. Essentially, whatever settings are applied in the last pass are the ones that stick.

In my testing, it appears to run between 1 and 3 times on each row. It seems to most commonly run twice — once when it sets up the row and pre-populates every cell with ‘…’ and then a second time when it actually fills in the data. (I tested this by reviewing the full contents of the row node.)

It seems to run 3 times on the first chunk of rows displayed when the grid is first loaded. It only runs once one when the data has already been loaded or if the row is read-protected and thus cannot display any data.

Adding event code

I enter code for the onStyleRow event via the All Properties tab and not directly in the event view. Take a look at this post to see why this works differently.

Grid 30 - A

Up Next

Now that we’ve explored what happens in the event and what’s available to it, the next couple of posts will show how to use the event to provide additional row styling.

CSS Tip: Dealing with Table Spacing in IE Compatibility Mode

One of the most frustrating things about dealing with IE compatibility mode is how it handles table layouts. In my recent experience, it seems to automatically stretch them out to take up more room than you’d expect. It seems to generally disregard padding, spacing, and column width CSS settings (unless the column width is greater than the amount of space the browser wants to provide for a column).

Even worse, it doesn’t always space the columns evenly. In a recent application, cells with consistent content were sized differently in compatibility mode, so the content of some cells would wrap and others wouldn’t — even though there would have been plenty of space for all of the data if the columns had been spaced evenly.

Since the pattern seems to be that it will stretch tables out to the full available width, the quick workaround to improve table layouts in compatibility mode is to put a container around the table (such as a div) and use CSS to fix the width of that container. This doesn’t cause it to space the columns perfectly, but it can be very handy in limiting the size of the table as needed.