Quantcast
Channel: XPages – Xcellerant
Viewing all 216 articles
Browse latest View live

XPages Tip: Fixing the Display of ComboBoxes in Read Mode

$
0
0

There’s a quirk with the display of combobox values when XPages are in read mode. Instead of just displaying the value, it generates a table with one row and one cell. This can cause problems with your form alignment if your fields are aleady in a table (especially a OneUI form layout table). This post contains a few lines of dojo code that can be used to fix the problem.

If you have a one-row two-cell table that contains a label and a combobox, it looks like this in the page source in Domino Designer:

<table>
  <tr>
    <td>
      <xp:label value="Label" id="label1" for="comboBox1"></xp:label>
    </td>
    <td>
      <xp:comboBox id="comboBox1" value="#{document1.Field1}">
        <xp:selectItem itemLabel="Value 1"></xp:selectItem>
        <xp:selectItem itemLabel="Value 2"></xp:selectItem>
        <xp:selectItem itemLabel="Value 3"></xp:selectItem>
      </xp:comboBox>
    </td>
  </tr>
</table>

But this is the output in read mode:

<table>
  <tr>
    <td>
      <label id="view:_id1:label1" for="view:_id1:comboBox1" class="xspTextLabel">Label</label>
    </td>
    <td>
      <table id="view:_id1:comboBox1">
        <tr>
          <td>Value 1</td>
        </tr>
      </table>
    </td>
  </tr>
</table>

Instead of just writing out the value of the combobox, it wraps it in a table.

(A regular field value is generally written out within a span tag that has the id of the control.)

When the combobox doesn’t have a value, then an empty table is inserted (no rows or cells):

<table id="view:_id1:comboBox1"></table>

This code, when run onClientLoad of the page, will fix this issue by replacing the table with just the value of the combobox.

if("#{javascript:document1.isEditable()}" == "false"){
  // Search for all nested tables with ids
  dojo.query('table td table[id]').forEach(function(node) {
    var value = '';

    // Locate the first table cell, which contains the value
    dojo.query('td:first-child', node).forEach(function(innerNode) {
      value = innerNode.innerHTML;
    });

    // Replace the table with only the value (or a blank)
    node.outerHTML = value;
  });
}

Line 1 tells it to only run in read mode. (Update the name of the document data source variable if you need to.)

Line 3 gets a handle on tables with ids that are nested inside of table cells.

Lines 7-9 search for the first cell within the table and retrieve it’s innerHTML, which is the value of the combobox. If there is no value, then there won’t be a table cell and it will replace the table with an empty string.

Line 12 replaces the original combobox table with just the value that needs to be displayed.

And now the output from the example shown above looks like this, as it should:

<table>
  <tr>
    <td>
      <label id="view:_id1:label1" for="view:_id1:comboBox1" class="xspTextLabel">Label</label>
    </td>
    <td>
      Value 1
    </td>
  </tr>
</table>

If you run into conflicts with this affecting other tables in your page, you may need to refine the selector in line 3.

If you need to preserve the of the element and/or wrap it in a span tag like other field values, you can tweak the code accordingly.



XPages Tip: Fixing the Display of Radio Button Groups in Read Mode with Dojo

$
0
0

In my last post, I showed a script that can be used to fix the display of combo boxes in read mode. As it turns out, the same code will fix radio button groups, because the output is the same!

The same code will also fix the display of single-value checkbox groups and listboxes. It will not properly handle multi-valued checkbox groups or listboxes, so I’ll be working on that next.

I have updated the comments on the XSnippet accordingly.


XPages Tip: Fixing the Display of Comboboxes, Radio Button Groups, Checkbox Groups, and Listboxes in Read Mode with Dojo

$
0
0

With a couple of minor adjustments to the code shown in a previous post, I now have a script that will fix the display of comboboxes, radio button groups, checkbox groups (single or multi-valued), and listboxes (single or multi-valued) all in one fell swoop!

The output of a single-value for any of these field types looks like this:

<table id="id">
  <tr>
    <td>value </td>
  </tr>
</table>

However, if you have a field with multiple values, it separates each value out into its own row, so the previous code needed to be adjusted to read the values out of all cells in the nested table. This code will concatenate multiple values to be separated by a comma and a space, but you can easily change that by modifying the code below.

<table id="id">
  <tr>
    <td>value 1</td>
  </tr>
  <tr>
    <td>value 2</td>
  </tr>
  <tr>
    <td>value 3</td>
  </tr>
...and so on...
</table>

This code, when run onClientLoad of the page, will fix all of these fields types, by replacing the table with just the value of the field, concatenating multiple values as needed.

if("#{javascript:document1.isEditable()}" == "false"){

  dojo.query('table td table[id]').forEach(function(node) {
    var value = '';

    // Get the value out of all cells in the nested table and concatenate them
    dojo.query('td', node).forEach(function(innerNode) {
      value += innerNode.innerHTML + ', ';
    });

    // Replace the table with only the value(s) (or a blank), but cut off the trailing comma
    node.outerHTML = value.substring(0, value.length-2);
  });
}

Line 1 tells it to only run in read mode. (Update the name of the document data source variable if you need to.)

Line 3 gets a handle on tables with ids that are nested inside of table cells.

Lines 7-9 search for all table cells within the table and retrieve each cell’s innerHTML, which contains a value. If there is no value, then there won’t be a table cell and it will replace the table with an empty string.

Line 12 replaces the nested with just the value that needs to be displayed.

And now the output from the example shown above looks like this, as it should:

If you run into conflicts with this affecting other tables in your page, you may need to refine the selector in line 3.

If you need to preserve the of the element and/or wrap it in a span tag like other field values, you can tweak the code accordingly.

XSnippet

The latest version of the code is posted as an XSnippet on OpenNTF


Accessing the Value of Components within a Repeat Control from Outside

$
0
0

As a general rule, XPages variable resolution makes it very easy to access components within the same instance of a repeat control, but very difficult to access a component that’s within a repeat control from outside of it. In this post, I’ll show you you can configure the repeat control and define component IDs in a way that you can access them from outside of the repeat control.

1. Set the “Create Controls at Page Creation” Property

By default, the JSF component tree only includes one copy of each component in for the repeat control and it iterates over it as many times as needed to generate each instance of the repeat. I’m not aware of a way to access an individual instance of a component this way.

This is where the Create controls at page creation property of a repeat control comes into play. This property adds the repeatControls attribute to your repeat control tag and sets it to true. When enabled, it causes an instance of each component to be created for each instance of the repeat control in the JSF tree.

RepeatControls

2. Dynamically-Assign Component IDs Based on the Repeat Index

In order to access a specific control within a specific instance of the repeat, I need to know what its name is. I need to assign a unique ID to each instance of each component in order to be able to access it.

With inspiration from this great blog post by Chris Toohey (which was, in turn, assisted by Tim Tripcony), I found a way to make all of this work.

As Chris pointed out, you cannot compute component IDs dynamically, but you can compute them on page load.

By setting the Index name property of the repeat control (see screen shot above), I’ll have an index variable available for each instance of the repeat control. To create a unique name, I took the existing component name and updated it to dynamically add a suffix based on the index variable.

There’s no blue diamond to compute the ID of a component, so you have to go into the source and change it directly.

<xp:comboBox id="MyComboBox_${rptIndex}">

Now the component is uniquely but predictably named and can be accessed as needed!

Example Repeat Control Source

Here’s the source of the repeat control from my simple sample XPage. Each instance of the repeat control displays a combobox with a few hard-coded options. An array with 4 elements is passed to the repeat control in order to create 4 instances of the repeat. (The values in that array are not used at all in this simplistic example.)

<xp:repeat id="repeat1" rows="30" indexVar="rptIndex" repeatControls="true">
  <xp:this.value>
    <![CDATA[#{javascript:return ['aa', 'bb', 'cc', 'dd']}]]>
  </xp:this.value>
		
  <xp:comboBox id="MyComboBox_${rptIndex}">
    <xp:selectItems>
      <xp:this.value><![CDATA[#{javascript:return ['', '1', '2', '3', '4'];}]]></xp:this.value>
    </xp:selectItems>
  </xp:comboBox>
  <xp:br /><xp:br />
</xp:repeat>

Checking the Component Values

The code check the values within the repeat control to can be dynamic. Since I don’t know how many instances there will be when using this in a more dynamic application, I set it up to look for a component within the repeat and loop until it doesn’t exist with a next index suffix.

Here is sample SSJS code on a button on the page (outside of the repeat control) that will check the value of the combobox within each instance of the repeat control and print the value to the server console.

var i=0;
var boolContinue = getComponent('MyComboBox_' + i);
while (boolContinue) {
  print ('value ' + i + ': ' + getComponent('MyComboBox_' + i).getValue());						
		
  // Check whether there's another RCA form an determine whether to continue
  boolContinue = getComponent('MyComboBox_' + ++i);
}

Line 2 sets a boolean value based on whether the component in the first instance of the repeat control can be found. (If there are no entries in the repeat control, then the code will not proceed.)

Line 4 accesses the value of the control with the index suffix and prints the value.

Line 7 checks if there’s another instance of the control with the next suffix number and determines whether to continue based on that.

Proactive Disclaimer

I know there are some (**cough** Tim **cough) who would strongly suggest that I read data from the document directly rather than try to access the components in this way. As a general rule, I wholeheartedly agree. However, the use case that necessitated this workaround is that it’s for form validation for related documents within a repeat control and, with the method of validation I’m using, I need to access the components in order to mark them as invalid as needed.


XPages Data Views – Part 1: Overview

$
0
0

The Data View control in XPages is easy to create like a view panel, but highly flexible like a repeat control or data table, which makes it easy to create good-looking and highly-functional views very quickly. In this series, I’ll show how to make use of its many features and customize the content to create more modern data displays in your applications.

I recorded two NotesIn9 shows (Part 1 – Implementation and Part 2 – Customization) after learning the Data View, but I also want to write about many of the features so I can go more in depth to explain them further, show where all the settings are, share some code, and have it all be easily searchable.

One of the great features of this control is that it works well on a mobile device, but in this series, I’ll be focusing on designing for the full browser. You can find more information on using the data view on a mobile device in these NotesIn9 shows recorded by Peter Presnell and Kathy Brown.

Features

Here are some of the great features of the Data View control that will be covered in the series:

  • Property-driven simple configuration
  • Flexible summary layout
  • Built-in link to open document
  • Collapsible details section
  • Multi-column layout
  • Categorization
  • Response hierarchy
  • Icon columns
  • Selection checkbox
  • Pager More Rows control
  • Pager Save State control

Example

Here’s a screen shot from the Domino App Dev Wiki that shows one example of what a Data View can look like (without a collapsible Details section):

Data View Example Domino App Dev Wiki

Layout

This screen shot highlights the different aspects of another data view control, so you can get familiar with the terminology and the placement of each component.

DataViewDesign

Availability

The Data View control is not a core control, so it will not always be available in Domino Designer. It is available if you have any of the following configurations:

  • Extension Library
  • Notes 8.5.3 with Upgrade Pack 1
  • Notes 9

Up Next

In the next post, I’ll step through how to create a Data View, taking a look at the minimum requirements to get it up and running and adding a few features from there.


XPages Data Views – Part 2: Creating a Data View

$
0
0

In the first part of this series, we talked about the Data View control and it’s features at a high level. In this post, we’ll see how to create a minimal data view. We’ll then look at how to compute the summary column and add extra columns and categorization.

Data View Design – Key Point

The most important thing to understand with the data view is that, in it’s default layout, it revolves around a single piece of information called the Summary Column.

Before you can create an effective data view, you need to know what the summary will be. The summary is the main link that opens the document and it’s the primary piece of information that identifies the document. It can be a single column from the underlying view or it can be a computed value that combines multiple pieces of information.

Minimum Steps to Create a Data View

At minimum, the Data View control needs a data source and a summary column.

In its simplest form, you can create a data view with 3 steps:

  1. Add a Data View control to the page (under Extension Library)

    DataView2_A

  2. Set the data source. You can do this at the time you drag and drop or later in the Data subtab of the Data View properties.

    DataView2_B

  3. Set the Summary column. All Properties > format > summaryColumn < + (then enter the columnName)

    DataView2_C

Now I have a Data View. It isn’t terribly useful yet, but it is a list of active links that will open the documents.

DataView2_D

The example shown here uses data from David Leedy’s FakeNames database. I have a view with a column that combines the first and last name into a single column, called fullname.

If your view has more documents than the data view is configured to display (via the rows property), you can drag and drop a pager control into one of the pager facets on the data view. (We’ll take a look at another method of navigation later in the series.)

I combined the first and last name fields in an underlying view column, so I could easily use that single column as the summary.

Column Names

The Data View does not provide a method of selecting the column name — you need to type it in manually. (This goes for all Data View column names.)

The name must match the programmatic name of the underlying view column. For columns that display a single field, it will generally be the name of the field. For computed columns, it will generally start with $ and end with a number.

In my example, I created a computed column, but changed the programmatic name of the column to something that was easy to remember.

Document Links

The column value defined as the summary will automatically be activated as a link that will open the document.

By default it will use the XPage associated with with document’s form, but you can change that to specify the page to use in the Data View properties.

DataView2_E

Computed Summary Value

If you need to compute the summary value (because you don’t have a single view column that uniquely identifies the data well enough), you can compute the value of the summary column.

First you need to set the var property of the data view in order to have a handle to the underlying view entry.

DataView2_F

Then you can compute the value with SSJS in the value property of the summary column.

DataView2_G

return dvEntry.getColumnValue('fullname') + ', ' + dvEntry.getColumnValue('occupation');

Now, the data view displays a summary that combines the person’s name and occupation.

DataView2_H

Note: If you set both the columnName and value properties of the summaryColumn, the computed value will take precedence.

Extra Columns

We have a working data view, but what we’ve provided so far generally isn’t going to be enough information when used in a full browser. (On a mobile device, a summary column is sufficient.)

To add a few more pieces of information, we can add Extra Columns to the data view.

You add them under All Properties > format > extraColumns. You can click on the plus (+) button to add a column and then manually set the columnName property. In this example, I’ve added the phone number and birthday.

DataView2_I

Here is the result:

DataView2_J

As you can see, extra columns are right-justified on the screen.

The data view is not designed to display a bunch of columns like a regular view panel, so use extra columns judiciously.

Column Titles

You can add column titles by setting the Show column titles property of the data view and setting the columnLabel property on each column. Personally, I think they look good in this type of layout, but the option is there if you need them.

DataView2_N

Styling Provided by OneUI

The Data View is designed to work with OneUI. You can certainly add your own styling with the provided class properties, but you get a much nicer look
and feel out of the box if you’re using a OneUI theme, which the preceding examples show.

Here’s the same data view as the previous screen shot, but without a OneUI theme in place.

DataView2_K

Categorization

Another useful feature that the Data View provides (and most other controls don’t) is the ability to display categorized views.

All you have to do is go to All Properties > format > categoryColumn and click the plus (+) button to add a category column. Then manually enter the
categorized column name from the underlying view.

DataView2_L

In my example, I have switched the data view to display a view categorized by state. Here is the result:

DataView2_M

You can have multiple levels of categorization, provided the underlying view supports that categorization.

Up Next

In the next post I’ll demonstrate the feature that I think makes the Data View control truly great — the collapsible Detail section.


XPages Data Views – Part 3: Collapsible Details

$
0
0

In the last post we looked at how to create a Data View, compute the summary column and add extra columns and categorization. This post will demonstrate how to add what I believe is the killer feature of the Data View control — the collapsible detail section, which provides the ability to make more information available, yet not clutter the screen with it until the user requests it.

Data View Series

Adding Details

Starting with one of the examples from the last post, we’ll add the person’s full address to the Details section.

To add information to the Details section, simply drag and drop a Computed Field control onto the detail facet of the Data View (the green circle). Then set the value of the field.

DataView_3_A

In order to get information from the underlying view entry, you’ll need to set the var property of the data view in order to provide that handle to the view entry. (I’ve set my var property to dvEntry.) I also set the Content type of the computed field to HTML, since I want to insert break tags between the lines of the address.

Here’s the value of my computed field:

var address = dvEntry.getColumnValue('address') + '';
address += dvEntry.getColumnValue('city') + ', ';
address += dvEntry.getColumnValue('state') + ' ';
address += dvEntry.getColumnValue('zip') + '';
address += dvEntry.getColumnValue('country');
return address;

(As your details get more elaborate, you’ll want to drag a panel or div into the detail facet and add controls there.)

In order to see the details, you’ll need to set one of two Display Options properties of the data view — Show details by default or Can collapse details.

DataView_3_B

Show details by default

The Show details by default property will automatically show the details of every entry in the data view. (It’s the same property as All Properties > basics > expandedDetail.)
Here’s what it looks like if I set the property:

DataView_3_C

Can collapse details

The Can collapse details property will default all detail sections to being collapsed and will provide an expand/collapse link on the right-hand edge of each entry in the data view. When you click on that link, it will toggle the details section for that entry. (This is the same property as All Properties > format > collapsibleDetail)

Here’s what it looks like if I set this property:

DataView_3_D

This is a tremendous feature! You can add any amount of additional data in the details without cluttering up the screen. This provides user-driven interactivity. It can also help your views load faster because you don’t need to show the details until they are requested.

I’ve used this section to create repeat controls with documents related to the parent document. It can contain a form to enter new data. (Both of these techniques were demonstrated in Part 2 of my series on the Data View on NotesIn9.) The possibilities are endless.

detailsOnClient

By default, the detail sections are not loaded. The expand/collapse link will hit the server to request the details as they are needed. However, you have the option to pre-load all of the detail sections on the client with the detailsOnClient property. (All Properties > basics > detailsOnClient)

Here’s the source of the first entry (while still collapsed) in the data view when the detailsOnClient property is false (or not set):

<tr id="view:_id1:dataView1:0:_row" class="lotusFirst">
<td class="lotusFirstCell" style="width: 100%">
<div>
<h4 id="view:_id1:dataView1:0_sum" style="margin: 0px; opacity: 1;">
<a id="view:_id1:dataView1:0_sumLink" href="/DataViews.nsf/%24%24OpenDominoDocument.xsp?databaseName=Server/LocalDev!!DataViews.nsf&documentId=E48D147AD012645905257838007ABBEA&action=editDocument">Adam Gonzales</a>
</h4>
</div>
</td>
<td class="lotusMeta lotusNowrap">212-774-8218</td>
<td class="lotusMeta lotusNowrap">Feb 8, 1952</td>
<td class="lotusRight lotusLastCell">
</tr>

Lines 4-6 define the summary column and lines 9-10 show the extra columns.

Here’s the source of the first entry when it is expanded:

<tr id="view:_id1:dataView1:0:_row" class="lotusFirst">
<td class="lotusFirstCell" style="width: 100%">
<div>
<h4 id="view:_id1:dataView1:0_sum" style="margin: 0px; opacity: 1;">
<a id="view:_id1:dataView1:0_sumLink" href="/DataViews.nsf/%24%24OpenDominoDocument.xsp?databaseName=Server/LocalDev!!DataViews.nsf&documentId=E48D147AD012645905257838007ABBEA&action=editDocument">Adam Gonzales</a>
</h4>
<div id="view:_id1:dataView1:0_detail" style="opacity: 1;">
<span id="view:_id1:dataView1:0:computedField1" class="xspTextComputedField">
392 Shinn Street
<br>
New York, NY 10021
<br>
US
</span>
</div>
</div>
</td>
<td class="lotusMeta lotusNowrap">212-774-8218</td>
<td class="lotusMeta lotusNowrap">Feb 8, 1952</td>
<td class="lotusRight lotusLastCell">
</tr>

Lines 7-16 show the detail section that has been inserted.

Here’s what the collapsed first row looks like when the detailsOnClient property is set to true:

<tr id="view:_id1:dataView1:0:_row" class="lotusFirst">
<td class="lotusFirstCell" style="width: 100%">
<div>
<h4 id="view:_id1:dataView1:0_sum" style="margin: 0">
<a id="view:_id1:dataView1:0_sumLink" href="/DataViews.nsf/%24%24OpenDominoDocument.xsp?databaseName=StepanDev/LocalDev!!DataViews.nsf&documentId=E48D147AD012645905257838007ABBEA&action=editDocument">Adam Gonzales</a>
</h4>
<div id="view:_id1:dataView1:0_detail" style="display: none">
<span id="view:_id1:dataView1:0:computedField1" class="xspTextComputedField">
392 Shinn Street
<br>
New York, NY 10021
<br>
US
</span>
</div>
</div>
</td>
<td class="lotusMeta lotusNowrap">212-774-8218</td>
<td class="lotusMeta lotusNowrap">Feb 8, 1952</td>
<td class="lotusRight lotusLastCell">
</tr>

Lines 7-16 define the detail section, but notice line 7 specifically — the detail data is there, but its style is set to display: none; When the row is expanded, the style simply changes to display:block; opacity: 1;

There’s a tradeoff. Set it to true if you can wait longer to load, but want faster toggling. Set to false for faster initial load, but every expand/collapse hits the server.

disableHideRow

One more property related to detail sections is disableHideRow (All Properties > format > disableHideRow). This lets you compute whether the expand/collapse link should be displayed on a row-by-row basis.

Extra Columns and Details

I mentioned in the first post that the Data View is not intended for the display a lot of extra columns. This comes into play when you have both extra columns and a details section.

The most important thing to be aware of is that details cannot use the space underneath extra columns.

You can see it in the Data View layout (the first screen shot on this page); the detail section’s width stops where the extra columns start.

Up Next

In the next post, I’ll show how to add icons to the Data View.


XPages Data Views – Part 4: Icon Columns

$
0
0

The Data View control layout includes a placeholder for an icon column. In this post, I’ll show how to use this feature and dynamically detemine the icon to display.

Data View Series

Example

This screen shot shows an example that was demonstrated in the first NotesIn9 video on the Data View control that I recorded

DataView_4_A

Icon Column

The icon column in the data view does display icon columns from an underlying Notes client view. Instead, you provide a list of available icons and specify the value from an underlying column that would cause the icon to be displayed.

Icon columns are defined under All Properties > format > iconColumn.

1) Define the columnName from the underlying view that will provide data.

2) Click the plus (+) icon in the icons property to add an icon and define the url path to the icon. If you click into the url field, you will see a folder icon that will provide a list of images in the current database to choose from.

3) Define the selectedValue property. When the data in the underlying column matches the selectedValue property, the icon will be displayed.

DataView_4_B

In this example, the column from the underlying view is named $2. The first icon is set to be displayed if the column value is 1. The second icon is defined to be displayed when the underlying view column is 2, and so on.

Another option that you have is to compute the URL for the icon to display.

A third option that you have is to set the selected property of the icon and compute a value that returns true or false, based on whether you want to display the icon.

Up Next

In the next post, I’ll show how to use the Pager Add Rows control to provide a more modern method of view navigation than a pager.



XPages Data Views – Part 5: Pager Add Rows Control

$
0
0

The Pager Add Rows control is simple to add, but it provides a great feature for navigation in your Data Views. In this post, I’ll show how to use it.

Data View Series

Pager Add Rows Control

The Pager Add Rows control provides a different way to navigate the data in your Data View. You’ve probably seen pagers in a lot of view controls (and that’s an option here as well), but the Pager Add Rows control provides a more modern interface.

When the user gets to the end of the number of rows shown on the page, there’s a link to add more. The user can continue to add more rows until the end of the data set is reached, at which point the link will be disabled (but still visible).

This is critical in a mobile application, but it can also be very useful in full browser applications as well. It allows you to limit the number of entries loaded initially, but still allow the user to continue viewing more data as needed.

DataView_5_0

Adding the Control

The Pager Add Rows control can be found in the Extension Library section of the Controls view.

DataView_5_A

Just drag and drop it into a facet of the Data View control. It does not need to be bound specifically — it will automatically work when added to a fact.
DataView_5_B

Properties

You can use the text property to change the text of the link that adds more rows.

There are several properties that allow you to adjust partial refresh and partial execution settings, but none of them are necessary for the control to work. I tested it with the default settings (all of those properties blank) and it appeared to only partially execute and partially refresh the data view itself. But there are exceptions to this rule, noted below.

When you click the Show more… link, it will display an additional set of rows. By default, the number of rows will be the same as the number of rows shown in the Data View (per the rows property). You can change this by setting the rowCount property of the Pager Add Rows control. However, it also seems to require the refreshPage property set to true or a custom setting does not take effect, regardless of whether you hard-code or compute the rowCount.

Enhancements

One minor enhancement is to hide the Pager Add Rows control if there aren’t more documents in the view than can be displayed, based on the Data View’s rows property. This code on the rendered property of the Pager Add Rows control will do the trick:

var dv = getComponent('dataView1');
return (dv.getRowCount() > dv.getRows());

It reads the rows property of the Data View, so it can be used as is on any Pager Add Rows control.

This will work on the initial page display without the refreshPage property being set. However, if that property is set, it will also hide the control when the end of the data set is reached.

It’s interesting to note that the getRows() method of the Data View always seems to return a number slightly higher than the number currently being displayed. That seems like good design for performance.

Another enhancement you can provide is to give the user a way to define how many rows the pager will add. If you compute the rowCount property to read a value from a combobox on the page, you can make this work. The combobox’s onchange event must trigger a partial refresh on the Pager Add Rows control (to update the computed row count) and the refreshPage property of the Pager Add Rows control must be set to true.

Here’s the source code for a combobox and Pager Add Rows control where this works (and also includes the code to hide the control when there are no more rows):

<xp:comboBox id="cbNumRows" xp:key="pagerBottomLeft" defaultValue="10">
  <xp:selectItem itemLabel="10"></xp:selectItem>
  <xp:selectItem itemLabel="25"></xp:selectItem>
  <xp:selectItem itemLabel="50"></xp:selectItem>
  <xp:eventHandler event="onchange" submit="true"
    refreshMode="partial" refreshId="pagerAddRows1">
  </xp:eventHandler>
</xp:comboBox>
<xe:pagerAddRows id="pagerAddRows1" xp:key="pagerBottom" refreshPage="true">
  <xe:this.rendered><![CDATA[#{javascript:var dv = getComponent('dataView1');
return (dv.getRowCount() > dv.getRows());}]]>
  </xe:this.rendered>

  <xe:this.rowCount><![CDATA[#{javascript:print ('row count: ' + parseInt(getComponent('cbNumRows').getValue()));
return parseInt(getComponent('cbNumRows').getValue());}]]>
  </xe:this.rowCount>
</xe:pagerAddRows>

Up Next

In the next post, I’ll show how to use the Pager Save State control to allow users to restore the previous state of expanding/collapsing when returning to the view later in the session.


XPages Data Views – Part 6: Pager Save State Control

$
0
0

The Pager Save State control is another great feature available to work with a Data View. It allows you to restore the expand/collapse state of each element in the view to the state the user last left it.

Data View Series

By default, any time you open a Data View, it will open with all categories and details sections collapsed, regardless of any changes that the user made to the state previously. With the Pager Save State control, it’s easy to maintain the previous state and restore it when the user returns to the view.

Adding the Control

1. Drag and drop a Pager Save State control onto the page from the the Extension Library section of the controls palette.

DataView6_A

It looks like a gold 3.5″ floppy disk icon in Domino Designer.

DataView6_B

2. Set the for property of the control to the id of the Data View.

Using the Control

3. To make use of the control, you need to execute a single line of SSJS that will make use of the Pager Save State Bean that the control provides and restores the view state.

viewStateBean.restoreState = true;

Just call this before re-opening the Data View and it will restore the state as it was left. If the user has used the Pager Add Rows control to add more rows to the view, it will also restore the same number of rows that were last displayed.

In addition to working if you’re using SSJS to return to the view, you can make it work if you’re using Simple Actions as well. For example, if you’re using an Open Page Simple Action to return to the view, you can add an Execute Script simple action before it that contains that one line of code.

Up Next

In the next post, we’ll take a look at how to take your Data View UI to the next level by customizing the Summary section.


The Side Effect of Creating Repeat Controls at Runtime

$
0
0

In a recent post, I showed how to access the value of components within a repeat control from outside. While the technique served a great purpose in a recent application, there is a significant side effect that you need to be aware of before implementing a similar solution.

The technique described in the post requires all controls within the repeat to be created at runtime and dynamically but consistently named (based on the repeat index) so they can be programmatically accessed in a predictable manner.

I had a good discussion about this topic with Tim Tripcony and he pointed out that the side effect of the Create controls at page creation property of the repeat control is that all of the controls within the repeat are locked into place at page creation. This means that you cannot dynamically update the repeat control. A partial refresh won’t do it. A full refresh won’t even do it.

I saw this side effect in my application. In order to see any updates to the repeat control while the page is still loaded required context.reloadPage().

That’s still fine in my case, but it wouldn’t be fine in many cases where I use repeat controls, so please keep it in mind that setting that property will prevent you from being able to update a repeat control with a partial refresh.


XPages Data Views – Part 7: Customizing the Summary Section

$
0
0

The ability to customize the summary section allows you take the interface of the Data View to another level. You’re not limited to just a link based on the summary column — you can take full control over the layout and add more information.

Data View Series

Custom Summary Examples

For the sake of comparison, here’s a data view with just a summaryColumn defined:

DataView7_1

Let’s take a look at a few examples of Data Views with customized summary sections.

Here’s an example from the second NotesIn9 video I did on the Data View control. It’s nothing fancy, but you can see the concept of adding more information to the summary. Additional information can still be included in the collapsible detail section.

DataView7_2

Here’s an example from IBM Domino Developer wiki. This summary includes graphics and 3 lines’ worth of information.

DataView7_3

Here’s an example from an application that I recently worked on with Kathy Brown, master of icons. The images are used to convey information without requiring labels that would repeat on every row.

DataView7_RAIN_Sample

The possibilities are endless.

Customizing the Summary

All you have to do to customize the summary section is to drag and drop a container control (panel or div) into the summary facet of the data view, then put whatever you want inside that container.

You’ll need to use the Data View variable (var property) to access information in the view entry.

Creating Your Own Link

One thing to keep in mind is that you will have to manually add the link to open the document if you create a custom summary.

In order to pick up the same styling as the default summary column data view link, use a Computed Field control, set it’s Content type to HTML and output the link as an <a> tag within an <h4> tag.
You’ll then need to build link to open the document.

Here’s an example, assuming the var property of the data view is set to rowHandle.

return "<h4><a href='PageName.xsp?openDocument&documentId=" + rowHandle.getUniversalID() + "'>" + rowHandle.getDocument().getItemValueString('FieldName') + "</a></h4>";

XPages Data Views – Part 8: Sorting and Filtering

$
0
0

There are several properties available for searching and filtering a data view. In this post, I’ll show how to use them.

The Data View properties make a few of these features prominently available.

DataView8_A

Data View Series

Sort column

The Sort column property allows you to choose a column on which the data view should be sorted. The combobox will give you a list of all columns in the underlying view.

However, you need to be aware that the underlying view column must have that sort option available (“click oncolumn header to sort”) or it won’t work.

The data view will be sorted the way the underlying view is sorted by default. You can choose an existing column, but you can also compute the value.

To add even more flexibility to your view, you can provide links or a combobox to let the user choose the sort option.

Here’s how you can make it happen:

1) Put a combobox on the page with a list of columns that are viable sort options for the view. (You can event put it in one of the pager top facets of the data view to tie it in.)
2) Bind the combobox to a sessionScope variable
3) Set the onchange event of the combobox to trigger a partial refresh on the data view
4) Compute the Sort column property to return that sessionScope variable

Filter by column value

The Filter by column value property sets the keys property of the data source (which is also available on other view data sources).

You can enter or compute a value here that will set the ‘keys’ property and filter out the data based on the sorted column in the view, which is the default sorted column or the column defined in the Sort column property.

Just like with a search field, you can provide the user a field to type and filter the data. You can provide a highly flexible experience for the user if you allow them to choose both the sort column and the filter to apply to that column.

Search in view results

Searching and category filtering work the same as view data sources in several other data display controls. For an example of how to implement searching, take a look at this post I wrote about searching with the View Panel control.


XPages Data Views – Part 9: Multi-Column Layout

$
0
0

Another great feature of the Data View control is its ability to easily provide a multiple-column layout. In this post, I’ll show you can use that property to let the user dynamically determine the number of columns to display.

Data View Series

Multiple Column Layout

If your data lends itself to a multiple-column layout (e.g. a business card-style display), you can easily achieve this by setting the multiColumnCount property of the Data View. (All Properties > format > multiColumnCount)

DataView9_A

You can still expand/collapse detail sections when multiple columns are used.

Giving the user control

Taking this a step further, you can compute the property and give the user the ability to adjust the display as desired.

The steps are virtually the same as shown in the last post on sorting and filtering.

1) Put a combobox on the page with options for the number of columns to display. (You can event put it in one of the pager top facets of the data view to tie it in.)
2) Bind the combobox to a sessionScope variable
3) Set the onchange event of the combobox to trigger a partial refresh on the data view
4) Compute the Sort column property to return that sessionScope variable


MWLUG – Presentation Slide Decks


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

$
0
0

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

XPages Data Views – Part 10: Nested Repeat in the Detail Section

$
0
0

The great benefit of the collapsible detail section in the Data View control is that you can make a lot more information available in the view, but not clutter the screen with it unless the user requests it. I’ve had several cases where I’ve created a repeat control in the detail section and used it to display information related to the main document. In this post, I’ll show how to do it.

Data View Series

Nested Repeat Control

Here’s an example from the NotesIn9 video I did on customizing the Data View control.

DataView10_A

The sample database has a list of companies and a list of stock prices documents related to each company. When the user expands a company in the Data View, they see the list of related stock prices (along with a company description).

Here are the steps:

  1. Set the var property of the data view to provide a handle to each entry
  2. Create a repeat control in the detail section. (Add a panel or div to the Detail section and add the repeat control within that container.)
  3. Compute the value of the repeat control (All properties > data > value) to retrieve the ID of the main document and use it to look up related documents to display in the repeat control

Here is the code that populates the repeat control:

var vwPrices:NotesView = database.getView('Prices');
if (rowHandle.isDocument()) {
  var companyID = rowHandle.getDocument().getItemValueString('CompanyID');
  var vecPrices:NotesViewEntryCollection = vwPrices.getAllEntriesByKey(companyID);
  return vecPrices;
} else {
  return null;
}

The key to making this happen is having the ability to retrieve the UNID of the main document when populating the repeat control. In this example, the var property of the Data View is set to rowHandle and it used in line 3 to retrieve the CompanyID.

In line 4, the list of related stock prices is looked up from a view.

In line 5, the viewEntryCollection of price documents is returned to be the source of the repeat control.

At this point, the repeat control has the data and you just need to add computed fields to display it like you would with any repeat control.


XPages Data Views – Part 11: Custom Expand/Collapse Links

$
0
0

If you’re not a big fan of the built-in small expand/collapse icon that sits off to the right of each entry (IMHO, it works well on a mobile device but is not a great interface in a full browser), you can create your own. In this post, I’ll show how to create your own links when the details are on the server or on the client. I’ll also point you in the right direction to work around a bug in Notes9.

Data View Series

Example

Here’s a very simple example of how it can look with your own expand/collapse icon:

DataView11_A

Creating Your own Expand/Collapse Link – Details On Server

At a high level, here are the steps:

  1. Add images resources to your application
  2. Create a custom summary section and display the images that will be used to toggle
  3. Add code to toggle the images
  4. Add code to take care of the expand/collapse and trigger a partial refresh as needed
  5. Optionally hide the built-in link

There differences in how to implement it, based on both the Data View’s detailsOnClient property and the version of Notes that you’re using.

Expand/Collapse Images

To start, we’ll set up two images that the user can click to expand or collapse the details.

They’ll need to be displayed in the summary section, so we’ll have to customize the summary as shown in this post. Add two image resources to your database (one for expand and one for collapse). To display them next to the summary link, you’ll have to use CSS or put them in a table.

Since the details will be collapsed by default, we want to display the ‘expand’ image and hide the ‘collapse’ image. We also want their display to toggle as the details section toggles. Since we’re using a server-side refresh to retrieve the details, we’ll use server-side logic to determine whether the images are displayed.

The rendered formula for the ‘expand’ icon is this:

return !viewScope.containsKey('Row_' + getComponent('dataView1').getRowIndex());

The rendered formula for the ‘collapse’ icon is this:

return viewScope.containsKey('Row_' + getComponent('dataView1').getRowIndex());

The scope variable that is referenced will be added and removed in the code shown in the next section. It will be effective because the event code will trigger a partial refresh on the data view.

The next step will be to add the code that actually expands or collapses the section.

Details on Server

The default behavior of the Data View is that the expand/collapse link will make a request to the server to retrieve the details section for that entry. We can recreate this link with either the toggleDetailVisible() or setDetailVisible() methods of the data view.

Paul Withers showed how to use the toggleDetailVisible() method with SSJS in this post on Stack Overflow.

var idex=getComponent("dataView1").getRowIndex();
getComponent("dataView1").toggleDetailVisible(@Text(idex+1));

The same code can be applied to both the expand and collapse images. The server-side event also needs to trigger a partial refresh on the data view so you’ll see the changes.

We just need to add an additional line that also sets or removes the scope variable that is used to determine whether the expand or collapse link is displayed.

Here’s the full source of the expand and collapse images, including the code to toggle the detail section, show or hide the scope variable, and partially refresh the data view:

<xp:image url="/plus.png" id="imgExpand"
  rendered="#{javascript:return !viewScope.containsKey('Row_' + getComponent('dataView1').getRowIndex());}">
  <xp:eventHandler event="onclick"
    submit="true" refreshMode="partial" refreshId="dataView1">
    <xp:this.action><![CDATA[#{javascript:var idex=getComponent("dataView1").getRowIndex();
      viewScope.put('Row_' + idex, '');
      getComponent("dataView1").toggleDetailVisible(@Text(idex+1));}]]>
    </xp:this.action>
  </xp:eventHandler>
</xp:image>
<xp:image url="/minus.png" id="imgCollapse"
  rendered="#{javascript:return viewScope.containsKey('Row_' + getComponent('dataView1').getRowIndex());}">
  <xp:eventHandler event="onclick"
    submit="true" refreshMode="partial" refreshId="dataView1">
    <xp:this.action><![CDATA[#{javascript:var idex=getComponent("dataView1").getRowIndex();
      viewScope.remove('Row_' + idex);
      getComponent("dataView1").toggleDetailVisible(@Text(idex+1));}]]>
    </xp:this.action>
  </xp:eventHandler>
</xp:image>

If you need finer control over the state, you can use the setDetailVisible() method instead of the toggleDetailVisible() method. The difference with this method is that you pass a second parameter (true or false) to the setDetailVisible() method in order to set the visibility state.

Side Note: I was able to figure these things out via two great resources for learning XPages — Stack Overflow and NotesIn9. The toggleDetailVisible method was described by Paul Withers in the Stack Overflow post referenced above, and I used the method described in this video (also by Paul Withers) on NotesIn9 to figure out that there is also a setDetailVisible() method.

Workaround for Bug in Notes 9

Unfortunately, there appears to be a bug in Notes9 that prevents the toggleDetailVisible() method from working.

The workaround is to make the expand/collapse links trigger a click() event on the built-in expand/collapse link.

Henry Newberry worked out the code and posted it on the same Stack Overflow post mentioned above, so you can find it there.

Expand/Collapse with Details On Client

The code shown in both solutions above will work regardless of the detailsOnClient property, but if we’re using the extra overhead to pre-load the details into the client, it’s a waste of resources to hit the server to partially-refresh the view anyway.

When the detailsOnClient property is set to true, a div tag with each detail section is already on the page, but hidden with css.

Here’s an example of the detail section for the first entry in the view:

<div id="view:_id1:dataView1:0_detail" style="display: none">
  <span id="view:_id1:dataView1:0:computedField1" class="xspTextComputedField">
    392 Shinn Street
    <br></br>
    New York, NY  10021
    <br></br>
    US
  </span>
</div>

Since the information is already on the page, it will be much more efficient if we use client-side javascript to toggle the image display and toggle the detail section display. This way, there’s no need to send any requests to the server.

Expand/Collapse Images

To do this, I set the styleClass of the ‘collapse’ image to ‘hidden’ and added this css to a style sheet that’s included on the page:

.hidden {
  display:none;
}

Next, I added this same block of client-side JavaScript code to both images:

idCollapse = '#{id:imgCollapse}'.replace(/:/gi, "\\:");
idExpand = '#{id:imgExpand}'.replace(/:/gi, "\\:");
dojo.query('#' + idCollapse).toggleClass('hidden');
dojo.query('#' + idExpand).toggleClass('hidden');

I wanted to use the dojo toggleClass() method to add/remove the ‘hidden’ class from each image. However, dojo.query() doesn’t like the colons that are prevalent in XPages element ids, so I adapted code from Mark Roden’s jQuery XSnippet to format ids that dojo.query() can handle. The toggleClass will remove the class from the element if it has it and it will add the class to the element if it does not already have it. (This block of code will also work as is if you only have a single image/link/button that will both expand and collapse.)

At this point, we have image to use for expanding and collapsing and they’re set up to toggle based on which option has been clicked.

Expand/Collapse Logic

To toggle the visibility of the detail section, we need to be able to get the handle to it. Fortunately, the names of each section can be derived from the name of the data view and the (0-based) row number, in this format:

[dataViewID]:[rowNum]_detail

In this example, here is the ID of the Data View is view:_id1:dataView1 and the id of the detail section is view:_id1:dataView1:0_detail.

Fortunately, it’s pretty easy to retrieve. When you retrieve the ID of the data view from within the data view, it also includes the row number! To retrieve the ID of the detail section, all you have to do is append ‘_detail’!

Here is the client-side code on the ‘expand’ link that will toggle both the image and detail section display. The code on the ‘collapse’ image is identical, except that the last line sets the display style of the detail section to ‘none’, rather than ‘block’.

idCollapse = '#{id:imgCollapse}'.replace(/:/gi, "\\:");
idExpand = '#{id:imgExpand}'.replace(/:/gi, "\\:");
dojo.query('#' + idCollapse).toggleClass('hidden');
dojo.query('#' + idExpand).toggleClass('hidden');

var dvID = '#{id:dataView1}';
var detailID = dvID + '_detail';
dojo.byId(detailID).style.display='block';

Optionally Hide the Built-In Link

Now that you have your own link to expand and collapse, you may want to hide the built-in link.

You can hide the built in link that the Data View provides to expand/collapse, you can add this css:

a img.lotusIconShow, a img.lotusIconHide {
  display:none;
}

The code looks for all images with the class of lotusIconShow or lotusIconHide within a link and hides them.


Dojo Data Grids – Sample Database on OpenNTF

$
0
0

I’ve added a demo database with 14 dojo grid samples to OpenNTF.

http://www.openntf.org/Internal/home.nsf/project.xsp?action=openDocument&name=Dojo%20Data%20Grids%20in%20XPages

The application includes 14 demo grids that implement several features and variations of Dojo Data Grids in XPages.

  1. Basic Features
  2. Sorting – Only allow even-numbered columns to sort
  3. Opening Documents
  4. Full-Text Search
  5. Field-Specific Search
  6. Editable Columns – Including highlighting edited rows
  7. HTML and Icon Columns
  8. Enhanced Grid with Drag and Drop plugin
  9. Enhanced Grid with Filter plugin
  10. Enhanced Grid with Print plugin
  11. Enhanced Grid with Export plugin
  12. Enhanced Grid with Context Menu plugin
  13. Categorized Tree Grid
  14. Categorized Tree Grid with Totals

Tip: Finding All Properties and Methods Available for XPages Components

$
0
0

As any XPages developer (especially one with a history of Notes development) knows, the documentation isn’t as – (ahem) – thorough as it could be. However, there are two great resources that you may not be aware of that are very helpful in finding out the available properties and methods of XPages components.

XPages Controls Documentation

The XPages Controls Documentation on openNTF is an excellent way to find out about properties of XPages components, including Extension Library components. It even includes a hierarchical structure so you can see what properties are inherited.

When I’m looking for a method to access a property value, I generally follow these steps:

  1. Check the Domino Designer Help
  2. Check the XPages Controls Documentation and start guessing what corresponding method names might be, because they’re often consistent. For a property called foo, I’d try getFoo()
  3. Dig into the Java source for the component and review it’s provided and inherited methods via the class hierarchy

Using F4 to Locate Java Class Hierarchy

In this excellent NotesIn9 video (episode 34), Paul Withers shows an invaluable technique for locating the underlying Java objects generated by XPages components and how to track down the source to find the methods that are available.

You can open Package Explorer, review the source of an XPage and look for a reference to creating your component. Then look for the name of the Java class being created, highlight it, and hit F4, which opens that class in the hierarchy view. There, you can view the methods that it implements; you can also go up the hierarchy to find what it inherits from other classes.

It also shows how to use the class name that you’ve located in order to set a variable type so you can get content assist for that object.


Viewing all 216 articles
Browse latest View live