Gridx in XPages – 18: Formatting Date and Currency Columns

Certain data types in the grid are not automatically formatted in the way that you’d prefer. In this post, I’ll show how to format date and currency columns in a grid using features built into Dojo.

Gridx Series

Gridx in XPages — Entire Series

Formatting Dates

By default, a rest service providing a Notes Date/Time will provide it in a much longer format than you probably want to see in the grid.

Gridx 18 A

To format it, you can use a decorator function (described previously in this post).

Include the dojo locale module in the require statement: dojo/date/locale

Then add a decorator function to format the date. (Make sure the column dataType is set to date.)

decorator: function(value)
{
  try {
    if (value) {
      // NotesDateTime comes out in this format: 2014-10-21T14:47:38Z
      var parsedDate = value.substring(0, 10);
      
      // Create and format the date 
      var dt = new Date(parsedDate);
      var dateString = locale.format(dt,
        {
          selector: "date",
          datePattern: "dd-MMM-yyyy"
        }); 
      
      return dateString;
    }
  } catch (e) {
    console.error('error decorating date: ' + e.toString());
  }
}

Line 6 parses out the first 10 characters from the date string

Line 9 creates a date object from the parsed string.

Lines 10-14 use the dojo locale formatting functionality to format the date to the desired pattern.

Gridx 18 B

Now the date column is formatted in a way that’s much easier to read.

Formatting Currencies

By default a numeric column will display as a plain number.

Gridx 18 C

Similar to the previous example, we can use a dojo module to format the data. In this case, we’ll add dojo/currency to the require statement.

Here’s a decorator function that will format the data. (Make sure the column dataType is set to number.)

decorator: function(value) { 
  if (value) { 
    var formattedCurrency = currency.format(value, {currency: "USD"});
    return formattedCurrency;   
  } 
}

Line 3 is the core of this logic. It uses the dojo currency module to format the data as a currency. The currency attribute defines the currency to use. (Other examples include “EUR”, “GBP”, etc)

Gridx 18 D

Here’s the same data with the currency set to EUR:

Gridx 18 E

Date and currency conversions are a great example of why it is extremely handy to have a JavaScript framework like Dojo available.

Gridx in XPages – 17: Defining Column Data Types in order to Provide Number and Date Range Filtering

In the last post, we looked at how to easily add advanced filtering filtering to the grid. In this post, I’ll show how to define number and date columns so they can be filtered appropriately.

Gridx Series

Gridx in XPages — Entire Series

Column Data Types

By default, all columns are treated as strings. But if you define columns as numbers and dates, you get filtering options specific to those data types.

Here’s what I get when I add the Birthday and Zip columns (from the FakeNames database) to my grid:

Gridx17 A

If I try to filter based on the number or date columns, I get the options that make sense for string filtering.

Gridx17 B

Number Column

To improve this, just add the dataType attribute to the column definition and define the type as number.

{id: 'zip', field: 'zip', name: 'Zip', dataType:'number', width: '60px'}

Now when I filter on that column, I get a set of options that are much more useful when dealing with numeric data.

Gridx17 C

Date Column

Date columns require a little extra work, but it’s still simple.

First, we need to add the dataType attribute and set it to date.

Now, when I filter on that column, I get a set of options that are much more useful when dealing with dates.

Gridx17 D

And, when you select values to set up the filtering, you get a date picker to make it easy.

Gridx17 E

However, it doesn’t work properly yet. The next thing we need to do is add a dateParser function. I can’t say I know why this is necessary,but all you need to do is add a function that returns the same value and it does the trick.

Now the filtering will work properly.

Here’s the source for the birthday column:

{ 
  id: 'bday', 
  field: 'birthday',
  name: 'Birthday', 
  width:'100px',
  dataType:'date',
  dateParser: function(value){ 
    return value; 
  }
}

Gridx in XPages – 16: Advanced Searching with the FilterBar Module

In the last post, we looked at simple full-text searching with the QuickFilter module. In this post, I’ll show how to use provided more advanced search capabilities with the FilterBar module, which allows for multiple rules, column-specific searching, and all or any rule matching.

Gridx Series

Gridx in XPages — Entire Series

FilterBar

The FilterBar module is simple to add and provides great search functionality. When added to the grid, it provides — wait for it — a filter bar at the top of the grid.

Gridx 16 A

By default, it tells you that no filter is in effect. When you click on the button in the upper left hand corner, you are presented with the filter dialog.

Gridx 16 B

The Column drop-down lets you choose to search any column or to choose a single grid column to search.

Gridx 16 C

The Condition drop-down gives you several options for the filtering condition — contains, equal, starts with, ends with, etc. This provides a lot of functionality for your searches.

Gridx 16 D

The Value field is where you enter the search value. If you have selected a column to search, you will get type ahead for values in that column to optionally choose from.

Gridx 16 D2

The plus (+) icon in the lower left gives you the ability to add more rules to the filter. In this example, I added 3 rules to match.

Gridx 16 E

When I executed my search, it returned a single row and the filter bar tells me that it’s showing 1 out of 1301 rows. It also provides a link to clear the filter. (The ‘x’ icon closes the filter bar.)

Gridx 16 F

The Match drop-down gives you the ability to allow the search to work on a combination of all rules or to include rows that match at least one of the rules.

Gridx 16 G

If I change the Match from all rules to any rule, I get more results.

Gridx 16 H

Implementing FilterBar

Adding FilterBar is very straightforward; you just need to add two more modules to the grid.

Here’s the updated require() in my example:

require([ 
  "gridx/Grid", 
  "dojo/store/Memory",
  "gridx/core/model/cache/Sync", 
  "gridx/modules/ColumnResizer",
  "gridx/modules/NestedSort", 
  "gridx/modules/Filter",
  "gridx/modules/filter/FilterBar",
  "dojo/domReady!" ], 
  function(Grid, MemoryStore, Cache, Resizer, NestedSort, Filter, FilterBar) {

And here is the updated grid object:

grid = new Grid({ 
  id: "my_gridX", 
  cacheClass: Cache, 
  store: store, 
  structure: columns, 
  modules: [ 
    Resizer, 
    NestedSort,
    Filter,
    FilterBar
  ] 
});

That’s it!

Combine with QuickFilter

You can use both QuickFilter and FilterBar together in the same grid to provide quick full-text searching and rule-based advanced filtering.

Just add both modules and the filter base (gridx/modules/Filter)!

Local Data Only

Note: This will only work simply on a local data store, so I am using an AJAX request to pull the data from a REST service locally.

If you are using a remote data store, you’ll need to filter the data server-side before sending it client-side.

Unique IDs Required

Note: If your REST service provides data from a categorized row or a totals row at the end, it can cause filtering functionality not to work properly. This is because the grid requires each row to have a unique ID (which we’ve set to use NoteID in our examples), but category rows and totals rows don’t represent documents so they do not include a NoteID.

It does not cause an obvious error but filtering doesn’t work, the page freezes and you eventually get a message asking you about stopping or debugging JavaScript.

Claro Theme Required

As mentioned in a previous post, the claro theme must be used properly for this to work well.

Without it, the filtering dialog looks like this — it’s not even distinguished from the rest of the screen:

Gridx 16 I

Up Next

In next post, we’ll look at how to filter based on non-string columns, such as dates and numbers.

Gridx in XPages – 15: Adding QuickFilter for Full-Text Searching

The QuickFilter module provides simple full-text search functionality to a grid. In this post, I’ll show how to use it and how it works.

Gridx Series

Gridx in XPages — Entire Series

QuickFilter

The QuickFilter module adds a text box and icon to the top right area of the grid.

Gridx 15 A

Once you type a value to search for in the box, it will automatically filter the data. (It appears to start after you pause typing.) You can also trigger the search by clicking on the filter icon to the right.

In this example, I typed ‘pa’ into the box. It filtered the list to people who live in Pennsylvania or have a first or last name that includes ‘pa’.

Gridx 15 B

Once a search has been executed, you can click the ‘x’ icon in the right side of the search box to clear the results. If you change the search string, it will execute a new search over the entire data store; it does not search the filtered results.

It does not seem to support anything other than simple text searching (i.e. no wildcards or logical operators to combine search terms).

Sorting Search Results

If you have a sorting module in the grid (such as NestedSort, in my example), you can sort the filtered results.

Gridx 15 C

Implementing QuickFilter

Adding QuickFilter is very straightforward; you just need to add two more modules to the grid.

Here’s the updated require() in my example:

require([ 
  "gridx/Grid", 
  "dojo/store/Memory",
  "gridx/core/model/cache/Sync", 
  "gridx/modules/ColumnResizer",
  "gridx/modules/NestedSort", 
  "gridx/modules/Filter",
  "gridx/modules/filter/QuickFilter",
  "dojo/domReady!" ], 
  function(Grid, MemoryStore, Cache, Resizer, NestedSort, Filter, QuickFilter) {

And here is the updated grid object:

grid = new Grid({ 
  id: "my_gridX", 
  cacheClass: Cache, 
  store: store, 
  structure: columns, 
  modules: [ 
    Resizer, 
    NestedSort,
    Filter,
    QuickFilter
  ] 
});

That’s it!

Local Data Only

Note: This will only work simply on a local data store, so I am using an AJAX request to pull the data from a REST service locally.

If you are using a remote data store, you’ll need to filter the data server-side before sending it client-side.

Unique IDs Required

Note: If your REST service provides data from a categorized row or a totals row at the end, it can cause filtering functionality not to work properly. This is because the grid requires each row to have a unique ID (which we’ve set to use NoteID in our examples), but category rows and totals rows don’t represent documents so they do not include a NoteID.

It does not cause an obvious error but filtering doesn’t work, the page freezes and you eventually get a message asking you about stopping or debugging JavaScript.

Up Next

In the next post, we’ll look at the FilterBar module, which provides much more advanced searching functionality.

Gridx in XPages – 14: Preparing to add Filtering by Using the Claro Theme

In the next few posts, I’m going to dig into the great filtering features provided by Gridx. But I ran into problems using them without the Dojo theme being set correctly, so this post will show what needs to be done for the grid to pick up the theme properly.

Gridx Series

Gridx in XPages — Entire Series

Gridx Dojo Theme

You may have noticed that we’ve included stylesheets from Dojo’s claro theme when setting up Gridx. Three of the four resources included are related to it.

  <xp:this.resources>
    <!-- Claro Theme -->
    <xp:styleSheet href="/.ibmxspres/dojoroot/dijit/themes/claro/claro.css"></xp:styleSheet>
    <xp:styleSheet href="/.ibmxspres/dojoroot/dijit/themes/claro/document.css"></xp:styleSheet>

    <!--  Module Path to locate Gridx Library -->
    <xp:dojoModulePath url="/gridx" prefix="gridx"></xp:dojoModulePath>

    <!-- -Main GridX Stylesheet  -->
    <xp:styleSheet href="gridx/resources/claro/Gridx.css"></xp:styleSheet>
		
  </xp:this.resources>

However, the grid isn’t actually using it properly at this point.

The reason is that XPages uses the tundra theme by default. This theme provides the general look and feel that we’ve seen in our Gridx examples so far.

Gridx 14 A

We haven’t focused on the UI up to this point, so it really wasn’t a big deal. However, I noticed when I started implementing filtering that it wouldn’t work properly — and it looked awful.

If you look at the Gridx files, you’ll see that it only includes a claro theme. There are 4 Dojo themes automatically available in XPages and claro is one of them.

In order to get the filtering looking and working properly, I had to get the grid using the claro theme.

Using the claro Theme

There are a few different ways to go about using the claro theme.

One way is to implement it application-wide via a Theme resource. This post shows how to use the Dojo themes available in XPages.

This does the job, but it may have side effects. It can affect fonts or other styling in your application that may be styled by the tundra theme, even if not intentionally, but because it’s in use by default. This should not be an issue if you’ve implemented a custom UI (e.g. using a framework like Bootstrap) that doesn’t make use of any Dojo theme styling.

In a standard web application using Dojo, the way to use a theme is to include the related stylesheets and then add the theme name as the class on the body tag for the page.

In XPages, you don’t use a body tag per se, but you can add a class to the body tag generated by the page.

For the sake of simplicity in this example, I use this technique to set it at the page level by setting the styleClass property of the XPage; now the Grid picks up the claro theme.

Gridx 14 B


If you still run into issues with other elements on the page that need the tundra styling, you can wrap a div around the problematic component and give it a class of tundra to set it back to the default XPages theme.

FWIW – You can also add a div around the grid with the claro class. This styles the grid fine, but doesn’t style the popups related to filtering, so it doesn’t fully do the job.

Up Next

In the next few posts, I’ll dig into the awesome Quick Filter and Filter bar features that let you filter the data without any coding.

Gridx in XPages – 13: Customizing Cell Content

So far, we’ve only looked at displaying text from the REST service in the grid. However, you can also customize the content dynamically based on a value. In this post, I’ll show how to do use the decorator property to modify cell content.

Gridx Series

Gridx in XPages — Entire Series

The decorator Property

The decorator property of a grid column is like the formatter function for a regular Dojo data grid.

It calls a function that will process column data and return whatever you want to display in the cell.

An Example

In this hideous example, I added a column to the grid that reads the State value from the data store and writes out a span with a background color based on the state.

Gridx 13

Here is the column structure for this grid:

  var columns = [
    {id: 'first', field: 'firstname', name: 'First', width: '70px'},
    {id: 'last', field: 'lastname', name: 'Last'},
    {id: 'state', field: 'state', name: 'State', width: '40px'},
    {id: 'stateColor', field: 'state', name: '', width: '20px',
      decorator:function(value) {
        var color;
        switch (value) {
        case 'IL':
          color = 'red';
          break;
        case 'FL':
          color = 'blue';
          break;
        case 'GA':
          color = 'yellow';
          break;
        default:
          color = 'gray';
          break;
        }

        return '<span style="background-color:' + color + ';">' + value + '</span>';
      }
    }
  ];

The decorator property of the stateColor column writes out the cell data for that column. It automatically receives an argument with the raw data for the state.

In this example, it uses a switch statement to check the value of the state and set a color variable.

Line 23 returns a span tag with the background color defined. It also displays the state text (although it is not necessary).

This is a simple example, but the possibilities are endless. You can use this to compute images to display in a cell based on a status. You could put any other HTML content — including a link or a button, etc.

Gridx in XPages – 12: Adding Event Handlers and Opening a Document

In the last post, I showed how to use the Gridx API to get information about rows, columns, and cells. In this post, I’ll show how to attach an event handler and use that information to open a document by double-clicking on a grid row.

Gridx Series

Gridx in XPages — Entire Series

Available Event Handlers

Gridx provides a number of events for several regions and 4 different ways to add event handlers.

Events

  • Click
  • DblClick
  • ContextMenu
  • MouseOver
  • MouseOut
  • MouseDown
  • MouseUp
  • KeyDown
  • KeyUp
  • KeyPress

Regions

  • Row
  • Cell
  • Header
  • HeaderCell
  • RowHeaderHeader
  • RowHeaderCell

The general naming convention is “on” + region + event. In our example, we want to trap the row double click event, so we would listen for onRowDblClick.

Attaching an Event Handler

You can attach an event handler using dojo.on(), grid.on(), dojo.connect(), or grid.connect()

Note that there’s a slight difference in naming based on whether you use on() or connect() — if you use on(), then you can omit “on” from the event name (rowDblClick rather than onRowDblClick)

The documentation suggests that you use grid.on() or grid.connect() because they will be cleaned up as the grid is destroyed, so there’s less chance for a memory leak.

Event Object

When an event handler is triggered, it provides an object with a number of useful properties for determining the location of the click so you can take appropriate action. The properties of the object vary based on the context, but some of the common properties are the rowId, rowIndex, columnId, columnIndex, and cellNode (DOM node of the current cell).

To access the object, include a parameter in your event handling function (the name is up to you) and use that to access the properties.

Opening a Document on Row Double Click

To open a document based on a row double click, we’ll use the row ID to get a handle to the related item in the data store, as shown in the last post.

grid.connect(grid, "onRowDblClick", function(eventInfo) {
  var unid = grid.row(eventInfo.rowId).item()['@unid'];
  location.href = "MyPageName.xsp?action=openDocument&documentId=" + unid;
}); 

Line 1 adds the event listener to the row double-click event.

Line 2 uses the event object to get the row ID and then uses that to retrieve the item from the data store and get the ‘@unid’ attribute.

Line 3 builds the new url to open an XPage and include the document UNID in the URL.

Note: Compiler throws an error on the location.href line related to &documentId. Needed to move the code from a tag on the page into an xp:outputScript tag.

This is better anyway, because the code within tags often gets reformatted and broken when other areas of the page are updated.

Follow

Get every new post delivered to your Inbox.

Join 60 other followers